Merge branch 'develop' into features/JAL-1723_sequenceReport
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 31 Oct 2016 10:25:06 +0000 (10:25 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 31 Oct 2016 10:25:06 +0000 (10:25 +0000)
Conflicts:
src/jalview/io/SequenceAnnotationReport.java

595 files changed:
.checkstyle [new file with mode: 0644]
.classpath
AUTHORS
CITATION [new file with mode: 0644]
RELEASE
THIRDPARTYLIBS
appletlib/plugin.jar [deleted file]
build.xml
doc/AddingGroovySupport.html
doc/building.html
examples/appletDeployment.html
examples/appletParameters.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 [new file with mode: 0644]
examples/groovy/multipleFeatureAnnotations.groovy [new file with mode: 0644]
examples/groovy/printtitle.groovy
examples/index.html
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/simpleGff3.gff
examples/testdata/test.html
examples/testdata/test_fts_data_columns.conf [new file with mode: 0644]
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/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 [new file with mode: 0644]
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/selectfetchdb.gif
help/html/features/seqfeatures.html
help/html/features/seqfetch.html
help/html/features/seqmappings.html
help/html/features/sifts_mapping_output.png [new file with mode: 0644]
help/html/features/siftsmapping.html [new file with mode: 0644]
help/html/features/splitView.html
help/html/features/structurechooser.html
help/html/features/uniprotqueryfields.html [new file with mode: 0644]
help/html/features/uniprotseqfetcher.png [new file with mode: 0644]
help/html/features/uniprotsequencefetcher.html [new file with mode: 0644]
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/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
lib/VARNAv3-93.jar
lib/castor-1.1-cycle-xml.jar
lib/groovy-all-1.8.2.jar [deleted file]
lib/groovy-all-2.4.6-indy.jar [new file with mode: 0644]
lib/min-jabaws-client-2.1.0.jar
lib/quaqua-filechooser-only-8.0.jar
lib/xercesImpl.jar [changed mode: 0755->0644]
resources/authors.props
resources/embl_mapping.xml
resources/fts/pdb_data_columns.txt [new file with mode: 0644]
resources/fts/uniprot_data_columns.txt [new file with mode: 0644]
resources/images/blank_16x16_placeholder.png [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
resources/uniprot_mapping.xml
schemas/jalview.xsd
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/ChimeraManager.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/Grouping.java
src/jalview/analysis/NJTree.java
src/jalview/analysis/Profile.java [new file with mode: 0644]
src/jalview/analysis/ResidueCount.java [new file with mode: 0644]
src/jalview/analysis/Rna.java
src/jalview/analysis/SeqsetUtils.java
src/jalview/analysis/SequenceIdMatcher.java
src/jalview/analysis/StructureFrequency.java
src/jalview/analysis/scoremodels/FeatureScoreModel.java
src/jalview/api/AlignCalcManagerI.java
src/jalview/api/AlignCalcWorkerI.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/AlignmentPanel.java
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/AnnotationRowFilter.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/FeatureColourChooser.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SequenceRenderer.java
src/jalview/appletgui/SliderPanel.java
src/jalview/appletgui/TreeCanvas.java
src/jalview/appletgui/UserDefinedColours.java
src/jalview/bin/ArgsParser.java [new file with mode: 0644]
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/AlignmentView.java
src/jalview/datamodel/CigarBase.java
src/jalview/datamodel/ColumnSelection.java
src/jalview/datamodel/DBRefEntry.java
src/jalview/datamodel/DBRefSource.java
src/jalview/datamodel/FeatureProperties.java
src/jalview/datamodel/HiddenSequences.java
src/jalview/datamodel/Mapping.java
src/jalview/datamodel/MappingType.java
src/jalview/datamodel/PDBEntry.java
src/jalview/datamodel/SeqCigar.java
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/EmblFeature.java
src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java [deleted file]
src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java [deleted file]
src/jalview/datamodel/xdb/embl/EmblFile.java
src/jalview/datamodel/xdb/embl/EmblSequence.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 [new file with mode: 0644]
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/paradise/Annotate3D.java
src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java
src/jalview/ext/so/SequenceOntology.java
src/jalview/fts/api/FTSData.java [moved from src/jalview/datamodel/xdb/embl/BasePosition.java with 60% similarity]
src/jalview/fts/api/FTSDataColumnI.java [new file with mode: 0644]
src/jalview/fts/api/FTSRestClientI.java [new file with mode: 0644]
src/jalview/fts/api/GFTSPanelI.java [new file with mode: 0644]
src/jalview/fts/core/DecimalFormatTableCellRenderer.java [new file with mode: 0644]
src/jalview/fts/core/FTSDataColumnPreferences.java [moved from src/jalview/jbgui/PDBDocFieldPreferences.java with 59% similarity]
src/jalview/fts/core/FTSRestClient.java [new file with mode: 0644]
src/jalview/fts/core/FTSRestRequest.java [moved from src/jalview/ws/uimodel/PDBRestRequest.java with 79% similarity]
src/jalview/fts/core/FTSRestResponse.java [new file with mode: 0644]
src/jalview/fts/core/GFTSPanel.java [new file with mode: 0644]
src/jalview/fts/service/pdb/PDBFTSPanel.java [new file with mode: 0644]
src/jalview/fts/service/pdb/PDBFTSRestClient.java [new file with mode: 0644]
src/jalview/fts/service/uniprot/UniProtFTSRestClient.java [new file with mode: 0644]
src/jalview/fts/service/uniprot/UniprotFTSPanel.java [new file with mode: 0644]
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/BlogReader.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/DasSourceBrowser.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureColourChooser.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/FontChooser.java
src/jalview/gui/Help.java
src/jalview/gui/IdCanvas.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/JalviewDialog.java
src/jalview/gui/OptsAndParamsPage.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PDBSearchPanel.java [deleted file]
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/RedundancyPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/SequenceRenderer.java
src/jalview/gui/SliderPanel.java
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/StructureViewer.java
src/jalview/gui/TextColourChooser.java
src/jalview/gui/TreeCanvas.java
src/jalview/gui/TreePanel.java
src/jalview/gui/VamsasApplication.java
src/jalview/io/AlignFile.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/FormatAdapter.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JSONFile.java
src/jalview/io/MSFfile.java
src/jalview/io/PDBFeatureSettings.java
src/jalview/io/PfamFile.java
src/jalview/io/RnamlFile.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 [new file with mode: 0644]
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/packed/ParsePackedSet.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/GPDBSearchPanel.java [deleted file]
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GSequenceLink.java
src/jalview/jbgui/GStructureChooser.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/ScaleRenderer.java [new file with mode: 0644]
src/jalview/renderer/seqfeatures/FeatureRenderer.java
src/jalview/schemabinding/version2/.castor.cdr
src/jalview/schemabinding/version2/JSeq.java
src/jalview/schemabinding/version2/descriptors/AnnotationColoursDescriptor.java
src/jalview/schemabinding/version2/descriptors/FeaturesDescriptor.java
src/jalview/schemabinding/version2/descriptors/JSeqDescriptor.java
src/jalview/schemabinding/version2/descriptors/JalviewUserColoursDescriptor.java
src/jalview/schemabinding/version2/descriptors/UserColourSchemeDescriptor.java
src/jalview/schemabinding/version2/descriptors/VamsasModelDescriptor.java
src/jalview/schemes/Blosum62ColourScheme.java
src/jalview/schemes/ColourSchemeI.java
src/jalview/schemes/FeatureColour.java [new file with mode: 0644]
src/jalview/schemes/FeatureColourAdapter.java [deleted file]
src/jalview/schemes/FeatureSettingsAdapter.java
src/jalview/schemes/FollowerColourScheme.java
src/jalview/schemes/GraduatedColor.java [deleted file]
src/jalview/schemes/PIDColourScheme.java
src/jalview/schemes/RNAHelicesColour.java
src/jalview/schemes/RNAHelicesColourChooser.java
src/jalview/schemes/ResidueColourScheme.java
src/jalview/schemes/ResidueProperties.java
src/jalview/schemes/TCoffeeColourScheme.java
src/jalview/schemes/UserColourScheme.java
src/jalview/structure/StructureImportSettings.java [new file with mode: 0644]
src/jalview/structure/StructureMapping.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/structure/StructureViewSettings.java [deleted file]
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 [new file with mode: 0644]
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/viewmodel/seqfeatures/FeatureRendererSettings.java
src/jalview/workers/AlignCalcManager.java
src/jalview/workers/AlignCalcWorker.java
src/jalview/workers/AlignmentAnnotationFactory.java [new file with mode: 0644]
src/jalview/workers/AnnotationProviderI.java [new file with mode: 0644]
src/jalview/workers/AnnotationWorker.java [new file with mode: 0644]
src/jalview/workers/ColumnCounterWorker.java [new file with mode: 0644]
src/jalview/workers/ComplementConsensusThread.java
src/jalview/workers/ConsensusThread.java
src/jalview/workers/ConservationThread.java
src/jalview/workers/FeatureCounterI.java [new file with mode: 0644]
src/jalview/workers/StrucConsensusThread.java
src/jalview/ws/AWSThread.java
src/jalview/ws/DBRefFetcher.java
src/jalview/ws/DasSequenceFeatureFetcher.java
src/jalview/ws/SequenceFetcher.java
src/jalview/ws/SequenceFetcherFactory.java [new file with mode: 0644]
src/jalview/ws/dbsources/EmblXmlSource.java
src/jalview/ws/dbsources/PDBRestClient.java [deleted file]
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/Xfam.java
src/jalview/ws/dbsources/das/datamodel/DasSourceRegistry.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws1/MsaWSClient.java
src/jalview/ws/jws1/MsaWSThread.java
src/jalview/ws/jws1/SeqSearchWSClient.java
src/jalview/ws/jws1/SeqSearchWSThread.java
src/jalview/ws/jws2/AADisorderClient.java
src/jalview/ws/jws2/AbstractJabaCalcWorker.java
src/jalview/ws/jws2/JPred301Client.java
src/jalview/ws/jws2/Jws2Client.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/jws2/MsaWSThread.java
src/jalview/ws/jws2/RNAalifoldClient.java
src/jalview/ws/jws2/SequenceAnnotationWSClient.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
src/jalview/ws/uimodel/PDBRestResponse.java [deleted file]
test/MCview/AtomTest.java
test/MCview/PDBChainTest.java
test/MCview/PDBfileTest.java
test/jalview/analysis/AAFrequencyTest.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/CrossRefTest.java
test/jalview/analysis/DnaTest.java
test/jalview/analysis/GroupingTest.java
test/jalview/analysis/ResidueCountTest.java [new file with mode: 0644]
test/jalview/analysis/RnaTest.java
test/jalview/analysis/SeqsetUtilsTest.java [new file with mode: 0644]
test/jalview/analysis/SequenceIdMatcherTest.java
test/jalview/analysis/scoremodels/FeatureScoreModelTest.java
test/jalview/bin/ArgsParserTest.java [new file with mode: 0644]
test/jalview/bin/CacheTest.java [new file with mode: 0644]
test/jalview/commands/EditCommandTest.java
test/jalview/controller/AlignViewControllerTest.java [new file with mode: 0644]
test/jalview/datamodel/AlignedCodonFrameTest.java
test/jalview/datamodel/AlignmentAnnotationTests.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/ColumnSelectionTest.java
test/jalview/datamodel/DBRefEntryTest.java
test/jalview/datamodel/HiddenSequencesTest.java [new file with mode: 0644]
test/jalview/datamodel/MappingTest.java
test/jalview/datamodel/MappingTypeTest.java
test/jalview/datamodel/PDBEntryTest.java
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/EmblFileTest.java
test/jalview/datamodel/xdb/embl/EmblTestHelper.java [new file with mode: 0644]
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/JmolViewerTest.java
test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java [new file with mode: 0644]
test/jalview/ext/paradise/TestAnnotate3D.java
test/jalview/ext/rbvi/chimera/JalviewChimeraView.java
test/jalview/ext/so/SequenceOntologyTest.java
test/jalview/fts/core/FTSRestClientTest.java [new file with mode: 0644]
test/jalview/fts/service/pdb/PDBFTSPanelTest.java [moved from test/jalview/gui/PDBSearchPanelTest.java with 79% similarity]
test/jalview/fts/service/pdb/PDBFTSRestClientTest.java [moved from test/jalview/ws/dbsources/PDBRestClientTest.java with 59% similarity]
test/jalview/gui/AlignFrameTest.java [new file with mode: 0644]
test/jalview/gui/AlignViewportTest.java
test/jalview/gui/AnnotationChooserTest.java
test/jalview/gui/JAL1353bugdemo.java
test/jalview/gui/MouseEventDemo.java [new file with mode: 0644]
test/jalview/gui/PaintRefresherTest.java
test/jalview/gui/PopupMenuTest.java
test/jalview/gui/StructureChooserTest.java
test/jalview/gui/StructureViewerTest.java [new file with mode: 0644]
test/jalview/io/1a70.pdb [new file with mode: 0644]
test/jalview/io/2nq2.pdb [new file with mode: 0644]
test/jalview/io/AnnotatedPDBFileInputTest.java
test/jalview/io/AnnotationFileIOTest.java
test/jalview/io/CrossRef2xmlTests.java [new file with mode: 0644]
test/jalview/io/FeaturesFileTest.java
test/jalview/io/FileIOTester.java
test/jalview/io/FormatAdapterTest.java [new file with mode: 0644]
test/jalview/io/IdentifyFileTest.java
test/jalview/io/JSONFileTest.java
test/jalview/io/Jalview2xmlBase.java [new file with mode: 0644]
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/JalviewExportPropertiesTests.java
test/jalview/io/NewickFileTests.java
test/jalview/io/PfamFormatInputTest.java
test/jalview/io/RNAMLfileTest.java
test/jalview/io/SequenceAnnotationReportTest.java [new file with mode: 0644]
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 [new file with mode: 0644]
test/jalview/schemes/ResidueColourSchemeTest.java [new file with mode: 0644]
test/jalview/schemes/UserColourSchemeTest.java [new file with mode: 0644]
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 [new file with mode: 0644]
test/jalview/util/FormatTest.java [new file with mode: 0644]
test/jalview/util/MapListTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/util/QuickSortTest.java
test/jalview/util/SparseCountTest.java [new file with mode: 0644]
test/jalview/util/StringUtilsTest.java
test/jalview/util/UrlLinkTest.java [new file with mode: 0644]
test/jalview/workers/AlignCalcManagerTest.java [new file with mode: 0644]
test/jalview/ws/PDBSequenceFetcherTest.java
test/jalview/ws/SequenceFetcherTest.java
test/jalview/ws/dbsources/UniprotTest.java
test/jalview/ws/dbsources/XfamFetcherTest.java [new file with mode: 0644]
test/jalview/ws/ebi/EBIFetchClientTest.java [new file with mode: 0644]
test/jalview/ws/gui/Jws2ParamView.java
test/jalview/ws/jabaws/DisorderAnnotExportImport.java
test/jalview/ws/jabaws/JalviewJabawsTestUtils.java
test/jalview/ws/jabaws/JpredJabaStructExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/jws2/ParameterUtilsTest.java
test/jalview/ws/seqfetcher/DbRefFetcherTest.java
test/jalview/ws/sifts/SiftsClientTest.java
utils/BufferedLineReader.java [new file with mode: 0644]
utils/HelpLinksChecker.java [new file with mode: 0644]
utils/InstallAnywhere/Jalview.iap_xml
utils/JettyExamplesDir.java
utils/MessageBundleChecker.java [new file with mode: 0644]
utils/checkstyle/README.txt [new file with mode: 0644]
utils/checkstyle/checkstyle-suppress.xml [new file with mode: 0644]
utils/checkstyle/checkstyle.xml [new file with mode: 0644]
utils/checkstyle/import-control.xml [new file with mode: 0644]
utils/getJavaVersion.java
utils/help2Website.java
utils/i18nAnt.xml

diff --git a/.checkstyle b/.checkstyle
new file mode 100644 (file)
index 0000000..0329bb7
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+  <local-check-config name="JalviewCheckstyle" location="utils/checkstyle/checkstyle.xml" type="project" description="">
+    <additional-data name="protect-config-file" value="false"/>
+  </local-check-config>
+  <fileset name="source" enabled="true" check-config-name="JalviewCheckstyle" local="true">
+    <file-match-pattern match-pattern="src/.*.java" include-pattern="true"/>
+    <file-match-pattern match-pattern="resources/.*.properties" include-pattern="true"/>
+  </fileset>
+  <filter name="NonSrcDirs" enabled="false"/>
+</fileset-config>
index cad9e2b..6583992 100644 (file)
@@ -39,7 +39,6 @@
        <classpathentry kind="lib" path="lib/jdas-1.0.4.jar"/>
        <classpathentry kind="lib" path="lib/spring-core-3.0.5.RELEASE.jar"/>
        <classpathentry kind="lib" path="lib/spring-web-3.0.5.RELEASE.jar"/>
-       <classpathentry kind="lib" path="lib/groovy-all-1.8.2.jar"/>
        <classpathentry kind="lib" path="lib/min-jabaws-client-2.1.0.jar" sourcepath="/clustengine"/>
        <classpathentry kind="lib" path="lib/json_simple-1.1.jar" sourcepath="/Users/jimp/Downloads/json_simple-1.1-all.zip"/>
        <classpathentry kind="lib" path="lib/slf4j-api-1.7.7.jar"/>
@@ -69,5 +68,6 @@
        <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
        <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
+       <classpathentry kind="lib" path="lib/groovy-all-2.4.6-indy.jar"/>
        <classpathentry kind="output" path="classes"/>
 </classpath>
diff --git a/AUTHORS b/AUTHORS
index 30db2a1..f0b4787 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -7,7 +7,7 @@ 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 6th Oct 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 ! 
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..702d6e7 100644 (file)
--- a/RELEASE
+++ b/RELEASE
@@ -1,2 +1,2 @@
-jalview.release=Release_2_9_0b1_Branch
-jalview.version=2.9.0b2
+jalview.release=Release_2_10_0_Branch
+jalview.version=2.10.0b1
index c6c817a..31ad2f5 100644 (file)
@@ -21,6 +21,7 @@ commons-discovery.jar
 commons-logging-1.1.1.jar
 commons-logging.jar
 commons-net-3.3.jar
+groovy-all-2.4.6-indy.jar      APL 2.0 License - downloaded and extracted from https://dl.bintray.com/groovy/maven/apache-groovy-binary-2.4.6.zip
 httpclient-4.0.3.jar
 httpcore-4.0.1.jar
 httpmime-4.0.3.jar
@@ -45,7 +46,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,6 +59,3 @@ 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.
-
diff --git a/appletlib/plugin.jar b/appletlib/plugin.jar
deleted file mode 100644 (file)
index d19dcc5..0000000
Binary files a/appletlib/plugin.jar and /dev/null differ
index b23293f..1d4878b 100755 (executable)
--- a/build.xml
+++ b/build.xml
@@ -27,7 +27,9 @@
     <echo message="build - compiles all necessary files for Application" />
     <echo message="makedist - compiles and places all necessary jar files into directory dist" />
     <echo message="makefulldist - signs all jar files and builds jnlp file for full distribution" />
-    <echo message="              this needs a keystore and key. Add -Dtimestamp to timestamp signed jars"/>
+    <echo message="              this needs a keystore and key."/>
+    <echo message="              Add -Dtimestamp to timestamp signed jars"/>
+    <echo message="              -Djalview.keyalg and -Djalview.keydig are SHA1/SHA1withRSA"/>
     <echo message="              See docs/building.html for more information." />
     <echo message="compileApplet - compiles all necessary files for Applet" />
     <echo message="makeApplet - compiles, then packages and obfuscates the Applet" />
@@ -88,6 +90,9 @@
     <!-- locally valid proxy for signing with external time server -->
     <property name="proxyPort" value="80"/>
     <property name="proxyHost" value="sqid"/>
+    <!-- key sign/digest algorithms -->
+    <property name="jalview.keyalg" value="SHA1withRSA" description="key algorithm for signing"/>
+    <property name="jalview.keydig" value="SHA1" description="algorithm for jar digest"/>
 
     <!-- default TestNG groups to run -->
     <property name="testng-groups" value="Functional" />
   </target>
 
   <target name="-jarsignwithtsa" depends="makedist,preparejnlp" if="timestamp">
-    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="SHA1withRSA"
+    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}"
       tsaproxyhost="${proxyHost}" tsaproxyport="${proxyPort}" tsaurl="${jalview.tsaurl}">
       <fileset dir="${packageDir}">
         <include name="*.jar" />
     </signjar>
   </target>
   <target name="-jarsignnotsa" depends="makedist,preparejnlp" unless="timestamp">
-    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="SHA1withRSA">
+    <signjar storepass="${jalview.keystore.pass}" keypass="${jalview.key.pass}" keystore="${jalview.keystore}" alias="${jalview.key}" lazy="false" verbose="false" sigalg="${jalview.keyalg}" digestalg="${jalview.keydig}">
       <fileset dir="${packageDir}">
         <include name="*.jar" />
       </fileset>
         </information>
         <resources>
           <j2se version="${j2sev}" initial_heap_size="${inih}" max_heap_size="${maxh}" />
+          <jar main="true" href="jalview.jar"/>
           <fileset dir="${packageDir}">
-            <include name="jalview.jar" />
-          </fileset>
-          <fileset dir="${packageDir}">
+            <exclude name="jalview.jar" />
             <include name="*.jar" />
             <include name="*_*.jar" />
-            <exclude name="jalview.jar" />
             <exclude name="*jnilib.jar" />
           </fileset>
           <property name="jalview.version" value="${JALVIEW_VERSION}" />
   </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}" />
-    <pathelement location="appletlib/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=".">
       <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 41e34ce..e3e453f 100644 (file)
 </title>
 <body>
 <h1>
-Adding Groovy Support to Jalview
+Groovy Support in Jalview
 </h1>
 <p>
-There is currently no scripting language 
-extension within Jalview, in part because a 
-scripting API has not yet been developed.
-</p>
-<p>It is, however, really easy to embed scripting
-engines like groovy. If groovy is detected on the 
-classpath, a new menu entry on the Desktop's Tools 
-menu will open the GroovyShell.
+  <a href="http://www.groovy-lang.org">Groovy</a> has been bundled with the Jalview desktop since circa 2012. The program supports interactive execution of groovy scripts via the Groovy Console, and command line execution via the '-groovy' option. The main source for documentation about Groovy in Jalview is the <a href="http://www.jalview.org/help/html/features/groovy.html">online help pages</a>.
 </p>
 <p>Here are some scripts to get you started:</p>
 <ul><li>Getting the title, alignment and first sequence from the current alignFrame<br>
 <pre>
-def alf = Jalview.getAlignframes();
+def alf = Jalview.getAlignFrames();
 print alf[0].getTitle();
 def alignment = alf[0].viewport.alignment;
 def seq = alignment.getSequenceAt(0);
 </pre>
 </li>
 </ul>
-<h1>Getting Groovy...</h1>
-<p>
-You need the core groovy jars which include the GroovyShell. The easiest way of doing
-this is to add the groovy-all-*.jar to the lib directory whose path is given in the java.ext.dirs property.</p>
-<p>The is obtained from the <em>embedded</em> directory within the <a 
-href="http://dist.codehaus.org/groovy/distributions"/>groovy distribution</a>).
-</p>
 <h2>TODO</h2>
 <p>
 Using Java class methods from Groovy is straightforward, but currently, there isn't a set of easy to use methods for the jalview objects. A Jalview Scripting API needs to be developed to make this easier.</p>
index 3a39691..ecde4d8 100755 (executable)
 <p>
 You will need the following (hopefully):<br>
 <ul>
-<li>Java development kit (JDK1.6 is the recommended platform for developing with Jalview, although JDK1.7 seems to work too!).</li>
-<li>Ant (we think 1.5.4 is quite sufficient to use the simple build
-file supplied, and it seems to work with later versions e.g. 1.7).</li>
+<li>Java development kit (JDK1.8 is now the recommended platform for developing with Jalview.</li>
+<li>Ant (1.7 or later will be needed for some of the jarsigning tools).</li>
 </ul>
 With any luck, after setting your paths and JAVA_HOME correctly, you
 just need to change to the Jalview directory and run ant (this works
-from JBuilder and eclipse too, but NetBeans is a bit trickier).
+from eclipse too, but NetBeans is a bit trickier).
 <pre>
    ant
 </pre>
@@ -46,23 +45,24 @@ build target in ant to make the signed jar files in a directory called
 dist. But first you need to make your own key:
 <p><strong>Making your own key</strong></p>
 
-<p>The ant 'makefulldist' target assumes that a keystore exists in a
-directory 'keys'. To make a key accessible using the default settings
-in the build.xml file then make the keys directory and add the
-jarsigner key with the following :
-</p>
-<pre>
-mkdir keys
-keytool -genkey -keystore keys/.keystore -keypass alignmentisfun
--storepass alignmentisfun -alias jalview
- (you will have to answer some personal questions here)
-ant makedist
- (should eventually generate a Jalview.jnlp file
-  in ./dist along with a set of signed jars using the jalview
-  key)
-</pre>
-
-       <p>
+  <p>The ant 'makefulldist' target assumes that a keystore exists in
+    a directory 'keys'. To make a key accessible using the default
+    settings in the build.xml file then make the keys directory and add
+    the jarsigner key with the following :</p>
+  <pre>mkdir keys</pre>
+  <pre>keytool -genkey -keystore keys/.keystore -keypass alignmentisfun
+  -storepass alignmentisfun -sigalg SHA1withRSA -keyalg RSA -alias jalview</pre>
+  <em>(you will have to answer some personal questions here)</em>
+  <pre>ant makedist -DWebStartLocation="file://.pathtojalviewsource./dist" -Dapplication.codebase="*"</pre>
+  <p>This should eventually generate a jalview.jnlp file in ./dist
+    along with a set of signed jars using the jalview key). In order to
+    test locally via webstart you'll now need to add 'file:/' to your
+    java webstart security exception list. Then:</p>
+  <pre>javaws file://.pathtojalviewsource./dist/jalview.jnlp</pre>
+  <p>Please remember to remove that entry afterwards, since it will leave
+  your system vulnerable to malicious code.
+  </p>
+  <p>
                <strong>Building the JalviewLite applet<br>
                </strong> The JalviewLite applet is compiled using a subset of the packages in
                the src directory (specifically: MCView, and jalview.{datamodel,
index a7653ed..7fcca00 100644 (file)
 -->
 
 
-<div id="view_decorated" name="view_decorated"  style="margin:8px; padding:10px; border: 2px solid red; text-align:center; display:none;"><b>Click <a href="index.html#appletDeployment"> here</a> to view decorated page</b></div>
+<div id="view_decorated" name="view_decorated"  style="margin:8px; padding:10px; border: 2px solid red; text-align:center; display:none;"><b>Click <a href="index.html#appletDeployment"> here </a> to view decorated page</b></div>
 
 <!-- content start -->
-<h2><a name="appletdeploymentnotes"/>Notes on applet deployment</h2>
-        <ul>
-          <li>Package all your data files into a single (or multiple) zip / jar 
-            files. This is very useful to reduce download time of large data files. 
-            The applet archive tag can take multiple entries separated by commas, 
-            eg<br>
-            <pre>&lt;applet code=&quot;jalview.bin.JalviewLite&quot;<em><strong> 
-            archive=&quot;jalviewApplet.jar, mydata.zip&quot;</strong></em>&gt;
-            </pre></li>
-          <li> Use Jalview for input to a HTML form. For an example of how to 
-            code this using Javascript, click <a href="javascript:doSubmit('formComplete')">here</a>. 
-            <br>
-          </li>
-          <li>Embed Jalview into the web page, without the &quot;Start Jalview&quot; 
-            button by setting the embed parameter to true;<br>
-            &lt;param name=&quot;embedded&quot;
-          value=&quot;true&quot;&gt; </li>
-       <li><a href="javascript:doSubmit('appletParameters')">View full list of supported parameters here.</a> </li>
-        </ul>
-        
-        <p><strong>**NEW FEATURES** in Jalview 2.9</strong></p> 
+<h2 name="appletDeployment"> Notes on applet deployment</h2>
+<table width=80% border="1">
+  <tr><th colspan="2" align="center">Required Dependency Downloads</th></tr>
+  <tr>
+    <th>Dependency</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/jalviewApplet.jar">JalviewApplet.jar</a> </td>
+    <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>Jmol Applet Jar</td>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/java-json.jar">java-json.jar</a></td>
+    <td>Required for BioJSON Generation</td>
+  </tr>
+  <tr>
+    <td><a href="http://www.jalview.org/builds/develop/examples/json_simple-1.1.jar">json_simple-1.1.jar</a></td>
+    <td>Required for BioJSON Generation</td>
+  </tr>
+</table>
+
+<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;param name="permissions" value="sandbox" /&gt;
+       &lt;param name="file" value="plantfdx.fa" /&gt;
+       &lt;param name="features" value="plantfdx.features" /&gt;
+       &lt;param name="userDefinedColour" value="C=yellow; R,K,H=FF5555; D,E=5555FF" /&gt;
+       &lt;param name="showFullId" value="false" /&gt;
+       &lt;param name="embedded" value="true" /&gt;
+       &lt;param name="linkLabel_1" value="Uniprot" /&gt;
+       &lt;param name="linkUrl_1"      value="http://www.uniprot.org/uniprot/$SEQUENCE_ID$" /&gt;
+       &lt;param name="linkLabel_2" value="EMBL-EBI Search" /&gt;
+       &lt;param name="linkUrl_2"      value="http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$SEQUENCE_ID$" /&gt;
+       &lt;param name="APPLICATION_URL" value="http://www.jalview.org/services/launchApp" /&gt;
+&lt;/applet&gt;
+</code></pre> 
+
+
+
+
+<ul>
+       <li>View full list of <a href="javascript:doSubmit('appletParameters')"> supported applet parameters here.</a></li>
+       <li>Package all your data files into a single (or multiple) zip /
+               jar files. This is very useful to reduce download time of large data
+               files. The applet archive tag can take multiple entries separated by
+               commas, eg<br> <pre>&lt;applet code=&quot;jalview.bin.JalviewLite&quot;<em><strong> archive=&quot;jalviewApplet.jar, mydata.zip&quot;</strong></em>&gt;
+            </pre>
+       </li>
+       <li>Use Jalview for input to a HTML form. For an example of how to
+               code this using Javascript, click <a
+               href="javascript:doSubmit('formComplete')">here</a>. <br>
+       </li>
+       <li>Embed Jalview into the web page, without the &quot;Start
+               Jalview&quot; button by setting the embed parameter to true;<br>
+               &lt;param name=&quot;embedded&quot; value=&quot;true&quot;&gt;
+       </li>
+       <li>For more examples, see the links to the left.</li>
+</ul>
+
+<table border="1" width=80%>
+       <tr><th colspan="2">Applet Release History</th>
+       <tr>
+               <th>Release</th>
+
+               <th>New Features / required changes</th>
+       </tr>
+       <tr>
+               <td><strong>2.9<br>(Latest)</strong></td>
+               <td>
         <ul>
         <li>Split Views for cDNA and Protein alignments<br/>Specify second alignment with 'file2' parameter, and set cDNA/Protein column scaling with scaleProteinAsCdna
         </li>
             <pre>archive=&quot;jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,<font color="red">java-json.jar,json_simple-1.1.jar</font>&quot;</pre>              
        </li>
         </ul>
-        </p>
-        <p><strong>**NEW FEATURES** in Jalview 2.8</strong></p> 
-        <ul>
+               </td>
+       </tr>
+       <tr>
+               <td><strong>2.8</strong></td>
+               <td><ul>
         <li>Normalised sequence logo display
         </li>
         <li>RNA secondary structure annotation row
             original Jalview structure viewer will still be available. <br>
           </li>
           
-        </ul>
-        <p><strong>**NEW FEATURES** in Jalview 2.7</strong></p>
-        <ul>
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.7</strong></td>
+               <td><ul>
         <li>Javascript callbacks capabilities<ul><li>oninit parameter and methods for registering javascript handlers for selections, mouseovers and linking to Jmol applets on the page.</li>
         <li>To use javascript callbacks, ensure the applet tag includes the '<a href="http://download.oracle.com/javase/6/docs/technotes/guides/plugin/developer_guide/java_js.html">mayscript</a>' attribute - either as a parameter (&lt;param name="mayscript" value="true"/;gt;) or as a bare attribute in the applet html tag).</li></ul>
         </li>
           the Jmol binary distribution available at the Jmol Sourceforge site, 
           or <a href="JmolApplet-12.1.13.jar">download the Jmol applet from here</a></li>
           <li>Minimum recommended version of Java runtime for the applet is now 1.5 (JalviewLite v2.6 without the Jmol viewer may work ok on earlier Java environments but compatibility can no-longer be guaranteed).</li>
-  </ul>
-        <br><strong>**NEW FEATURES** in Jalview 2.5</strong></p>
-        <ul>
-        <li>New parameters to control display of tree annotation, width of alignment columns, and to disable the jalview button and check for Jmol on startup.</li>
-  </ul>        
-        <br><strong>**NEW FEATURES** in Jalview 2.4</strong></p>
-        <ul>
+  </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.5</strong></td>
+               <td><ul>
+        <li>New parameters to control display of tree annotation, width of alignment columns, and to disable the jalview button and check for Jmol on startup.</li>  </ul>
+    </td>
+       </tr>
+       <tr>
+               <td><strong>2.4</strong></td>
+               <td><ul>
         <li>New applet API methods for feature display control, views, and obtaining current selection via javascript.</li>
           <li>Group show and hide parameters:
         &quot;showfeaturegroups&quot; and
         <li>&quot;debug&quot; parameter to control verbosity of the applet's console output.</li>
         <li>&quot;showbutton&quot; parameter to disable launch button and open JalviewLite immediatly.</li>
         <li>&quot;nojmol&quot; parameter to disable check for Jmol classes.</li>
-        </ul><br>
-        <strong>**NEW FEATURES** in Jalview 2.3</strong></p>
-        <ul>
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.3</strong></td>
+               <td><ul>
           <li>Note that Parameter &quot;PDBFile&quot; now takes 
             the PDB file followed by a space separated list of alignment sequence 
             ids to associate the structure to. It is also possible to associate 
           <li>Note parameter &quot;PDBSeq&quot; is no longer required.<br>
           </li>
           <li>Jalview 2.3 was updated to work with Jmol 11. See the <a href="/development">versions archive if you want to download the old Jmol applet</a>.</li> 
-            <p>&nbsp;</p>
-          </li>
-        </ul>
-        <strong>**NEW FEATURES** in Jalview 2.1</strong> 
-        <ul>
+          
+        </ul></td>
+       </tr>
+       <tr>
+               <td><strong>2.1</strong></td>
+               <td><ul>
           <li>Jalview Applet can read and display JNet secondary structure annotation 
             directly via the <strong>jnetfile</strong> parameter. <br>
           </li>
             &lt;param name=&quot;sequence2&quot; value=&quot;FER1_PEA/14-29 TSFLRTQPMPMSVTTT&quot;&gt;<br>
             </pre>(All the usual Jalview File formats are valid, however each 
             new line in an alignment file must be entered as a parameter)</li>
-        </ul>
+        </ul></td>
+       </tr>
+</table>
+
+        
 <!-- content end -->
index 433f5a9..cc95ecb 100644 (file)
@@ -28,7 +28,7 @@ which are described <a href="#parameters"> below</a>. Once initialised,
 the applet can be interacted with <em>via</em> its 
 <a href="javascript:doSubmit('jalviewLiteJs')">Javascript API</a>. 
 </p><p><strong>Issues arising from tightening of Java Security default settings</strong><br/>JalviewLite is provided as a signed applet with 'sandbox' permissions and wildcards that allow it to be run from any website. Unfortunately, earlier versions of Java may not be compatible with these settings. </p>
-    <p>For additional deployment notes, <a href="#appletdeploymentnotes">see below</a>.</p>
+    <p>For additional deployment notes, <a href="javascript:doSubmit('appletDeployment')">see Applet Deployment</a>.</p>
            <p><h2>Applet Parameters</h2><br/>The applet takes the following initialisation parameters.</p>
         <a name="parameters"></a>        <table width="97%" class="borderTable" align="center" >
           <tr> 
index 34118b8..1f65565 100644 (file)
 
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
 </div>
-</div>
-
 <!-- content template start -->
 
 <p align="left">
 <h2>JalviewLite Button Examples</h2>
-Try out JalviewLite by pressing one of the buttons below.<br/>
- For more information on how to use the applet in your website, see the <a href="javascript:doSubmit('appletParameters')"><strong>applet parameters</strong></a> and other documentation in the links to the left.</p>
+Try out JalviewLite by pressing one of the buttons below. 
+  <a href="view-source:http://www.jalview.org/builds/develop/examples/applets.html" target="_blank">View the source for the examples below here</a> (If the link doesn't work on your browser try going to <a href="http://www.jalview.org/builds/develop/examples/applets.html">this page</a> and viewing the page source manually).<br/>
+ For more information on how to use the applet in your website, see the <a href="javascript:doSubmit('appletDeployment')"><strong>applet deployment,</strong></a> <a href="javascript:doSubmit('appletParameters')"><strong>applet parameters,</strong></a> and other documentation in the links to the left.</p>
 <p>&nbsp;</p><div align="center">
   <p align="center">
     <h2>Ferredoxins, chloroplast precursor related UniRef50
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 aa67325..0d5ddf3 100644 (file)
@@ -23,9 +23,6 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
 </div>
 </div>
 
@@ -40,6 +37,7 @@
     <li><a href="plantfdx.annotations">plantfdx.annotations</a> -
       Jalview Alignment Annotations File</li>
   </ul>
+  <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">
index f629312..501c20e 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#"
@@ -260,11 +280,7 @@ jmolInitialize("","JmolApplet-14.2.14_2015.06.11.jar");
   modeltofiles+="1gaq.txt";
 </script> 
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
-</div>
+
 </div>
 
 <!-- content template start -->
index dfadb50..2de9817 100755 (executable)
@@ -1,5 +1,5 @@
 ST-TURN-IIL    blue|255,0,255|absolute|20.0|95.0|below|66.0
-GAMMA-TURN-CLASSIC             red|0,255,255|20.0|95.0|below|66.0
+GAMMA-TURN-CLASSIC     red|0,255,255|20.0|95.0|below|66.0
 BETA-TURN-IR   9a6a94
 BETA-TURN-IL   d6a6ca
 BETA-BULGE     1dc451
@@ -26,73 +26,74 @@ BETA-TURN-IIL       8b5b50
 ST-MOTIF       ac25a1
 
 STARTGROUP     uniprot
+<html><a href="http://pfam.xfam.org/family/PF00111">Pfam family</a></html>     FER_CAPAA       -1      0       0       Pfam
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      77      77      METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER_CAPAA       -1      8       83      Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER_CAPAA       -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER_CAPAA       -1      3       93      Cath
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      124     124     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       FER_CAPAN       -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   FER_CAPAN       -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  FER_CAPAN       -1      45      140     Cath
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      124     124     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       FER1_SOLLC      -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   FER1_SOLLC      -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  FER1_SOLLC      -1      45      140     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_13</a></html>       Q93XJ9_SOLTU    -1      55      130     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_13</a></html>   Q93XJ9_SOLTU    -1      55      130     Pfam
 Ferredoxin_fold Status: True Positive  Q93XJ9_SOLTU    -1      45      140     Cath
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER1_PEA        -1      60      135     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER1_PEA        -1      60      135     Pfam
 Ferredoxin_fold Status: True Positive  FER1_PEA        -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 63_13</a></html>       Q7XA98_TRIPR    -1      63      138     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 63_13</a></html>   Q7XA98_TRIPR    -1      63      138     Pfam
 Ferredoxin_fold Status: True Positive  Q7XA98_TRIPR    -1      53      148     Cath
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      90      90      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      95      95      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      98      98      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      128     128     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 59_13</a></html>       FER1_MESCR      -1      59      134     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 59_13</a></html>   FER1_MESCR      -1      59      134     Pfam
 Ferredoxin_fold Status: True Positive  FER1_MESCR      -1      49      144     Cath
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      89      89      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      97      97      METAL
 Iron-sulfur (2Fe-2S)   FER1_SPIOL      -1      127     127     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 58_13</a></html>       FER1_SPIOL      -1      58      133     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 58_13</a></html>   FER1_SPIOL      -1      58      133     Pfam
 Ferredoxin_fold Status: True Positive  FER1_SPIOL      -1      48      143     Cath
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      77      77      METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER3_RAPSA      -1      8       83      Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_8</a></html>     FER3_RAPSA      -1      8       83      Pfam
 Ferredoxin_fold Status: True Positive  FER3_RAPSA      -1      3       93      Cath
 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>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_8</a></html> FER_BRANA       -1      8       83      Pfam
+<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.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER2_ARATH      -1      60      135     Pfam
-Ferredoxin_fold Status: True Positive  FER2_ARATH      -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_11</a></html>       Q93Z60_ARATH    -1      60      118     Pfam
+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
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_MAIZE      -1      129     129     METAL
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_13</a></html>       FER1_MAIZE      -1      60      135     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_13</a></html>   FER1_MAIZE      -1      60      135     Pfam
 Ferredoxin_fold Status: True Positive  FER1_MAIZE      -1      50      145     Cath
-<html>Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 52_12</a></html>       O80429_MAIZE    -1      52      127     Pfam
+<html>Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 52_12</a></html>   O80429_MAIZE    -1      52      127     Pfam
 Ferredoxin_fold Status: True Positive  O80429_MAIZE    -1      42      137     Cath
 ENDGROUP       uniprot
 
@@ -126,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 91d94f8..9e89990 100644 (file)
@@ -24,9 +24,7 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
+
 </div>
 </div>
 
@@ -35,7 +33,7 @@
 <p>Using the Javascript API to fill out forms using data from JalviewLite
 <br/>Click the Javascript buttons below to interact with the Applet
 instance on the page.</p>
-View the source in your browser to see how it has been done. <br/>
+  <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">
diff --git a/examples/groovy/featureCounter.groovy b/examples/groovy/featureCounter.groovy
new file mode 100644 (file)
index 0000000..9059dd0
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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;
+
+/*
+ * Example script that registers two alignment annotation calculators
+ * - one that counts residues in a column with Pfam annotation
+ * - one that counts only charged residues with Pfam annotation
+ *
+ * To try:
+ * 1. load uniref50.fa from the examples folder
+ * 2. load features onto it from from examples/exampleFeatures.txt
+ * 3. Open this script in the Groovy console.
+ * 4. Either execute this script from the console, or via Calculate->Run Groovy Script
+ * To explore further, try changing this script to count other kinds of occurrences of 
+ * residue and sequence features at columns in an alignment.
+ */
+
+/*
+ * A closure that returns true for any Charged residue
+ */
+def isCharged = { residue ->
+    switch(residue) {
+        case ['D', 'd', 'E', 'e', 'H', 'h', 'K', 'k', 'R', 'r']:
+            return true
+    }
+    false
+} 
+
+/*
+ * A closure that returns 1 if sequence features include type 'Pfam', else 0
+ * Argument should be a list of SequenceFeature 
+ */
+def hasPfam = { features -> 
+    for (sf in features)
+    {
+        /*
+         * Here we inspect the type of the sequence feature.
+         * You can also test sf.description, sf.score, sf.featureGroup,
+         * sf.strand, sf.phase, sf.begin, sf.end
+         * or sf.getValue(attributeName) for GFF 'column 9' properties
+         */
+        if ("Pfam".equals(sf.type))
+        {
+            return true
+        }
+    }
+    false
+}
+
+/*
+ * Closure that computes an annotation based on 
+ * presence of particular residues and features
+ * Parameters are
+ * - the name (label) for the alignment annotation
+ * - the description (tooltip) for the annotation
+ * - a closure (groovy function) that tests whether to include a residue
+ * - a closure that tests whether to increment count based on sequence features  
+ */
+def getColumnCounter = { name, desc, acceptResidue, acceptFeatures ->
+    [
+     getName: { name }, 
+     getDescription: { desc },
+     getMinColour: { [0, 255, 255] }, // cyan
+     getMaxColour: { [0, 0, 255] }, // blue
+     count: 
+         { res, feats -> 
+            def c = 0
+            if (acceptResidue.call(res))
+            {
+                if (acceptFeatures.call(feats))
+                {
+                    c++
+                }
+            }
+            c
+         }
+     ] as FeatureCounterI
+}
+
+/*
+ * Define an annotation row that counts any residue with Pfam domain annotation
+ */
+def pfamAnnotation = getColumnCounter("Pfam", "Count of residues with Pfam domain annotation", {true}, hasPfam)
+
+/*
+ * Define an annotation row that counts charged residues with Pfam domain annotation
+ */
+def chargedPfamAnnotation = getColumnCounter("Pfam charged", "Count of charged residues with Pfam domain annotation", isCharged, hasPfam)
+
+/*
+ * Register the annotations
+ */
+AlignmentAnnotationFactory.newCalculator(pfamAnnotation) 
+AlignmentAnnotationFactory.newCalculator(chargedPfamAnnotation)
diff --git a/examples/groovy/multipleFeatureAnnotations.groovy b/examples/groovy/multipleFeatureAnnotations.groovy
new file mode 100644 (file)
index 0000000..592c7f5
--- /dev/null
@@ -0,0 +1,110 @@
+import jalview.workers.AlignmentAnnotationFactory;
+import jalview.workers.AnnotationProviderI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+import java.awt.Color;
+
+/*
+ * Example script to compute two alignment annotations
+ * - count of Phosphorylation features
+ * - count of Turn features
+ * To try this, first load example file uniref50.fa and load on features file
+ * exampleFeatures.txt, before running this script
+ *
+ * The script only needs to be run once - it will be registered by Jalview
+ * and recalculated automatically when the alignment changes.
+ */
+
+/*
+ * A closure that returns true if value includes "PHOSPHORYLATION"
+ */
+def phosCounter = { type ->    type.contains("PHOSPHORYLATION") }
+
+/*
+ * A closure that returns true if value includes "TURN"
+ */
+def turnCounter = { type ->    type.contains("TURN") }
+
+/*
+ * A closure that computes and returns an array of Annotation values,
+ * one for each column of the alignment
+ */
+def getAnnotations(al, fr, counter) 
+{
+    def width = al.width
+    def counts = new int[width] 
+    def max = 0
+    
+    /*
+     * count features in each column, record the maximum value
+     */
+    for (col = 0 ; col < width ; col++)
+    {
+        def count = 0
+        for (row = 0 ; row < al.height ; row++)
+        {
+            seq = al.getSequenceAt(row)
+            if (seq != null && col < seq.getLength())
+            {
+                def res = seq.getCharAt(col)
+                if (!Comparison.isGap(res))
+                {
+                    pos = seq.findPosition(col)
+                    features = fr.findFeaturesAtRes(seq, pos)
+                    for (feature in features)
+                    {
+                        if (counter.call(feature.type))
+                        {
+                            count++
+                        }
+                    }
+                }
+            }
+        }
+        counts[col] = count
+        if (count > max)
+        {
+            max = count
+        }
+    }
+    
+    /*
+     * make the Annotation objects, with a graduated colour scale 
+     * (from min value to max value) for the histogram bars 
+     */
+    def zero = '0' as char
+    def anns = new Annotation[width] 
+    for (col = 0 ; col < width ; col++)
+    {
+        def c = counts[col]
+        if (c > 0)
+        {
+            Color color = ColorUtils.getGraduatedColour(c, 0, Color.cyan,
+                max, Color.blue)
+            anns[col] = AlignmentAnnotationFactory.newAnnotation(String.valueOf(c),
+                String.valueOf(c), zero, c, color)
+        }
+    }
+    anns
+}
+
+/*
+ * Define the method that performs the calculations, and builds two
+ * AlignmentAnnotation objects
+ */
+def annotator = 
+    [ calculateAnnotation: { al, fr ->
+        def phosAnns = getAnnotations(al, fr, phosCounter)
+        def ann1 = AlignmentAnnotationFactory.newAlignmentAnnotation("Phosphorylation", "Count of Phosphorylation features", phosAnns)
+        def turnAnns = getAnnotations(al, fr, turnCounter)
+        def ann2 = AlignmentAnnotationFactory.newAlignmentAnnotation("Turn", "Count of Turn features", turnAnns)
+        return [ann1, ann2]
+      } 
+    ] as AnnotationProviderI
+    
+/*
+ * Register the annotation calculator with Jalview
+ */
+AlignmentAnnotationFactory.newCalculator(annotator) 
index 813df63..b3387ea 100644 (file)
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 // do something groovy in jalview
-print "Hello World.\n";
-def alf = Jalview.getAlignFrames();
+println "Hello World.\n"
+println "First sequence is " + currentAlFrame.viewport.alignment.getSequenceAt(0).getDisplayId(true)
+
+def alf = Jalview.getAlignFrames()
 for (ala in alf)
 {
        // ala is an jalview.gui.AlignFrame object 
-       print ala.getTitle()+"\n";
+       println ala.getTitle()
        // get the parent jalview.datamodel.Alignment from the alignment viewport
-       def alignment = ala.viewport.alignment;
+       def alignment = ala.viewport.alignment
        // get the first sequence from the jalview.datamodel.Alignment object
-       def seq = alignment.getSequenceAt(0); 
+       def seq = alignment.getSequenceAt(0) 
 }
+Jalview.quit()
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#"
index e161ad6..35b1d81 100644 (file)
 
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
-<div style="width:35%; align:left; float:right;">
 
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
-</div>
 </div>
 
 <!-- content template start -->
@@ -120,7 +115,7 @@ archive="jalviewApplet.jar,JmolApplet-14.2.14_2015.06.11.jar,java-json.jar,json_
 <param name="showbutton" value="false"/>
 </applet>
 
-<h2>Javascript Launch Button</h2><p>The button below demonstrates how JalviewLite can be launched via a javascript action.</p>
+<h2>Javascript Launch Button</h2><p>The button below demonstrates how JalviewLite can be launched via a javascript action.  <a href="view-source:http://www.jalview.org/builds/develop/examples/javascriptLaunch.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/javascriptLaunch.html">this page</a> and viewing the page source manually). </p>
 
   <input type="button" name="Button1" value="Start"
 onClick="startJalview('plantfdx.fa','Button1.alignment','alwvar')"/>
index 0449c0b..5890515 100644 (file)
@@ -22,9 +22,7 @@
 <!-- boiler plate link to alternate demopage -->
 <div style="width: 100%">
 <div style="width:35%; align:left; float:right;">
-<div style="margin:8px; padding:10px; border: 2px solid black; align: left;">
-<p>Quick Links to jars for example:<br/><a href="jalviewApplet.jar">jalviewApplet.jar</a> and <a href="JmolApplet-14.2.14_2015.06.11.jar">JmolApplet.jar</a>
-</p></div>
+
 </div>
 </div>
 
@@ -36,7 +34,7 @@
 
     <h2>JalviewLite Linked Applets Demo</h2>
     <p>The two applets below use <a href="javascript:doSubmit('jalviewLiteJs')">JalviewLite's javascript API</a> to exchange events about the currently selected region and mouse position in the alignment.
-    </p>
+    <a href="view-source:http://www.jalview.org/builds/develop/examples/linkedapplets_ng.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/linkedapplets_ng.html">this page</a> and viewing the page source manually).</p>
 
 
 <applet
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 a23d152..6a2e058 100644 (file)
@@ -14,22 +14,22 @@ Iron-sulfur (2Fe-2S)        FER_CAPAA       -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      44      44      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      47      47      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAA       -1      77      77      METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 8_83</a></html>   FER_CAPAA       -1      8       83      Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 8_83</a></html>       FER_CAPAA       -1      8       83      Pfam
 Chloroplast    FER_CAPAN       -1      1       47      TRANSIT
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER_CAPAN       -1      124     124     METAL
 Phosphothreonine       FER_CAPAN       -1      136     136     MOD_RES
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> FER_CAPAN       -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     FER_CAPAN       -1      55      130     Pfam
 Chloroplast    FER1_SOLLC      -1      1       47      TRANSIT
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      86      86      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      91      91      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      94      94      METAL
 Iron-sulfur (2Fe-2S)   FER1_SOLLC      -1      124     124     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> FER1_SOLLC      -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     FER1_SOLLC      -1      55      130     Pfam
 Evidence: EI4  Q93XJ9_SOLTU    -1      1       48      SIGNAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 55_130</a></html> Q93XJ9_SOLTU    -1      55      130     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 55_130</a></html>     Q93XJ9_SOLTU    -1      55      130     Pfam
 Chloroplast    FER1_PEA        -1      1       52      TRANSIT
 L -> I (in strain: cv. Onward)         FER1_PEA        -1      59      59      VARIANT
 I -> L (in strain: cv. Onward)         FER1_PEA        -1      85      85      VARIANT
@@ -38,14 +38,14 @@ Iron-sulfur (2Fe-2S)        FER1_PEA        -1      96      96      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      99      99      METAL
 Iron-sulfur (2Fe-2S)   FER1_PEA        -1      129     129     METAL
 YPTS -> PPPA (in Ref. 2)       FER1_PEA        -1      132     135     CONFLICT
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER1_PEA        -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 63_138</a></html> Q7XA98_TRIPR    -1      63      138     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_PEA        -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 63_138</a></html>     Q7XA98_TRIPR    -1      63      138     Pfam
 Chloroplast    FER1_MESCR      -1      1       51      TRANSIT
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      90      90      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      95      95      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      98      98      METAL
 Iron-sulfur (2Fe-2S)   FER1_MESCR      -1      128     128     METAL
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 59_134</a></html> FER1_MESCR      -1      59      134     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 59_134</a></html>     FER1_MESCR      -1      59      134     Pfam
 Chloroplast    FER1_SPIOL      -1      1       50      TRANSIT
 STRAND FER1_SPIOL      -1      52      59      STRAND
 TURN   FER1_SPIOL      -1      60      61      TURN
@@ -68,7 +68,7 @@ Iron-sulfur (2Fe-2S)  FER1_SPIOL      -1      127     127     METAL
 STRAND FER1_SPIOL      -1      130     133     STRAND
 STRAND FER1_SPIOL      -1      135     138     STRAND
 HELIX  FER1_SPIOL      -1      142     144     HELIX
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 58_133</a></html> FER1_SPIOL      -1      58      133     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 58_133</a></html>     FER1_SPIOL      -1      58      133     Pfam
 I -> V         FER3_RAPSA      -1      8       8       VARIANT
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      39      39      METAL
 Iron-sulfur (2Fe-2S)   FER3_RAPSA      -1      44      44      METAL
@@ -77,25 +77,25 @@ S -> T      FER3_RAPSA      -1      55      55      VARIANT
 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.sanger.ac.uk/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.sanger.ac.uk/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.sanger.ac.uk/family/PF00111">Pfam 8_83</a></html>   FER_BRANA       -1      8       83      Pfam
+<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    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.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER2_ARATH      -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_118</a></html> Q93Z60_ARATH    -1      60      118     Pfam
+<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
 STRAND FER1_MAIZE      -1      72      74      STRAND
@@ -113,6 +113,6 @@ Iron-sulfur (2Fe-2S)        FER1_MAIZE      -1      129     129     METAL
 STRAND FER1_MAIZE      -1      132     135     STRAND
 STRAND FER1_MAIZE      -1      137     141     STRAND
 TURN   FER1_MAIZE      -1      142     142     TURN
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 60_135</a></html> FER1_MAIZE      -1      60      135     Pfam
-<html>Description: Fer2 Status: True Positive <a href="http://pfam.sanger.ac.uk/family/PF00111">Pfam 52_127</a></html> O80429_MAIZE    -1      52      127     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 60_135</a></html>     FER1_MAIZE      -1      60      135     Pfam
+<html>Description: Fer2 Status: True Positive <a href="http://pfam.xfam.org/family/PF00111">Pfam 52_127</a></html>     O80429_MAIZE    -1      52      127     Pfam
 ENDGROUP       uniprot
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 34b64ee..614b440 100644 (file)
@@ -24,4 +24,3 @@ seq1  exonerate:protein2genome:local  similarity      9       11      3652    -       .       alignment_id 0 ; Qu
 ACTACGACACGACGACGACGACG
 >seq2
 CDEQEATGTQDAQEQAQC
-
index 229596c..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; }
@@ -26,4 +46,4 @@ subCatContainer.scroll(
 function() {
 subCatContainer.scrollTop($(this).scrollTop());
 });
-</script></hmtl>
\ No newline at end of file
+</script></html>
diff --git a/examples/testdata/test_fts_data_columns.conf b/examples/testdata/test_fts_data_columns.conf
new file mode 100644 (file)
index 0000000..10f5043
--- /dev/null
@@ -0,0 +1,153 @@
+uniprot_data_columns
+#
+_group.id
+_group.name
+_group.sort_order
+g1;Quality Measures;3
+g2;Cross References;2
+g3;Names & Taxonomy;1
+g4;Procedures & Softwares;4
+g5;Date Of;5
+g6;Miscellenous;6
+g7;Sequences;7
+g8;Function;8
+g9;Interaction;9
+g10;Expression;10
+g11;Gene Ontology;11
+g12;Pathology & Biotech;12
+g13;Subcellular location;13
+g14;PTM / Processing;14
+g15;Structure;15
+g16;Publications;16
+g17;Date of;17
+g18;Family & Domain;18
+#
+_data_column.primary_key;entry name
+_data_column.default_response_page_size;100
+#
+_data_column.name
+_data_column.code
+_data_column.group_id
+_data_column.data_type
+_data_column.min_col_width
+_data_column.max_col_width
+_data_column.preferred_col_width
+_data_column.is_shown_by_default
+_data_column.is_searchable
+Entry Name;entry name;String;g3;80;100;85;true;true
+Protein names;protein names;String;g3;300;1500;500;true;true
+Gene Names;genes;String;g3;50;1000;95;true;true
+Organism;organism;String;g3;50;1000;95;true;true
+Organism ID;organism-id;int;g3;60;100;80;false;true
+Proteomes;proteome;String;g3;50;1000;95;false;true
+Taxonomic lineage (ALL);lineage(ALL);String;g3;50;400;95;false;false
+Virus hosts;virus hosts;String;g3;50;1000;95;false;true
+Fragment;fragment;String;g7;50;1000;95;false;true
+Gene encoded by;encodedon;String;g7;50;1000;95;false;true
+Alternative products (isoforms);comment(ALTERNATIVE PRODUCTS);String;g7;50;1000;95;false;false
+Erroneous gene model prediction;comment(ERRONEOUS GENE MODEL PREDICTION);String;g7;50;1000;95;false;false
+Erroneous initiation;comment(ERRONEOUS INITIATION);String;g7;50;1000;95;false;false
+Erroneous translation;comment(ERRONEOUS TRANSLATION);String;g7;50;1000;95;false;false
+Frameshift;comment(FRAMESHIFT);String;g7;50;1000;95;false;false
+Mass spectrometry;comment(MASS SPECTROMETRY);String;g7;50;1000;95;false;false
+Polymorphism;comment(POLYMORPHISM);String;g7;50;1000;95;false;false
+RNA editing;comment(RNA EDITING);String;g7;50;1000;95;false;false
+Sequence caution;comment(SEQUENCE CAUTION);String;g7;50;1000;95;false;false
+Length;length;int;g7;50;100;95;false;true
+Mass;mass;String;g7;50;100;80;false;true
+Sequence;sequence;String;g7;50;1000;95;false;true
+Alternative sequence;feature(ALTERNATIVE SEQUENCE);String;g7;50;1000;95;false;false
+Natural variant;feature(NATURAL VARIANT);String;g7;50;1000;95;false;false
+Non-adjacent residues;feature(NON ADJACENT RESIDUES);String;g7;50;1000;95;false;false
+Non-standard residue;feature(NON STANDARD RESIDUE);String;g7;50;1000;95;false;false
+Non-terminal residue;feature(NON TERMINAL RESIDUE);String;g7;50;1000;95;false;false
+Sequence conflict;feature(SEQUENCE CONFLICT);String;g7;50;1000;95;false;false
+Sequence uncertainty;feature(SEQUENCE UNCERTAINTY);String;g7;50;1000;95;false;false
+Version (Sequence);version(sequence);String;g7;50;1000;95;false;false
+EC number;ec;String;g8;50;1000;95;false;true
+Absorption;comment(ABSORPTION);String;g8;50;1000;95;false;false
+Catalytic activity;comment(CATALYTIC ACTIVITY);String;g8;50;1000;95;false;false
+Cofactor;comment(COFACTOR);String;g8;50;1000;95;false;false
+Enzyme regulation;comment(ENZYME REGULATION);String;g8;50;1000;95;false;false
+Function [CC];comment(FUNCTION);String;g8;50;1000;95;false;false
+Kinetics;comment(KINETICS);String;g8;50;1000;95;false;false
+Pathway;comment(PATHWAY);String;g8;50;1000;95;false;false
+Redox potential;comment(REDOX POTENTIAL);String;g8;50;1000;95;false;false
+Temperature dependence;comment(TEMPERATURE DEPENDENCE);String;g8;50;1000;95;false;false
+pH dependence;comment(PH DEPENDENCE);String;g8;50;1000;95;false;false
+Active site;feature(ACTIVE SITE);String;g8;50;1000;95;false;false
+Binding site;feature(BINDING SITE);String;g8;50;1000;95;false;false
+DNA binding;feature(DNA BINDING);String;g8;50;1000;95;false;false
+Metal binding;feature(METAL BINDING);String;g8;50;1000;95;false;false
+Nucleotide binding;feature(NP BIND);String;g8;50;1000;95;false;false
+Site;feature(SITE);String;g8;50;1000;95;false;false
+Annotation;annotation score;String;g6;50;1000;95;false;true
+Features;features;String;g6;50;1000;95;false;true
+Caution;comment(CAUTION);String;g6;50;1000;95;false;false
+Miscellaneous [CC];comment(GENERAL);String;g6;50;1000;95;false;false
+Keywords;keywords;String;g6;50;1000;95;false;true
+Protein existence;existence;String;g6;50;1000;95;false;true
+Status;reviewed;String;g6;50;1000;95;false;true
+ALL;entry name;String;g7;50;1000;95;false;true;
+Subunit structure [CC];comment(SUBUNIT);String;g9;50;1000;95;false;false
+Interacts with;interactor;String;g9;50;1000;95;false;true
+Developmental stage;comment(DEVELOPMENTAL STAGE);String;g10;50;1000;95;false;false
+Induction;comment(INDUCTION);String;g10;50;1000;95;false;false
+Tissue specificity;comment(TISSUE SPECIFICITY);String;g10;50;1000;95;false;false
+Gene ontology (GO);go;String;g11;50;1000;95;false;true
+Gene ontology (biological process);go(biological process);String;g11;50;1000;95;false;false
+Gene ontology (molecular function);go(molecular function);String;g11;50;1000;95;false;false
+Gene ontology (cellular component);go(cellular component);String;g11;50;1000;95;false;false
+Gene ontology IDs;go-id;String;g11;50;1000;95;false;true
+Allergenic properties;comment(ALLERGEN);String;g12;50;1000;95;false;false
+Biotechnological use;comment(BIOTECHNOLOGY);String;g12;50;1000;95;false;false
+Disruption phenotype;comment(DISRUPTION PHENOTYPE);String;g12;50;1000;95;false;false
+Involvement in disease;comment(DISEASE);String;g12;50;1000;95;false;false
+Pharmaceutical use;comment(PHARMACEUTICAL);String;g12;50;1000;95;false;false
+Toxic dose;comment(TOXIC DOSE);String;g12;50;1000;95;false;false
+Subcellular location [CC];comment(SUBCELLULAR LOCATION);String;g13;50;1000;95;false;false
+Intramembrane;feature(INTRAMEMBRANE);String;g13;50;1000;95;false;false
+Topological domain;feature(TOPOLOGICAL DOMAIN);String;g13;50;1000;95;false;false
+Transmembrane;feature(TRANSMEMBRANE);String;g13;50;1000;95;false;false
+Post-translational modification;comment(PTM);String;g14;50;1000;95;false;false
+Chain;feature(CHAIN);String;g14;50;1000;95;false;false
+Cross-link;feature(CROSS LINK);String;g14;50;1000;95;false;false
+Disulfide bond;feature(DISULFIDE BOND);String;g14;50;1000;95;false;false
+Glycosylation;feature(GLYCOSYLATION);String;g14;50;1000;95;false;false
+Initiator methionine;feature(INITIATOR METHIONINE);String;g14;50;1000;95;false;false
+Lipidation;feature(LIPIDATION);String;g14;50;1000;95;false;false
+Modified residue;feature(MODIFIED RESIDUE);String;g14;50;1000;95;false;false
+Peptide;feature(PEPTIDE);String;g14;50;1000;95;false;false
+Propeptide;feature(PROPEPTIDE);String;g14;50;1000;95;false;false
+Signal peptide;feature(SIGNAL);String;g14;50;1000;95;false;false
+Transit peptide;feature(TRANSIT);String;g14;50;1000;95;false;false
+3D;3d;String;g15;50;1000;95;false;false
+Beta strand;feature(BETA STRAND);String;g15;50;1000;95;false;false
+Helix;feature(HELIX);String;g15;50;1000;95;false;false
+Turn;feature(TURN);String;g15;50;1000;95;false;false
+PubMed ID;citation;String;g16;50;1000;95;false;true
+Date of creation;created;String;g17;80;150;100;true;true
+Date of last modification;last-modified;String;g17;80;150;100;true;true
+Date of last sequence modification;sequence-modified;String;g17;80;150;100;false;true
+Version (entry);version(entry);int;g17;80;100;80;false;false
+Domain [CC];comment(DOMAIN);String;g18;80;1000;95;false;false
+Sequence similarities;comment(SIMILARITY);String;g18;50;1000;95;false;false
+Protein families;families;String;g18;50;1000;95;false;true
+Coiled coil;feature(COILED COIL);String;g18;50;1000;95;false;false
+Compositional bias;feature(COMPOSITIONAL BIAS);String;g18;50;1000;95;false;false
+Domain [FT];feature(DOMAIN EXTENT);String;g18;50;1000;95;false;false
+Motif;feature(MOTIF);String;g18;50;1000;95;false;false
+Region;feature(REGION);String;g18;50;1000;95;false;false
+Repeat;feature(REPEAT);String;g18;50;1000;95;false;false
+Zinc finger;feature(ZINC FINGER);String;g18;50;1000;95;false;false
+Cross-reference (EMBL);database(EMBL);String;g2;50;1000;95;false;false
+Cross-reference (PDB);database(PDB);String;g2;50;1000;95;false;false
+Cross-reference (ENSEMBL);database(ENSEMBL);String;g2;50;1000;95;false;false
+Cross-reference (PFAM);database(PFAM);String;g2;50;1000;95;false;false
+Cross-reference (RFAM);database(RFAM);String;g2;50;1000;95;false;false
+Cross-reference (CATH);database(CATH);String;g2;50;1000;95;false;false
+Cross-reference (SCOPE);database(SCOPE);String;g2;50;1000;95;false;false
+Cross-reference (GO);database(GO);String;g2;50;1000;95;false;false
+Cross-reference (INTERPRO);database(INTERPRO);String;g2;50;1000;95;false;false
+Mapped PubMed ID;citationmapping;String;g16;50;1000;95;false;true
+#
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..407899e 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.0b1"/>
    <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 2594738..bf1710c 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="Retrieval from ENSEMBL" target="ensemblfetch" />
+                               <tocitem text="UniProt Free Text Search" target="uniprotfetcher" />
+                               <tocitem text="SIFTS for mapping PDB structures to UniProt" target="siftsmapping" />
                                <tocitem text="Latest Release Notes" target="release"/>
                </tocitem>
                
@@ -49,7 +47,7 @@
                <tocitem text="Viewing Trees" target="treeviewer" expand="false" />
                <tocitem text="Fetching Sequences" target="seqfetch" />         
                
-               <tocitem text="Select columns by annotation" target="selectcolbyannot" />
+               <tocitem text="Select Columns by Annotation" target="selectcolbyannot" />
                
                <tocitem text="Nucleic Acid Support" target="nucleicAcids" expand="false">
                        <tocitem text="Viewing RNA structure" target="varna" />
                        <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="Consensus" target="calcs.consensus" />
                        <tocitem text="RNA Structure Consensus" target="calcs.alstrconsensus" />
                        <tocitem text="Annotations File Format" target="annotations.fileformat" />
-                       <tocitem text="Select Column by Annotation" target="calcs.annotation" />
+                       <tocitem text="Select Columns by Annotation" target="selectcolbyannot" />
                </tocitem>
                <tocitem text="3D Structure Data" target="viewingpdbs" expand="false">
                        <tocitem text="PDB Sequence Fetcher" target="pdbfetcher" />
                        <tocitem text="PDB Structure Chooser" target="pdbchooser" />
                        <tocitem text="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 0a0214e..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
   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>
+  <p>
     <strong>cDNA Consensus</strong>
   </p>
   A
index df8b5ff..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
     (e.g. !proline).
   </p>
   <p>
-    <em>Colouring an alignment by conservation</em><br>
+    <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.
   </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 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 a645630..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>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 545f0c1..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="featuresFile.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 f8f87dc..59b4936 100644 (file)
@@ -20,7 +20,7 @@
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
 <head>
-<title>BioJSON in Jalviwe</title>
+<title>BioJSON in Jalview</title>
 </head>
 <body>
   <p>
@@ -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..1b0b9c1 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
@@ -90,8 +70,8 @@
     Help menu.
   <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 63a14af..4b4aab9 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>
     </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>
+      </td>
+    </tr>
+    <tr>
+      <td>
         <div align="center">-nousagestats</div>
       <td>
         <div align="left">Turn off google analytics usage tracking</div>
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 c0c888a..1965e70 100644 (file)
   <p>
     <strong>DAS Sequence Feature Retrieval</strong>
   </p>
-  <p>
-    Jalview includes a client for retrieving sequences and their
-    features via the <a href="http://www.biodas.org">Distributed
-      Annotation System</a>.
-  </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 />
+  <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>
+  </p>
   <p>&nbsp;
 </body>
 </html>
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..ec1e093 100755 (executable)
 
   <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
+    <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,
     you can use Jalview's own sequence feature annotation format, which
     additionally allows HTML and URLs to be directly attached to each
 </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 9164afd..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>
     the bottom of the list is rendered <em>below</em> a feature higher
     up in the list.<br> <em><strong>You can change
         the order of a feature by dragging it up and down the list with
-        the mouse</strong></em>.
+        the mouse (not applet)</strong></em>.
   </p>
   <p>
     The <strong><em>Optimise order</em></strong> button (currently only
     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 adabdf1..254f92e 100644 (file)
     <strong>The Groovy Shell</strong>
   </p>
   <p>
-    <a href="http://groovy.codehaus.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 Groovy
-    support is only possible if the core groovy jars which include the
-    GroovyShell are present on the CLASSPATH when Jalview is started.
-  </p>
-  <p>
-    The jars are obtained from the <em>embedded</em> directory within
-    the <a href="http://dist.codehaus.org/groovy/distributions">groovy
-      distribution</a>. The easiest way of adding them to the Jalview
-    classpath is to download and build Jalview from its source
-    distribution, and then add the groovy-all-*.jar to the lib directory
-    whose path is given in the java.ext.dirs property.
-  </p>
-  <p>
-    <strong>Opening Jalview's Groovy Console</strong><br>If groovy
-    is available, then the <strong>Tools&#8594;Groovy
-      Console...</strong> menu entry will be available from the Jalview Desktop's
-    drop-down menu. Selecting this will open the <a
-      href="http://groovy.codehaus.org/Groovy+Console"
-    >Groovy Console</a> which 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>
   </p>
   <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>
@@ -87,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..2f10196 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>
         </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>
diff --git a/help/html/features/mmcif.html b/help/html/features/mmcif.html
new file mode 100644 (file)
index 0000000..b507fe1
--- /dev/null
@@ -0,0 +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>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>Support for importing 3D structure data from flat file and
+    EMBL-PDBe as mmCIF was added in Jalview 2.10</em>
+</body>
+</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 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 ac63c9e..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>
+  <em><a href="siftsmapping.html">SIFTS Mapping</a> between PDB and
+    UniProt data was introduced in Jalview 2.10</em>
 </body>
 </html>
diff --git a/help/html/features/sifts_mapping_output.png b/help/html/features/sifts_mapping_output.png
new file mode 100644 (file)
index 0000000..ddc8a1f
Binary files /dev/null and b/help/html/features/sifts_mapping_output.png differ
diff --git a/help/html/features/siftsmapping.html b/help/html/features/siftsmapping.html
new file mode 100644 (file)
index 0000000..c12d45b
--- /dev/null
@@ -0,0 +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 from UniProt for PDB Structures</title>
+</head>
+<body>
+
+  <p>
+    <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>
+    <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>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>
+    <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>
+
+    &emsp;<img src="sifts_mapping_output.png" align="left"
+      alt="SIFTS mapping output" /> <br />
+  <p>
+    <em>SIFTS Mapping integration was added in Jalview 2.10</em>
+  </p>
+
+</body>
+</html>
index ed5bef3..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="../calculate/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>
       panels.</li>
     <li>Panel heights are adjusted dragging the divider between
       them using the mouse</li>
-    <li><a href="menus/alwview.html"><strong>"View&#8594;New
+    <li><a href="../menus/alwview.html"><strong>"View&#8594;New
           View / Expand Views / Gather Views"</strong></a> behave as for a normal
       alignment window, but always create new views as Split Frames</li>
   </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>
diff --git a/help/html/features/uniprotqueryfields.html b/help/html/features/uniprotqueryfields.html
new file mode 100644 (file)
index 0000000..182b206
--- /dev/null
@@ -0,0 +1,391 @@
+<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>UniProtKB query fields</title>
+</head>
+
+<body>
+  <p>
+    <strong>UniProtKB query fields</strong>
+  </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 />
+        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>
+
+    <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>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/help/html/features/uniprotseqfetcher.png b/help/html/features/uniprotseqfetcher.png
new file mode 100644 (file)
index 0000000..a592e8e
Binary files /dev/null and b/help/html/features/uniprotseqfetcher.png differ
diff --git a/help/html/features/uniprotsequencefetcher.html b/help/html/features/uniprotsequencefetcher.html
new file mode 100644 (file)
index 0000000..edd8995
--- /dev/null
@@ -0,0 +1,169 @@
+<html>
+<!--
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ -->
+<head>
+<title>The UniProt Free Text Search Interface</title>
+</head>
+<body>
+
+  <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>
+    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.10)" />
+  </p>
+
+  <p>
+    <strong>Searching the UniProt Database</strong>
+  </p>
+  <p>
+    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> 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><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>
+  <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.10.0</em>
+  </p>
+</body>
+</html>
\ No newline at end of file
index 029edce..77f56dc 100644 (file)
@@ -27,9 +27,9 @@
     <strong>The VARNA RNA Viewer</strong>
   </p>
   <p>
-    <a href="http://varna.lri.fr/index.html">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 4d35516..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.
     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..ba97557 100644 (file)
@@ -43,8 +43,7 @@
       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 c0a89cf..b0d6b04 100755 (executable)
       NBRF/PIR (including MODELLER variant), Pfam/Stockholm</em>
   </p>
   <p>
-    The EBI has <a href="http://www.ebi.ac.uk/help/formats.html">examples</a>
-    of these file formats.
-  </p>
-  <p>
     Additionally, whole sets of coloured and annotated alignments and
     trees can be read from a <a href="../features/jalarchive.html">Jalview
       (jar) format</a> file using <strong>Desktop&#8594;Load
   </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 a477457..2ba9a49 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>
       <td>Both</td>
       <td>Cuts the (fully) selected sequences from the alignment. <!-- not yet in this version 
 This will not happen if only some
-columns are selected, you should use the <a href="features/regionHiding.html">Hide Regions feature</a> instead.-->
+columns are selected, you should use the <a href="features/hiddenRegions.html">Hide Regions feature</a> instead.-->
       </td>
     </tr>
     <tr>
@@ -279,7 +279,7 @@ columns are selected, you should use the <a href="features/regionHiding.html">Hi
       <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 +317,22 @@ columns are selected, you should use the <a href="features/regionHiding.html">Hi
       <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..c8b2270 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>
       </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..b93f85b 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>
   </ul>
 </body>
 </html>
index 0d5b698..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>.
@@ -82,9 +82,8 @@
             <a href="../webServices/newsreader.html">Jalview News</a>
             dialog box.
         </em></li>
-        <li><strong>Groovy Console...<em> (only
-              available if groovy is on the classpath)</em><br></strong> <em>Open's
-            the <a href="../groovy.html">Groovy Console</a> for
+        <li><strong>Groovy Console...<br></strong> <em>Opens
+            the <a href="../features/groovy.html">Groovy Console</a> for
             interactive scripting.
         </em><strong><br></strong></li>
 
         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 1eb2366..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><a href="sqaddrefannot"><strong>Add
-              Reference Annotations<br>
-          </strong><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 ae4c1c6..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:8080/LocARNA.jsp"
-    >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 23e958c..3fe08cb 100755 (executable)
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.9.0b2">2.9.0b2</a><br />
-            <em>16/10/2015</em></strong>
+          <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>
-      <em>General</em>
-      <ul>
-            <li>Time stamps for signed Jalview application and applet jars</li>
-      </ul>
+        <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-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-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>
       <td>
         <div align="left">
-        <em>Application</em><ul>
-          <li>Duplicate group consensus and conservation rows shown when tree is partitioned</li>
-            <li>Erratic behaviour when tree partitions made with multiple cDNA/Protein split views</li>
-            </ul>
+          <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-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>
+          </ul>
+          <em>Application</em>
+          <ul>
+            <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>
+            <!--  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>
+              <!-- 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>
     </tr>
     <tr>
       <td width="60" nowrap>
         <div align="center">
-          <strong><a name="Jalview.2.9.0b1">2.9.0b1</a><br />
-            <em>8/10/2015</em></strong>
+          <strong><a name="Jalview.2.9.0b2">2.9.0b2</a><br />
+            <em>16/10/2015</em></strong>
         </div>
       </td>
+      <td><em>General</em>
+        <ul>
+          <li>Time stamps for signed Jalview application and applet
+            jars</li>
+        </ul></td>
       <td>
-      <em>General</em>
-      <ul>
-            <li>Updated Spanish translations of localized text for 2.9</li>
-      </ul>
-      <em>Application</em><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>
+        <div align="left">
+          <em>Application</em>
+          <ul>
+            <li>Duplicate group consensus and conservation rows
+              shown when tree is partitioned</li>
+            <li>Erratic behaviour when tree partitions made with
+              multiple cDNA/Protein split views</li>
+          </ul>
+        </div>
       </td>
+    </tr>
+    <tr>
+      <td width="60" nowrap>
+        <div align="center">
+          <strong><a name="Jalview.2.9.0b1">2.9.0b1</a><br />
+            <em>8/10/2015</em></strong>
+        </div>
+      </td>
+      <td><em>General</em>
+        <ul>
+          <li>Updated Spanish translations of localized text for
+            2.9</li>
+        </ul> <em>Application</em>
+        <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></td>
       <td>
         <div align="left">
-        <em>General</em>
+          <em>General</em>
           <ul>
-            <li>Mapping of cDNA to protein in split frames incorrect when sequence start > 1</li>
-            <li>Broken images in filter column by annotation dialog documentation</li>
+            <li>Mapping of cDNA to protein in split frames
+              incorrect when sequence start > 1</li>
+            <li>Broken images in filter column by annotation dialog
+              documentation</li>
             <li>Feature colours not parsed from features file</li>
-            <li>Exceptions and incomplete link URLs recovered when loading a features file containing HTML tags in feature description</li>
-            
+            <li>Exceptions and incomplete link URLs recovered when
+              loading a features file containing HTML tags in feature
+              description</li>
+
           </ul>
-      <em>Application</em><ul>
-            <li>Annotations corrupted after BioJS export and reimport</li>
-            <li>Incorrect sequence limits after Fetch DB References with 'trim retrieved sequences'</li>
-            <li>Incorrect warning about deleting all data when deleting selected columns</li>
-            <li>Patch to build system for shipping properly signed JNLP templates for webstart launch</li>
-            <li>EMBL-PDBe fetcher/viewer dialogs do not offer unreleased structures for download or viewing</li>
-            <li>Tab/space/return keystroke operation of EMBL-PDBe fetcher/viewer dialogs works correctly</li>
-            <li>Disabled 'minimise' button on Jalview windows running on OSX to workaround redraw hang bug</li>
-            <li>Split cDNA/Protein view position and geometry not recovered from jalview project</li>
-            <li>Initial enabled/disabled state of annotation menu sorter 'show autocalculated first/last' corresponds to alignment view</li>
-            <li>Restoring of Clustal, RNA Helices and T-Coffee color schemes from BioJSON</li>
-            </ul>
-      <em>Applet</em><ul>
-            <li>Reorder sequences mirrored in cDNA/Protein split frame</li>
+          <em>Application</em>
+          <ul>
+            <li>Annotations corrupted after BioJS export and
+              reimport</li>
+            <li>Incorrect sequence limits after Fetch DB References
+              with 'trim retrieved sequences'</li>
+            <li>Incorrect warning about deleting all data when
+              deleting selected columns</li>
+            <li>Patch to build system for shipping properly signed
+              JNLP templates for webstart launch</li>
+            <li>EMBL-PDBe fetcher/viewer dialogs do not offer
+              unreleased structures for download or viewing</li>
+            <li>Tab/space/return keystroke operation of EMBL-PDBe
+              fetcher/viewer dialogs works correctly</li>
+            <li>Disabled 'minimise' button on Jalview windows
+              running on OSX to workaround redraw hang bug</li>
+            <li>Split cDNA/Protein view position and geometry not
+              recovered from jalview project</li>
+            <li>Initial enabled/disabled state of annotation menu
+              sorter 'show autocalculated first/last' corresponds to
+              alignment view</li>
+            <li>Restoring of Clustal, RNA Helices and T-Coffee
+              color schemes from BioJSON</li>
+          </ul>
+          <em>Applet</em>
+          <ul>
+            <li>Reorder sequences mirrored in cDNA/Protein split
+              frame</li>
             <li>Applet with Jmol examples not loading correctly</li>
-            </ul>
+          </ul>
         </div>
       </td>
     </tr>
                 region export in flat file generation</li>
 
               <li>Export alignment views for display with the <a
-                href="http://biojs.io/d/msa">BioJS MSAViewer</a></li>
+                href="http://msa.biojs.net/">BioJS MSAViewer</a></li>
 
               <li>Export scrollable SVG in HTML page</li>
               <li>Optional embedding of BioJSON data when exporting
     <tr>
       <td><div align="center">
           <strong><a name="Jalview.2.8.0b1">2.8.0b1</a><br />
-          <em>30/1/2014</em></strong>
+            <em>30/1/2014</em></strong>
         </div></td>
       <td>
         <ul>
             <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>
         <ul>
           <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 <a
-            href="webServices/index.html#envision2">Envision2</a>
-            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>Cancel button for DAS Feature Fetching
           <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>
           <li>Fixed Remove Empty Columns Bug (empty columns at end
             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 5dd4472..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://www.well.ox.ac.uk/~valdar/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..52220d2 100644 (file)
   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.
+    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 04ccd8f..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-performace
-    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 b685576..2fbbdbc 100644 (file)
       from the input</li>
     <li><em>realignment</em> - where any aligned sequences will be
       used by the service to construct a profile based alignment of the
-      remaining unaligned sequences.</li>
+      remaining unaligned sequences</li>
   </ul>
   <strong>JABAWS Alignment services</strong>
   <br> Most alignment services are provided by the
   <a href="JABAWS.html">JABAWS framework</a>, which allows you to
   customise the precise parameters used when running each alignment
-  prgoram. In addition to the 'Default settings', you may choose from a
+  program. In addition to the 'Default settings', you may choose from a
   range of alignment preset settings, or create your own using the
   <a href="webServicesParams.html">'Edit Settings And Run ..' dialog
     box</a>.
   <ul>
     <li><a href="http://www.clustal.org/">Clustal Omega and
         Clustal W</a> (version 2.0.12)</li>
-    <li><a href="http://align.bmr.kyushu-u.ac.jp/mafft/software/">Mafft</a>
+    <li><a href="http://mafft.cbrc.jp/alignment/software/">Mafft</a>
       (version 6.8.57b)</li>
     <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 ee69290..c3c1d3f 100644 (file)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  -->
-<head>Jalview Desktop RSS News Reader
+<head>
 </head>
 <body>
   <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 'Tools' menu.</p>
-  <img src="jalviewrssreader.gif" align="center" width="513"
-    height="337" alt="Snapshot of the Jalview Desktop's RSS reader"
-  />
+  <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>
     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>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 de0f8cd..0a4c650 100644 (file)
@@ -29,8 +29,7 @@
     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>.
+      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;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>
     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
@@ -83,7 +82,7 @@
     <em>Please Note:
       <ul>
         <li>The regular expressions supported by Jalview are those
-          provided by the <a href="www.javaregex.com">Stevesoft
+          provided by the <a href="http://www.javaregex.com">Stevesoft
             javaregex package</a>.
         </li>
         <li>Some characters must be escaped when specifying them as
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 19be76f..448430d 100755 (executable)
 </head>
 <body>
   <p>
-    <strong>What's new ?</strong>
+    <strong>What's new in Jalview 2.10.0b1 ?</strong>
   </p>
   <p>
-    Jalview 2.9.0b2 is a bug fix release for Jalview 2.9.
-    The release of Jalview 2.9 in September 2015 included
-    a multitude of bug fixes and minor improvements (both small, and
-    rather big!), it also brings major new capabilities for codon-level
-    analysis of protein alignments and the retrieval and manipulation of
-    structural data.</p><p>For the patches since version 2.9 was released, see the
-    <a href="releases.html#Jalview.2.9.0b2">Jalview 2.9.0b2 Release Notes</a>.
+    Jalview 2.10.0b1 is a patch release for 2.10, the next major release
+    in the Jalview 2 series. Full details are in the <a
+      href="releases.html#Jalview.2.10.0b1">Jalview 2.10b1 Release
+      Notes</a>, but the highlights are below.
   </p>
-  <p>
-    <strong>Highlights in Jalview 2.9</strong>
   <ul>
-    <li><strong>Visualisation, editing and analysis of
-        cDNA and Protein alignments</strong><br />A new <a
-      href="features/splitView.html">Split View</a> window allows linked
-      protein and nucleotide sequence alignments to be viewed, edited,
-      and analysed as one. <br />cDNA alignments can also be
-      reconstructed from protein alignments calculated by Jalview's web
-      services, and update in response to edits in the amino acid view.<br />To
-      start experimenting with cDNA/Protein analysis, jut drop a file
-      containing cDNA sequences which code for proteins in an existing
-      alignment, and Jalview will do the rest.</li>
-    <li><strong>Enhanced Integration of UCSF Chimera</strong> <br>Jalview
-      2.9 provides full support for the use of Chimera to view 3D
-      structures linked to alignment views in the Jalview Desktop. We've
-      also included support for saving Chimera sessions in Jalview
-      project files.<br />Jalview and Chimera communicate using local
-      web server connections, which may cause firewall alerts on some
-      systems, but has the advantage of allowing bidirectional
-      communication. Communication between Jalview and Chimera is now
-      much more responsive, and selected regions in Chimera are now
-      shown as highlighted regions in the Jalview desktop.</li>
-    <li><strong>Interactive querying of the PDBe</strong><br />Jalview
-      users can now <a href="features/pdbsequencefetcher.html">browse</a> and <a href="features/viewingpdbs.html">retrieve 3D structure</a> data from the PDB
-      via the <a href="http://www.ebi.ac.uk/pdbe/api/doc/search.html">PDBe
-        Search API</a> (<a href="http://dx.doi.org/10.1093%2Fnar%2Fgkt1180">Gutmanas
-        et al 2014</a>). Developed in collaboration with the PDBe group at
-      EMBL-EBI, the interface allows both structured and free-text
-      queries to be performed, and allows automatic selection of the
-      most relevant structures for an alignment acording to a variety of
-      criteria.</li>
-    <li><strong>Improved support for RNA visualisation</strong><br />Jalview
-      2.9 integrates the latest version of the <a
-      href="features/varna.html">VARNA RNA Viewer</a>, and VARNA views
-      can also now be stored in Jalview projects. We've also dealt with
-      a number of lingering bugs in the VARNA/Jalview interface,
-      including the loss of pseudoknots when RNA secondary structure is
-      shown VARNA.</li>
-    <li><strong>Protein Secondary Structure predictions
-        with JPred4</strong><br />Jalview includes a number of new features for
-      working with secondary structure predictions from the JPred4
-      server. These include new <a href="menus/popupMenu.html#hideinserts">popup menu actions</a> to automatically hide insertions and highlight
-      mutations in an alignment with respect to a <a href="calculations/referenceseq.html">Reference
-        Sequence</a>. Jalview 2.9's new <a href="io/export.html#htmlexport">scrollable
-        SVG HTML export</a> was also developed specifically for the JPred4
-      server.</li>
+    <li>Drag and drop reinstated for the Jalview desktop on
+      Windows, Linux and older OSX systems.</li>
+    <li>Problems loading local PDB files have been fixed</li>
+    <li>Conservation shading can be disabled for PID and consensus
+      based colour scheme</li>
+  </ul>
+  <p><em>Major highlights of the 2.10.0 Release</em></p>
+  <ul>
+    <li><strong>Ensembl sequence fetcher</strong><br />Annotated
+      Genes, transcripts and proteins can be retrieved via Jalview's new
+      <a href="features/ensemblsequencefetcher.html">Ensembl REST
+        client</a>. Support for import of Ensembl data allows:
+      <ul>
+        <li><strong>Aligned locus view</strong><br />Transcripts
+          retrieved for a gene identifier via the Ensembl or
+          EnsemblGenomes sequence databases are automatically aligned to
+          their reference genome, and introns hidden from the view.</li>
+        <li><strong>Sequence variant data</strong><br />Jalview
+          propagates variant annotation on genomic regions onto
+          transcripts and protein products, complete with associated
+          metadata such as clinical significance.</li>
+      </ul></li>
+    <li><strong>Ensembl and ENA 'show cross-references'
+        support</strong><br />The Calculations menu's <strong>'Show
+        cross-references'</strong> now offers Ensembl as well as EMBLCDS and
+      Uniprot when CDS/Protein mapping data is available for download or
+      display. This allows variant annotation to be added directly to an
+      alignment of UniProt sequences.</li>
+    <li><strong>Working with structures</strong>
+      <ul>
+        <li><strong>More accurate structure mappings</strong><br />
+          Jalview now utilises the PDBe's SIFTS database (at EMBL-EBI)
+          to <a href="features/siftsmapping.html">match structures
+            to UniProt sequences</a>, even for structures containing
+          multiple copies of a sequence.</li>
+        <li><strong>Import structures as mmCIF</strong><br />Jalview
+          now downloads data from the EMBL-EBI's PDBe site as <a
+          href="features/mmcif.html">mmCIF</a>. This allows very large
+          structures to be imported, such as the HIV virus capsid
+          assembly.</li>
+        <li><strong>Chimera users will need to upgrade to
+            1.11.1</strong><br />If you use Chimera to view structures
+          downloaded by Jalview 2.10, you will need to make sure you are
+          running the latest version of <a href="features/chimera.html">Chimera</a>.</li>
+      </ul></li>
+    <li><strong>UniProt Free Text Search</strong><br />The new
+      search dialog for UniProt allows you to browse and retrieve
+      sequences with free-text search, or structured queries.</li>
+    <li><strong>Reference sequence alignment view</strong><br />
+      Jalview 2.9 introduced support for reference sequences. In 2.10,
+      when a reference sequence is defined for the alignment, the
+      alignment column ruler is now numbered according to the reference
+      sequence. The reference sequence for alignment views can also be
+      saved and restored from Jalview projects.</li>
   </ul>
 
 </body>
index f77f5f0..1470745 100644 (file)
Binary files a/lib/Jmol-14.2.14_2015.06.11.jar and b/lib/Jmol-14.2.14_2015.06.11.jar differ
index b73b58d..9d41f6b 100644 (file)
Binary files a/lib/VARNAv3-93.jar and b/lib/VARNAv3-93.jar differ
index 1cfc700..5070435 100644 (file)
Binary files a/lib/castor-1.1-cycle-xml.jar and b/lib/castor-1.1-cycle-xml.jar differ
diff --git a/lib/groovy-all-1.8.2.jar b/lib/groovy-all-1.8.2.jar
deleted file mode 100644 (file)
index 85af249..0000000
Binary files a/lib/groovy-all-1.8.2.jar and /dev/null differ
diff --git a/lib/groovy-all-2.4.6-indy.jar b/lib/groovy-all-2.4.6-indy.jar
new file mode 100644 (file)
index 0000000..5f3d51c
Binary files /dev/null and b/lib/groovy-all-2.4.6-indy.jar differ
index 7ad030a..ea5a1f4 100644 (file)
Binary files a/lib/min-jabaws-client-2.1.0.jar and b/lib/min-jabaws-client-2.1.0.jar differ
index 429fe77..182e0da 100644 (file)
Binary files a/lib/quaqua-filechooser-only-8.0.jar and b/lib/quaqua-filechooser-only-8.0.jar differ
old mode 100755 (executable)
new mode 100644 (file)
index d41c2ca..bcb07cf 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, 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, 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 ccbde5e..3b80821 100644 (file)
 <!--
        History: Originally created from EMBL_common_V1.0
        Updated on 24th April 2007 for WsDBFetch Service move to EMBL_Services_V1.1.xsd
+       Updated May 2016 for EMBL XML 1.2 JAL-2113 JAL-2114
+         see ftp://ftp.sra.ebi.ac.uk/meta/xsd/sra_1_5/ENA.embl.xsd
+         see http://www.ebi.ac.uk/ena/submit/data-formats
        -->
        <class name="jalview.datamodel.xdb.embl.EmblFile">
-               <map-to xml="EMBL_Services"/>
+               <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>
-               
                <field name="errors" type="jalview.datamodel.xdb.embl.EmblError" collection="vector">
                        <bind-xml name="Error"/>
                </field>
        </class>
        <class name="jalview.datamodel.xdb.embl.EmblEntry">
                <field name="accession" type="string">
-                       <bind-xml location="accession" node="attribute"/>
+                       <bind-xml name="accession" node="attribute"/>
                </field>
-               <!--  May 2015 changed from last-updated to match xml -->
-               <field name="lastUpdated" type="string">
-                       <bind-xml location="lastUpdated" node="attribute"/>
+               <!-- 
+                   in EMBL XML 1.2 sequence/@version became entry/version 
+                   entry/@version became entry/@entryVersion
+               -->
+               <field name="sequenceVersion" type="string">
+                       <bind-xml name="version" node="attribute"/>
                </field>
-               <field name="version" type="string">
-                       <bind-xml location="version" node="attribute"/>
+               <field name="entryVersion" type="string">
+                       <bind-xml name="entryVersion" node="attribute"/>
+               </field>
+               <field name="dataClass" type="string">
+                       <bind-xml name="dataClass" node="attribute"/>
+               </field>
+               <field name="taxonomicDivision" type="string">
+                       <bind-xml name="taxonomicDivision" node="attribute"/>
+               </field>
+               <field name="moleculeType" type="string">
+                       <bind-xml name="moleculeType" node="attribute"/>
+               </field>
+               <field name="sequenceLength" type="string">
+                       <bind-xml name="sequenceLength" node="attribute"/>
+               </field>
+               <field name="topology" type="string">
+                       <bind-xml name="topology" node="attribute" location="type"/>
                </field>
-               <field name="rCreated" type="string">
-                       <bind-xml location="releaseCreated" node="attribute"/>
+               <field name="firstPublicDate" type="string">
+                       <bind-xml name="firstPublic" node="attribute"/>
                </field>
-               <field name="rLastUpdated" type="string">
-                       <bind-xml location="releaseLastUpdated" node="attribute"/>
+               <field name="firstPublicRelease" type="string">
+                       <bind-xml name="firstPublicRelease" node="attribute"/>
                </field>
-               <field name="desc" type="string">
+               <field name="lastUpdatedDate" type="string">
+                       <bind-xml name="lastUpdated" node="attribute"/>
+               </field>
+               <field name="lastUpdatedRelease" type="string">
+                       <bind-xml name="lastUpdatedRelease" node="attribute"/>
+               </field>
+               <field name="description" type="string">
                        <bind-xml name="description" node="element"/>
                </field>
                <field name="keywords" type="string" collection="vector">
                        <bind-xml name="feature"/>
                </field>
                <field name="dbRefs" type="jalview.datamodel.DBRefEntry" collection="vector">
-                       <bind-xml name="dbreference" />
+                       <bind-xml name="xref" />
                </field>
                <field name="sequence" type="jalview.datamodel.xdb.embl.EmblSequence">
                        <bind-xml name="sequence"/>
                </field>
        </class>
        <class name="jalview.datamodel.xdb.embl.EmblSequence">
-               <field name="type" type="string">
-                       <bind-xml name="type" node="attribute" location="type"/>
-               </field>
-               <field name="version" type="string">
-                       <bind-xml name="version" node="attribute" location="version"/>
-               </field>
                <field name="sequence" type="string">
                        <bind-xml node="text"/>
                </field>
                <field name="name" type="string">
                        <bind-xml name="name" node="attribute"/>
                </field>
+               <field name="location" type="string">
+                       <bind-xml name="location" node="attribute"/>
+               </field>
                <field name="dbRefs" type="jalview.datamodel.DBRefEntry" collection="vector">
-                       <bind-xml name="dbreference" node="element"/>
+                       <bind-xml name="xref" node="element"/>
                </field>
                <field name="qualifiers" type="jalview.datamodel.xdb.embl.Qualifier" collection="vector">
                        <bind-xml name="qualifier"/>
                </field>                                        
-               <field name="locations" type="jalview.datamodel.xdb.embl.EmblFeatureLocations" collection="vector">
-                       <bind-xml name="location"/>
-               </field>
        </class>
        <class name="jalview.datamodel.DBRefEntry" verify-constructable="false">
                <field name="accessionId" type="java.lang.String">
-                       <bind-xml name="primary" node="attribute"/>
+                       <bind-xml name="id" node="attribute"/>
                </field>
                <field name="source" type="java.lang.String"> 
                        <bind-xml name="db" node="attribute"/>
                </field>
                <field name="version" type="string">
-                       <bind-xml name="secondary" node="attribute"/>
+                       <bind-xml name="secondaryId" node="attribute"/>
                </field>
        </class>
        <class  name="jalview.datamodel.xdb.embl.Qualifier" verify-constructable="false">
                        <bind-xml name="value" node="element"/>
                </field>
        </class>
-       <class name="jalview.datamodel.xdb.embl.EmblFeatureLocations">
-               <field name="locationType" type="string">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="locationComplement" type="boolean">
-                       <bind-xml name="complement" node="attribute"/>
-               </field>
-               <field name="locElements" type="jalview.datamodel.xdb.embl.EmblFeatureLocElement" collection="vector">
-                       <bind-xml name="locationElement"/>
-               </field>
-       </class>
-       <class name="jalview.datamodel.xdb.embl.EmblFeatureLocElement">
-               <field name="type" type="string">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="accession" type="string">
-                       <bind-xml name="accession" node="attribute"/>                   
-               </field>
-               <field name="version" type="string">
-                       <bind-xml name="version" node="attribute"/>
-               </field>
-               <field name="complement" type="boolean">
-                       <bind-xml name="complement"/>
-               </field>
-               <field name="basePositions" type="jalview.datamodel.xdb.embl.BasePosition" collection="array">
-                       <bind-xml name="basePosition" node="element"/>
-               </field>
-       </class>
-       <class name="jalview.datamodel.xdb.embl.BasePosition">
-               <field name="type">
-                       <bind-xml name="type" node="attribute"/>
-               </field>
-               <field name="pos">
-                       <bind-xml node="text"/>
-               </field>
-       </class>
 </mapping>
diff --git a/resources/fts/pdb_data_columns.txt b/resources/fts/pdb_data_columns.txt
new file mode 100644 (file)
index 0000000..278b86e
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+pdb_data_columns
+#
+_group.id
+_group.name
+_group.sort_order
+g1;Quality Measures;1
+g2;Cross References;2
+g3;Names & Taxonomy;3
+g4;Procedures & Software;4
+g5;Date Of;5
+g6;Miscellaneous;6
+#
+_data_column.primary_key;pdb_id
+_data_column.default_response_page_size;100
+#
+_data_column.name
+_data_column.code
+_data_column.group_id
+_data_column.data_type | _data_column.isFormated | _data_column.significantDigit
+_data_column.min_col_width
+_data_column.max_col_width
+_data_column.preferred_col_width
+_data_column.is_shown_by_default
+_data_column.is_searchable
+PDB Id;pdb_id;String;g2;40;60;45;true;true
+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
+PFAM Accession;pfam_accession;String;g2;50;400;95;false;true
+PFAM Name;pfam_name;String;g3;50;400;95;false;true
+InterPro Name;interpro_name;String;g3;50;400;95;false;false
+InterPro Accession;interpro_accession;String;g2;50;400;95;false;false
+UniProt Id;uniprot_id;String;g2;50;400;95;false;true
+UniProt Accession;uniprot_accession;String;g2;50;400;95;false;false
+UniProt Coverage;uniprot_coverage;String;g6;50;400;95;false;false
+Uniprot Features;uniprot_features;String;g6;50;400;95;false;false
+R Factor;r_factor;Double|T|3;g1;50;150;85;false;false
+Experimental Method;experimental_method;String;g4;50;400;105;true;false
+Resolution;resolution;Double|T|3;g1;50;150;85;true;false
+Data Quality;data_quality;Double|T|2;g1;50;150;85;false;false
+Overall Quality;overall_quality;Double|T|1;g1;50;150;85;false;false
+Number of Polymers;number_of_polymers;int;g6;50;400;95;false;false
+Number of Protein Chains;number_of_protein_chains;int;g6;50;400;95;false;false
+Number of Bound Molecule;number_of_bound_molecules;int;g6;50;400;95;false;false
+Number of Polymer Residue;number_of_polymer_residues;int;g6;50;400;95;false;false
+GENUS;genus;String;g3;50;400;95;false;true
+Gene Name;gene_name;String;g3;50;400;95;false;true
+GO Id;go_id;String;g2;50;400;95;false;false
+Assembly Id;assembly_id;String;g2;50;400;95;false;false
+Assembly Form;assembly_form;String;g6;50;400;95;false;false
+Assembly Type;assembly_type;String;g6;50;400;95;false;false
+Space Group;spacegroup;String;g6;50;400;95;false;false
+Cath Code;cath_code;String;g2;50;400;95;false;false
+Tax Id;tax_id;String;g2;50;400;95;false;false
+Tax Query;tax_query;String;g2;50;400;95;false;false
+Interacting Entity Id;interacting_entity_id;String;g2;50;400;95;false;false
+Interacting Molecules;interacting_molecules;String;g6;50;400;95;false;false
+Pubmed Id;pubmed_id;int;g2;50;400;95;false;false
+Status;status;String;g6;50;400;95;false;false
+Model Quality;model_quality;Double|T|2;g1;50;150;85;false;false
+Pivot Resolution;pivot_resolution;Double|T|3;g1;50;150;85;false;false
+Data reduction software;data_reduction_software;String;g4;50;400;95;false;false
+Max observed residues;max_observed_residues;Integer|F;g6;50;400;95;false;false
+Organism scientific name;organism_scientific_name;String;g3;50;400;95;false;false
+Super kingdom;superkingdom;String;g3;50;400;95;false;false
+Rank;rank;String;g3;50;400;95;false;false
+Crystallisation Ph;crystallisation_ph;String;g6;50;400;95;false;false
+Biological Function;biological_function;String;g6;50;400;95;false;false
+Biological Process;biological_process;String;g6;50;400;95;false;false
+Biological Cell Component;biological_cell_component;String;g6;50;400;95;false;false
+Compound Name;compound_name;String;g3;50;400;95;false;false
+Compound Id;compound_id;String;g2;50;400;95;false;false
+Compound Weight;compound_weight;String;g6;50;400;95;false;false
+Compound Systematic Name;compound_systematic_name;String;g3;50;400;95;false;false
+Interacting Ligands;interacting_ligands;String;g6;50;400;95;false;false
+Journal;journal;String;g6;50;400;95;false;false
+All Authors;all_authors;String;g6;50;400;95;false;false
+Experiment Data Available;experiment_data_available;String;g6;50;400;95;false;false
+Diffraction Protocol;diffraction_protocol;String;g4;50;400;95;false;false
+Refinement Software;refinement_software;String;g4;50;400;95;false;false
+Structure Determination Method;structure_determination_method;String;g4;50;400;95;false;false
+Synchrotron Site;synchrotron_site;String;g6;50;400;95;false;false
+Sample Preparation Method;sample_preparation_method;String;g4;50;400;95;false;false
+Entry Authors;entry_authors;String;g6;50;400;95;false;false
+Citation Title;citation_title;String;g6;50;400;95;false;false
+Structure Solution Software;structure_solution_software;String;g4;50;400;95;false;false
+Entry Entity;entry_entity;String;g6;50;400;95;false;false
+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 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
+Number of Copies;number_of_copies;int;g6;50;400;95;false;false
+Struc Asym Id;struct_asym_id;String;g2;50;400;95;false;false
+Homologus PDB Entity Id;homologus_pdb_entity_id;String;g2;50;400;95;false;false
+Molecule Synonym;molecule_synonym;String;g6;50;400;95;false;false
+Deposition Site;deposition_site;String;g6;50;400;95;false;false
+Synchrotron Beamline;synchrotron_beamline;String;g6;50;400;95;false;false
+Entity Id; entity_id;String;g2;50;400;95;false;false
+Beam Source Name;beam_source_name;String;g3;50;400;95;false;false
+Processing Site;processing_site;String;g6;50;400;95;false;false
+Entity Weight;entity_weight;Double|T|0;g6;50;400;95;false;false
+Version;_version_;Double|F|0;g6;50;400;95;false;false
+ALL;text;String;g6;50;400;95;false;true
+#
diff --git a/resources/fts/uniprot_data_columns.txt b/resources/fts/uniprot_data_columns.txt
new file mode 100644 (file)
index 0000000..f506648
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+uniprot_data_columns
+#
+_group.id
+_group.name
+_group.sort_order
+g1;Quality Measures;3
+g2;Cross References;2
+g3;Names & Taxonomy;1
+g4;Procedures & Softwares;4
+g5;Date Of;5
+g6;Miscellaneous;6
+g7;Sequences;7
+g8;Function;8
+g9;Interaction;9
+g10;Expression;10
+g11;Gene Ontology;11
+g12;Pathology & Biotech;12
+g13;Subcellular location;13
+g14;PTM / Processing;14
+g15;Structure;15
+g16;Publications;16
+g17;Date of;17
+g18;Family & Domain;18
+#
+_data_column.primary_key;id
+_data_column.default_response_page_size;500
+#
+_data_column.name
+_data_column.code|_data_column.alt_code (optional: used for specifying search code when different from original code)
+_data_column.group_id
+_data_column.data_type
+_data_column.min_col_width
+_data_column.max_col_width
+_data_column.preferred_col_width
+_data_column.is_shown_by_default
+_data_column.is_searchable
+Uniprot Id;id;String;g3;80;150;85;true;true
+Entry Name;entry name|mnemonic;String;g3;100;150;105;true;true
+Protein names;protein names|name;String;g3;300;1500;500;true;true
+Gene Names;genes|gene;String;g3;100;1000;145;true;true
+Organism;organism;String;g3;100;1000;200;true;true
+Organism ID;organism-id;int;g3;60;100;80;false;false
+Proteomes;proteome;String;g3;50;1000;95;false;false
+Taxonomic lineage (ALL);lineage(ALL)|taxonomy;String;g3;50;400;95;false;false
+Virus hosts;virus hosts|host;String;g3;50;1000;95;false;true
+Fragment;fragment;String;g7;50;1000;95;false;false
+Gene encoded by;encodedon;String;g7;50;1000;95;false;false
+Alternative products (isoforms);comment(ALTERNATIVE PRODUCTS);String;g7;50;1000;95;false;false
+Erroneous gene model prediction;comment(ERRONEOUS GENE MODEL PREDICTION);String;g7;50;1000;95;false;false
+Erroneous initiation;comment(ERRONEOUS INITIATION);String;g7;50;1000;95;false;false
+Erroneous translation;comment(ERRONEOUS TRANSLATION);String;g7;50;1000;95;false;false
+Frameshift;comment(FRAMESHIFT);String;g7;50;1000;95;false;false
+Mass spectrometry;comment(MASS SPECTROMETRY);String;g7;50;1000;95;false;false
+Polymorphism;comment(POLYMORPHISM);String;g7;50;1000;95;false;false
+RNA editing;comment(RNA EDITING);String;g7;50;1000;95;false;false
+Sequence caution;comment(SEQUENCE CAUTION);String;g7;50;1000;95;false;false
+Status;reviewed;String;g6;50;100;95;true;true
+Length;length;int|T|0;g7;50;100;65;true;true
+Mass;mass;int|T|0;g7;50;100;80;false;true
+Sequence;sequence;String;g7;50;1000;95;false;false
+Alternative sequence;feature(ALTERNATIVE SEQUENCE);String;g7;50;1000;95;false;false
+Natural variant;feature(NATURAL VARIANT);String;g7;50;1000;95;false;false
+Non-adjacent residues;feature(NON ADJACENT RESIDUES);String;g7;50;1000;95;false;false
+Non-standard residue;feature(NON STANDARD RESIDUE);String;g7;50;1000;95;false;false
+Non-terminal residue;feature(NON TERMINAL RESIDUE);String;g7;50;1000;95;false;false
+Sequence conflict;feature(SEQUENCE CONFLICT);String;g7;50;1000;95;false;false
+Sequence uncertainty;feature(SEQUENCE UNCERTAINTY);String;g7;50;1000;95;false;false
+Version (Sequence);version(sequence);String;g7;50;1000;95;false;false
+EC number;ec;String;g8;50;1000;95;false;true
+Absorption;comment(ABSORPTION);String;g8;50;1000;95;false;false
+Catalytic activity;comment(CATALYTIC ACTIVITY);String;g8;50;1000;95;false;false
+Cofactor;comment(COFACTOR);String;g8;50;1000;95;false;false
+Enzyme regulation;comment(ENZYME REGULATION);String;g8;50;1000;95;false;false
+Function [CC];comment(FUNCTION);String;g8;50;1000;95;false;false
+Kinetics;comment(KINETICS);String;g8;50;1000;95;false;false
+Pathway;comment(PATHWAY);String;g8;50;1000;95;false;false
+Redox potential;comment(REDOX POTENTIAL);String;g8;50;1000;95;false;false
+Temperature dependence;comment(TEMPERATURE DEPENDENCE);String;g8;50;1000;95;false;false
+pH dependence;comment(PH DEPENDENCE);String;g8;50;1000;95;false;false
+Active site;feature(ACTIVE SITE);String;g8;50;1000;95;false;false
+Binding site;feature(BINDING SITE);String;g8;50;1000;95;false;false
+DNA binding;feature(DNA BINDING);String;g8;50;1000;95;false;false
+Metal binding;feature(METAL BINDING);String;g8;50;1000;95;false;false
+Nucleotide binding;feature(NP BIND);String;g8;50;1000;95;false;false
+Site;feature(SITE);String;g8;50;1000;95;false;false
+Annotation;annotation score;String;g6;50;1000;95;false;false
+Features;features;String;g6;50;1000;95;false;false
+Caution;comment(CAUTION);String;g6;50;1000;95;false;false
+Miscellaneous [CC];comment(GENERAL);String;g6;50;1000;95;false;false
+Keywords;keywords|keyword;String;g6;50;1000;95;false;true
+Protein existence;existence;String;g6;50;1000;95;false;true
+ALL;Search All;String;g7;50;1000;95;false;true
+Subunit structure [CC];comment(SUBUNIT);String;g9;50;1000;95;false;false
+Interacts with;interactor;String;g9;50;1000;95;false;false
+Developmental stage;comment(DEVELOPMENTAL STAGE);String;g10;50;1000;95;false;false
+Induction;comment(INDUCTION);String;g10;50;1000;95;false;false
+Tissue specificity;comment(TISSUE SPECIFICITY);String;g10;50;1000;95;false;false
+Gene ontology (GO);go;String;g11;50;1000;95;false;true
+Gene ontology (biological process);go(biological process);String;g11;50;1000;95;false;false
+Gene ontology (molecular function);go(molecular function);String;g11;50;1000;95;false;false
+Gene ontology (cellular component);go(cellular component);String;g11;50;1000;95;false;false
+Gene ontology IDs;go-id;String;g11;50;1000;95;false;true
+Allergenic properties;comment(ALLERGEN);String;g12;50;1000;95;false;false
+Biotechnological use;comment(BIOTECHNOLOGY);String;g12;50;1000;95;false;false
+Disruption phenotype;comment(DISRUPTION PHENOTYPE);String;g12;50;1000;95;false;false
+Involvement in disease;comment(DISEASE);String;g12;50;1000;95;false;false
+Pharmaceutical use;comment(PHARMACEUTICAL);String;g12;50;1000;95;false;false
+Toxic dose;comment(TOXIC DOSE);String;g12;50;1000;95;false;false
+Subcellular location [CC];comment(SUBCELLULAR LOCATION);String;g13;50;1000;95;false;false
+Intramembrane;feature(INTRAMEMBRANE);String;g13;50;1000;95;false;false
+Topological domain;feature(TOPOLOGICAL DOMAIN);String;g13;50;1000;95;false;false
+Transmembrane;feature(TRANSMEMBRANE);String;g13;50;1000;95;false;false
+Post-translational modification;comment(PTM);String;g14;50;1000;95;false;false
+Chain;feature(CHAIN);String;g14;50;1000;95;false;false
+Cross-link;feature(CROSS LINK);String;g14;50;1000;95;false;false
+Disulfide bond;feature(DISULFIDE BOND);String;g14;50;1000;95;false;false
+Glycosylation;feature(GLYCOSYLATION);String;g14;50;1000;95;false;false
+Initiator methionine;feature(INITIATOR METHIONINE);String;g14;50;1000;95;false;false
+Lipidation;feature(LIPIDATION);String;g14;50;1000;95;false;false
+Modified residue;feature(MODIFIED RESIDUE);String;g14;50;1000;95;false;false
+Peptide;feature(PEPTIDE);String;g14;50;1000;95;false;false
+Propeptide;feature(PROPEPTIDE);String;g14;50;1000;95;false;false
+Signal peptide;feature(SIGNAL);String;g14;50;1000;95;false;false
+Transit peptide;feature(TRANSIT);String;g14;50;1000;95;false;false
+3D;3d;String;g15;50;1000;95;false;false
+Beta strand;feature(BETA STRAND);String;g15;50;1000;95;false;false
+Helix;feature(HELIX);String;g15;50;1000;95;false;false
+Turn;feature(TURN);String;g15;50;1000;95;false;false
+PubMed ID;citation;String;g16;50;1000;95;false;true
+Date of creation;created;String;g17;80;150;100;false;true
+Date of last modification;last-modified;String;g17;80;150;100;false;true
+Date of last sequence modification;sequence-modified;String;g17;80;150;100;false;true
+Version (entry);version(entry);int;g17;80;100;80;false;false
+Domain [cc];comment(DOMAIN)|domain;String;g18;80;1000;95;false;true
+Sequence similarities;comment(SIMILARITY);String;g18;50;1000;95;false;false
+Protein families;families|family;String;g18;50;1000;95;false;true
+Coiled coil;feature(COILED COIL);String;g18;50;1000;95;false;false
+Compositional bias;feature(COMPOSITIONAL BIAS);String;g18;50;1000;95;false;false
+Domain [FT];feature(DOMAIN EXTENT);String;g18;50;1000;95;false;false
+Motif;feature(MOTIF);String;g18;50;1000;95;false;false
+Region;feature(REGION);String;g18;50;1000;95;false;false
+Repeat;feature(REPEAT);String;g18;50;1000;95;false;false
+Zinc finger;feature(ZINC FINGER);String;g18;50;1000;95;false;false
+Cross-reference (EMBL);database(EMBL);String;g2;50;1000;95;false;false
+Cross-reference (PDB);database(PDB);String;g2;50;1000;95;false;false
+Cross-reference (ENSEMBL);database(ENSEMBL);String;g2;50;1000;95;false;false
+Cross-reference (PFAM);database(PFAM);String;g2;50;1000;95;false;false
+Cross-reference (RFAM);database(RFAM);String;g2;50;1000;95;false;false
+Cross-reference (CATH);database(CATH);String;g2;50;1000;95;false;false
+Cross-reference (SCOPE);database(SCOPE);String;g2;50;1000;95;false;false
+Cross-reference (GO);database(GO);String;g2;50;1000;95;false;false
+Cross-reference (INTERPRO);database(INTERPRO);String;g2;50;1000;95;false;false
+Mapped PubMed ID;citationmapping;String;g16;50;1000;95;false;true
+#
diff --git a/resources/images/blank_16x16_placeholder.png b/resources/images/blank_16x16_placeholder.png
new file mode 100644 (file)
index 0000000..885ad87
Binary files /dev/null and b/resources/images/blank_16x16_placeholder.png differ
index 9a064b1..864e34a 100644 (file)
@@ -38,7 +38,6 @@ action.cancel = Cancel
 action.create = Create
 action.update = Update
 action.delete = Delete
-action.snapshot = Snapshot
 action.clear = Clear
 action.accept = Accept
 action.select_ddbb = --- Select Database ---
@@ -121,7 +120,6 @@ action.save_as_default = Save as default
 action.save_as = Save as...
 action.save = Save
 action.cancel_fetch = Cancel Fetch
-action.save_omit_hidden_columns = Save / Omit Hidden Regions
 action.change_font = Change Font
 action.change_font_tree_panel = Change Font (Tree Panel)
 action.colour = Colour
@@ -137,21 +135,22 @@ action.show_group = Show Group
 action.fetch_db_references = Fetch DB References
 action.view_flanking_regions = Show flanking regions
 label.view_flanking_regions = Show sequence data either side of the subsequences involved in this alignment
-label.str = Str:
-label.seq = Seq:
 label.structures_manager = Structures Manager
 label.nickname = Nickname:
 label.url = URL:
 label.input_file_url = Enter URL or Input File
-label.select_feature = Select feature:
+label.select_feature = Select feature
 label.name = Name
+label.name\: = Name:
 label.name_param = Name: {0}
 label.group = Group
+label.group\: = Group:
 label.group_name = Group Name
 label.group_description = Group Description
 label.edit_group_name_description = Edit Group Name/Description
 label.colour = Colour:
-label.description = Description:
+label.description = Description
+label.description\: = Description:
 label.start = Start:
 label.end = End:
 label.current_parameter_set_name = Current parameter set name:
@@ -222,8 +221,8 @@ label.proteins = Proteins
 label.to_new_alignment = To New Alignment
 label.to_this_alignment = Add To This Alignment
 label.apply_colour_to_all_groups = Apply Colour To All Groups
-label.modify_identity_thereshold = Modify Identity Threshold...
-label.modify_conservation_thereshold = Modify Conservation Threshold...
+label.modify_identity_threshold = Modify Identity Threshold...
+label.modify_conservation_threshold = Modify Conservation Threshold...
 label.input_from_textbox = Input from textbox
 label.centre_column_labels = Centre column labels
 label.automatic_scrolling = Automatic Scrolling
@@ -240,7 +239,6 @@ label.except_selected_sequences = All except selected sequences
 label.all_but_selected_region = All but Selected Region (Shift+Ctrl+H)
 label.selected_region = Selected Region
 label.all_sequences_columns = All Sequences and Columns
-label.hide_insertions = Hide columns gapped for selection
 label.hide_selected_annotations = Hide selected annotations
 label.show_selected_annotations = Show selected annotations
 label.group_consensus = Group Consensus
@@ -321,7 +319,6 @@ label.found_match_for = Found match for {0}
 label.font = Font:
 label.size = Size:
 label.style = Style:
-label.enter_redundancy_threshold = Enter the redundancy threshold
 label.calculating = Calculating....
 label.modify_conservation_visibility = Modify conservation visibility
 label.colour_residues_above_occurence = Colour residues above % occurence
@@ -365,7 +362,6 @@ label.example = Example
 label.example_param = Example: {0}
 label.select_file_format_before_saving = You must select a file format before saving!
 label.file_format_not_specified = File format not specified
-label.alignment_contains_hidden_columns = The Alignment contains hidden regions (hidden sequences/columns).\nDo you want to save only the visible alignment?
 label.couldnt_save_file = Couldn't save file: {0}
 label.error_saving_file = Error Saving File
 label.remove_from_default_list = Remove from default list?
@@ -386,14 +382,14 @@ 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
 label.enter_view_name = Enter View Name
 label.enter_label = Enter label
-label.enter_label_for_the_structure = Enter a label for the structure?
+label.enter_label_for_the_structure = Enter a label for the structure
 label.pdb_entry_is_already_displayed = {0} is already displayed.\nDo you want to re-use this viewer ?
 label.map_sequences_to_visible_window = Map Sequences to Visible Window: {0}
 label.add_pdbentry_to_view = Do you want to add {0} to the view called\n{1}\n
@@ -467,7 +463,6 @@ label.no_features_added_to_this_alignment = No Features added to this alignment!
 label.features_can_be_added_from_searches_1 = (Features can be added from searches or
 label.features_can_be_added_from_searches_2 = from Jalview / GFF features files)
 label.calculating_pca= Calculating PCA
-label.reveal_columns = Reveal Columns
 label.jalview_cannot_open_file = Jalview can't open file
 label.jalview_applet = Jalview applet
 label.loading_data = Loading data
@@ -475,7 +470,6 @@ label.memory_stats = Total Free Memory: {0} MB; Max Memory: {1} MB; {2} %
 label.calculating_tree = Calculating tree
 label.state_queueing = queuing
 label.state_running = running
-label.state_complete = complete
 label.state_completed = finished
 label.state_job_cancelled = job cancelled!!
 label.state_job_error = job error!
@@ -501,7 +495,6 @@ label.jmol_help = Jmol Help
 label.chimera_help = Chimera Help
 label.close_viewer = Close Viewer
 label.confirm_close_chimera = This will close Jalview''s connection to {0}.<br>Do you want to close the Chimera window as well?
-label.chimera_help = Chimera Help
 label.all = All
 label.sort_by = Sort alignment by
 label.sort_by_score = Sort by Score
@@ -521,15 +514,14 @@ label.reset_min_max_colours_to_defaults = Reset min and max colours to defaults
 label.align_structures_using_linked_alignment_views = Align structures using {0} linked alignment views
 label.connect_to_session = Connect to session {0}
 label.threshold_feature_display_by_score = Threshold the feature display by score.
-label.threshold_feature_no_thereshold = No Threshold
-label.threshold_feature_above_thereshold = Above Threshold
-label.threshold_feature_below_thereshold = Below Threshold
-label.adjust_thereshold = Adjust threshold
+label.threshold_feature_no_threshold = No Threshold
+label.threshold_feature_above_threshold = Above Threshold
+label.threshold_feature_below_threshold = Below Threshold
+label.adjust_threshold = Adjust threshold
 label.toggle_absolute_relative_display_threshold = Toggle between absolute and relative display threshold.
 label.display_features_same_type_different_label_using_different_colour = Display features of the same type with a different label using a different colour. (e.g. domain features)
 label.select_colour_minimum_value = Select Colour for Minimum Value
 label.select_colour_maximum_value = Select Colour for Maximum Value
-label.open_new_jmol_view_with_all_structures_associated_current_selection_superimpose_using_alignment = Open a new structure viewer with all structures associated with the current selection and superimpose them using the alignment.
 label.open_url_param = Open URL {0}
 label.open_url_seqs_param = Open URL ({0}..) ({1} seqs)
 label.load_pdb_file_associate_with_sequence = Load a PDB file and associate it with sequence {0}
@@ -584,8 +576,8 @@ label.histogram = Histogram
 label.logo = Logo
 label.non_positional_features = List Non-positional Features
 label.database_references = List Database References
-label.share_selection_across_views = Share selection across views
-label.scroll_highlighted_regions = Scroll to highlighted regions
+#label.share_selection_across_views = Share selection across views
+#label.scroll_highlighted_regions = Scroll to highlighted regions
 label.gap_symbol = Gap Symbol
 label.prot_alignment_colour = Protein Alignment Colour
 label.nuc_alignment_colour = Nucleotide Alignment Colour
@@ -608,7 +600,6 @@ label.automatically_set_id_width = Automatically set ID width
 label.figure_id_column_width = Figure ID column width
 label.use_modeller_output = Use Modeller Output
 label.wrap_alignment = Wrap Alignment
-label.hide_introns = Hide Introns
 label.right_align_ids = Right Align Ids
 label.sequence_name_italics = Italic Sequence Ids
 label.open_overview = Open Overview
@@ -669,20 +660,12 @@ label.cut_paste = Cut'n'Paste
 label.adjusting_parameters_for_calculation = Adjusting parameters for existing Calculation
 label.2d_rna_structure_line = 2D RNA {0} (alignment)
 label.2d_rna_sequence_name = 2D RNA - {0}
-label.edit_name_and_description_current_group = Edit name and description of current group.
-label.view_structure_for = View structure for {0}
-label.view_all_structures = View all {0} structures.
-label.view_all_representative_structures = View all {0} representative structures.
-label.open_new_jmol_view_with_all_representative_structures_associated_current_selection_superimpose_using_alignment = Opens a new structure viewer with all representative structures\nassociated with the current selection\nsuperimposed with the current alignment.
-label.associate_structure_with_sequence = Associate Structure with Sequence
+label.edit_name_and_description_current_group = Edit name and description of current group
 label.from_file = From File
-label.enter_pdb_id = Enter PDB Id
-label.discover_pdb_ids = Discover PDB IDs
+label.enter_pdb_id = Enter PDB Id (or pdbid:chaincode)
 label.text_colour = Text Colour
 action.set_text_colour = Text Colour...
 label.structure = Structure
-label.view_structure = View Structure
-label.view_protein_structure = View Protein Structure
 label.show_pdbstruct_dialog = 3D Structure Data...
 label.view_rna_structure = VARNA 2D Structure
 label.clustalx_colours = Clustalx colours
@@ -710,7 +693,6 @@ label.translate_cDNA = Translate as cDNA
 label.reverse = Reverse
 label.reverse_complement = Reverse Complement
 label.linked_view_title = Linked CDS and protein view
-label.align = Align
 label.extract_scores = Extract Scores
 label.get_cross_refs = Get Cross-References
 label.sort_alignment_new_tree = Sort Alignment With New Tree
@@ -722,7 +704,6 @@ label.use_registry = Use Registry
 label.add_local_source = Add Local Source
 label.set_as_default = Set as Default
 label.show_labels = Show labels
-label.background_colour = Background Colour
 action.background_colour = Background Colour...
 label.associate_nodes_with = Associate Nodes With
 label.jalview_pca_calculation = Jalview PCA Calculation
@@ -748,8 +729,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}
@@ -791,7 +772,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 PDB 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}
@@ -802,10 +783,14 @@ label.wswublast_client_credits = To display sequence features an exact Uniprot i
 label.blasting_for_unidentified_sequence = BLASTing for unidentified sequences
 label.select_columns_containing = Select columns containing
 label.select_columns_not_containing = Select columns that do not contain
+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_2 = to embed sequence id in URL
+label.use_sequence_id_3 = Use $SEQUENCE_NAME$ similarly to embed sequence name
+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
@@ -813,7 +798,6 @@ label.services_at = Services at {0}
 label.rest_client_submit = {0} using {1}
 label.fetch_retrieve_from =Retrieve from {0}</html>
 label.fetch_retrieve_from_all_sources = Retrieve from all {0} sources in {1}<br>First is :{2}<html> 
-#label.feature_settings_click_drag = <html>Click/drag feature types up or down to change render order.<br/>Double click to select columns containing feature in alignment/current selection<br/>Pressing Alt will select columns outside features rather than inside<br/>Pressing Shift to modify current selection (rather than clear current selection)<br/>Press CTRL or Command/Meta to toggle columns in/outside features<br/></html>
 label.feature_settings_click_drag = Drag up or down to change render order.<br/>Double click to select columns containing feature.
 label.transparency_tip = Adjust transparency to 'see through' feature colours.
 label.opt_and_params_further_details = see further details by right-clicking
@@ -829,17 +813,10 @@ label.user_preset = User Preset
 label.service_preset = Service Preset
 label.run_with_preset = Run {0} with preset
 label.view_service_doc_url = <html>View <a href="{0}">{1}</a></html>
-label.submit_sequence = <html>Submit {0} {1} {2} {3} to<br/>{4}</html>
 action.by_title_param = By {0}
-label.alignment = Alignment
-label.secondary_structure_prediction = Secondary Structure Prediction
-label.sequence_database_search = Sequence Database Search
-label.analysis = Analysis
-label.protein_disorder = Protein Disorder 
 label.source_from_db_source = Sources from {0}
 label.from_msname = from {0}
 label.superpose_with = Superpose with
-action.do = Do
 label.scale_label_to_column = Scale Label to Column
 label.add_new_row = Add New Row
 label.edit_label_description = Edit Label/Description
@@ -883,7 +860,7 @@ label.service_url = Service URL
 label.copied_sequences = Copied sequences
 label.cut_sequences = Cut Sequences
 label.conservation_colour_increment = Conservation Colour Increment ({0})
-label.percentage_identity_thereshold = Percentage Identity Threshold ({0})
+label.percentage_identity_threshold = Percentage Identity Threshold ({0})
 label.error_unsupported_owwner_user_colour_scheme = Unsupported owner for User Colour scheme dialog
 label.save_alignment_to_file = Save Alignment to file
 label.save_features_to_file = Save Features to File
@@ -899,7 +876,6 @@ label.save_vamsas_document_archive = Save Vamsas Document Archive
 label.saving_vamsas_doc = Saving VAMSAS Document to {0}
 label.load_feature_colours = Load Feature Colours
 label.save_feature_colours = Save Feature Colour Scheme
-label.dataset_for = {0} Dataset for {1}
 label.select_startup_file = Select startup file
 label.select_default_browser = Select default web browser
 label.save_tree_as_newick = Save tree as newick file
@@ -927,15 +903,9 @@ error.null_from_clone1 = Null from clone1!
 error.implementation_error_sortbyfeature = Implementation Error - sortByFeature method must be one of FEATURE_SCORE, FEATURE_LABEL or FEATURE_DENSITY.
 error.not_yet_implemented = Not yet implemented
 error.unknown_type_dna_or_pep = Unknown Type {0} - dna or pep are the only allowed values.
-error.implementation_error_dont_know_thereshold_annotationcolourgradient = Implementation error: don't know about threshold setting for current AnnotationColourGradient.
-error.implementation_error_embeddedpopup_not_null = Implementation error - embeddedPopup must be non-null
-error.invalid_colour_for_mycheckbox = Invalid color for MyCheckBox
-error.implementation_error_unrecognised_render_object_for_features_type = Implementation Error: Unrecognised render object {0} for features of type {1}
-error.implementation_error_unsupported_feature_colour_object = Implementation error: Unsupported feature colour object.
+error.implementation_error_dont_know_threshold_annotationcolourgradient = Implementation error: don't know about threshold setting for current AnnotationColourGradient.
 error.invalid_separator_parameter = Invalid separator parameter - must be non-zero length
 error.alignment_cigararray_not_implemented = Alignment(CigarArray) not yet implemented
-error.weak_sequencei_equivalence_not_yet_implemented = Weak sequenceI equivalence not yet implemented.
-error.implementation_error_can_only_make_alignmnet_from_cigararray = Implementation Error - can only make an alignment view from a CigarArray of sequences.
 error.empty_view_cannot_be_updated = empty view cannot be updated.
 error.mismatch_between_number_of_sequences_in_block = Mismatch between number of sequences in block {0} ({1}) and the original view ({2})
 error.padding_not_yet_implemented = Padding not yet implemented
@@ -957,21 +927,18 @@ error.not_yet_implemented_cigar_object_from_cigar_string = NOT YET Implemented:
 error.implementation_bug_cigar_operation = Implementation Bug. Cigar Operation {0} {1} not one of {2}, {3}, or {4}.
 error.implementation_error_for_new_cigar = Implementation error for new Cigar(SequenceI)
 error.implementation_error_cigar_seq_no_operations = Implementation error: {0}th sequence Cigar has no operations.
-error.implementation_error_jmol_getting_data = Implementation error - Jmol seems to be still working on getting its data - report at http://issues.jalview.org/browse/JAL-1016
 error.implementation_error_no_pdbentry_from_index = Implementation error - no corresponding pdbentry (for index {0}) to add sequences mappings to
 error.jmol_version_not_compatible_with_jalview_version = Jmol version {0} is not compatible with this version of Jalview. Report this problem at issues.jalview.org
 error.not_implemented_remove = Remove: Not implemented
 error.not_implemented_clone = Clone: Not implemented
-error.implementation_error_chimera_getting_data = Implementation error - Chimera seems to be still working on getting its data - report at http://issues.jalview.org/browse/JAL-1016
 error.call_setprogressbar_before_registering_handler = call setProgressBar before registering the progress bar's handler.
 label.cancelled_params = Cancelled {0}
 error.implementation_error_cannot_show_view_alignment_frame = Implementation error: cannot show a view from another alignment in an AlignFrame.
-error.implementation_error_dont_know_about_thereshold_setting = Implementation error: don't know about threshold setting for current AnnotationColourGradient.
+error.implementation_error_dont_know_about_threshold_setting = Implementation error: don't know about threshold setting for current AnnotationColourGradient.
 error.eps_generation_not_implemented = EPS Generation not yet implemented
 error.png_generation_not_implemented = PNG Generation not yet implemented
 error.try_join_vamsas_session_another = Trying to join a vamsas session when another is already connected
 error.invalid_vamsas_session_id = Invalid vamsas session id
-error.implementation_error_cannot_create_groovyshell = Implementation Error. Cannot create groovyShell without Groovy on the classpath!
 label.groovy_support_failed = Jalview Groovy Support Failed
 label.couldnt_create_groovy_shell = Couldn't create the groovy Shell. Check the error log for the details of what went wrong.
 error.unsupported_version_calcIdparam = Unsupported Version for calcIdparam {0}
@@ -986,7 +953,6 @@ error.setstatus_called_non_existent_job_pane = setStatus called for non-existent
 error.implementation_error_cannot_find_marshaller_for_param_set =Implementation error: Can't find a marshaller for the parameter set
 error.implementation_error_old_jalview_object_not_bound =IMPLEMENTATION ERROR: old jalview object is not bound ! ({0})
 error.implementation_error_vamsas_doc_class_should_bind_to_type = Implementation Error: Vamsas Document Class {0} should bind to a {1} (found a {2})
-error.implementation_error_jalview_class_should_bind_to_type = Implementation Error: Jalview Class {0} should bind to a {1} (found a {2})
 error.invalid_vamsas_rangetype_cannot_resolve_lists = Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!
 error.implementation_error_maplist_is_null = Implementation error. MapList is null for initMapType.
 error.implementation_error_cannot_have_null_alignment = Implementation error: Cannot have null alignment property key
@@ -1028,10 +994,11 @@ error.implementation_error_need_to_have_httpresponse = Implementation Error: nee
 error.dbrefsource_implementation_exception =DBRefSource Implementation Exception
 error.implementation_error_dbinstance_must_implement_interface = Implmentation Error - getDbInstances must be given a class that implements jalview.ws.seqfetcher.DbSourceProxy (was given{0})
 error.implementation_error_must_init_dbsources =Implementation error. Must initialise dbSources
-label.view_controller_toggled_marked = {0} {1} columns {2} containing features of type {3}  across {4} sequence(s)
+label.view_controller_toggled_marked = {0} {1} columns {2} features of type {3}  across {4} sequence(s)
 label.toggled = Toggled
 label.marked = Marked
-label.not = not
+label.containing = containing
+label.not_containing = not containing
 label.no_feature_of_type_found = No features of type {0} found.
 label.submission_params = Submission {0}
 label.empty_alignment_job = Empty Alignment Job
@@ -1041,7 +1008,7 @@ label.pca_recalculating = Recalculating PCA
 label.pca_calculating = Calculating PCA
 label.select_foreground_colour = Choose foreground colour
 label.select_colour_for_text = Select Colour for Text
-label.adjunst_foreground_text_colour_thereshold = Adjust Foreground Text Colour Threshold
+label.adjunst_foreground_text_colour_threshold = Adjust Foreground Text Colour Threshold
 label.select_subtree_colour = Select Sub-Tree Colour
 label.create_new_sequence_features = Create New Sequence Feature(s)
 label.amend_delete_features = Amend/Delete Features for {0}
@@ -1061,7 +1028,6 @@ exception.mismatched_unseen_closing_char = Mismatched (unseen) closing character
 exception.mismatched_closing_char = Mismatched closing character {0}
 exception.mismatched_opening_char = Mismatched opening character {0} at {1}
 exception.invalid_datasource_couldnt_obtain_reader = Invalid datasource. Could not obtain Reader
-exception.index_value_not_in_range = {0}: Index value {1} not in range [0..{2}]
 exception.unterminated_cigar_string = Unterminated cigar string
 exception.unexpected_operation_cigar_string_pos = Unexpected operation {0} in cigar string (position {1} in {2}
 exception.couldnt_parse_responde_from_annotated3d_server = Couldn't parse response from Annotate3d server
@@ -1089,7 +1055,6 @@ exception.ranml_problem_parsing_data = Problem parsing data as RNAML ({0})
 exception.pfam_no_sequences_found = No sequences found (PFAM input)
 exception.stockholm_invalid_format = This file is not in valid STOCKHOLM format: First line does not contain '# STOCKHOLM'
 exception.couldnt_parse_sequence_line = Could not parse sequence line: {0}
-exception.error_parsing_line = Error parsing {0}
 exception.unknown_annotation_detected = Unknown annotation detected: {0} {1}
 exception.couldnt_store_sequence_mappings = Couldn't store sequence mappings for {0}
 exception.matrix_too_many_iteration = Too many iterations in {0} (max is {1})
@@ -1097,7 +1062,6 @@ exception.browser_not_found = Exception in finding browser: {0}
 exception.browser_unable_to_locate = Unable to locate browser: {0}
 exception.invocation_target_exception_creating_aedesc = InvocationTargetException while creating AEDesc: {0}
 exception.illegal_access_building_apple_evt= IllegalAccessException while building AppleEvent: {0}
-exception.instantiation_creating_aedesc = InstantiationException while creating AEDesc: {0}
 exception.unable_to_launch_url = Unable to launch URL: {0}
 exception.unable_to_create_internet_config = Unable to create an Internet Config instance: {0}
 exception.invocation_target_calling_url = InvocationTargetException while calling openURL: {0}
@@ -1106,8 +1070,6 @@ exception.interrupted_launching_browser = InterruptedException while launching b
 exception.das_source_doesnt_support_sequence_command = Source {0} does not support the sequence command.
 exception.invalid_das_source = Invalid das source: {0}
 exception.ebiembl_retrieval_failed_on = EBI EMBL XML retrieval failed on {0}:{1}
-label.no_embl_record_found = # No EMBL record retrieved for {0}:{1}
-label.embl_successfully_parsed = # Successfully parsed the {0} queries into an Alignment
 exception.no_pdb_records_for_chain = No PDB Records for {0} chain {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Unexpected exception when handling RNAML translation of PDB data
 exception.couldnt_recover_sequence_properties_for_alignment = Couldn't recover sequence properties for alignment
@@ -1168,7 +1130,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
@@ -1198,8 +1160,8 @@ label.edit_jabaws_url = Edit JABAWS URL
 label.add_jabaws_url = Add new JABAWS URL
 label.news_from_jalview = News from http://www.jalview.org
 label.cut_paste_alignmen_file = Cut & Paste Alignment File
-label.enter_redundancy_thereshold = Enter the redundancy threshold
-label.select_dark_light_set_thereshold = <html><i>Select a dark and light text colour, then set the threshold to<br>switch between colours, based on background colour</i></html>
+label.enter_redundancy_threshold = Enter the redundancy threshold
+label.select_dark_light_set_threshold = <html><i>Select a dark and light text colour, then set the threshold to<br>switch between colours, based on background colour</i></html>
 label.select_feature_colour = Select Feature Colour
 label.delete_all = Delete all sequences
 warn.delete_all = <html>Deleting all sequences will close the alignment window.<br>Confirm deletion or Cancel.
@@ -1220,29 +1182,24 @@ label.no_colour_selection_in_scheme = Please make a colour selection before appl
 label.no_colour_selection_warn = Error saving colour scheme
 label.open_split_window? = Would you like to open as a split window, with cDNA and protein linked?
 label.open_split_window = Open split window
-label.no_mappings = No mappings found
 action.no = No
 action.yes = Yes
 label.for = for
 label.select_by_annotation = Select/Hide Columns by Annotation
 action.select_by_annotation = Select/Hide Columns by Annotation...
 label.threshold_filter =  Threshold Filter
-action.hide = Hide
-action.select = Select
 label.alpha_helix = Alpha Helix
 label.beta_strand = Beta Strand
 label.turn = Turn
 label.select_all = Select All
 label.structures_filter = Structures Filter
 label.search_filter = Search Filter
-label.description = Description
 label.include_description= Include Description
 action.back = Back
 label.hide_insertions = Hide Insertions
 label.mark_as_representative = Mark as representative
 label.open_jabaws_web_page = Open JABAWS web page
-label.opens_the_jabaws_server_homepage = Opens the JABAWS server's homepage in web browser
-label.pdb_sequence_getcher = PDB Sequence Fetcher
+label.pdb_sequence_fetcher = PDB Sequence Fetcher
 label.result = result
 label.results = results
 label.structure_chooser = Structure Chooser
@@ -1259,7 +1216,6 @@ label.biojs_html_export = BioJS
 label.scale_as_cdna = Scale protein residues to codons
 label.scale_protein_to_cdna = Scale Protein to cDNA
 label.scale_protein_to_cdna_tip = Make protein residues same width as codons in split frame views
-label.hide_introns_tip = Hide intron columns after fetching genomic sequences
 info.select_annotation_row = Select Annotation Row
 info.enter_search_text_here = Enter Search Text Here
 info.enter_search_text_to_enable = Enter Search Text to Enable
@@ -1281,16 +1237,34 @@ label.structure_chooser_filter_time = Structure Chooser - Filter time ({0})
 label.structure_chooser_no_of_structures = Structure Chooser - {0} Found ({1})
 info.no_pdb_entry_found_for = No PDB entry found for {0}
 exception.unable_to_detect_internet_connection = Jalview is unable to detect an internet connection
-exception.pdb_rest_service_no_longer_available = PDB rest services no longer available!
+exception.fts_rest_service_no_longer_available = {0} rest services no longer available!
 exception.resource_not_be_found = The requested resource could not be found
-exception.pdb_server_error = There seems to be an error from the PDB server
-exception.pdb_server_unreachable = Jalview is unable to reach the PDBe Solr server. \nPlease ensure that you are connected to the internet and try again.
+exception.fts_server_error = There seems to be an error from the {0} server
+exception.fts_server_unreachable = Jalview is unable to reach the {0} server. \nPlease ensure that you are connected to the internet and try again.
 label.nw_mapping = Needleman & Wunsch Alignment
 label.sifts_mapping = SIFTs Mapping
 label.mapping_method = Sequence \u27f7 Structure mapping method
-label.mapping_method = Sequence \u27f7 Structure mapping method
-status.waiting_for_user_to_select_output_file = Waiting for user to select {0} file.
-status.cancelled_image_export_operation = Cancelled {0} export operation.
-info.error_creating_file = Error creating {0} file.
+status.waiting_for_user_to_select_output_file = Waiting for user to select {0} file
+status.cancelled_image_export_operation = Cancelled {0} export operation
+info.error_creating_file = Error creating {0} file
 exception.outofmemory_loading_mmcif_file = Out of memory loading mmCIF File
-info.error_creating_file = Error creating {0} file.
+label.run_groovy = Run Groovy console script
+label.run_groovy_tip = Run the script in the Groovy console over this alignment
+label.couldnt_run_groovy_script = Failed to run Groovy script
+label.uniprot_sequence_fetcher = UniProt Sequence Fetcher
+action.next_page= >> 
+action.prev_page= << 
+label.next_page_tooltip=Next Page
+label.prev_page_tooltip=Previous Page
+exception.bad_request=Bad request. There is a problem with your input.
+exception.service_not_available=Service not available. The server is being updated, try again later.
+status.launching_3d_structure_viewer = Launching 3D Structure viewer...
+status.fetching_3d_structures_for_selected_entries = Fetching 3D Structures for selected entries...
+status.fetching_dbrefs_for_sequences_without_valid_refs = Fetching db refs for {0} sequence(s) without valid db ref required for SIFTS mapping
+status.fetching_3d_structures_for = Fetching 3D Structure for {0}
+status.obtaining_mapping_with_sifts = Obtaining mapping with SIFTS
+status.obtaining_mapping_with_nw_alignment = Obtaining mapping with NW alignment
+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
index 3535f4b..754d94d 100644 (file)
@@ -38,7 +38,6 @@ action.cancel = Cancelar
 action.create = Crear
 action.update = Actualizar
 action.delete = Borrar
-action.snapshot = Imagen
 action.clear = Limpiar
 action.accept = Aceptar
 action.select_ddbb = --- Seleccionar base de datos ---
@@ -118,7 +117,6 @@ action.save_as_default = Guardar como por defecto
 action.save_as = Guardar como
 action.save = Guardar
 action.cancel_fetch = Cancelar búsqueda
-action.save_omit_hidden_columns = Guardar / Omitir las columnas ocultas
 action.change_font = Cambiar Fuente
 action.change_font_tree_panel = Cambiar fuente (panel del Ã¡rbol)
 action.colour = Color
@@ -134,21 +132,22 @@ action.show_group = Mostrar grupo
 action.fetch_db_references = Recuperar referencias a base de datos
 action.view_flanking_regions = Mostrar flancos
 label.view_flanking_regions = Mostrar los datos de la secuencia a ambos lados de las subsecuencias implicadas en este alineamiento
-label.str = Str: 
-label.seq = Seq: 
 label.structures_manager = Administrar estructuras
 label.nickname = Sobrenombre:
 label.url = URL: 
 label.input_file_url = Introducir URL en el fichero de entrada
-label.select_feature = Seleccionar función:
-label.name = Nombre:
+label.select_feature = Seleccionar característica
+label.name = Nombre
+label.name\: = Nombre:
 label.name_param = Nombre: {0}
-label.group = Grupo:
+label.group = Grupo
+label.group\: = Grupo:
 label.group_name = Nombre del grupo
 label.group_description = Descripción del grupo
 label.edit_group_name_description = Editar nombre/descripción del grupo
 label.colour = Color:
-label.description = Descripción:
+label.description = Descripción
+label.description\: = Descripción:
 label.start = Comenzar:
 label.end = Terminar:
 label.current_parameter_set_name = Nombre actual del conjunto de parámetros:
@@ -208,8 +207,8 @@ label.nucleotide = Nucle
 label.to_new_alignment = A nuevo alineamiento
 label.to_this_alignment = Añadir a este alineamiento
 label.apply_colour_to_all_groups = Aplicar color a todos los grupos
-label.modify_identity_thereshold = Modificar el umbral de identidad...
-label.modify_conservation_thereshold = Modificar el umbral de conservación...
+label.modify_identity_threshold = Modificar el umbral de identidad...
+label.modify_conservation_threshold = Modificar el umbral de conservación...
 label.input_from_textbox = Introducir desde el cuadro de texto
 label.centre_column_labels = Centrar las etiquetas de las columnas
 label.automatic_scrolling = Desplazamiento automático
@@ -217,7 +216,6 @@ label.documentation = Documentaci
 label.about = Acerca de...
 label.show_sequence_limits = Mostrar los límites de la secuencia
 label.feature_settings = Ajustar funciones...
-label.sequence_features = Funciones de la secuencia
 label.all_columns = Todas las columnas
 label.all_sequences = Todas las secuencias
 label.selected_columns = Columnas seleccionadas
@@ -277,7 +275,7 @@ label.order_by_params = Ordenar por {0}
 label.html_content = <html>{0}</html>
 label.paste_pdb_file= Pegar tu fichero PDB aquí.
 label.paste_pdb_file_for_sequence = Pegar fichero PDB para la secuencia {0}
-label.could_not_parse_newick_file  = No se pudo analizar el fichero Newick\\\!\\n {0}
+label.could_not_parse_newick_file  = No se pudo analizar el fichero Newick\!\n {0}
 label.successfully_pasted_tcoffee_scores_to_alignment= Pegada exitosamente la puntuación T-Coffee al alineamiento.
 label.failed_add_tcoffee_scores = Fallo al añadir las puntuaciones T-Coffee: 
 label.successfully_pasted_annotation_to_alignment = Anotación pegada exitosamente al alineamiento.
@@ -291,7 +289,6 @@ label.found_match_for = Buscar coincidencia para {0}
 label.font = Fuente:
 label.size = Talla:
 label.style = Estilo:
-label.enter_redundancy_threshold = Introducir el umbral de redundancia
 label.calculating = Calculando....
 label.modify_conservation_visibility = Modificar la visibilidad de conservación
 label.colour_residues_above_occurence = Residuos de color por encima del % de aparición 
@@ -315,13 +312,11 @@ label.blog_item_published_on_date = {0} {1}
 label.select_das_service_from_table = Seleccionar servicio DAS de la tabla para leer una descripción completa aquí.
 label.session_update = Actualizar sesión
 label.new_vamsas_session = Nueva sesión Vamsas
-label.load_vamsas_session = Cargar sesión Vamsas
-label.save_vamsas_session = Guardar sesión Vamsas
 action.save_vamsas_session = Guardar Sesión Vamsas
 label.select_vamsas_session_opened_as_new_vamsas_session= Selecciones una sesión vamsas para abrirla como una nueva sesión.
 label.open_saved_vamsas_session = Abrir una sesión VAMSAS guardada
 label.groovy_console = Consola Groovy 
-label.lineart = lineart
+label.lineart = Lineart
 label.dont_ask_me_again = No volver a preguntar
 label.select_eps_character_rendering_style = Seleccionar el carácter EPS como estilo de visualización 
 label.invert_selection = Invertir selección
@@ -336,39 +331,38 @@ label.example = Ejemplo
 label.example_param = Ejemplo: {0}
 label.select_file_format_before_saving = Debe seleccionar un formato de fichero antes de guardar!
 label.file_format_not_specified = Formato de fichero no especificado
-label.alignment_contains_hidden_columns = El alineamiento contiene columnas ocultas.\\nQuieres guardar s\u00F3lo el alineamiento visible?
 label.couldnt_save_file = No se pudo guardar el fichero: {0}
 label.error_saving_file = Error guardando el fichero
 label.remove_from_default_list = eliminar de la lista de defectuosos?
 label.remove_user_defined_colour = Eliminar el color definido por el usuario
 label.you_must_select_least_two_sequences = Debes seleccionar al menos 2 secuencias.
 label.invalid_selection = Selección inválida
-label.principal_component_analysis_must_take_least_four_input_sequences = El an\u00E1lisis de la componente principal debe tomar\\nal menos 4 secuencias de entrada.
+label.principal_component_analysis_must_take_least_four_input_sequences = El an\u00E1lisis de la componente principal debe tomar\nal menos 4 secuencias de entrada.
 label.sequence_selection_insufficient = Selección de secuencias insuficiente
 label.you_need_more_two_sequences_selected_build_tree = necesitas seleccionar más de dos secuencias para construir un Ã¡rbol!
 label.not_enough_sequences = No suficientes secuencias
-label.selected_region_to_tree_may_only_contain_residues_or_gaps = La regi\u00F3n seleccionada para construir un \u00E1rbol puede\\ncontener s\u00F3lo residuos o espacios.\\nPrueba usando la funci\u00F3n Pad en el men\u00FA de edici\u00F3n,\\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
+label.selected_region_to_tree_may_only_contain_residues_or_gaps = La regi\u00F3n seleccionada para construir un \u00E1rbol puede\ncontener s\u00F3lo residuos o espacios.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de edici\u00F3n,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
 label.sequences_selection_not_aligned = Las secuencias seleccionadas no están alineadas
-label.sequences_must_be_aligned_before_creating_tree = Las secuencias deben estar alineadas antes de crear el \u00E1rbol.\\nPrueba usando la funci\u00F3n Pad en el men\u00FA de editar,\\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
+label.sequences_must_be_aligned_before_creating_tree = Las secuencias deben estar alineadas antes de crear el \u00E1rbol.\nPrueba usando la funci\u00F3n Pad en el men\u00FA de editar,\n o uno de los m\u00FAltiples servicios web de alineamiento de secuencias.
 label.sequences_not_aligned = Secuencias no alineadas
 label.problem_reading_tree_file =  Problema al leer el fichero del Ã¡rbol
 label.possible_problem_with_tree_file = Posible problema con el fichero del Ã¡rbol
 label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation = Por favor seleccionar al menos tres bases de al menos una secuencia para poder realizar la traducción de cDNA.
 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.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 structure con las secuencias del alineamiento que tengan el mismo nombre?
+label.automatically_associate_structure_files_by_name = Asociar los ficheros structure 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 = Introducir nombre visible (¿?)
+label.enter_view_name = Introduzca un nombre para la vista
 label.enter_label = Introducir etiqueta
-label.enter_label_for_the_structure = Introducir una etiqueta para la estructura?
-label.pdb_entry_is_already_displayed = {0} Ya est\u00E1 mostrado.\\nQuieres volver a usar este visor?
+label.enter_label_for_the_structure = Introducir una etiqueta para la estructura
+label.pdb_entry_is_already_displayed = {0} Ya est\u00E1 mostrado.\nQuieres volver a usar este visor?
 label.map_sequences_to_visible_window = Mapa de secuencias en ventana visible: {0}
-label.add_pdbentry_to_view = Quieres a\u00F1adir {0} a la vista llamada\\n{1}\\n
+label.add_pdbentry_to_view = Quieres a\u00F1adir {0} a la vista llamada\n{1}\n
 label.align_to_existing_structure_view = Alinear a una estructura ya existente
-label.pdb_entries_couldnt_be_retrieved = Las siguientes entradas pdb no pueden ser extra\u00EDdas del PDB\\\:\\n{0}\\nPor favor, prueba descarg\u00E1ndolas manualmente.
+label.pdb_entries_couldnt_be_retrieved = Las siguientes entradas pdb no pueden ser extra\u00EDdas del PDB\:\n{0}\nPor favor, prueba descarg\u00E1ndolas manualmente.
 label.couldnt_load_file = No se pudo cargar el fichero
 label.couldnt_find_pdb_id_in_file = No se pudo encontrar un Id PDB en el fichero suministrado. Por favor, introduzca un Id para identificar esta estructura.
 label.no_pdb_id_in_file = No hay un Id PDB en el fichero
@@ -394,11 +388,11 @@ label.invalid_url = URL Invalido!
 label.error_loading_file = Error al cargar el fichero
 label.problems_opening_file = Encontrados problemas al abrir el fichero {0}!!
 label.file_open_error = Error al abrir el fichero
-label.no_das_sources_selected_warn = No han sido seleccionadas fuentes DAS.\\nPor favor, seleccione algunas fuentes y\\npruebe de nuevo.
+label.no_das_sources_selected_warn = No han sido seleccionadas fuentes DAS.\nPor favor, seleccione algunas fuentes y\npruebe de nuevo.
 label.no_das_sources_selected_title = No han sido seleccionadas fuentes DAS
-label.colour_scheme_exists_overwrite = El esquema de colores {0} ya existe.\\nContinuar guardando el esquema de colores como {1}?
+label.colour_scheme_exists_overwrite = El esquema de colores {0} ya existe.\nContinuar guardando el esquema de colores como {1}?
 label.duplicate_scheme_name = Duplicar nombre de esquema
-label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\\n
+label.jalview_new_questionnaire = Hay un nuevo cuestionario disponible. Querr\u00EDa completarlo ahora ?\n
 label.jalview_user_survey = Encuesta de usuario Jalview 
 label.alignment_properties = Propiedades del alineamiento: {0}
 label.alignment_props = Propiedades del alineamiento
@@ -436,7 +430,6 @@ label.no_features_added_to_this_alignment = No hay funciones asociadas a este al
 label.features_can_be_added_from_searches_1 = (Las funciones pueden ser añadidas de búsquedas o
 label.features_can_be_added_from_searches_2 = de ficheros de funciones Jalview / GFF)
 label.calculating_pca= Calculando PCA
-label.reveal_columns = Mostrar Columnas
 label.jalview_cannot_open_file = Jalview no puede abrir el fichero
 label.jalview_applet = Aplicación Jalview  
 label.loading_data = Cargando datos
@@ -444,7 +437,6 @@ label.memory_stats = Memoria libre total: {0} MB; Memoria m
 label.calculating_tree = Calculando Ã¡rbol
 label.state_queueing = En cola 
 label.state_running = Procesando
-label.state_complete = Completar
 label.state_completed = Finalizado
 label.state_job_cancelled = Â¡Trabajo cancelado!
 label.state_job_error = Error del trabajo!
@@ -458,8 +450,6 @@ label.load_associated_tree = Cargar 
 label.load_features_annotations = Cargar características/anotaciones ...
 label.export_features = Exportar características...
 label.export_annotations = Exportar anotaciones ...
-label.jalview_copy = Copiar (sólo Jalview)
-label.jalview_cut = Cortar (sólo Jalview)
 label.to_upper_case = Pasar a mayúsculas
 label.to_lower_case = Pasar a minúsculas
 label.toggle_case = Alternar mayúsculas y minúsculas
@@ -468,8 +458,9 @@ label.create_sequence_feature = Crear funci
 label.edit_sequence = Editar secuencia
 label.edit_sequences = Editar secuencias
 label.sequence_details = Detalles de la secuencia
-label.jmol_help = Ayuda de Jmol 
-label.all = Todo
+label.jmol_help = Ayuda de Jmol
+# Todos/Todas is gender-sensitive, but currently only used for feminine (cadena / anotación)! 
+label.all = Todas
 label.sort_by = Ordenar por
 label.sort_by_score = Ordenar por puntuación
 label.sort_by_density = Ordenar por densidad
@@ -485,15 +476,14 @@ label.reset_min_max_colours_to_defaults = Reiniciar los colores min y max colour
 label.align_structures_using_linked_alignment_views = Alinear las estructuras utlizando las {0} vistas de alineamiento enlazadas
 label.connect_to_session = Conectar a la sesión {0}
 label.threshold_feature_display_by_score = Filtrar la característica mostrada por puntuación.
-label.threshold_feature_no_thereshold = Sin umbral
-label.threshold_feature_above_thereshold = Por encima del umbral
-label.threshold_feature_below_thereshold = Por debajo del umbral
-label.adjust_thereshold = Ajustar umbral
+label.threshold_feature_no_threshold = Sin umbral
+label.threshold_feature_above_threshold = Por encima del umbral
+label.threshold_feature_below_threshold = Por debajo del umbral
+label.adjust_threshold = Ajustar umbral
 label.toggle_absolute_relative_display_threshold = Cambiar entre mostrar el umbral absoluto y el relativo.
 label.display_features_same_type_different_label_using_different_colour = Mostrar las características del mismo tipo con una etiqueta diferente y empleando un color distinto (p.e. características del dominio)
 label.select_colour_minimum_value = Seleccionar el color para el valor mínimo
 label.select_colour_maximum_value = Seleccionar el color para el valor máximo
-label.open_new_jmol_view_with_all_structures_associated_current_selection_superimpose_using_alignment = Abrir una nueva vista Jmol con todas las estructuras asociadas con la selección acxtual y superponer las utilizando el alineamiento.
 label.open_url_param = Abrir URL {0}
 label.open_url_seqs_param = Abrir URL ({0}..) ({1} secuencias)
 label.load_pdb_file_associate_with_sequence = Cargar un fichero PDB y asociarlo con la secuencia {0}
@@ -544,10 +534,9 @@ label.histogram = Histograma
 label.logo = Logo
 label.non_positional_features = Características no posicionales
 label.database_references = Referencias a base de datos
-label.share_selection_across_views = Compartir la selección en todas las vistas
-label.scroll_highlighted_regions = Desplazarse hasta las regiones resaltadas
+#label.share_selection_across_views = Compartir la selección en todas las vistas
+#label.scroll_highlighted_regions = Desplazarse hasta las regiones resaltadas
 label.gap_symbol = Símbolo del hueco
-label.alignment_colour = Color del alineamiento
 label.address = Dirección
 label.port = Puerto
 label.default_browser_unix = Navegador por defecto (Unix)
@@ -626,18 +615,11 @@ label.cut_paste = Cortar y pegar
 label.adjusting_parameters_for_calculation = Ajustar los parámetros para el cálculo existente
 label.2d_rna_structure_line = 2D RNA {0}
 label.2d_rna_sequence_name = 2D RNA - {0}
-label.edit_name_and_description_current_group = Editar el nombre y la descripción del grupo actual.
-label.view_structure_for = Visualizar la estructura para {0}
-label.view_all_structures = Visualizar todas las {0} estructuras.
-label.view_all_representative_structures = Visualizar todas las {0} estructuras representativas.
-label.open_new_jmol_view_with_all_representative_structures_associated_current_selection_superimpose_using_alignment = Abrir una nueva vista de Jmol con todas las estructuras representativas\nasociadas con la selecci\u00F3n actual\nsuperpuesta con el alineamiento actual.
-label.associate_structure_with_sequence = Asociar estructura con la secuencia
+label.edit_name_and_description_current_group = Editar el nombre y la descripción del grupo actual
 label.from_file = desde fichero
 label.enter_pdb_id = Introducir PDB Id
-label.discover_pdb_ids = Buscar PDB ids
 label.text_colour = Color del texto
 label.structure = Estructura
-label.view_structure = Visualizar estructura
 label.clustalx_colours = Colores de Clustalx
 label.above_identity_percentage = Sobre % identidad
 label.create_sequence_details_report_annotation_for = Anotación para {0}
@@ -670,7 +652,6 @@ label.use_registry = Utilizar el registro
 label.add_local_source = Añadir fuente local
 label.set_as_default = Establecer por defecto
 label.show_labels = Mostrar etiquetas
-label.background_colour = Color de fondo
 label.associate_nodes_with = Asociar nodos con
 label.jalview_pca_calculation = Cálculo del PCA por Jalview
 label.link_name = Nombre del enalce
@@ -693,8 +674,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}
@@ -740,7 +721,9 @@ 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_2 = para embeber el id de la secuencia en una URL
+label.use_sequence_id_3 = Utilice $SEQUENCE_NAME$ de manera similar para embeber
+label.use_sequence_id_4 = el nombre 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
@@ -763,17 +746,10 @@ label.user_preset = Preselecci
 label.service_preset = Preselección del servicio
 label.run_with_preset = Ejecutar {0} con preselección
 label.view_service_doc_url = Visualizar <a href="{0}">{1}</a></html>
-label.submit_sequence = Enviar {0} {1} {2} {3} a<br/>{4}</html>
 action.by_title_param = por {0}
-label.alignment = Alineamiento
-label.secondary_structure_prediction = Predicción de la estructura secundaria
-label.sequence_database_search = Búsqueda en base de datos de secuencias
-label.analysis = Análisis
-label.protein_disorder = Desorden en la proteína 
 label.source_from_db_source = Fuentes de {0}
 label.from_msname = de {0}
 label.superpose_with = Superponer con...
-action.do = Hacer
 label.scale_label_to_column = Ajustar la etiqueta a la columna
 label.add_new_row = Añadir nuevo fila
 label.edit_label_description = Editar etiqueta/descripción
@@ -817,7 +793,7 @@ label.service_url = URL del servicio
 label.copied_sequences = Secuencias copiadas
 label.cut_sequences = Cortar secuencias
 label.conservation_colour_increment = Incremento de Conservación del Color ({0})
-label.percentage_identity_thereshold = Umbral del Porcentaje de Identidad ({0})
+label.percentage_identity_threshold = Umbral del Porcentaje de Identidad ({0})
 label.error_unsupported_owwner_user_colour_scheme = Propietario no soportado para el diálogo del Esquema Cromático del Usuario
 label.save_alignment_to_file = Guardar Alineamiento en fichero
 label.save_features_to_file = Guardar Características en un fichero
@@ -833,7 +809,6 @@ label.save_vamsas_document_archive = Guardar el archivo de documento Vamsas
 label.saving_vamsas_doc = Guardando el documento VAMSAS en {0}
 label.load_feature_colours = Cargar colores de características
 label.save_feature_colours = Guardar esquema cromático de características
-label.dataset_for = {0} conjunto de datos para {1}
 label.select_startup_file = Seleccionar fichero de arranque
 label.select_default_browser = Seleccionar navegador web por defecto
 label.save_tree_as_newick = Guardar Ã¡rbol como fichero newick
@@ -861,15 +836,9 @@ error.null_from_clone1 = Nulo de clone1!
 error.implementation_error_sortbyfeature = Error de implementación - sortByFeature debe ser uno de FEATURE_SCORE, FEATURE_LABEL o FEATURE_DENSITY.
 error.not_yet_implemented = No se ha implementado todavía
 error.unknown_type_dna_or_pep = Tipo desconocido {0} - dna o pep son los Ãºnicos valores permitidos
-error.implementation_error_dont_know_thereshold_annotationcolourgradient = Error de implementación: no se conoce el valor umbral para el AnnotationColourGradient actual.
-error.implementation_error_embeddedpopup_not_null = Error de implementación - embeddedPopup debe ser no nulo.
-error.invalid_colour_for_mycheckbox = Color no válido para MyCheckBox
-error.implementation_error_unrecognised_render_object_for_features_type = Error de implementación: no se reconoce el objeto de representación {0} para las características de tipo {1}
-error.implementation_error_unsupported_feature_colour_object = Error de implementación: objeto de color de características no soportado.
+error.implementation_error_dont_know_threshold_annotationcolourgradient = Error de implementación: no se conoce el valor umbral para el AnnotationColourGradient actual.
 error.invalid_separator_parameter = Separador de parámetros no válido - debe tener longitud mayor que cero
 error.alignment_cigararray_not_implemented = Alignment(CigarArray) no se ha implementado todavía
-error.weak_sequencei_equivalence_not_yet_implemented = Equivalencia débil sequenceI no se ha implementado todavía.
-error.implementation_error_can_only_make_alignmnet_from_cigararray = Error de implementación - sólo se puede construir un vista de alineamiento a partir de una CigarArray de secuencias.
 error.empty_view_cannot_be_updated = una vista vacía no se puede actualizar.
 error.mismatch_between_number_of_sequences_in_block = No hay coincidencia entre el número de secuencias en el bloque {0} ({1}) y la vista original ({2})
 error.padding_not_yet_implemented = El relleno no se ha implementado todavía
@@ -891,21 +860,18 @@ error.not_yet_implemented_cigar_object_from_cigar_string = No implementado todav
 error.implementation_bug_cigar_operation = Bug de implementación. La operación Cigar {0} {1} no es ni {2}, ni {3} ni {4}.
 error.implementation_error_for_new_cigar = Error de implementación en new Cigar(SequenceI)
 error.implementation_error_cigar_seq_no_operations = Error de implementación: la {0}a secuencia Cigar no tiene operaciones.
-error.implementation_error_jmol_getting_data = Error de implementación - Jmol parece estar todavía intentando recuperar sus datos - informe de ello en http://issues.jalview.org/browse/JAL-1016
 error.implementation_error_no_pdbentry_from_index = Error de implementación - no existe la correspondiente entrada pdb (para el Ã­ndice {0}) para añadir el mapeo de secuencias a
 error.jmol_version_not_compatible_with_jalview_version = La versión {0} de Jmol no es compatible con esta versión de Jalview. Informe de este problema en http://issues.jalview.org
 error.not_implemented_remove = Borrar: no implementado
 error.not_implemented_clone = Clonar: no implementado
-error.implementation_error_chimera_getting_data = Error de implementación - Chimera parece estar todavía intentando recuperar sus datos - informe de ello en http://issues.jalview.org/browse/JAL-1016
 error.call_setprogressbar_before_registering_handler = llamada a setProgressBar antes de registrar el manejador de la barra de estado
 label.cancelled_params = {0} cancelado
 error.implementation_error_cannot_show_view_alignment_frame = Error de implementación: no es posible mostrar una vista de otro alineamiento en un AlignFrame.
-error.implementation_error_dont_know_about_thereshold_setting = Error de implementación: no se conoce la configuración del umbral para el AnnotationColourGradient actual.
+error.implementation_error_dont_know_about_threshold_setting = Error de implementación: no se conoce la configuración del umbral para el AnnotationColourGradient actual.
 error.eps_generation_not_implemented = La generación de EPS no se ha implementado todavía
 error.png_generation_not_implemented = La generación de PNG no se ha implementado todavía
 error.try_join_vamsas_session_another = Tratando de establecer una sesión VAMSAS cuando ya había otra conectada
 error.invalid_vamsas_session_id = Identificador de sesión VAMSAS no válido
-error.implementation_error_cannot_create_groovyshell = Error de implementación:no se puede crear groovyShell sin Groovy en el classpath
 label.groovy_support_failed = El soporte Groovy de Jalview ha fallado
 label.couldnt_create_groovy_shell = No es posible crear el shell de Groovy. Compruebe el fichero de log para conocer los detalles.
 error.unsupported_version_calcIdparam = Versión no soportada de {0}
@@ -920,7 +886,6 @@ error.setstatus_called_non_existent_job_pane = se lllamado a setStatus para el p
 error.implementation_error_cannot_find_marshaller_for_param_set =Error de implementación: no puede encontrar un marshaller para el conjunto de parámetros
 error.implementation_error_old_jalview_object_not_bound =Error de implementación: Â¡el objeto Jalview antiguo no está enlazado! ({0})
 error.implementation_error_vamsas_doc_class_should_bind_to_type = Error de implementación: la clase de documento VAMSAS {0} debe enlazar a {1} (pero se ha encontrado que lo está a {2})
-error.implementation_error_jalview_class_should_bind_to_type = Error de implementación: la clase Jalview {0} debe enlazar a {1} (pero se ha encontrado que lo está a {2})
 error.invalid_vamsas_rangetype_cannot_resolve_lists = RangeType VAMSAS no válido - Â¡no es posible resolver ambas listas de Pos y Seg con los valores elegidos!
 error.implementation_error_maplist_is_null = Error de implementación. MapList es nulo en initMapType.
 error.implementation_error_cannot_have_null_alignment = Error de implementación: no es posible tener una clave nula en el alineamiento
@@ -962,10 +927,11 @@ error.implementation_error_need_to_have_httpresponse = Error de implementaci
 error.dbrefsource_implementation_exception = Excepción de implementación DBRefSource
 error.implementation_error_dbinstance_must_implement_interface = Error de Implementación- getDbInstances debe recibir una clase que implemente jalview.ws.seqfetcher.DbSourceProxy (recibió {0})
 error.implementation_error_must_init_dbsources =Error de implementación. Debe inicializar dbSources
-label.view_controller_toggled_marked = {0} {1} columnas {2} conteniendo características del tipo  {3} en {4} secuencia(s)
+label.view_controller_toggled_marked = {0} {1} columnas {2} características del tipo {3} en {4} secuencia(s)
 label.toggled = Invertida
 label.marked = Marcada
-label.not = no
+label.containing = conteniendo
+label.not_containing = no conteniendo
 label.no_feature_of_type_found = No se han encontrado características del tipo {0}.
 label.submission_params = Envío {0}
 label.empty_alignment_job = Trabajo de alineamiento vacío
@@ -975,7 +941,7 @@ label.pca_recalculating = Recalculando PCA
 label.pca_calculating = Calculando PCA
 label.select_foreground_colour = Escoger color del primer plano
 label.select_colour_for_text = Seleccione el color del texto
-label.adjunst_foreground_text_colour_thereshold = Ajustar el umbral del color del texto en primer plano
+label.adjunst_foreground_text_colour_threshold = Ajustar el umbral del color del texto en primer plano
 label.select_subtree_colour = Seleccioanr el color del sub-árbol
 label.create_new_sequence_features = Crear nueva(s) característica(s) de secuencia
 label.amend_delete_features = Arrelgar/Borrar características de {0}
@@ -995,7 +961,6 @@ exception.mismatched_unseen_closing_char = Discordancia (no vista) en el car
 exception.mismatched_closing_char = Carácter de cierre discordante {0}
 exception.mismatched_opening_char = Carácter de apertura discordante {0} en {1}
 exception.invalid_datasource_couldnt_obtain_reader = Fuente de datos no válida. No es posible obtener el Reader
-exception.index_value_not_in_range = {0}: el valor del Ã­ndice {1} en se encuentra en el rango [0..{2}]
 exception.unterminated_cigar_string = Cadena cigar sin terminar
 exception.unexpected_operation_cigar_string_pos = Operación no esperada {0} en una cadena cigar (posición {1} en {2})
 exception.couldnt_parse_responde_from_annotated3d_server = No es posible parsear la respuesta procedente del servidor Annotate3d 
@@ -1023,7 +988,6 @@ exception.ranml_problem_parsing_data = Problema parseando los datos como RNAML (
 exception.pfam_no_sequences_found = No se han encontrado secuencias (entrada PFAM)
 exception.stockholm_invalid_format = Este fichero no es tiene un formato STOCKHOLM válido: la primera línea no contiene '# STOCKHOLM'
 exception.couldnt_parse_sequence_line = No es posible parse la línea de secuencia: {0}
-exception.error_parsing_line = Error parseando {0}
 exception.unknown_annotation_detected = Anotación desconocida detectada: {0} {1}
 exception.couldnt_store_sequence_mappings = No es posible almacenar los mapeos de secuencia para {0}
 exception.matrix_too_many_iteration = Demasiadas iteraciones en {0} (el máximo es {1})
@@ -1031,7 +995,6 @@ exception.browser_not_found = Excepci
 exception.browser_unable_to_locate = Imposible encontrar el navegador: {0}
 exception.invocation_target_exception_creating_aedesc = InvocationTargetException mientras se creaba AEDesc: {0}
 exception.illegal_access_building_apple_evt= IllegalAccessException mientras se construía AppleEvent: {0}
-exception.instantiation_creating_aedesc = InstantiationException mientras se creaba AEDesc: {0}
 exception.unable_to_launch_url = Imposible lanzar la URL: {0}
 exception.unable_to_create_internet_config = Imposible crear una instancia de configuración de Internet: {0}
 exception.invocation_target_calling_url = InvocationTargetException mientras se invocaba openURL: {0}
@@ -1040,8 +1003,6 @@ exception.interrupted_launching_browser = InterruptedException mientras se lanza
 exception.das_source_doesnt_support_sequence_command = La fuente {0} no soporta el comando sequence.
 exception.invalid_das_source = Fuente DAS no válida: {0}
 exception.ebiembl_retrieval_failed_on = La recuperación de datos EBI EMBL XML ha fallado en {0}:{1}
-label.no_embl_record_found = # No se ha recuperado ningún registro EMBL de {0}:{1}
-label.embl_successfully_parsed = # Se han parseado con Ã©xito las consultas {0} en un alineamiento
 exception.no_pdb_records_for_chain = No se han encontrado registros {0} para la cadena {1}
 exception.unexpected_handling_rnaml_translation_for_pdb = Excepcion inesperada cuando se traducían a RNAML los datos PDB
 exception.couldnt_recover_sequence_properties_for_alignment = No es posible recuperar las propiedades de la secuencia para el alineamiento
@@ -1055,7 +1016,7 @@ error.implementation_error_cannot_find_service_url_in_given_set = Error de imple
 error.implementation_error_cannot_find_service_url_in_given_set_param_store = Error de implementación: la URL del servicio en el conjunto de URL  para este almacén de parámetros del servicio({0})
 exception.jobsubmission_invalid_params_set = Conjunto de parámetros no válido. Comprueba la implementación de Jalview
 exception.notvaliddata_group_contains_less_than_min_seqs = El grupo contiene menos de {0} secuencias.
-exception.outofmemory_loading_pdb_file = Sin menoria al cargar el fichero PDB
+exception.outofmemory_loading_pdb_file = Sin memoria al cargar el fichero PDB
 exception.eps_coudnt_write_output_file = No es posible escribir el fichero de salida: {0}
 exception.eps_method_not_supported = Método actualmente no suportado por la versión {0} de EpsGraphics2D
 exception.eps_unable_to_get_inverse_matrix = Imposible obtener la inversa de la matrix: {0}
@@ -1084,7 +1045,7 @@ status.fetching_pdb = Recuperando PDB {0}
 status.refreshing_news = Refrescando noticias
 status.importing_vamsas_session_from = Importando sesión VAMSAS de {0}
 status.opening_params = Abriendo {0}
-status.waiting_sequence_database_fetchers_init = Esperando la inicialización de los recuperadores de bases de datos de secuencias
+status.waiting_sequence_database_fetchers_init = Esperando inicialización de los recuperadores de bases de datos de secuencias
 status.init_sequence_database_fetchers = Inicializando recuperadores de bases de datos de secuencias
 status.fetching_sequence_queries_from = Recuperando {0} consultas de secuencias de {1}
 status.finshed_querying = Consulta finalizada
@@ -1123,8 +1084,8 @@ label.edit_jabaws_url = Editar JABAWS URL
 label.add_jabaws_url = Añadir nueva JABAWS URL
 label.news_from_jalview = Noticias de http://www.jalview.org
 label.cut_paste_alignmen_file = Cortar & Pegar fichero de alineamiento
-label.enter_redundancy_thereshold = Introducir el umbral de redundancia
-label.select_dark_light_set_thereshold = <i>Seleccionar un color oscuro y un color claro para el texto y establecer el umbral en que<br>cambiar entre colores, basándose en el color de fondo</i>
+label.enter_redundancy_threshold = Introducir el umbral de redundancia
+label.select_dark_light_set_threshold = <i>Seleccionar un color oscuro y un color claro para el texto y establecer el umbral en que<br>cambiar entre colores, basándose en el color de fondo</i>
 label.select_feature_colour = Seleccionar color de las características
 label.ignore_gaps_consensus = Ignorar huecos en el consenso
 label.show_group_histogram = Mostrar histograma de grupo
@@ -1144,7 +1105,6 @@ action.feature_settings=Ajustes de caracter
 info.invalid_msa_notenough=No suficientes datos de sequencia para alinear
 label.result=resultado
 label.results=resultados
-label.no_mappings=No hay mapeados encontrados
 label.struct_from_pdb=Procesar la estructura secundaria PDB
 label.hide_selected_annotations=Ocultar anotaciones seleccionados
 info.select_annotation_row=Seleccionar Fila de Anotaciones
@@ -1168,9 +1128,8 @@ action.no=No
 action.yes=Sí
 label.export_settings=Exportar Ajustes
 label.linked_view_title=Vista vinculada de cDNA y proteína
-label.view_protein_structure=Ver Estructura Proteica
 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
@@ -1213,7 +1172,6 @@ action.select_by_annotation=Seleccionar/Ocultar Columnas por Anotaci
 action.export_features=Exportar Características
 error.invalid_regex=Expresión regular inválida
 label.autoadd_temp=Añadir anotación factor de temperatura al alineamiento
-tooltip.rnalifold_settings=Modificar la configuración de la predicción RNAAlifold. Ãšselo para ocultar o mostrar resultados del cálculo de RNA, o cambiar parámetros de el plegado de RNA.
 label.chimera_path_tip=Jalview intentará primero las rutas introducidas aquí, Y si no las rutas usuales de instalación
 label.structure_chooser=Selector de Estructuras
 label.structure_chooser_manual_association=Selector de Estructuras - asociación manual
@@ -1229,9 +1187,7 @@ label.colour_with_chimera=Colorear con Chimera
 label.show_pdbstruct_dialog=Datos de Estructura 3D...
 label.hide_all=Ocultar todos
 label.invert=Invertir
-label.pdb_sequence_getcher=Buscador de Secuencias PDB
 tooltip.aacon_settings=Cambiar ajustes para cálculos AACon
-label.align=Alinear
 label.mark_as_representative=Marcar como representativa
 label.include_description=Incluir Descripción
 label.for=para
@@ -1247,15 +1203,13 @@ info.associate_wit_sequence=Asociar con secuencia
 label.protein=Proteína
 warn.oneseq_msainput_selection=La selección actual sólo contiene una Ãºnica secuencia. Â¿Quieres enviar todas las secuencias para la alineación en su lugar?
 label.use_rnaview=Usar RNAView para estructura secondaria
-label.opens_the_jabaws_server_homepage=Abre la página de inicio del servidor JABAWS en navegador
 label.search_all=Introducir uno o más valores de búsqueda separados por punto y coma ";" (Nota: buscará en toda la base de datos PDB)
 label.confirm_close_chimera=Cerrará la conexión de Jalview a {0}.<br>¿Quieres cerrar la ventana Chimera también?
 tooltip.rnalifold_calculations=Se calcularán predicciones de estructura secondaria de RNA para el alineaminento, y se actualizarán si se efectuan cambios
-Calcular predicciónes de estructura secondaria para el alineamiento
+tooltip.rnalifold_settings=Modificar la configuración de la predicción RNAAlifold. Ãšselo para ocultar o mostrar resultados del cálculo de RNA, o cambiar parámetros de el plegado de RNA.
 label.show_selected_annotations=Mostrar anotaciones seleccionadas
 status.colouring_chimera=Coloreando Chimera
 label.configure_displayed_columns=Configurar Columnas Mostradas
-exception.pdb_server_error=Error desde el servidor PDB
 exception.resource_not_be_found=El recurso solicitado no se ha encontrado
 label.aacon_calculations=cálculos AACon
 label.pdb_web-service_error=Error de servicio web PDB
@@ -1264,10 +1218,8 @@ label.chimera_path=Ruta de acceso a programa Chimera
 warn.delete_all=<html>Borrar todas las secuencias cerrará la ventana del alineamiento.<br>Confirmar o Cancelar.
 label.select_all=Seleccionar Todos
 label.alpha_helix=Hélice Alfa
-label.sequence_details_for=Detalles de secuencia para {0}
 label.chimera_help=Ayuda para Chimera
 label.find_tip=Buscar alineamiento, selección o IDs de secuencia para una subsecuencia (sin huecos)
-exception.pdb_server_unreachable=Jalview no puede conectar con el servidor PDBE Solr.\nPor favor, asegúrese de que está conectado a Internet y vuelva a intentarlo.
 label.structure_viewer=Visualizador de estructura for defecto
 label.embbed_biojson=Incrustar BioJSON al exportar HTML
 label.transparency_tip=Ajustar la transparencia a "ver a través" los colores de las características.
@@ -1280,4 +1232,40 @@ info.select_filter_option=Escoger Opci
 info.invalid_msa_input_mininfo=Necesita por lo menos dos secuencias con al menos 3 residuos cada una, sin regiones ocultas entre ellas.
 label.chimera_missing=Visualizador de estructura Chimera no encontrado.<br/>Por favor, introduzca la ruta de Chimera,<br/>o descargar e instalar la UCSF Chimera.
 label.save_as_biojs_html=Guardar como HTML BioJs
-exception.pdb_rest_service_no_longer_available=Servicios Rest PDB ya no están disponibles!
+exception.fts_server_unreachable=Jalview no puede conectar con el servidor {0}. \nPor favor asegúrese de que está conectado a Internet y vuelva a intentarlo.
+exception.outofmemory_loading_mmcif_file=Sin memoria al cargar el fichero mmCIF
+label.hide_columns_not_containing=Ocultar las columnas que no contengan
+label.pdb_sequence_fetcher=Recuperador de secuencias PDB
+exception.fts_server_error=Parece que hay un error desde el servidor {0}
+exception.service_not_available=Servicio no disponible. El servidor se está actualizando, vuelva a intentarlo más tarde.
+status.waiting_for_user_to_select_output_file=Esperando que el usuario seleccione el fichero {0}
+action.prev_page=<< 
+status.cancelled_image_export_operation=Operación de exportación {0} cancelada
+label.couldnt_run_groovy_script=No se ha podido ejecutar el script Groovy
+exception.bad_request=Solicitud incorrecta. Hay un problema con su entrada.
+label.run_groovy=Ejecutar script Groovy desde la consola
+action.next_page=>> 
+label.uniprot_sequence_fetcher=Recuperador de secuencias UniProt
+label.prev_page_tooltip=Página anterior
+label.reverse=Invertir
+label.hide_columns_containing=Ocultar las columnas que contengan
+label.nucleotides=Nucleótidos
+label.run_groovy_tip = Ejecutar script Groovy desde la consola sobre este alineamiento
+label.nw_mapping=Alineamiento Needleman y Wunsch
+label.proteins=Proteína 
+label.reverse_complement=Invertir y complementar
+label.next_page_tooltip=Página siguiente
+label.sifts_mapping=Mapeado SIFTs
+label.mapping_method=Método de mapeo de secuencia \u27F7 estructura
+info.error_creating_file=Error al crear fichero {0}
+exception.fts_rest_service_no_longer_available= Servicios Rest {0} ya no están disponibles! 
+status.launching_3d_structure_viewer=Lanzando visualizador de estructura 3D...
+status.obtaining_mapping_with_sifts=Obteniendo mapeo por SIFTS
+status.fetching_3d_structures_for=Buscando la estructura 3D para {0}
+status.fetching_3d_structures_for_selected_entries=Buscando las estructuras 3D para entradas seleccionadas...
+status.fetching_dbrefs_for_sequences_without_valid_refs=Buscando referencias para {0} secuencia(s) sin referencia válida necesaria para mapeado SIFTS
+status.obtaining_mapping_with_nw_alignment=Obteniendo mapeo por alineamiento Needleman y Wunsch
+status.exporting_alignment_as_x_file = Exportando alineamiento como fichero tipo {0}
+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
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 850b223..f0bd638 100755 (executable)
                                                <xs:attribute name="end" type="xs:int" use="required" />
                                                <xs:attribute name="id" type="xs:string" use="required" />
                                                <xs:attribute name="hidden" type="xs:boolean" />
+                                               <xs:attribute name="viewreference" type="xs:boolean" use="optional"/>
                                        </xs:complexType>
                                </xs:element>
                                <xs:element name="JGroup" minOccurs="0" maxOccurs="unbounded">
index df98833..ad5837e 100644 (file)
@@ -189,8 +189,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");
 
@@ -199,8 +201,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 68a7c21..904e307 100755 (executable)
@@ -81,7 +81,7 @@ public class Atom
     chain = str.substring(21, 22);
 
     resNumber = Integer.parseInt(str.substring(22, 26).trim());
-    resNumIns = str.substring(22, 27);
+    resNumIns = str.substring(22, 27).trim();
     insCode = str.substring(26, 27).charAt(0);
     this.x = (new Float(str.substring(30, 38).trim()).floatValue());
     this.y = (new Float(str.substring(38, 46).trim()).floatValue());
@@ -109,6 +109,24 @@ public class Atom
     }
   }
 
+  @Override
+  public boolean equals(Object that)
+  {
+    if (this == that || that == null)
+    {
+      return true;
+    }
+    if (that instanceof Atom)
+    {
+      Atom other = (Atom) that;
+      return other.resName.equals(this.resName)
+              && other.resNumber == this.resNumber
+              && other.resNumIns.equals(this.resNumIns)
+              && other.chain.equals(this.chain);
+    }
+    return false;
+  }
+
   public Atom(float x, float y, float z)
   {
     this.x = x;
index 1c7a1f7..0dd58ad 100644 (file)
@@ -188,8 +188,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 108ccf1..7774dac 100755 (executable)
@@ -29,8 +29,8 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
+import jalview.structure.StructureImportSettings;
 import jalview.structure.StructureMapping;
-import jalview.structure.StructureViewSettings;
 
 import java.awt.Color;
 import java.util.List;
@@ -82,7 +82,7 @@ public class PDBChain
 
   public PDBChain(String pdbid, String id)
   {
-    this.pdbid = pdbid.toLowerCase();
+    this.pdbid = pdbid == null ? pdbid : pdbid.toLowerCase();
     this.id = id;
   }
 
@@ -199,7 +199,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,63 +358,53 @@ public class PDBChain
       else
       {
 
-        // boolean baseDetected = false;
-        // for (Atom resAtom : resAtoms)
-        // {
-        // if (resAtom.insCode == ' ')
-        // {
-        // baseDetected = true;
-        // }
-        // }
-        // if (!baseDetected)
-        // {
-        // continue;
-        // }
-      // 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
+        // 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
         SequenceFeature sf = new SequenceFeature("RESNUM", tmpat.resName
-              + ":" + tmpat.resNumIns + " " + pdbid + id, "", offset
-              + count, offset + count, pdbid);
-      // MCview.PDBChain.PDBFILEFEATURE);
-      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)
+                + ":" + 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)
         {
-          seq.append("X");
-          // System.err.println("PDBReader:Null aa3Hash for " +
-          // tmpat.resName);
+          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++;
       }
     }
@@ -433,13 +424,13 @@ public class PDBChain
     // System.out.println("PDB Sequence is :\nSequence = " + seq);
     // System.out.println("No of residues = " + residues.size());
 
-    if (StructureViewSettings.isShowSeqFeatures())
-    {
-    for (i = 0, iSize = resFeatures.size(); i < iSize; i++)
+    if (StructureImportSettings.isShowSeqFeatures())
     {
-      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)
     {
@@ -592,12 +583,13 @@ public class PDBChain
         {
           for (AlignmentAnnotation ana : sequence.getAnnotation())
           {
-            List<AlignmentAnnotation> transfer = sq
+            List<AlignmentAnnotation> transfer = dsq
                     .getAlignmentAnnotations(ana.getCalcId(), ana.label);
             if (transfer == null || transfer.size() == 0)
             {
               ana = new AlignmentAnnotation(ana);
               ana.liftOver(dsq, sqmpping);
+              dsq.addAlignmentAnnotation(ana);
               // mapping.transfer(ana);
             }
             else
index da744a4..eaa33df 100755 (executable)
@@ -62,7 +62,6 @@ import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 import javax.swing.JRadioButtonMenuItem;
-import javax.swing.SwingUtilities;
 
 public class PDBViewer extends JInternalFrame implements Runnable
 {
@@ -129,18 +128,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);
   }
@@ -152,7 +150,7 @@ public class PDBViewer extends JInternalFrame implements Runnable
     {
       EBIFetchClient ebi = new EBIFetchClient();
       String query = "pdb:" + pdbentry.getId();
-      pdbentry.setFile(ebi.fetchDataAsFile(query, "default", "raw", ".xml")
+      pdbentry.setFile(ebi.fetchDataAsFile(query, "default", ".xml")
               .getAbsolutePath());
 
       if (pdbentry.getFile() != null)
@@ -416,35 +414,50 @@ public class PDBViewer extends JInternalFrame implements Runnable
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isControlDown()
-                    || SwingUtilities.isRightMouseButton(evt))
+            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 9a9b6f6..f5a0255 100755 (executable)
@@ -46,17 +46,16 @@ public class PDBfile extends StructureFile
   }
 
   public PDBfile(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr, String file, String protocol)
+          boolean externalSecStr, String dataObject, String protocol)
           throws IOException
   {
-    super(false, file, protocol);
+    super(false, dataObject, protocol);
     addSettings(addAlignmentAnnotations, predictSecStr, externalSecStr);
     doParse();
   }
 
   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);
@@ -145,7 +144,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..
@@ -203,8 +202,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 4201f43..fdcf34f 100644 (file)
@@ -27,6 +27,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;
@@ -199,8 +203,9 @@ public class ChimeraManager
       return null;
     }
 
-    List<ChimeraModel> newModelList = getModelList();
-    for (ChimeraModel newModel : newModelList)
+    // patch for Jalview - set model name in Chimera
+    // TODO: find a variant that works for sub-models
+    for (ChimeraModel newModel : getModelList())
     {
       if (!modelList.contains(newModel))
       {
@@ -209,15 +214,12 @@ public class ChimeraManager
                 "setattr M name " + modelName + " #"
                         + newModel.getModelNumber(), false);
         modelList.add(newModel);
-
       }
     }
 
     // assign color and residues to open models
     for (ChimeraModel chimeraModel : modelList)
     {
-      // // patch for Jalview - set model name in Chimera
-      // // TODO: find a variant that works for sub-models
       // get model color
       Color modelColor = getModelColor(chimeraModel);
       if (modelColor != null)
@@ -731,7 +733,7 @@ public class ChimeraManager
    */
   public List<String> sendChimeraCommand(String command, boolean reply)
   {
-    // System.out.println("chimeradebug>> " + command);
+   // System.out.println("chimeradebug>> " + command);
     if (!isChimeraLaunched() || command == null
             || "".equals(command.trim()))
     {
@@ -784,8 +786,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 3d61b11..61e11c4 100755 (executable)
  */
 package jalview.analysis;
 
+import jalview.analysis.ResidueCount.SymbolCounts;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
 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 +47,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 +62,13 @@ public class AAFrequency
     }
   }
 
-  public static final Hashtable[] calculate(List<SequenceI> list,
+  public static final Profile[] 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 Profile[] calculate(List<SequenceI> sequences,
           int start, int end, boolean profile)
   {
     SequenceI[] seqs = new SequenceI[sequences.size()];
@@ -93,7 +84,7 @@ public class AAFrequency
         }
       }
 
-      Hashtable[] reply = new Hashtable[width];
+      Profile[] reply = new Profile[width];
 
       if (end >= width)
       {
@@ -105,289 +96,242 @@ public class AAFrequency
     }
   }
 
-  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 start
+   *          start column (inclusive, base zero)
+   * @param end
+   *          end column (exclusive)
+   * @param result
+   *          array in which to store profile per column
+   * @param saveFullProfile
+   *          if true, store all symbol counts
+   */
+  public static final void calculate(final SequenceI[] sequences,
+          int start, int end, Profile[] result, boolean saveFullProfile)
   {
-    Hashtable residueHash;
-    int maxCount, nongap, i, j, v;
-    int jSize = sequences.length;
-    String maxResidue;
-    char c = '-';
-    float percentage;
-
-    int[] values = new int[255];
+    // long now = System.currentTimeMillis();
+    int seqCount = sequences.length;
+    boolean nucleotide = false;
+    int nucleotideCount = 0;
+    int peptideCount = 0;
 
-    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();
+      Profile 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;
     }
+    // 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 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)
+          Profile[] profiles, int iStart, int width, boolean ignoreGaps,
+          boolean showSequenceLogo, long nseq)
   {
+    // long now = System.currentTimeMillis();
     if (consensus == null || consensus.annotations == null
             || consensus.annotations.length < width)
     {
-      // 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);
+    final int dp = getPercentageDp(nseq);
 
     for (int i = iStart; i < width; i++)
     {
-      Hashtable hci;
-      if (i >= hconsensus.length || ((hci = hconsensus[i]) == null))
-      {
-        // happens if sequences calculated over were shorter than alignment
-        // width
-        consensus.annotations[i] = null;
-        continue;
-      }
-      Float fv = (Float) hci
-              .get(ignoreGapsInConsensusCalculation ? PID_NOGAPS : PID_GAPS);
-      if (fv == null)
+      Profile profile;
+      if (i >= profiles.length || ((profile = profiles[i]) == null))
       {
+        /*
+         * happens if sequences calculated over were 
+         * shorter than alignment width
+         */
         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)
-      {
-        mouseOver.append("[").append(maxRes).append("] ");
-        maxRes = "+";
-      }
-      else
-      {
-        mouseOver.append(hci.get(AAFrequency.MAXRESIDUE) + " ");
-      }
-      int[][] profile = (int[][]) hci.get(AAFrequency.PROFILE);
-      if (profile != null && includeAllConsSymbols)
+
+      float value = profile.getPercentageIdentity(ignoreGaps);
+
+      String description = getTooltip(profile, value, showSequenceLogo,
+              ignoreGaps, dp);
+
+      String modalResidue = profile.getModalResidue();
+      if ("".equals(modalResidue))
       {
-        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++;
-            }
-          }
-        }
+        modalResidue = "-";
       }
-      else
+      else if (modalResidue.length() > 1)
       {
-        mouseOver.append(
-                (((fmt != null) ? fmt.form(value) : ((int) value))))
-                .append("%");
+        modalResidue = "+";
       }
-      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(Profile 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);
     }
-    return scale <= 1 ? null : new Format("%3." + (scale - 1) + "f");
+    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 description;
   }
 
   /**
@@ -399,46 +343,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(Profile 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;
@@ -624,8 +568,11 @@ public class AAFrequency
       String modalCodon = String.valueOf(CodingUtils
               .decodeCodon(modalCodonEncoded));
       if (sortedCodonCounts.length > 1
-              && sortedCodonCounts[codons.length - 2] == modalCodonEncoded)
+              && sortedCodonCounts[codons.length - 2] == sortedCodonCounts[codons.length - 1])
       {
+        /*
+         * two or more codons share the modal count
+         */
         modalCodon = "+";
       }
       float pid = sortedCodonCounts[sortedCodonCounts.length - 1] * 100
@@ -644,7 +591,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--)
       {
@@ -666,7 +613,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)
@@ -692,4 +641,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..3ad3188 100755 (executable)
@@ -663,8 +663,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 28062c0..34fe221 100644 (file)
  */
 package jalview.analysis;
 
+import static jalview.io.gff.GffConstants.CLINICAL_SIGNIFICANCE;
+
 import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -36,10 +39,13 @@ import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
 import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
+import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 import jalview.util.StringUtils;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -66,6 +72,40 @@ import java.util.TreeMap;
 public class AlignmentUtils
 {
 
+  private static final int CODON_LENGTH = 3;
+
+  private static final String SEQUENCE_VARIANT = "sequence_variant:";
+
+  private static final String ID = "ID";
+
+  /**
+   * A data model to hold the 'normal' base value at a position, and an optional
+   * sequence variant feature
+   */
+  static final class DnaVariant
+  {
+    final String base;
+
+    SequenceFeature variant;
+
+    DnaVariant(String nuc)
+    {
+      base = nuc;
+      variant = null;
+    }
+
+    DnaVariant(String nuc, SequenceFeature var)
+    {
+      base = nuc;
+      variant = var;
+    }
+
+    public String getSource()
+    {
+      return variant == null ? null : variant.getFeatureGroup();
+    }
+  }
+
   /**
    * given an existing alignment, create a new alignment including all, or up to
    * flankSize additional symbols from each sequence's dataset sequence
@@ -396,7 +436,7 @@ public class AlignmentUtils
     /*
      * cdnaStart/End, proteinStartEnd are base 1 (for dataset sequence mapping)
      */
-    final int mappedLength = 3 * aaSeqChars.length;
+    final int mappedLength = CODON_LENGTH * aaSeqChars.length;
     int cdnaLength = cdnaSeqChars.length;
     int cdnaStart = cdnaSeq.getStart();
     int cdnaEnd = cdnaSeq.getEnd();
@@ -408,14 +448,14 @@ public class AlignmentUtils
      */
     if (cdnaLength != mappedLength && cdnaLength > 2)
     {
-      String lastCodon = String.valueOf(cdnaSeqChars, cdnaLength - 3, 3)
-              .toUpperCase();
+      String lastCodon = String.valueOf(cdnaSeqChars,
+              cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase();
       for (String stop : ResidueProperties.STOP)
       {
         if (lastCodon.equals(stop))
         {
-          cdnaEnd -= 3;
-          cdnaLength -= 3;
+          cdnaEnd -= CODON_LENGTH;
+          cdnaLength -= CODON_LENGTH;
           break;
         }
       }
@@ -427,12 +467,12 @@ public class AlignmentUtils
     int startOffset = 0;
     if (cdnaLength != mappedLength
             && cdnaLength > 2
-            && String.valueOf(cdnaSeqChars, 0, 3).toUpperCase()
+            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH).toUpperCase()
                     .equals(ResidueProperties.START))
     {
-      startOffset += 3;
-      cdnaStart += 3;
-      cdnaLength -= 3;
+      startOffset += CODON_LENGTH;
+      cdnaStart += CODON_LENGTH;
+      cdnaLength -= CODON_LENGTH;
     }
 
     if (translatesAs(cdnaSeqChars, startOffset, aaSeqChars))
@@ -441,7 +481,7 @@ public class AlignmentUtils
        * protein is translation of dna (+/- start/stop codons)
        */
       MapList map = new MapList(new int[] { cdnaStart, cdnaEnd }, new int[]
-      { proteinStart, proteinEnd }, 3, 1);
+      { proteinStart, proteinEnd }, CODON_LENGTH, 1);
       return map;
     }
 
@@ -471,10 +511,9 @@ public class AlignmentUtils
 
     int aaPos = 0;
     int dnaPos = cdnaStart;
-    for (; dnaPos < cdnaSeqChars.length - 2
-            && aaPos < aaSeqChars.length; dnaPos += 3, aaPos++)
+    for (; dnaPos < cdnaSeqChars.length - 2 && aaPos < aaSeqChars.length; dnaPos += CODON_LENGTH, aaPos++)
     {
-      String codon = String.valueOf(cdnaSeqChars, dnaPos, 3);
+      String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
       final String translated = ResidueProperties.codonTranslate(codon);
 
       /*
@@ -510,9 +549,9 @@ public class AlignmentUtils
     {
       return true;
     }
-    if (dnaPos == cdnaSeqChars.length - 3)
+    if (dnaPos == cdnaSeqChars.length - CODON_LENGTH)
     {
-      String codon = String.valueOf(cdnaSeqChars, dnaPos, 3);
+      String codon = String.valueOf(cdnaSeqChars, dnaPos, CODON_LENGTH);
       if ("STOP".equals(ResidueProperties.codonTranslate(codon)))
       {
         return true;
@@ -820,6 +859,11 @@ public class AlignmentUtils
    */
   public static int alignProteinAsDna(AlignmentI protein, AlignmentI dna)
   {
+    if (protein.isNucleotide() || !dna.isNucleotide())
+    {
+      System.err.println("Wrong alignment type in alignProteinAsDna");
+      return 0;
+    }
     List<SequenceI> unmappedProtein = new ArrayList<SequenceI>();
     Map<AlignedCodon, Map<SequenceI, AlignedCodon>> alignedCodons = buildCodonColumnsMap(
             protein, dna, unmappedProtein);
@@ -827,6 +871,178 @@ public class AlignmentUtils
   }
 
   /**
+   * Realigns the given dna to match the alignment of the protein, using codon
+   * mappings to translate aligned peptide positions to codons.
+   * 
+   * Always produces a padded CDS alignment.
+   * 
+   * @param dna
+   *          the alignment whose sequences are realigned by this method
+   * @param protein
+   *          the protein alignment whose alignment we are 'copying'
+   * @return the number of sequences that were realigned
+   */
+  public static int alignCdsAsProtein(AlignmentI dna, AlignmentI protein)
+  {
+    if (protein.isNucleotide() || !dna.isNucleotide())
+    {
+      System.err.println("Wrong alignment type in alignProteinAsDna");
+      return 0;
+    }
+    // todo: implement this
+    List<AlignedCodonFrame> mappings = protein.getCodonFrames();
+    int alignedCount = 0;
+    int width = 0; // alignment width for padding CDS
+    for (SequenceI dnaSeq : dna.getSequences())
+    {
+      if (alignCdsSequenceAsProtein(dnaSeq, protein, mappings,
+              dna.getGapCharacter()))
+      {
+        alignedCount++;
+      }
+      width = Math.max(dnaSeq.getLength(), width);
+    }
+    int oldwidth;
+    int diff;
+    for (SequenceI dnaSeq : dna.getSequences())
+    {
+      oldwidth = dnaSeq.getLength();
+      diff = width - oldwidth;
+      if (diff > 0)
+      {
+        dnaSeq.insertCharAt(oldwidth, diff, dna.getGapCharacter());
+      }
+    }
+    return alignedCount;
+  }
+
+  /**
+   * Helper method to align (if possible) the dna sequence to match the
+   * alignment of a mapped protein sequence. This is currently limited to
+   * handling coding sequence only.
+   * 
+   * @param cdsSeq
+   * @param protein
+   * @param mappings
+   * @param gapChar
+   * @return
+   */
+  static boolean alignCdsSequenceAsProtein(SequenceI cdsSeq,
+          AlignmentI protein, List<AlignedCodonFrame> mappings, char gapChar)
+  {
+    SequenceI cdsDss = cdsSeq.getDatasetSequence();
+    if (cdsDss == null)
+    {
+      System.err
+              .println("alignCdsSequenceAsProtein needs aligned sequence!");
+      return false;
+    }
+
+    List<AlignedCodonFrame> dnaMappings = MappingUtils
+            .findMappingsForSequence(cdsSeq, mappings);
+    for (AlignedCodonFrame mapping : dnaMappings)
+    {
+      SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein);
+      if (peptide != null)
+      {
+        int peptideLength = peptide.getLength();
+        Mapping map = mapping.getMappingBetween(cdsSeq, peptide);
+        if (map != null)
+        {
+          MapList mapList = map.getMap();
+          if (map.getTo() == peptide.getDatasetSequence())
+          {
+            mapList = mapList.getInverse();
+          }
+          int cdsLength = cdsDss.getLength();
+          int mappedFromLength = MappingUtils.getLength(mapList
+                  .getFromRanges());
+          int mappedToLength = MappingUtils
+                  .getLength(mapList.getToRanges());
+          boolean addStopCodon = (cdsLength == mappedFromLength
+                  * CODON_LENGTH + CODON_LENGTH)
+                  || (peptide.getDatasetSequence().getLength() == mappedFromLength - 1);
+          if (cdsLength != mappedToLength && !addStopCodon)
+          {
+            System.err
+                    .println(String
+                            .format("Can't align cds as protein (length mismatch %d/%d): %s",
+                                    cdsLength, mappedToLength,
+                                    cdsSeq.getName()));
+          }
+
+          /*
+           * pre-fill the aligned cds sequence with gaps
+           */
+          char[] alignedCds = new char[peptideLength * CODON_LENGTH
+                  + (addStopCodon ? CODON_LENGTH : 0)];
+          Arrays.fill(alignedCds, gapChar);
+
+          /*
+           * walk over the aligned peptide sequence and insert mapped 
+           * codons for residues in the aligned cds sequence 
+           */
+          char[] alignedPeptide = peptide.getSequence();
+          char[] nucleotides = cdsDss.getSequence();
+          int copiedBases = 0;
+          int cdsStart = cdsDss.getStart();
+          int proteinPos = peptide.getStart() - 1;
+          int cdsCol = 0;
+          for (char residue : alignedPeptide)
+          {
+            if (Comparison.isGap(residue))
+            {
+              cdsCol += CODON_LENGTH;
+            }
+            else
+            {
+              proteinPos++;
+              int[] codon = mapList.locateInTo(proteinPos, proteinPos);
+              if (codon == null)
+              {
+                // e.g. incomplete start codon, X in peptide
+                cdsCol += CODON_LENGTH;
+              }
+              else
+              {
+                for (int j = codon[0]; j <= codon[1]; j++)
+                {
+                  char mappedBase = nucleotides[j - cdsStart];
+                  alignedCds[cdsCol++] = mappedBase;
+                  copiedBases++;
+                }
+              }
+            }
+          }
+
+          /*
+           * append stop codon if not mapped from protein,
+           * closing it up to the end of the mapped sequence
+           */
+          if (copiedBases == nucleotides.length - CODON_LENGTH)
+          {
+            for (int i = alignedCds.length - 1; i >= 0; i--)
+            {
+              if (!Comparison.isGap(alignedCds[i]))
+              {
+                cdsCol = i + 1; // gap just after end of sequence
+                break;
+              }
+            }
+            for (int i = nucleotides.length - CODON_LENGTH; i < nucleotides.length; i++)
+            {
+              alignedCds[cdsCol++] = nucleotides[i];
+            }
+          }
+          cdsSeq.setSequence(new String(alignedCds));
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
    * Builds a map whose key is an aligned codon position (3 alignment column
    * numbers base 0), and whose value is a map from protein sequence to each
    * protein's peptide residue for that codon. The map generates an ordering of
@@ -883,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;
   }
 
@@ -1303,15 +1519,19 @@ public class AlignmentUtils
           Collection<String> types, List<SequenceI> forSequences,
           boolean anyType, boolean doShow)
   {
-    for (AlignmentAnnotation aa : al.getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
+    if (anns != null)
     {
-      if (anyType || types.contains(aa.label))
+      for (AlignmentAnnotation aa : anns)
       {
-        if ((aa.sequenceRef != null)
-                && (forSequences == null || forSequences
-                        .contains(aa.sequenceRef)))
+        if (anyType || types.contains(aa.label))
         {
-          aa.visible = doShow;
+          if ((aa.sequenceRef != null)
+                  && (forSequences == null || forSequences
+                          .contains(aa.sequenceRef)))
+          {
+            aa.visible = doShow;
+          }
         }
       }
     }
@@ -1370,75 +1590,294 @@ public class AlignmentUtils
    * added to the alignment dataset.
    * 
    * @param dna
-   *          aligned dna sequences
-   * @param mappings
-   *          from dna to protein
-   * @param al
+   *          aligned nucleotide (dna or cds) sequences
+   * @param dataset
+   *          the alignment dataset the sequences belong to
+   * @param products
+   *          (optional) to restrict results to CDS that map to specified
+   *          protein products
    * @return an alignment whose sequences are the cds-only parts of the dna
    *         sequences (or null if no mappings are found)
    */
   public static AlignmentI makeCdsAlignment(SequenceI[] dna,
-          List<AlignedCodonFrame> mappings, AlignmentI al)
+          AlignmentI dataset, SequenceI[] products)
   {
+    if (dataset == null || dataset.getDataset() != null)
+    {
+      throw new IllegalArgumentException(
+              "IMPLEMENTATION ERROR: dataset.getDataset() must be null!");
+    }
+    List<SequenceI> foundSeqs = new ArrayList<SequenceI>();
     List<SequenceI> cdsSeqs = new ArrayList<SequenceI>();
-    
-    for (SequenceI seq : dna)
+    List<AlignedCodonFrame> mappings = dataset.getCodonFrames();
+    HashSet<SequenceI> productSeqs = null;
+    if (products != null)
     {
-      AlignedCodonFrame cdsMappings = new AlignedCodonFrame();
+      productSeqs = new HashSet<SequenceI>();
+      for (SequenceI seq : products)
+      {
+        productSeqs.add(seq.getDatasetSequence() == null ? seq : seq
+                .getDatasetSequence());
+      }
+    }
+
+    /*
+     * Construct CDS sequences from mappings on the alignment dataset.
+     * The logic is:
+     * - find the protein product(s) mapped to from each dna sequence
+     * - if the mapping covers the whole dna sequence (give or take start/stop
+     *   codon), take the dna as the CDS sequence
+     * - else search dataset mappings for a suitable dna sequence, i.e. one
+     *   whose whole sequence is mapped to the protein 
+     * - if no sequence found, construct one from the dna sequence and mapping
+     *   (and add it to dataset so it is found if this is repeated)
+     */
+    for (SequenceI dnaSeq : dna)
+    {
+      SequenceI dnaDss = dnaSeq.getDatasetSequence() == null ? dnaSeq
+              : dnaSeq.getDatasetSequence();
+
       List<AlignedCodonFrame> seqMappings = MappingUtils
-              .findMappingsForSequence(seq, mappings);
-      List<AlignedCodonFrame> alignmentMappings = al.getCodonFrames();
+              .findMappingsForSequence(dnaSeq, mappings);
       for (AlignedCodonFrame mapping : seqMappings)
       {
-        for (Mapping aMapping : mapping.getMappingsFromSequence(seq))
+        List<Mapping> mappingsFromSequence = mapping
+                .getMappingsFromSequence(dnaSeq);
+
+        for (Mapping aMapping : mappingsFromSequence)
         {
-          SequenceI cdsSeq = makeCdsSequence(seq.getDatasetSequence(),
-                  aMapping);
+          MapList mapList = aMapping.getMap();
+          if (mapList.getFromRatio() == 1)
+          {
+            /*
+             * not a dna-to-protein mapping (likely dna-to-cds)
+             */
+            continue;
+          }
+
+          /*
+           * skip if mapping is not to one of the target set of proteins
+           */
+          SequenceI proteinProduct = aMapping.getTo();
+          if (productSeqs != null && !productSeqs.contains(proteinProduct))
+          {
+            continue;
+          }
+
+          /*
+           * try to locate the CDS from the dataset mappings;
+           * guard against duplicate results (for the case that protein has
+           * dbrefs to both dna and cds sequences)
+           */
+          SequenceI cdsSeq = findCdsForProtein(mappings, dnaSeq,
+                  seqMappings, aMapping);
+          if (cdsSeq != null)
+          {
+            if (!foundSeqs.contains(cdsSeq))
+            {
+              foundSeqs.add(cdsSeq);
+              SequenceI derivedSequence = cdsSeq.deriveSequence();
+              cdsSeqs.add(derivedSequence);
+              if (!dataset.getSequences().contains(cdsSeq))
+              {
+                dataset.addSequence(cdsSeq);
+              }
+            }
+            continue;
+          }
+
+          /*
+           * didn't find mapped CDS sequence - construct it and add
+           * its dataset sequence to the dataset
+           */
+          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);
+          }
+
           /*
            * add a mapping from CDS to the (unchanged) mapped to range
            */
           List<int[]> cdsRange = Collections.singletonList(new int[] { 1,
               cdsSeq.getLength() });
-          MapList map = new MapList(cdsRange, aMapping.getMap()
-                  .getToRanges(), aMapping.getMap().getFromRatio(),
-                  aMapping.getMap().getToRatio());
-          cdsMappings.addMap(cdsSeq, aMapping.getTo(), map);
+          MapList cdsToProteinMap = new MapList(cdsRange,
+                  mapList.getToRanges(), mapList.getFromRatio(),
+                  mapList.getToRatio());
+          AlignedCodonFrame cdsToProteinMapping = new AlignedCodonFrame();
+          cdsToProteinMapping.addMap(cdsSeqDss, proteinProduct,
+                  cdsToProteinMap);
+
+          /*
+           * guard against duplicating the mapping if repeating this action
+           */
+          if (!mappings.contains(cdsToProteinMapping))
+          {
+            mappings.add(cdsToProteinMapping);
+          }
 
+          propagateDBRefsToCDS(cdsSeqDss, dnaSeq.getDatasetSequence(),
+                  proteinProduct, aMapping);
           /*
            * add another mapping from original 'from' range to CDS
            */
-          map = new MapList(aMapping.getMap().getFromRanges(), cdsRange, 1,
-                  1);
-          cdsMappings.addMap(seq.getDatasetSequence(), cdsSeq, map);
+          AlignedCodonFrame dnaToCdsMapping = new AlignedCodonFrame();
+          MapList dnaToCdsMap = new MapList(mapList.getFromRanges(),
+                  cdsRange, 1, 1);
+          dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeqDss,
+                  dnaToCdsMap);
+          if (!mappings.contains(dnaToCdsMapping))
+          {
+            mappings.add(dnaToCdsMapping);
+          }
 
-          alignmentMappings.add(cdsMappings);
+          /*
+           * add DBRef with mapping from protein to CDS
+           * (this enables Get Cross-References from protein alignment)
+           * This is tricky because we can't have two DBRefs with the
+           * same source and accession, so need a different accession for
+           * the CDS from the dna sequence
+           */
+
+          // 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(
+                    primRef.getSource(), primRef.getVersion(),
+                    cdsSeq.getName());
+            //
+            proteinToCdsRef.setMap(new Mapping(cdsSeqDss, cdsToProteinMap
+                    .getInverse()));
+            proteinProduct.addDBRef(proteinToCdsRef);
+          }
 
           /*
            * transfer any features on dna that overlap the CDS
            */
-          transferFeatures(seq, cdsSeq, map, null, SequenceOntologyI.CDS);
+          transferFeatures(dnaSeq, cdsSeq, dnaToCdsMap, null,
+                  SequenceOntologyI.CDS);
         }
       }
     }
 
+    AlignmentI cds = new Alignment(cdsSeqs.toArray(new SequenceI[cdsSeqs
+            .size()]));
+    cds.setDataset(dataset);
+
+    return cds;
+  }
+
+  /**
+   * A helper method that finds a CDS sequence in the alignment dataset that is
+   * mapped to the given protein sequence, and either is, or has a mapping from,
+   * the given dna sequence.
+   * 
+   * @param mappings
+   *          set of all mappings on the dataset
+   * @param dnaSeq
+   *          a dna (or cds) sequence we are searching from
+   * @param seqMappings
+   *          the set of mappings involving dnaSeq
+   * @param aMapping
+   *          an initial candidate from seqMappings
+   * @return
+   */
+  static SequenceI findCdsForProtein(List<AlignedCodonFrame> mappings,
+          SequenceI dnaSeq, List<AlignedCodonFrame> seqMappings,
+          Mapping aMapping)
+  {
+    /*
+     * TODO a better dna-cds-protein mapping data representation to allow easy
+     * navigation; until then this clunky looping around lists of mappings
+     */
+    SequenceI seqDss = dnaSeq.getDatasetSequence() == null ? dnaSeq
+            : dnaSeq.getDatasetSequence();
+    SequenceI proteinProduct = aMapping.getTo();
+
     /*
-     * add CDS seqs to shared dataset
+     * is this mapping from the whole dna sequence (i.e. CDS)?
+     * allowing for possible stop codon on dna but not peptide
      */
-    Alignment dataset = al.getDataset();
-    for (SequenceI seq : cdsSeqs)
+    int mappedFromLength = MappingUtils.getLength(aMapping.getMap()
+            .getFromRanges());
+    int dnaLength = seqDss.getLength();
+    if (mappedFromLength == dnaLength
+            || mappedFromLength == dnaLength - CODON_LENGTH)
     {
-      if (!dataset.getSequences().contains(seq.getDatasetSequence()))
+      return seqDss;
+    }
+
+    /*
+     * looks like we found the dna-to-protein mapping; search for the
+     * corresponding cds-to-protein mapping
+     */
+    List<AlignedCodonFrame> mappingsToPeptide = MappingUtils
+            .findMappingsForSequence(proteinProduct, mappings);
+    for (AlignedCodonFrame acf : mappingsToPeptide)
+    {
+      for (SequenceToSequenceMapping map : acf.getMappings())
       {
-        dataset.addSequence(seq.getDatasetSequence());
+        Mapping mapping = map.getMapping();
+        if (mapping != aMapping
+                && mapping.getMap().getFromRatio() == CODON_LENGTH
+                && proteinProduct == mapping.getTo()
+                && seqDss != map.getFromSeq())
+        {
+          mappedFromLength = MappingUtils.getLength(mapping.getMap()
+                  .getFromRanges());
+          if (mappedFromLength == map.getFromSeq().getLength())
+          {
+            /*
+            * found a 3:1 mapping to the protein product which covers
+            * the whole dna sequence i.e. is from CDS; finally check it
+            * is from the dna start sequence
+            */
+            SequenceI cdsSeq = map.getFromSeq();
+            List<AlignedCodonFrame> dnaToCdsMaps = MappingUtils
+                    .findMappingsForSequence(cdsSeq, seqMappings);
+            if (!dnaToCdsMaps.isEmpty())
+            {
+              return cdsSeq;
+            }
+          }
+        }
       }
     }
-    AlignmentI cds = new Alignment(cdsSeqs.toArray(new SequenceI[cdsSeqs
-            .size()]));
-    cds.setDataset(dataset);
-
-    return cds;
+    return null;
   }
 
   /**
@@ -1448,9 +1887,14 @@ public class AlignmentUtils
    * 
    * @param seq
    * @param mapping
-   * @return
+   * @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();
@@ -1478,13 +1922,131 @@ public class AlignmentUtils
       }
     }
 
-    SequenceI newSeq = new Sequence(seq.getName() + "|"
-            + mapping.getTo().getName(), newSeqChars, 1, newPos);
-    newSeq.createDatasetSequence();
+    /*
+     * assign 'from id' held in the mapping if set (e.g. EMBL protein_id),
+     * else generate a sequence name
+     */
+    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.
@@ -1613,7 +2175,7 @@ public class AlignmentUtils
     /*
      * dna length should map to protein (or protein plus stop codon)
      */
-    int codesForResidues = mappedDnaLength / 3;
+    int codesForResidues = mappedDnaLength / CODON_LENGTH;
     if (codesForResidues == (proteinLength + 1))
     {
       // assuming extra codon is for STOP and not in peptide
@@ -1622,7 +2184,7 @@ public class AlignmentUtils
     if (codesForResidues == proteinLength)
     {
       proteinRange.add(new int[] { proteinStart, proteinEnd });
-      return new MapList(ranges, proteinRange, 3, 1);
+      return new MapList(ranges, proteinRange, CODON_LENGTH, 1);
     }
     return null;
   }
@@ -1744,71 +2306,232 @@ public class AlignmentUtils
      * /ENSP00000288602?feature=transcript_variation;content-type=text/xml
      * which would be a bit slower but possibly more reliable
      */
-    LinkedHashMap<Integer, List<String[][]>> variants = buildDnaVariantsMap(
+
+    /*
+     * build a map with codon variations for each potentially varying peptide
+     */
+    LinkedHashMap<Integer, List<DnaVariant>[]> variants = buildDnaVariantsMap(
             dnaSeq, dnaToProtein);
 
     /*
      * scan codon variations, compute peptide variants and add to peptide sequence
      */
     int count = 0;
-    for (Entry<Integer, List<String[][]>> variant : variants.entrySet())
+    for (Entry<Integer, List<DnaVariant>[]> variant : variants.entrySet())
     {
       int peptidePos = variant.getKey();
-      List<String[][]> codonVariants = variant.getValue();
-      String residue = String.valueOf(peptide.getCharAt(peptidePos - 1)); // 0-based
-      for (String[][] codonVariant : codonVariants)
+      List<DnaVariant>[] codonVariants = variant.getValue();
+      count += computePeptideVariants(peptide, peptidePos, codonVariants);
+    }
+
+    /*
+     * sort to get sequence features in start position order
+     * - would be better to store in Sequence as a TreeSet or NCList?
+     */
+    if (peptide.getSequenceFeatures() != null)
+    {
+      Arrays.sort(peptide.getSequenceFeatures(),
+              new Comparator<SequenceFeature>()
+              {
+                @Override
+                public int compare(SequenceFeature o1, SequenceFeature o2)
+                {
+                  int c = Integer.compare(o1.getBegin(), o2.getBegin());
+                  return c == 0 ? Integer.compare(o1.getEnd(), o2.getEnd())
+                          : c;
+                }
+              });
+    }
+    return count;
+  }
+
+  /**
+   * Computes non-synonymous peptide variants from codon variants and adds them
+   * as sequence_variant features on the protein sequence (one feature per
+   * allele variant). Selected attributes (variant id, clinical significance)
+   * are copied over to the new features.
+   * 
+   * @param peptide
+   *          the protein sequence
+   * @param peptidePos
+   *          the position to compute peptide variants for
+   * @param codonVariants
+   *          a list of dna variants per codon position
+   * @return the number of features added
+   */
+  static int computePeptideVariants(SequenceI peptide, int peptidePos,
+          List<DnaVariant>[] codonVariants)
+  {
+    String residue = String.valueOf(peptide.getCharAt(peptidePos - 1));
+    int count = 0;
+    String base1 = codonVariants[0].get(0).base;
+    String base2 = codonVariants[1].get(0).base;
+    String base3 = codonVariants[2].get(0).base;
+
+    /*
+     * variants in first codon base
+     */
+    for (DnaVariant var : codonVariants[0])
+    {
+      if (var.variant != null)
       {
-        List<String> peptideVariants = computePeptideVariants(codonVariant,
-                residue);
-        if (!peptideVariants.isEmpty())
+        String alleles = (String) var.variant.getValue("alleles");
+        if (alleles != null)
         {
-          String desc = residue
-                  + "->" // include canonical residue in description
-                  + StringUtils
-                          .listToDelimitedString(peptideVariants, ", ");
-          SequenceFeature sf = new SequenceFeature(
-                  SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
-                  peptidePos, 0f, null);
-          peptide.addSequenceFeature(sf);
-          count++;
+          for (String base : alleles.split(","))
+          {
+            String codon = base + base2 + base3;
+            if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
+            {
+              count++;
+            }
+          }
         }
       }
     }
 
     /*
-     * ugly sort to get sequence features in start position order
-     * - would be better to store in Sequence as a TreeSet or NCList?
+     * variants in second codon base
      */
-    Arrays.sort(peptide.getSequenceFeatures(),
-            new Comparator<SequenceFeature>()
+    for (DnaVariant var : codonVariants[1])
+    {
+      if (var.variant != null)
+      {
+        String alleles = (String) var.variant.getValue("alleles");
+        if (alleles != null)
+        {
+          for (String base : alleles.split(","))
+          {
+            String codon = base1 + base + base3;
+            if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
             {
-              @Override
-              public int compare(SequenceFeature o1, SequenceFeature o2)
-              {
-                int c = Integer.compare(o1.getBegin(), o2.getBegin());
-                return c == 0 ? Integer.compare(o1.getEnd(), o2.getEnd())
-                        : c;
-              }
-            });
+              count++;
+            }
+          }
+        }
+      }
+    }
+
+    /*
+     * variants in third codon base
+     */
+    for (DnaVariant var : codonVariants[2])
+    {
+      if (var.variant != null)
+      {
+        String alleles = (String) var.variant.getValue("alleles");
+        if (alleles != null)
+        {
+          for (String base : alleles.split(","))
+          {
+            String codon = base1 + base2 + base;
+            if (addPeptideVariant(peptide, peptidePos, residue, var, codon))
+            {
+              count++;
+            }
+          }
+        }
+      }
+    }
+
     return count;
   }
 
   /**
-   * Builds a map whose key is position in the protein sequence, and value is an
-   * array of all variants for the coding codon positions
+   * Helper method that adds a peptide variant feature, provided the given codon
+   * translates to a value different to the current residue (is a non-synonymous
+   * variant). ID and clinical_significance attributes of the dna variant (if
+   * present) are copied to the new feature.
+   * 
+   * @param peptide
+   * @param peptidePos
+   * @param residue
+   * @param var
+   * @param codon
+   * @return true if a feature was added, else false
+   */
+  static boolean addPeptideVariant(SequenceI peptide, int peptidePos,
+          String residue, DnaVariant var, String codon)
+  {
+    /*
+     * get peptide translation of codon e.g. GAT -> D
+     * note that variants which are not single alleles,
+     * e.g. multibase variants or HGMD_MUTATION etc
+     * are currently ignored here
+     */
+    String trans = codon.contains("-") ? "-"
+            : (codon.length() > CODON_LENGTH ? null : ResidueProperties
+                    .codonTranslate(codon));
+    if (trans != null && !trans.equals(residue))
+    {
+      String residue3Char = StringUtils
+              .toSentenceCase(ResidueProperties.aa2Triplet.get(residue));
+      String trans3Char = StringUtils
+              .toSentenceCase(ResidueProperties.aa2Triplet.get(trans));
+      String desc = "p." + residue3Char + peptidePos + trans3Char;
+      // set score to 0f so 'graduated colour' option is offered! JAL-2060
+      SequenceFeature sf = new SequenceFeature(
+              SequenceOntologyI.SEQUENCE_VARIANT, desc, peptidePos,
+              peptidePos, 0f, var.getSource());
+      StringBuilder attributes = new StringBuilder(32);
+      String id = (String) var.variant.getValue(ID);
+      if (id != null)
+      {
+        if (id.startsWith(SEQUENCE_VARIANT))
+        {
+          id = id.substring(SEQUENCE_VARIANT.length());
+        }
+        sf.setValue(ID, id);
+        attributes.append(ID).append("=").append(id);
+        // TODO handle other species variants JAL-2064
+        StringBuilder link = new StringBuilder(32);
+        try
+        {
+          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());
+        } catch (UnsupportedEncodingException e)
+        {
+          // as if
+        }
+      }
+      String clinSig = (String) var.variant.getValue(CLINICAL_SIGNIFICANCE);
+      if (clinSig != null)
+      {
+        sf.setValue(CLINICAL_SIGNIFICANCE, clinSig);
+        attributes.append(";").append(CLINICAL_SIGNIFICANCE).append("=")
+                .append(clinSig);
+      }
+      peptide.addSequenceFeature(sf);
+      if (attributes.length() > 0)
+      {
+        sf.setAttributes(attributes.toString());
+      }
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Builds a map whose key is position in the protein sequence, and value is a
+   * list of the base and all variants for each corresponding codon position
    * 
    * @param dnaSeq
    * @param dnaToProtein
    * @return
    */
-  static LinkedHashMap<Integer, List<String[][]>> buildDnaVariantsMap(
+  @SuppressWarnings("unchecked")
+  static LinkedHashMap<Integer, List<DnaVariant>[]> buildDnaVariantsMap(
           SequenceI dnaSeq, MapList dnaToProtein)
   {
     /*
-     * map from peptide position to all variant features of the codon for it
-     * LinkedHashMap ensures we add the peptide features in sequence order
+     * map from peptide position to all variants of the codon which codes for it
+     * LinkedHashMap ensures we keep the peptide features in sequence order
      */
-    LinkedHashMap<Integer, List<String[][]>> variants = new LinkedHashMap<Integer, List<String[][]>>();
+    LinkedHashMap<Integer, List<DnaVariant>[]> variants = new LinkedHashMap<Integer, List<DnaVariant>[]>();
     SequenceOntologyI so = SequenceOntologyFactory.getInstance();
 
     SequenceFeature[] dnaFeatures = dnaSeq.getSequenceFeatures();
@@ -1841,10 +2564,13 @@ public class AlignmentUtils
           continue;
         }
         int peptidePosition = mapsTo[0];
-        List<String[][]> codonVariants = variants.get(peptidePosition);
+        List<DnaVariant>[] codonVariants = variants.get(peptidePosition);
         if (codonVariants == null)
         {
-          codonVariants = new ArrayList<String[][]>();
+          codonVariants = new ArrayList[CODON_LENGTH];
+          codonVariants[0] = new ArrayList<DnaVariant>();
+          codonVariants[1] = new ArrayList<DnaVariant>();
+          codonVariants[2] = new ArrayList<DnaVariant>();
           variants.put(peptidePosition, codonVariants);
         }
 
@@ -1873,119 +2599,62 @@ public class AlignmentUtils
         lastCodon = codon;
 
         /*
-         * save nucleotide (and this variant) for each codon position
+         * save nucleotide (and any variant) for each codon position
          */
-        String[][] codonVariant = new String[3][];
-        for (int codonPos = 0; codonPos < 3; codonPos++)
+        for (int codonPos = 0; codonPos < CODON_LENGTH; codonPos++)
         {
           String nucleotide = String.valueOf(
                   dnaSeq.getCharAt(codon[codonPos] - dnaStart))
                   .toUpperCase();
-          if (codonVariant[codonPos] == null)
+          List<DnaVariant> codonVariant = codonVariants[codonPos];
+          if (codon[codonPos] == dnaCol)
           {
-            /*
-             * record current dna base
-             */
-            codonVariant[codonPos] = new String[] { nucleotide };
+            if (!codonVariant.isEmpty()
+                    && codonVariant.get(0).variant == null)
+            {
+              /*
+               * already recorded base value, add this variant
+               */
+              codonVariant.get(0).variant = sf;
+            }
+            else
+            {
+              /*
+               * add variant with base value
+               */
+              codonVariant.add(new DnaVariant(nucleotide, sf));
+            }
           }
-          if (codon[codonPos] == dnaCol)
+          else if (codonVariant.isEmpty())
           {
             /*
-             * add alleles to dna base (and any previously found alleles)
+             * record (possibly non-varying) base value
              */
-            String[] known = codonVariant[codonPos];
-            String[] dnaVariants = new String[alleles.length + known.length];
-            System.arraycopy(known, 0, dnaVariants, 0, known.length);
-            System.arraycopy(alleles, 0, dnaVariants, known.length,
-                    alleles.length);
-            codonVariant[codonPos] = dnaVariants;
+            codonVariant.add(new DnaVariant(nucleotide));
           }
         }
-        codonVariants.add(codonVariant);
       }
     }
     return variants;
   }
 
   /**
-   * Returns a sorted, non-redundant list of all peptide translations generated
-   * by the given dna variants, excluding the current residue value
-   * 
-   * @param codonVariants
-   *          an array of base values (acgtACGT) for codon positions 1, 2, 3
-   * @param residue
-   *          the current residue translation
-   * @return
-   */
-  static List<String> computePeptideVariants(String[][] codonVariants,
-          String residue)
-  {
-    List<String> result = new ArrayList<String>();
-    for (String base1 : codonVariants[0])
-    {
-      for (String base2 : codonVariants[1])
-      {
-        for (String base3 : codonVariants[2])
-        {
-          String codon = base1 + base2 + base3;
-          /*
-           * get peptide translation of codon e.g. GAT -> D
-           * note that variants which are not single alleles,
-           * e.g. multibase variants or HGMD_MUTATION etc
-           * are ignored here
-           */
-          String peptide = codon.contains("-") ? "-"
-                  : (codon.length() > 3 ? null : ResidueProperties
-                          .codonTranslate(codon));
-          if (peptide != null && !result.contains(peptide)
-                  && !peptide.equalsIgnoreCase(residue))
-          {
-            result.add(peptide);
-          }
-        }
-      }
-    }
-
-    /*
-     * sort alphabetically with STOP at the end
-     */
-    Collections.sort(result, new Comparator<String>()
-    {
-
-      @Override
-      public int compare(String o1, String o2)
-      {
-        if ("STOP".equals(o1))
-        {
-          return 1;
-        }
-        else if ("STOP".equals(o2))
-        {
-          return -1;
-        }
-        else
-        {
-          return o1.compareTo(o2);
-        }
-      }
-    });
-    return result;
-  }
-
-  /**
    * Makes an alignment with a copy of the given sequences, adding in any
    * non-redundant sequences which are mapped to by the cross-referenced
    * sequences.
    * 
    * @param seqs
    * @param xrefs
+   * @param dataset
+   *          the alignment dataset shared by the new copy
    * @return
    */
   public static AlignmentI makeCopyAlignment(SequenceI[] seqs,
-          SequenceI[] xrefs)
+          SequenceI[] xrefs, AlignmentI dataset)
   {
     AlignmentI copy = new Alignment(new Alignment(seqs));
-
+    copy.setDataset(dataset);
+    boolean isProtein = !copy.isNucleotide();
     SequenceIdMatcher matcher = new SequenceIdMatcher(seqs);
     if (xrefs != null)
     {
@@ -1996,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;
             }
@@ -2030,19 +2700,32 @@ public class AlignmentUtils
    */
   public static int alignAs(AlignmentI unaligned, AlignmentI aligned)
   {
+    /*
+     * easy case - aligning a copy of aligned sequences
+     */
+    if (alignAsSameSequences(unaligned, aligned))
+    {
+      return unaligned.getHeight();
+    }
+
+    /*
+     * fancy case - aligning via mappings between sequences
+     */
     List<SequenceI> unmapped = new ArrayList<SequenceI>();
     Map<Integer, Map<SequenceI, Character>> columnMap = buildMappedColumnsMap(
             unaligned, aligned, unmapped);
     int width = columnMap.size();
     char gap = unaligned.getGapCharacter();
     int realignedCount = 0;
+    // TODO: verify this loop scales sensibly for very wide/high alignments
 
     for (SequenceI seq : unaligned.getSequences())
     {
       if (!unmapped.contains(seq))
       {
         char[] newSeq = new char[width];
-        Arrays.fill(newSeq, gap);
+        Arrays.fill(newSeq, gap); // JBPComment - doubt this is faster than the
+                                  // Integer iteration below
         int newCol = 0;
         int lastCol = 0;
 
@@ -2064,7 +2747,7 @@ public class AlignmentUtils
           }
           newCol++;
         }
-        
+
         /*
          * trim trailing gaps
          */
@@ -2074,6 +2757,7 @@ public class AlignmentUtils
           System.arraycopy(newSeq, 0, tmp, 0, lastCol + 1);
           newSeq = tmp;
         }
+        // TODO: optimise SequenceI to avoid char[]->String->char[]
         seq.setSequence(String.valueOf(newSeq));
         realignedCount++;
       }
@@ -2082,6 +2766,72 @@ public class AlignmentUtils
   }
 
   /**
+   * If unaligned and aligned sequences share the same dataset sequences, then
+   * simply copies the aligned sequences to the unaligned sequences and returns
+   * true; else returns false
+   * 
+   * @param unaligned
+   *          - sequences to be aligned based on aligned
+   * @param aligned
+   *          - 'guide' alignment containing sequences derived from same dataset
+   *          as unaligned
+   * @return
+   */
+  static boolean alignAsSameSequences(AlignmentI unaligned,
+          AlignmentI aligned)
+  {
+    if (aligned.getDataset() == null || unaligned.getDataset() == null)
+    {
+      return false; // should only pass alignments with datasets here
+    }
+
+    // map from dataset sequence to alignment sequence(s)
+    Map<SequenceI, List<SequenceI>> alignedDatasets = new HashMap<SequenceI, List<SequenceI>>();
+    for (SequenceI seq : aligned.getSequences())
+    {
+      SequenceI ds = seq.getDatasetSequence();
+      if (alignedDatasets.get(ds) == null)
+      {
+        alignedDatasets.put(ds, new ArrayList<SequenceI>());
+      }
+      alignedDatasets.get(ds).add(seq);
+    }
+
+    /*
+     * first pass - check whether all sequences to be aligned share a dataset
+     * sequence with an aligned sequence
+     */
+    for (SequenceI seq : unaligned.getSequences())
+    {
+      if (!alignedDatasets.containsKey(seq.getDatasetSequence()))
+      {
+        return false;
+      }
+    }
+
+    /*
+     * second pass - copy aligned sequences;
+     * heuristic rule: pair off sequences in order for the case where 
+     * more than one shares the same dataset sequence 
+     */
+    for (SequenceI seq : unaligned.getSequences())
+    {
+      List<SequenceI> alignedSequences = alignedDatasets.get(seq
+              .getDatasetSequence());
+      // TODO: getSequenceAsString() will be deprecated in the future
+      // TODO: need to leave to SequenceI implementor to update gaps
+      seq.setSequence(alignedSequences.get(0).getSequenceAsString());
+      if (alignedSequences.size() > 0)
+      {
+        // pop off aligned sequences (except the last one)
+        alignedSequences.remove(0);
+      }
+    }
+
+    return true;
+  }
+
+  /**
    * Returns a map whose key is alignment column number (base 1), and whose
    * values are a map of sequence characters in that column.
    * 
@@ -2095,13 +2845,13 @@ public class AlignmentUtils
   {
     /*
      * Map will hold, for each aligned column position, a map of
-     * {unalignedSequence, sequenceCharacter} at that position.
+     * {unalignedSequence, characterPerSequence} at that position.
      * TreeMap keeps the entries in ascending column order. 
      */
     Map<Integer, Map<SequenceI, Character>> map = new TreeMap<Integer, Map<SequenceI, Character>>();
 
     /*
-     * r any sequences that have no mapping so can't be realigned
+     * record any sequences that have no mapping so can't be realigned
      */
     unmapped.addAll(unaligned.getSequences());
 
@@ -2150,6 +2900,15 @@ public class AlignmentUtils
       return false;
     }
 
+    /*
+     * invert mapping if it is from unaligned to aligned sequence
+     */
+    if (seqMap.getTo() == fromSeq.getDatasetSequence())
+    {
+      seqMap = new Mapping(seq.getDatasetSequence(), seqMap.getMap()
+              .getInverse());
+    }
+
     char[] fromChars = fromSeq.getSequence();
     int toStart = seq.getStart();
     char[] toChars = seq.getSequence();
@@ -2183,7 +2942,8 @@ public class AlignmentUtils
          * of the next character of the mapped-to sequence; stop when all
          * the characters of the range have been counted
          */
-        while (mappedCharPos <= range[1])
+        while (mappedCharPos <= range[1] && fromCol <= fromChars.length
+                && fromCol >= 0)
         {
           if (!Comparison.isGap(fromChars[fromCol - 1]))
           {
index d4ae57d..8127747 100755 (executable)
@@ -24,11 +24,13 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.ext.android.SparseIntArray;
+import jalview.schemes.ResidueProperties;
 
 import java.awt.Color;
-import java.util.Enumeration;
-import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 import java.util.Vector;
 
 /**
@@ -45,13 +47,14 @@ public class Conservation
 
   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;
+  Map<String, Integer>[] total;
 
   boolean canonicaliseAa = true; // if true then conservation calculation will
 
@@ -60,22 +63,18 @@ 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];
+  private double[] qualityRange = new double[2];
 
-  String consString = "";
+  private Sequence consSequence;
 
-  Sequence consSequence;
+  private int threshold;
 
-  Hashtable propHash;
+  private String name = "";
 
-  int threshold;
-
-  String name = "";
-
-  int[][] cons2;
+  private int[][] cons2;
 
   private String[] consSymbs;
 
@@ -84,8 +83,6 @@ public class Conservation
    * 
    * @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
@@ -95,11 +92,10 @@ public class Conservation
    * @param end
    *          end residue position
    */
-  public Conservation(String name, Hashtable propHash, int threshold,
+  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 +147,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,29 +189,26 @@ 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 jSize = sequences.length;
+    // int[] values; // Replaces residueHash
+    SparseIntArray values = new SparseIntArray();
 
-    total = new Hashtable[maxLength];
+    total = new Map[maxLength];
 
     for (int i = start; i <= end; i++)
     {
-      values = new int[255];
+      // values = new int[255];
+      values.clear();
 
-      for (j = 0; j < jSize; j++)
+      for (int j = 0; j < jSize; j++)
       {
         if (sequences[j].getLength() > i)
         {
-          c = sequences[j].getCharAt(i);
+          char c = sequences[j].getCharAt(i);
 
           if (canonicaliseAa)
           { // lookup the base aa code symbol
-            c = (char) jalview.schemes.ResidueProperties.aaIndex[sequences[j]
-                    .getCharAt(i)];
+            c = (char) ResidueProperties.aaIndex[sequences[j].getCharAt(i)];
             if (c > 20)
             {
               c = '-';
@@ -223,7 +216,7 @@ public class Conservation
             else
             {
               // recover canonical aa symbol
-              c = jalview.schemes.ResidueProperties.aa[c].charAt(0);
+              c = ResidueProperties.aa[c].charAt(0);
             }
           }
           else
@@ -235,38 +228,38 @@ public class Conservation
               c = '-';
             }
 
-            if (!canonicaliseAa && 'a' <= c && c <= 'z')
-            {
-              c -= (32); // 32 = 'a' - 'A'
-            }
+            c = toUpperCase(c);
           }
-          values[c]++;
+          // values[c]++;
+          values.add(c, 1);
         }
         else
         {
-          values['-']++;
+          // values['-']++;
+          values.add('-', 1);
         }
       }
 
       // What is the count threshold to count the residues in residueHash()
-      thresh = (threshold * (jSize)) / 100;
+      int thresh = (threshold * jSize) / 100;
 
       // loop over all the found residues
-      resultHash = new Hashtable();
-      for (char v = '-'; v < 'Z'; v++)
+      // Hashtable<String, Integer> resultHash = new Hashtable<String,
+      // Integer>();
+      Map<String, Integer> resultHash = new TreeMap<String, Integer>();
+      // for (char v = '-'; v < 'Z'; v++)
+      for (int key = 0; key < values.size(); key++)
       {
-
-        if (values[v] > thresh)
+        char v = (char) values.keyAt(key);
+        // if (values[v] > thresh)
+        if (values.valueAt(key) > thresh)
         {
-          res = String.valueOf(v);
+          String res = String.valueOf(v);
 
           // Now loop over the properties
-          enumeration2 = propHash.keys();
-
-          while (enumeration2.hasMoreElements())
+          for (String type : ResidueProperties.propHash.keySet())
           {
-            type = (String) enumeration2.nextElement();
-            ht = (Hashtable) propHash.get(type);
+            Map<String, Integer> ht = ResidueProperties.propHash.get(type);
 
             // Have we ticked this before?
             if (!resultHash.containsKey(type))
@@ -280,7 +273,7 @@ public class Conservation
                 resultHash.put(type, ht.get("-"));
               }
             }
-            else if (((Integer) resultHash.get(type)).equals(ht.get(res)) == false)
+            else if (!resultHash.get(type).equals(ht.get(res)))
             {
               resultHash.put(type, new Integer(-1));
             }
@@ -326,6 +319,7 @@ public class Conservation
       }
       else
       {
+        c = toUpperCase(c);
         nres++;
 
         if (nres == 1)
@@ -347,24 +341,33 @@ public class Conservation
   }
 
   /**
+   * Returns the upper-cased character if between 'a' and 'z', else the
+   * unchanged value
+   * 
+   * @param c
+   * @return
+   */
+  char toUpperCase(char c)
+  {
+    if ('a' <= c && c <= 'z')
+    {
+      c -= (32); // 32 = 'a' - 'A'
+    }
+    return c;
+  }
+
+  /**
    * Calculates the conservation sequence
    * 
    * @param consflag
-   *          if true, poitiveve conservation; false calculates negative
+   *          if true, positive conservation; false calculates negative
    *          conservation
    * @param percentageGaps
    *          commonly used value is 25
    */
   public void verdict(boolean consflag, float percentageGaps)
   {
-    StringBuffer consString = new StringBuffer();
-    String type;
-    Integer result;
-    int[] gapcons;
-    int totGaps, count;
-    float pgaps;
-    Hashtable resultHash;
-    Enumeration enumeration;
+    StringBuilder consString = new StringBuilder(end);
 
     // NOTE THIS SHOULD CHECK IF THE CONSEQUENCE ALREADY
     // EXISTS AND NOT OVERWRITE WITH '-', BUT THIS CASE
@@ -376,50 +379,63 @@ 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 = countConsNGaps(i);
+      int totGaps = gapcons[1];
+      float pgaps = ((float) totGaps * 100) / sequences.length;
+      StringBuilder positives = new StringBuilder(64);
+      StringBuilder negatives = new StringBuilder(32);
+      // consSymbs[i - start] = "";
 
       if (percentageGaps > pgaps)
       {
-        resultHash = total[i - start];
+        Map<String, Integer> resultHash = total[i - start];
         // Now find the verdict
-        count = 0;
-        enumeration = resultHash.keys();
-
-        while (enumeration.hasMoreElements())
+        int count = 0;
+        for (String type : resultHash.keySet())
         {
-          type = (String) enumeration.nextElement();
-          result = (Integer) resultHash.get(type);
+          int result = resultHash.get(type).intValue();
           // Do we want to count +ve conservation or +ve and -ve cons.?
           if (consflag)
           {
-            if (result.intValue() == 1)
+            if (result == 1)
             {
-              consSymbs[i - start] = type + " " + consSymbs[i - start];
+              // consSymbs[i - start] = type + " " + consSymbs[i - start];
+              positives.append(positives.length() == 0 ? "" : " ");
+              positives.append(type);
               count++;
             }
           }
           else
           {
-            if (result.intValue() != -1)
+            if (result != -1)
             {
+              if (result == 0)
               {
-                if (result.intValue() == 0)
-                {
-                  consSymbs[i - start] = consSymbs[i - start] + " !" + type;
-                }
-                else
-                {
-                  consSymbs[i - start] = type + " " + consSymbs[i - start];
-                }
+                /*
+                 * add negatively conserved properties on the end
+                 */
+                // consSymbs[i - start] = consSymbs[i - start] + " !" + type;
+                negatives.append(negatives.length() == 0 ? "" : " ");
+                negatives.append("!").append(type);
+              }
+              else
+              {
+                /*
+                 * put positively conserved properties on the front
+                 */
+                // consSymbs[i - start] = type + " " + consSymbs[i - start];
+                positives.append(positives.length() == 0 ? "" : " ");
+                positives.append(type);
               }
-
               count++;
             }
           }
         }
+        if (negatives.length() > 0)
+        {
+          positives.append(" ").append(negatives);
+        }
+        consSymbs[i - start] = positives.toString();
 
         if (count < 10)
         {
@@ -460,7 +476,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?
@@ -487,7 +503,7 @@ public class Conservation
 
       while (j < sequences.length)
       {
-        sqnum = (int[]) seqNums.elementAt(j);
+        sqnum = seqNums.elementAt(j);
 
         for (i = 1; i < sqnum.length; i++)
         {
@@ -517,17 +533,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();
@@ -542,10 +558,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;
 
@@ -569,8 +585,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++)
@@ -603,9 +621,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);
@@ -618,12 +636,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.
    * 
@@ -661,7 +679,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];
@@ -669,17 +687,17 @@ 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 = 0; i < alWidth; i++)
+    for (int i = istart; i < alWidth; i++)
     {
       float value = 0;
 
@@ -698,20 +716,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
@@ -726,9 +747,6 @@ 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)
@@ -746,29 +764,12 @@ public class Conservation
    * @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)
+          int threshold, List<SequenceI> seqs, int start, int end,
+          boolean posOrNeg, int consPercGaps, boolean calcQuality)
   {
+    Conservation cons = new Conservation(name, threshold, seqs, start, end);
     cons.calculate();
-    cons.verdict(b, consPercGaps);
+    cons.verdict(posOrNeg, consPercGaps);
 
     if (calcQuality)
     {
index 3563eba..4ba7e41 100644 (file)
@@ -31,16 +31,15 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
-import jalview.ws.SequenceFetcher;
+import jalview.ws.SequenceFetcherFactory;
 import jalview.ws.seqfetcher.ASequenceFetcher;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
-import java.util.Vector;
 
 /**
- * Functions for cross-referencing sequence databases. user must first specify
- * if cross-referencing from protein or dna (set dna==true)
+ * Functions for cross-referencing sequence databases.
  * 
  * @author JimP
  * 
@@ -48,195 +47,182 @@ import java.util.Vector;
 public class CrossRef
 {
   /*
-   * A sub-class that ignores Parent attribute when comparing sequence 
-   * features. This avoids 'duplicate' CDS features that only
-   * differ in their parent Transcript ids.
+   * the dataset of the alignment for which we are searching for 
+   * cross-references; in some cases we may resolve xrefs by 
+   * searching in the dataset
    */
-  class MySequenceFeature extends SequenceFeature
-  {
-    private SequenceFeature feat;
+  private AlignmentI dataset;
 
-    MySequenceFeature(SequenceFeature sf)
-    {
-      this.feat = sf;
-    }
+  /*
+   * the sequences for which we are seeking cross-references
+   */
+  private SequenceI[] fromSeqs;
 
-    @Override
-    public boolean equals(Object o)
-    {
-      return feat.equals(o, true);
-    }
-  }
+  /**
+   * matcher built from dataset
+   */
+  SequenceIdMatcher matcher;
 
   /**
-   * Select just the DNA or protein references for a protein or dna sequence
-   * 
-   * @param fromDna
-   *          if true, select references from DNA (i.e. Protein databases), else
-   *          DNA database references
-   * @param refs
-   *          a set of references to select from
-   * @return
+   * sequences found by cross-ref searches to fromSeqs
    */
-  public static DBRefEntry[] findXDbRefs(boolean fromDna, DBRefEntry[] refs)
-  {
-    return DBRefUtils.selectRefs(refs, fromDna ? DBRefSource.PROTEINDBS
-            : DBRefSource.DNACODINGDBS);
-    // could attempt to find other cross
-    // refs here - ie PDB xrefs
-    // (not dna, not protein seq)
-  }
+  List<SequenceI> rseqs;
 
   /**
-   * @param dna
-   *          true if seqs are DNA seqs
+   * Constructor
+   * 
    * @param seqs
-   * @return a list of sequence database cross reference source types
+   *          the sequences for which we are seeking cross-references
+   * @param ds
+   *          the containing alignment dataset (may be searched to resolve
+   *          cross-references)
    */
-  public static String[] findSequenceXrefTypes(boolean dna, SequenceI[] seqs)
+  public CrossRef(SequenceI[] seqs, AlignmentI ds)
   {
-    return findSequenceXrefTypes(dna, seqs, null);
+    fromSeqs = seqs;
+    dataset = ds.getDataset() == null ? ds : ds.getDataset();
   }
 
   /**
-   * Indirect references are references from other sequences from the dataset to
-   * any of the direct DBRefEntrys on the given sequences.
+   * Returns a list of distinct database sources for which sequences have either
+   * <ul>
+   * <li>a (dna-to-protein or protein-to-dna) cross-reference</li>
+   * <li>an indirect cross-reference - a (dna-to-protein or protein-to-dna)
+   * reference from another sequence in the dataset which has a cross-reference
+   * to a direct DBRefEntry on the given sequence</li>
+   * </ul>
    * 
    * @param dna
-   *          true if seqs are DNA seqs
-   * @param seqs
-   * @return a list of sequence database cross reference source types
+   *          - when true, cross-references *from* dna returned. When false,
+   *          cross-references *from* protein are returned
+   * @return
    */
-  public static String[] findSequenceXrefTypes(boolean dna,
-          SequenceI[] seqs, AlignmentI dataset)
+  public List<String> findXrefSourcesForSequences(boolean dna)
   {
-    String[] dbrefs = null;
-    List<String> refs = new ArrayList<String>();
-    for (SequenceI seq : seqs)
+    List<String> sources = new ArrayList<String>();
+    for (SequenceI seq : fromSeqs)
     {
       if (seq != null)
       {
-        SequenceI dss = seq;
-        while (dss.getDatasetSequence() != null)
-        {
-          dss = dss.getDatasetSequence();
-        }
-        DBRefEntry[] rfs = findXDbRefs(dna, dss.getDBRefs());
-        if (rfs != null)
-        {
-          for (DBRefEntry ref : rfs)
-          {
-            if (!refs.contains(ref.getSource()))
-            {
-              refs.add(ref.getSource());
-            }
-          }
-        }
-        if (dataset != null)
-        {
-          // search for references to this sequence's direct references.
-          DBRefEntry[] lrfs = CrossRef.findXDbRefs(!dna, seq.getDBRefs());
-          List<SequenceI> rseqs = new ArrayList<SequenceI>();
-          CrossRef.searchDatasetXrefs(seq, !dna, lrfs, dataset, rseqs,
-                  null); // don't need to specify codon frame for mapping here
-          for (SequenceI rs : rseqs)
-          {
-            DBRefEntry[] xrs = findXDbRefs(dna, rs.getDBRefs());
-            if (xrs != null)
-            {
-              for (DBRefEntry ref : xrs)
-              {
-                if (!refs.contains(ref.getSource()))
-                {
-                  refs.add(ref.getSource());
-                }
-              }
-            }
-            // looks like copy and paste - change rfs to xrs?
-            // for (int r = 0; rfs != null && r < rfs.length; r++)
-            // {
-            // if (!refs.contains(rfs[r].getSource()))
-            // {
-            // refs.add(rfs[r].getSource());
-            // }
-            // }
-          }
-        }
+        findXrefSourcesForSequence(seq, dna, sources);
       }
     }
-    if (refs.size() > 0)
+    sources.remove(DBRefSource.EMBL); // hack to prevent EMBL xrefs resulting in
+                                      // redundant datasets
+    if (dna)
     {
-      dbrefs = new String[refs.size()];
-      refs.toArray(dbrefs);
+      sources.remove(DBRefSource.ENSEMBL); // hack to prevent Ensembl and
+                                           // EnsemblGenomes xref option shown
+                                           // from cdna panel
+      sources.remove(DBRefSource.ENSEMBLGENOMES);
     }
-    return dbrefs;
+    // redundant datasets
+    return sources;
   }
 
-  public static boolean hasCdnaMap(SequenceI[] seqs)
+  /**
+   * Returns a list of distinct database sources for which a sequence has either
+   * <ul>
+   * <li>a (dna-to-protein or protein-to-dna) cross-reference</li>
+   * <li>an indirect cross-reference - a (dna-to-protein or protein-to-dna)
+   * reference from another sequence in the dataset which has a cross-reference
+   * to a direct DBRefEntry on the given sequence</li>
+   * </ul>
+   * 
+   * @param seq
+   *          the sequence whose dbrefs we are searching against
+   * @param fromDna
+   *          when true, context is DNA - so sources identifying protein
+   *          products will be returned.
+   * @param sources
+   *          a list of sources to add matches to
+   */
+  void findXrefSourcesForSequence(SequenceI seq, boolean fromDna,
+          List<String> sources)
   {
-    // TODO unused - remove?
-    String[] reftypes = findSequenceXrefTypes(false, seqs);
-    for (int s = 0; s < reftypes.length; s++)
+    /*
+     * first find seq's xrefs (dna-to-peptide or peptide-to-dna)
+     */
+    DBRefEntry[] rfs = DBRefUtils.selectDbRefs(!fromDna, seq.getDBRefs());
+    addXrefsToSources(rfs, sources);
+    if (dataset != null)
     {
-      if (reftypes.equals(DBRefSource.EMBLCDS))
+      /*
+       * find sequence's direct (dna-to-dna, peptide-to-peptide) xrefs
+       */
+      DBRefEntry[] lrfs = DBRefUtils.selectDbRefs(fromDna, seq.getDBRefs());
+      List<SequenceI> foundSeqs = new ArrayList<SequenceI>();
+
+      /*
+       * find sequences in the alignment which xref one of these DBRefs
+       * i.e. is xref-ed to a common sequence identifier
+       */
+      searchDatasetXrefs(fromDna, seq, lrfs, foundSeqs, null);
+
+      /*
+       * add those sequences' (dna-to-peptide or peptide-to-dna) dbref sources
+       */
+      for (SequenceI rs : foundSeqs)
       {
-        return true;
-        // no map
+        DBRefEntry[] xrs = DBRefUtils
+                .selectDbRefs(!fromDna, rs.getDBRefs());
+        addXrefsToSources(xrs, sources);
       }
     }
-    return false;
   }
 
-  public static SequenceI[] getCdnaMap(SequenceI[] seqs)
+  /**
+   * Helper method that adds the source identifiers of some cross-references to
+   * a (non-redundant) list of database sources
+   * 
+   * @param xrefs
+   * @param sources
+   */
+  void addXrefsToSources(DBRefEntry[] xrefs, List<String> sources)
   {
-    // TODO unused - remove?
-    Vector cseqs = new Vector();
-    for (int s = 0; s < seqs.length; s++)
+    if (xrefs != null)
     {
-      DBRefEntry[] cdna = findXDbRefs(true, seqs[s].getDBRefs());
-      for (int c = 0; c < cdna.length; c++)
+      for (DBRefEntry ref : xrefs)
       {
-        if (cdna[c].getSource().equals(DBRefSource.EMBLCDS))
+        /*
+         * avoid duplication e.g. ENSEMBL and Ensembl
+         */
+        String source = DBRefUtils.getCanonicalName(ref.getSource());
+        if (!sources.contains(source))
         {
-          System.err
-                  .println("TODO: unimplemented sequence retrieval for coding region sequence.");
-          // TODO: retrieve CDS dataset sequences
-          // need global dataset sequence retriever/resolver to reuse refs
-          // and construct Mapping entry.
-          // insert gaps in CDS according to peptide gaps.
-          // add gapped sequence to cseqs
+          sources.add(source);
         }
       }
     }
-    if (cseqs.size() > 0)
-    {
-      SequenceI[] rsqs = new SequenceI[cseqs.size()];
-      cseqs.copyInto(rsqs);
-      return rsqs;
-    }
-    return null;
-
   }
 
   /**
+   * Attempts to find cross-references from the sequences provided in the
+   * constructor to the given source database. Cross-references may be found
+   * <ul>
+   * <li>in dbrefs on the sequence which hold a mapping to a sequence
+   * <ul>
+   * <li>provided with a fetched sequence (e.g. ENA translation), or</li>
+   * <li>populated previously after getting cross-references</li>
+   * </ul>
+   * <li>as other sequences in the alignment which share a dbref identifier with
+   * the sequence</li>
+   * <li>by fetching from the remote database</li>
+   * </ul>
+   * The cross-referenced sequences, and mappings to them, are added to the
+   * alignment dataset.
    * 
-   * @param seqs
-   *          sequences whose xrefs are being retrieved
-   * @param dna
-   *          true if sequences are nucleotide
    * @param source
-   * @param al
-   *          alignment to search for cross-referenced sequences (and possibly
-   *          add to)
-   * @return products (as dataset sequences)
+   * @return cross-referenced sequences (as dataset sequences)
    */
-  public static Alignment findXrefSequences(SequenceI[] seqs,
-          final boolean dna, final String source, AlignmentI al)
+  public Alignment findXrefSequences(String source, boolean fromDna)
   {
-    AlignmentI dataset = al.getDataset() == null ? al : al.getDataset();
-    List<SequenceI> rseqs = new ArrayList<SequenceI>();
+
+    rseqs = new ArrayList<SequenceI>();
     AlignedCodonFrame cf = new AlignedCodonFrame();
-    for (SequenceI seq : seqs)
+    matcher = new SequenceIdMatcher(dataset.getSequences());
+
+    for (SequenceI seq : fromSeqs)
     {
       SequenceI dss = seq;
       while (dss.getDatasetSequence() != null)
@@ -244,242 +230,580 @@ public class CrossRef
         dss = dss.getDatasetSequence();
       }
       boolean found = false;
-      DBRefEntry[] xrfs = CrossRef.findXDbRefs(dna, dss.getDBRefs());
+      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)
       {
-        System.out.println("Attempting to find ds Xrefs refs.");
-        // FIXME should be dss not seq here?
-        DBRefEntry[] lrfs = CrossRef.findXDbRefs(!dna, seq.getDBRefs());
-        // less ambiguous would be a 'find primary dbRefEntry' method.
-        // filter for desired source xref here
-        found = CrossRef.searchDatasetXrefs(dss, !dna, lrfs, dataset,
-                rseqs, cf);
+        /*
+         * found no suitable dbrefs on sequence - look for sequences in the
+         * alignment which share a dbref with this one
+         */
+        DBRefEntry[] lrfs = DBRefUtils.selectDbRefs(fromDna,
+                seq.getDBRefs());
+
+        /*
+         * find sequences (except this one!), of complementary type,
+         *  which have a dbref to an accession id for this sequence,
+         *  and add them to the results
+         */
+        found = searchDatasetXrefs(fromDna, dss, lrfs, rseqs, cf);
       }
-      for (int r = 0; xrfs != null && r < xrfs.length; r++)
+      if (xrfs == null && !found)
       {
-        DBRefEntry xref = xrfs[r];
-        if (source != null && !source.equals(xref.getSource()))
-        {
-          continue;
-        }
-        if (xref.hasMap())
+        /*
+         * no dbref to source on this sequence or matched
+         * complementary sequence in the dataset 
+         */
+        continue;
+      }
+      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;
+        // we're only interested in coding cross-references, not
+        // locus->transcript
+        if (xref.hasMap() && xref.getMap().getMap().isTripletMap())
         {
-          if (xref.getMap().getTo() != null)
+          SequenceI mappedTo = xref.getMap().getTo();
+          if (mappedTo != null)
           {
-            SequenceI rsq = new Sequence(xref.getMap().getTo());
+            /*
+             * dbref contains the sequence it maps to; add it to the
+             * results unless we have done so already (could happen if 
+             * fetching xrefs for sequences which have xrefs in common)
+             * for example: UNIPROT {P0CE19, P0CE20} -> EMBL {J03321, X06707}
+             */
+            found = true;
+            /*
+             * problem: matcher.findIdMatch() is lenient - returns a sequence
+             * with a dbref to the search arg e.g. ENST for ENSP - wrong
+             * 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)
+            {
+              if (!rseqs.contains(matchInDataset))
+              {
+                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 (dna)
+              if (fromDna)
               {
                 // map is from dna seq to a protein product
-                cf.addMap(dss, rsq, xref.getMap().getMap());
+                cf.addMap(dss, rsq, xref.getMap().getMap(), xref.getMap()
+                        .getMappedFromId());
               }
               else
               {
                 // map should be from protein seq to its coding dna
-                cf.addMap(rsq, dss, xref.getMap().getMap().getInverse());
+                cf.addMap(rsq, dss, xref.getMap().getMap().getInverse(),
+                        xref.getMap().getMappedFromId());
               }
             }
-            found = true;
           }
         }
+
         if (!found)
         {
-          // do a bit more work - search for sequences with references matching
-          // xrefs on this sequence.
-          if (dataset != null)
+          SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|"
+                  + xref.getAccessionId());
+          // if there was a match, check it's at least the right type of
+          // molecule!
+          if (matchedSeq != null && matchedSeq.isProtein() == fromDna)
           {
-            found |= searchDataset(dss, xref, dataset, rseqs, cf, false,
-                    !dna);
-            if (found)
+            if (constructMapping(seq, matchedSeq, xref, cf, fromDna))
             {
-              xrfs[r] = null; // we've recovered seqs for this one.
+              found = true;
             }
           }
         }
+
+        if (!found)
+        {
+          // do a bit more work - search for sequences with references matching
+          // xrefs on this sequence.
+          found = searchDataset(fromDna, dss, xref, rseqs, cf, false);
+        }
+        if (found)
+        {
+          refIterator.remove();
+        }
+      }
+
+      /*
+       * fetch from source database any dbrefs we haven't resolved up to here
+       */
+      if (!sourceRefs.isEmpty())
+      {
+        retrieveCrossRef(sourceRefs, seq, xrfs, fromDna, cf);
+      }
+    }
+
+    Alignment ral = null;
+    if (rseqs.size() > 0)
+    {
+      ral = new Alignment(rseqs.toArray(new SequenceI[rseqs.size()]));
+      if (!cf.isEmpty())
+      {
+        dataset.addCodonFrame(cf);
+      }
+    }
+    return ral;
+  }
+
+  private void retrieveCrossRef(List<DBRefEntry> sourceRefs, SequenceI seq,
+          DBRefEntry[] xrfs, boolean fromDna, AlignedCodonFrame cf)
+  {
+    ASequenceFetcher sftch = SequenceFetcherFactory.getSequenceFetcher();
+    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);
+    } catch (Exception e)
+    {
+      System.err
+              .println("Problem whilst retrieving cross references for Sequence : "
+                      + seq.getName());
+      e.printStackTrace();
+    }
+
+    if (retrieved != null)
+    {
+      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();
+        addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+                retrievedDss);
       }
-      if (!found)
+      if (!addedXref)
       {
-        if (xrfs != null && xrfs.length > 0)
+        // 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)
         {
-          // Try and get the sequence reference...
-          /*
-           * Ideal world - we ask for a sequence fetcher implementation here if
-           * (jalview.io.RunTimeEnvironment.getSequenceFetcher()) (
-           */
-          ASequenceFetcher sftch = new SequenceFetcher();
-          SequenceI[] retrieved = null;
-          int l = xrfs.length;
-          for (int r = 0; r < xrfs.length; r++)
+          // 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))
           {
-            // filter out any irrelevant or irretrievable references
-            if (xrfs[r] == null
-                    || ((source != null && !source.equals(xrfs[r]
-                            .getSource())) || !sftch.isFetchable(xrfs[r]
-                            .getSource())))
-            {
-              l--;
-              xrfs[r] = null;
-            }
+            sourceRefs.remove(found);
+            dupeFound = true;
           }
-          if (l > 0)
+        }
+      }
+      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)
+        {
+          // 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)
           {
-            System.out
-                    .println("Attempting to retrieve cross referenced sequences.");
-            DBRefEntry[] t = new DBRefEntry[l];
-            l = 0;
-            for (int r = 0; r < xrfs.length; r++)
+            if (map.getTo() == sourceSequence)
             {
-              if (xrfs[r] != null)
-              {
-                t[l++] = xrfs[r];
-              }
+              // already called to import once, and most likely this sequence
+              // already imported !
+              continue;
             }
-            xrfs = t;
-            try
+            if (matched == null)
             {
-              retrieved = sftch.getSequences(xrfs, !dna);
-              // problem here is we don't know which of xrfs resulted in which
-              // retrieved element
-            } catch (Exception e)
-            {
-              System.err
-                      .println("Problem whilst retrieving cross references for Sequence : "
-                              + seq.getName());
-              e.printStackTrace();
+              /*
+               * sequence is new to dataset, so save a reference so it can be added. 
+               */
+              newDsSeqs.add(map.getTo());
+              continue;
             }
 
-            if (retrieved != null)
-            {
-              updateDbrefMappings(dna, seq, xrfs, retrieved, cf);
+            /*
+             * there was a matching sequence in dataset, so now, check to see if we can update the map.getTo() sequence to the existing one.
+             */
 
-              SequenceIdMatcher matcher = new SequenceIdMatcher(
-                      dataset.getSequences());
-              List<SequenceFeature> copiedFeatures = new ArrayList<SequenceFeature>();
-              CrossRef me = new CrossRef();
-              for (int rs = 0; rs < retrieved.length; rs++)
+            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: examine each sequence for 'redundancy'
-                DBRefEntry[] dbr = retrieved[rs].getDBRefs();
-                if (dbr != null && dbr.length > 0)
+                /*
+                 * 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)
                 {
-                  for (int di = 0; di < dbr.length; di++)
+                  /*
+                   * transfer database refs
+                   */
+                  for (DBRefEntry ref : toRefs)
                   {
-                    // find any entry where we should put in the sequence being
-                    // cross-referenced into the map
-                    Mapping map = dbr[di].getMap();
-                    if (map != null)
+                    if (dbref.getSrcAccString().equals(
+                            ref.getSrcAccString()))
                     {
-                      if (map.getTo() != null && map.getMap() != null)
+                      continue; // avoid overwriting the ref on source sequence
+                    }
+                    matched.addDBRef(ref); // add or update mapping
+                  }
+                }
+                doNotAdd.add(map.getTo());
+                map.setTo(matched);
+
+                /*
+                 * 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)
+                  {
+                    /*
+                     * 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)
                       {
-                        SequenceI matched = matcher
-                                .findIdMatch(map.getTo());
-                        if (matched != null)
-                        {
-                          /*
-                           * already got an xref to this sequence; update this
-                           * map to point to the same sequence, and add
-                           * any new dbrefs to it
-                           */
-                          for (DBRefEntry ref : map.getTo().getDBRefs())
-                          {
-                            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);
-                            // method to update all refs of existing To on
-                            // retrieved sequence with dss and merge any props
-                            // on To onto dss.
-                            map.setTo(dss);
-                            /*
-                             * copy sequence features as well, avoiding
-                             * duplication (e.g. same variation from 2 
-                             * transcripts)
-                             */
-                            SequenceFeature[] sfs = ms
-                                    .getSequenceFeatures();
-                            if (sfs != null)
-                            {
-                              for (SequenceFeature feat : sfs)
-                              {
-                                /* 
-                                 * we override SequenceFeature.equals here (but
-                                 * not elsewhere) to ignore Parent attribute
-                                 * TODO not quite working yet!
-                                 */
-                                if (!copiedFeatures
-                                        .contains(me.new MySequenceFeature(
-                                                feat)))
-                                {
-                                  dss.addSequenceFeature(feat);
-                                  copiedFeatures.add(feat);
-                                }
-                              }
-                            }
-                            cf.addMap(retrieved[rs].getDatasetSequence(),
-                                    dss, map.getMap());
-                          }
-                          else
-                          {
-                            cf.addMap(retrieved[rs].getDatasetSequence(),
-                                    map.getTo(), map.getMap());
-                          }
-                        } catch (Exception e)
-                        {
-                          System.err
-                                  .println("Exception when consolidating Mapped sequence set...");
-                          e.printStackTrace(System.err);
-                        }
+                        return super.equals(o, true);
                       }
-                    }
+                    };
+                    matched.addSequenceFeature(newFeature);
                   }
                 }
-                retrieved[rs].updatePDBIds();
-                rseqs.add(retrieved[rs]);
+
               }
+              cf.addMap(retrievedSequence, map.getTo(), map.getMap());
+            } catch (Exception e)
+            {
+              System.err
+                      .println("Exception when consolidating Mapped sequence set...");
+              e.printStackTrace(System.err);
             }
           }
         }
       }
     }
+    if (imported)
+    {
+      retrievedSequence.updatePDBIds();
+      rseqs.add(retrievedSequence);
+      if (dataset.findIndex(retrievedSequence) == -1)
+      {
+        dataset.addSequence(retrievedSequence);
+        matcher.add(retrievedSequence);
+      }
+    }
+    return imported;
+  }
 
-    Alignment ral = null;
-    if (rseqs.size() > 0)
+  /**
+   * Sets the inverse sequence mapping in the corresponding dbref of the mapped
+   * to sequence (if any). This is used after fetching a cross-referenced
+   * sequence, if the fetched sequence has a mapping to the original sequence,
+   * to set the mapping in the original sequence's dbref.
+   * 
+   * @param mapFrom
+   *          the sequence mapped from
+   * @param dbref
+   * @param mappings
+   */
+  void setReverseMapping(SequenceI mapFrom, DBRefEntry dbref,
+          AlignedCodonFrame mappings)
+  {
+    SequenceI mapTo = dbref.getMap().getTo();
+    if (mapTo == null)
     {
-      ral = new Alignment(rseqs.toArray(new SequenceI[rseqs.size()]));
-      if (cf != null && !cf.isEmpty())
+      return;
+    }
+    DBRefEntry[] dbrefs = mapTo.getDBRefs();
+    if (dbrefs == null)
+    {
+      return;
+    }
+    for (DBRefEntry toRef : dbrefs)
+    {
+      if (toRef.hasMap() && mapFrom == toRef.getMap().getTo())
       {
-        ral.addCodonFrame(cf);
+        /*
+         * found the reverse dbref; update its mapping if null
+         */
+        if (toRef.getMap().getMap() == null)
+        {
+          MapList inverse = dbref.getMap().getMap().getInverse();
+          toRef.getMap().setMap(inverse);
+          mappings.addMap(mapTo, mapFrom, inverse);
+        }
       }
     }
-    return ral;
+  }
+
+  /**
+   * 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)
+  {
+    if (xref == null || !xref.hasMap() || xref.getMap().getTo() == null)
+    {
+      return null;
+    }
+    SequenceI mapsTo = xref.getMap().getTo();
+    String name = xref.getAccessionId();
+    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 (firstIdMatch == null
+              && (name.equals(seq.getName()) || seq.getName().startsWith(
+                      name2)))
+      {
+        if (sameSequence(seq, dss))
+        {
+          firstIdMatch = seq;
+        }
+      }
+    }
+    return firstIdMatch;
+  }
+
+  /**
+   * Answers true if seq1 and seq2 contain exactly the same characters (ignoring
+   * case), else false. This method compares the lengths, then each character in
+   * turn, in order to 'fail fast'. For case-sensitive comparison, it would be
+   * possible to use Arrays.equals(seq1.getSequence(), seq2.getSequence()).
+   * 
+   * @param seq1
+   * @param seq2
+   * @return
+   */
+  // TODO move to Sequence / SequenceI
+  static boolean sameSequence(SequenceI seq1, SequenceI seq2)
+  {
+    if (seq1 == seq2)
+    {
+      return true;
+    }
+    if (seq1 == null || seq2 == null)
+    {
+      return false;
+    }
+    char[] c1 = seq1.getSequence();
+    char[] c2 = seq2.getSequence();
+    if (c1.length != c2.length)
+    {
+      return false;
+    }
+    for (int i = 0; i < c1.length; i++)
+    {
+      int diff = c1[i] - c2[i];
+      /*
+       * same char or differ in case only ('a'-'A' == 32)
+       */
+      if (diff != 0 && diff != 32 && diff != -32)
+      {
+        return false;
+      }
+    }
+    return true;
   }
 
   /**
@@ -487,62 +811,129 @@ public class CrossRef
    * retrieved sequence if found, and adds any new mappings to the
    * AlignedCodonFrame
    * 
-   * @param dna
    * @param mapFrom
    * @param xrefs
    * @param retrieved
    * @param acf
    */
-  static void updateDbrefMappings(boolean dna, SequenceI mapFrom,
-          DBRefEntry[] xrefs, SequenceI[] retrieved, AlignedCodonFrame acf)
+  void updateDbrefMappings(SequenceI mapFrom, DBRefEntry[] xrefs,
+          SequenceI[] retrieved, AlignedCodonFrame acf, boolean fromDna)
   {
-    SequenceIdMatcher matcher = new SequenceIdMatcher(retrieved);
+    SequenceIdMatcher idMatcher = new SequenceIdMatcher(retrieved);
     for (DBRefEntry xref : xrefs)
     {
       if (!xref.hasMap())
       {
         String targetSeqName = xref.getSource() + "|"
                 + xref.getAccessionId();
-        SequenceI[] matches = matcher.findAllIdMatches(targetSeqName);
+        SequenceI[] matches = idMatcher.findAllIdMatches(targetSeqName);
         if (matches == null)
         {
           return;
         }
         for (SequenceI seq : matches)
         {
-          MapList mapping = null;
-          if (dna)
-          {
-            mapping = AlignmentUtils.mapCdnaToProtein(seq, mapFrom);
-          }
-          else
-          {
-            mapping = AlignmentUtils.mapCdnaToProtein(mapFrom, seq);
-            if (mapping != null)
-            {
-              mapping = mapping.getInverse();
-            }
-          }
-          if (mapping != null)
-          {
-            xref.setMap(new Mapping(seq, mapping));
-            if (dna)
-            {
-              AlignmentUtils.computeProteinFeatures(mapFrom, seq, mapping);
-            }
-            if (dna)
-            {
-              acf.addMap(mapFrom, seq, mapping);
-            }
-            else
-            {
-              acf.addMap(seq, mapFrom, mapping.getInverse());
-            }
-            continue;
-          }
+          constructMapping(mapFrom, seq, xref, acf, fromDna);
+        }
+      }
+    }
+  }
+
+  /**
+   * Tries to make a mapping between sequences. If successful, adds the mapping
+   * to the dbref and the mappings collection and answers true, otherwise
+   * answers false. The following methods of making are mapping are tried in
+   * turn:
+   * <ul>
+   * <li>if 'mapTo' holds a mapping to 'mapFrom', take the inverse; this is, for
+   * example, the case after fetching EMBL cross-references for a Uniprot
+   * sequence</li>
+   * <li>else check if the dna translates exactly to the protein (give or take
+   * start and stop codons></li>
+   * <li>else try to map based on CDS features on the dna sequence</li>
+   * </ul>
+   * 
+   * @param mapFrom
+   * @param mapTo
+   * @param xref
+   * @param mappings
+   * @return
+   */
+  boolean constructMapping(SequenceI mapFrom, SequenceI mapTo,
+          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. 
+     * Note - we do this on dataset sequences only.
+     */
+    if (dsmapTo.getDBRefs() != null)
+    {
+      for (DBRefEntry dbref : dsmapTo.getDBRefs())
+      {
+        String name = dbref.getSource() + "|" + dbref.getAccessionId();
+        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(dsmapTo, reverse));
+          mappings.addMap(mapFrom, dsmapTo, reverse);
+          return true;
         }
       }
     }
+
+    if (fromDna)
+    {
+      mapping = AlignmentUtils.mapCdnaToProtein(mapTo, mapFrom);
+    }
+    else
+    {
+      mapping = AlignmentUtils.mapCdnaToProtein(mapFrom, mapTo);
+      if (mapping != null)
+      {
+        mapping = mapping.getInverse();
+      }
+    }
+    if (mapping == null)
+    {
+      return false;
+    }
+    xref.setMap(new Mapping(mapTo, mapping));
+
+    /*
+     * and add a reverse DbRef with the inverse mapping
+     */
+    if (mapFrom.getDatasetSequence() != null && false)
+    // && mapFrom.getDatasetSequence().getSourceDBRef() != null)
+    {
+      // 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)
+    {
+      AlignmentUtils.computeProteinFeatures(mapFrom, mapTo, mapping);
+      mappings.addMap(mapFrom, mapTo, mapping);
+    }
+    else
+    {
+      mappings.addMap(mapTo, mapFrom, mapping.getInverse());
+    }
+
+    return true;
   }
 
   /**
@@ -550,15 +941,16 @@ public class CrossRef
    * dataset (that is not equal to sequenceI) Identifies matching DBRefEntry
    * based on source and accession string only - Map and Version are nulled.
    * 
+   * @param fromDna
+   *          - true if context was searching from Dna sequences, false if
+   *          context was searching from Protein sequences
    * @param sequenceI
    * @param lrfs
-   * @param dataset
-   * @param rseqs
+   * @param foundSeqs
    * @return true if matches were found.
    */
-  private static boolean searchDatasetXrefs(SequenceI sequenceI,
-          boolean dna, DBRefEntry[] lrfs, AlignmentI dataset,
-          List<SequenceI> rseqs, AlignedCodonFrame cf)
+  private boolean searchDatasetXrefs(boolean fromDna, SequenceI sequenceI,
+          DBRefEntry[] lrfs, List<SequenceI> foundSeqs, AlignedCodonFrame cf)
   {
     boolean found = false;
     if (lrfs == null)
@@ -571,50 +963,44 @@ public class CrossRef
       // add in wildcards
       xref.setVersion(null);
       xref.setMap(null);
-      found = searchDataset(sequenceI, xref, dataset, rseqs, cf, false, dna);
+      found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf, false);
     }
     return found;
   }
 
   /**
-   * search a given sequence dataset for references matching cross-references to
-   * the given sequence
-   * 
-   * @param sequenceI
-   * @param xrf
-   * @param dataset
-   * @param rseqs
-   *          set of unique sequences
-   * @param cf
-   * @return true if one or more unique sequences were found and added
-   */
-  public static boolean searchDataset(SequenceI sequenceI, DBRefEntry xrf,
-          AlignmentI dataset, List<SequenceI> rseqs, AlignedCodonFrame cf)
-  {
-    return searchDataset(sequenceI, xrf, dataset, rseqs, cf, true, false);
-  }
-
-  /**
-   * TODO: generalise to different protein classifications Search dataset for
-   * DBRefEntrys matching the given one (xrf) and add the associated sequence to
-   * rseq.
+   * Searches dataset for DBRefEntrys matching the given one (xrf) and adds the
+   * associated sequence to rseqs
    * 
-   * @param sequenceI
+   * @param fromDna
+   *          true if context was searching for refs *from* dna sequence, false
+   *          if context was searching for refs *from* protein sequence
+   * @param fromSeq
+   *          a sequence to ignore (start point of search)
    * @param xrf
-   * @param dataset
-   * @param rseqs
+   *          a cross-reference to try to match
+   * @param foundSeqs
+   *          result list to add to
+   * @param mappings
+   *          a set of sequence mappings to add to
    * @param direct
-   *          - search all references or only subset
-   * @param dna
-   *          search dna or protein xrefs (if direct=false)
+   *          - indicates the type of relationship between returned sequences,
+   *          xrf, and sequenceI that is required.
+   *          <ul>
+   *          <li>direct implies xrf is a primary reference for sequenceI AND
+   *          the sequences to be located (eg a uniprot ID for a protein
+   *          sequence, and a uniprot ref on a transcript sequence).</li>
+   *          <li>indirect means xrf is a cross reference with respect to
+   *          sequenceI or all the returned sequences (eg a genomic reference
+   *          associated with a locus and one or more transcripts)</li>
+   *          </ul>
    * @return true if relationship found and sequence added.
    */
-  public static boolean searchDataset(SequenceI sequenceI, DBRefEntry xrf,
-          AlignmentI dataset, List<SequenceI> rseqs, AlignedCodonFrame cf,
-          boolean direct, boolean dna)
+  boolean searchDataset(boolean fromDna, SequenceI fromSeq, DBRefEntry xrf,
+          List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
+          boolean direct)
   {
     boolean found = false;
-    SequenceI[] typer = new SequenceI[1];
     if (dataset == null)
     {
       return false;
@@ -634,107 +1020,85 @@ public class CrossRef
           if (nxt.getDatasetSequence() != null)
           {
             System.err
-                    .println("Implementation warning: getProducts passed a dataset alignment without dataset sequences in it!");
+                    .println("Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
+                            + nxt.getDisplayId(true)
+                            + " has ds reference "
+                            + nxt.getDatasetSequence().getDisplayId(true)
+                            + ")");
+          }
+          if (nxt == fromSeq || nxt == fromSeq.getDatasetSequence())
+          {
+            continue;
           }
-          if (nxt != sequenceI && nxt != sequenceI.getDatasetSequence())
+          /*
+           * only look at same molecule type if 'direct', or
+           * complementary type if !direct
+           */
           {
-            // check if this is the correct sequence type
+            boolean isDna = !nxt.isProtein();
+            if (direct ? (isDna != fromDna) : (isDna == fromDna))
             {
-              typer[0] = nxt;
-              boolean isDna = jalview.util.Comparison.isNucleotide(typer);
-              if ((direct && isDna == dna) || (!direct && isDna != dna))
-              {
-                // skip this sequence because it is same molecule type
-                continue;
-              }
+              // skip this sequence because it is wrong molecule type
+              continue;
             }
+          }
 
-            // look for direct or indirect references in common
-            DBRefEntry[] poss = nxt.getDBRefs(), cands = null;
-            if (direct)
-            {
-              cands = jalview.util.DBRefUtils.searchRefs(poss, xrf);
-            }
-            else
+          // look for direct or indirect references in common
+          DBRefEntry[] poss = nxt.getDBRefs();
+          List<DBRefEntry> cands = null;
+
+          // todo: indirect specifies we select either direct references to nxt
+          // that match xrf which is indirect to sequenceI, or indirect
+          // references to nxt that match xrf which is direct to sequenceI
+          cands = DBRefUtils.searchRefs(poss, xrf);
+          // else
+          // {
+          // poss = DBRefUtils.selectDbRefs(nxt.isProtein()!fromDna, poss);
+          // cands = DBRefUtils.searchRefs(poss, xrf);
+          // }
+          if (!cands.isEmpty())
+          {
+            if (foundSeqs.contains(nxt))
             {
-              poss = CrossRef.findXDbRefs(dna, poss); //
-              cands = jalview.util.DBRefUtils.searchRefs(poss, xrf);
+              continue;
             }
-            if (cands != null)
+            found = true;
+            foundSeqs.add(nxt);
+            if (mappings != null && !direct)
             {
-              if (!rseqs.contains(nxt))
+              /*
+               * if the matched sequence has mapped dbrefs to
+               * protein product / cdna, add equivalent mappings to
+               * our source sequence
+               */
+              for (DBRefEntry candidate : cands)
               {
-                rseqs.add(nxt);
-                boolean foundmap = cf != null;
-                // don't search if we aren't given a codon map object
-                for (int r = 0; foundmap && r < cands.length; r++)
+                Mapping mapping = candidate.getMap();
+                if (mapping != null)
                 {
-                  if (cands[r].hasMap())
+                  MapList map = mapping.getMap();
+                  if (mapping.getTo() != null
+                          && map.getFromRatio() != map.getToRatio())
                   {
-                    if (cands[r].getMap().getTo() != null
-                            && cands[r].getMap().getMap().getFromRatio() != cands[r]
-                                    .getMap().getMap().getToRatio())
+                    /*
+                     * add a mapping, as from dna to peptide sequence
+                     */
+                    if (map.getFromRatio() == 3)
                     {
-                      foundmap = true;
-                      // get sense of map correct for adding to product
-                      // alignment.
-                      if (dna)
-                      {
-                        // map is from dna seq to a protein product
-                        cf.addMap(sequenceI, nxt, cands[r].getMap()
-                                .getMap());
-                      }
-                      else
-                      {
-                        // map should be from protein seq to its coding dna
-                        cf.addMap(nxt, sequenceI, cands[r].getMap()
-                                .getMap().getInverse());
-                      }
+                      mappings.addMap(nxt, fromSeq, map);
+                    }
+                    else
+                    {
+                      mappings.addMap(nxt, fromSeq, map.getInverse());
                     }
                   }
                 }
-                // TODO: add mapping between sequences if necessary
-                found = true;
               }
             }
-
           }
         }
       }
     }
     return found;
   }
-
-  /**
-   * precalculate different products that can be found for seqs in dataset and
-   * return them.
-   * 
-   * @param dna
-   * @param seqs
-   * @param dataset
-   * @param fake
-   *          - don't actually build lists - just get types
-   * @return public static Object[] buildXProductsList(boolean dna, SequenceI[]
-   *         seqs, AlignmentI dataset, boolean fake) { String types[] =
-   *         jalview.analysis.CrossRef.findSequenceXrefTypes( dna, seqs,
-   *         dataset); if (types != null) { System.out.println("Xref Types for:
-   *         "+(dna ? "dna" : "prot")); for (int t = 0; t < types.length; t++) {
-   *         System.out.println("Type: " + types[t]); SequenceI[] prod =
-   *         jalview.analysis.CrossRef.findXrefSequences(seqs, dna, types[t]);
-   *         System.out.println("Found " + ((prod == null) ? "no" : "" +
-   *         prod.length) + " products"); if (prod!=null) { for (int p=0;
-   *         p<prod.length; p++) { System.out.println("Prod "+p+":
-   *         "+prod[p].getDisplayId(true)); } } } } else {
-   *         System.out.println("Trying getProducts for
-   *         "+al.getSequenceAt(0).getDisplayId(true));
-   *         System.out.println("Search DS Xref for: "+(dna ? "dna" : "prot"));
-   *         // have a bash at finding the products amongst all the retrieved
-   *         sequences. SequenceI[] prod =
-   *         jalview.analysis.CrossRef.findXrefSequences(al
-   *         .getSequencesArray(), dna, null, ds); System.out.println("Found " +
-   *         ((prod == null) ? "no" : "" + prod.length) + " products"); if
-   *         (prod!=null) { // select non-equivalent sequences from dataset list
-   *         for (int p=0; p<prod.length; p++) { System.out.println("Prod "+p+":
-   *         "+prod[p].getDisplayId(true)); } } } }
-   */
 }
index be138f3..799a8ed 100644 (file)
@@ -69,7 +69,7 @@ public class Dna
 
   final private int dnaWidth;
 
-  final private Alignment dataset;
+  final private AlignmentI dataset;
 
   /*
    * Working variables for the translation.
@@ -852,13 +852,18 @@ public class Dna
     char[] originalSequence = sequence.toCharArray();
     int length = originalSequence.length;
     char[] reversedSequence = new char[length];
-
+    int bases = 0;
     for (int i = 0; i < length; i++)
     {
-      reversedSequence[length - i - 1] = complement ? getComplement(originalSequence[i])
+      char c = complement ? getComplement(originalSequence[i])
               : originalSequence[i];
+      reversedSequence[length - i - 1] = c;
+      if (!Comparison.isGap(c))
+      {
+        bases++;
+      }
     }
-    SequenceI reversed = new Sequence(newName, reversedSequence, 1, length);
+    SequenceI reversed = new Sequence(newName, reversedSequence, 1, bases);
     return reversed;
   }
 
@@ -873,7 +878,12 @@ public class Dna
   public static char getComplement(char c)
   {
     char result = c;
-    switch (c) {
+    switch (c)
+    {
+    case '-':
+    case '.':
+    case ' ':
+      break;
     case 'a':
       result = 't';
       break;
index 51a818f..2ddd015 100644 (file)
@@ -127,6 +127,11 @@ public class Grouping
         }
       }
     }
+
+    /*
+     * get selected columns (in the order they were selected);
+     * note this could include right-to-left ranges
+     */
     int[] spos = new int[cs.getSelected().size()];
     int width = -1;
     int i = 0;
@@ -134,7 +139,7 @@ public class Grouping
     {
       spos[i++] = pos.intValue();
     }
-    ;
+
     for (i = 0; i < sequences.length; i++)
     {
       int slen = sequences[i].getLength();
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()))
     {
       ;
     }
diff --git a/src/jalview/analysis/Profile.java b/src/jalview/analysis/Profile.java
new file mode 100644 (file)
index 0000000..d94d031
--- /dev/null
@@ -0,0 +1,157 @@
+package jalview.analysis;
+
+
+/**
+ * A data bean to hold the result of computing a profile for a column of an
+ * alignment
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class Profile
+{
+  /*
+   * counts of keys (chars)
+   */
+  private ResidueCount counts;
+
+  /*
+   * the number of sequences 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;
+  }
+
+  /**
+   * Set the full profile of counts
+   * 
+   * @param residueCounts
+   */
+  public void setCounts(ResidueCount residueCounts)
+  {
+    this.counts = 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 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;
+  }
+
+  /**
+   * Returns the full symbol counts for this profile
+   * 
+   * @return
+   */
+  public ResidueCount getCounts()
+  {
+    return counts;
+  }
+
+  /**
+   * Returns the number of sequences in the profile
+   * 
+   * @return
+   */
+  public int getHeight()
+  {
+    return height;
+  }
+
+  /**
+   * 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 int getGapped()
+  {
+    return gapped;
+  }
+
+  /**
+   * Returns the highest count for any symbol(s) in the profile
+   * 
+   * @return
+   */
+  public int getMaxCount()
+  {
+    return maxCount;
+  }
+
+  /**
+   * 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 String getModalResidue()
+  {
+    return modalResidue;
+  }
+
+  /**
+   * Answers the number of non-gapped sequences in the profile
+   * 
+   * @return
+   */
+  public int getNonGapped()
+  {
+    return height - gapped;
+  }
+}
diff --git a/src/jalview/analysis/ResidueCount.java b/src/jalview/analysis/ResidueCount.java
new file mode 100644 (file)
index 0000000..75decf2
--- /dev/null
@@ -0,0 +1,621 @@
+package jalview.analysis;
+
+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 every 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();
+  }
+}
index e752126..89c5c30 100644 (file)
@@ -31,82 +31,108 @@ import jalview.datamodel.SequenceFeature;
 import jalview.util.MessageManager;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Stack;
 import java.util.Vector;
 
 public class Rna
 {
 
-  static Hashtable<Integer, Integer> pairHash = new Hashtable();
-
-  private static final Character[] openingPars = { '(', '[', '{', '<', 'A',
-      'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
-      'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
-
-  private static final Character[] closingPars = { ')', ']', '}', '>', 'a',
-      'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-      'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
-
-  private static HashSet<Character> openingParsSet = new HashSet<Character>(
-          Arrays.asList(openingPars));
-
-  private static HashSet<Character> closingParsSet = new HashSet<Character>(
-          Arrays.asList(closingPars));
+  /**
+   * Answers true if the character is a valid open pair rna secondary structure
+   * symbol. Currently accepts A-Z, ([{<
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isOpeningParenthesis(char c)
+  {
+    return ('A' <= c && c <= 'Z' || c == '(' || c == '[' || c == '{' || c == '<');
+  }
 
-  private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>()
-  // Initializing final data structure
+  /**
+   * Answers true if the string is a valid open pair rna secondary structure
+   * symbol. Currently accepts A-Z, ([{<
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isOpeningParenthesis(String s)
   {
-    private static final long serialVersionUID = 1L;
-    {
-      for (int i = 0; i < openingPars.length; i++)
-      {
-        // System.out.println(closingPars[i] + "->" + openingPars[i]);
-        put(closingPars[i], openingPars[i]);
-      }
-    }
-  };
+    return s != null && s.length() == 1
+            && isOpeningParenthesis(s.charAt(0));
+  }
 
-  private static boolean isOpeningParenthesis(char c)
+  /**
+   * Answers true if the character is a valid close pair rna secondary structure
+   * symbol. Currently accepts a-z, )]}>
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isClosingParenthesis(char c)
   {
-    return openingParsSet.contains(c);
+    return ('a' <= c && c <= 'z' || c == ')' || c == ']' || c == '}' || c == '>');
   }
 
-  private static boolean isClosingParenthesis(char c)
+  /**
+   * Answers true if the string is a valid close pair rna secondary structure
+   * symbol. Currently accepts a-z, )]}>
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isClosingParenthesis(String s)
   {
-    return closingParsSet.contains(c);
+    return s != null && s.length() == 1
+            && isClosingParenthesis(s.charAt(0));
   }
 
-  private static char matchingOpeningParenthesis(char closingParenthesis)
-          throws WUSSParseException
+  /**
+   * Returns the matching open pair symbol for the given closing symbol.
+   * Currently returns A-Z for a-z, or ([{< for )]}>, or the input symbol if it
+   * is not a valid closing symbol.
+   * 
+   * @param c
+   * @return
+   */
+  public static char getMatchingOpeningParenthesis(char c)
   {
-    if (!isClosingParenthesis(closingParenthesis))
+    if ('a' <= c && c <= 'z')
     {
-      throw new WUSSParseException(
-              MessageManager.formatMessage(
-                      "exception.querying_matching_opening_parenthesis_for_non_closing_parenthesis",
-                      new String[] { new StringBuffer(closingParenthesis)
-                              .toString() }), -1);
+      return (char) (c + 'A' - 'a');
+    }
+    switch (c)
+    {
+    case ')':
+      return '(';
+    case ']':
+      return '[';
+    case '}':
+      return '{';
+    case '>':
+      return '<';
+    default:
+      return c;
     }
-
-    return closingToOpening.get(closingParenthesis);
   }
 
   /**
    * Based off of RALEE code ralee-get-base-pairs. Keeps track of open bracket
    * positions in "stack" vector. When a close bracket is reached, pair this
-   * with the last element in the "stack" vector and store in "pairs" vector.
-   * Remove last element in the "stack" vector. Continue in this manner until
-   * the whole string is processed.
+   * with the last matching element in the "stack" vector and store in "pairs"
+   * vector. Remove last element in the "stack" vector. Continue in this manner
+   * until the whole string is processed. Parse errors are thrown as exceptions
+   * wrapping the error location - position of the first unmatched closing
+   * bracket, or string length if there is an unmatched opening bracket.
    * 
    * @param line
    *          Secondary structure line of an RNA Stockholm file
-   * @return Array of SequenceFeature; type = RNA helix, begin is open base
-   *         pair, end is close base pair
+   * @return
+   * @throw {@link WUSSParseException}
    */
-  public static Vector<SimpleBP> GetSimpleBPs(CharSequence line)
+  public static Vector<SimpleBP> getSimpleBPs(CharSequence line)
           throws WUSSParseException
   {
     Hashtable<Character, Stack<Integer>> stacks = new Hashtable<Character, Stack<Integer>>();
@@ -128,13 +154,13 @@ public class Rna
       else if (isClosingParenthesis(base))
       {
 
-        char opening = matchingOpeningParenthesis(base);
+        char opening = getMatchingOpeningParenthesis(base);
 
         if (!stacks.containsKey(opening))
         {
           throw new WUSSParseException(MessageManager.formatMessage(
                   "exception.mismatched_unseen_closing_char",
-                  new String[] { new StringBuffer(base).toString() }), i);
+                  new String[] { String.valueOf(base) }), i);
         }
 
         Stack<Integer> stack = stacks.get(opening);
@@ -143,7 +169,7 @@ public class Rna
           // error whilst parsing i'th position. pass back
           throw new WUSSParseException(MessageManager.formatMessage(
                   "exception.mismatched_closing_char",
-                  new String[] { new StringBuffer(base).toString() }), i);
+                  new String[] { String.valueOf(base) }), i);
         }
         int temp = stack.pop();
 
@@ -156,33 +182,36 @@ public class Rna
       Stack<Integer> stack = stacks.get(opening);
       if (!stack.empty())
       {
+        /*
+         * we have an unmatched opening bracket; report error as at
+         * i (length of input string)
+         */
         throw new WUSSParseException(MessageManager.formatMessage(
                 "exception.mismatched_opening_char",
-                new String[] { new StringBuffer(opening).toString(),
-                    Integer.valueOf(stack.pop()).toString() }), i);
+                new String[] { String.valueOf(opening),
+                    String.valueOf(stack.pop()) }), i);
       }
     }
     return pairs;
   }
 
-  public static SequenceFeature[] GetBasePairs(CharSequence line)
+  public static SequenceFeature[] getBasePairs(List<SimpleBP> bps)
           throws WUSSParseException
   {
-    Vector<SimpleBP> bps = GetSimpleBPs(line);
     SequenceFeature[] outPairs = new SequenceFeature[bps.size()];
     for (int p = 0; p < bps.size(); p++)
     {
-      SimpleBP bp = bps.elementAt(p);
+      SimpleBP bp = bps.get(p);
       outPairs[p] = new SequenceFeature("RNA helix", "", "", bp.getBP5(),
               bp.getBP3(), "");
     }
     return outPairs;
   }
 
-  public static ArrayList<SimpleBP> GetModeleBP(CharSequence line)
+  public static List<SimpleBP> getModeleBP(CharSequence line)
           throws WUSSParseException
   {
-    Vector<SimpleBP> bps = GetSimpleBPs(line);
+    Vector<SimpleBP> bps = getSimpleBPs(line);
     return new ArrayList<SimpleBP>(bps);
   }
 
@@ -220,8 +249,8 @@ public class Rna
     int close; // Position of a close bracket under review
     int j; // Counter
 
-    Hashtable helices = new Hashtable(); // Keep track of helix number for each
-                                         // position
+    Hashtable<Integer, Integer> helices = new Hashtable<Integer, Integer>();
+    // Keep track of helix number for each position
 
     // Go through each base pair and assign positions a helix
     for (i = 0; i < pairs.length; i++)
@@ -255,7 +284,7 @@ public class Rna
         if ((popen < lastopen) && (popen > open))
         {
           if (helices.containsValue(popen)
-                  && (((Integer) helices.get(popen)) == helix))
+                  && ((helices.get(popen)) == helix))
           {
             continue;
           }
@@ -281,4 +310,194 @@ public class Rna
 
     }
   }
+
+  /**
+   * Answers true if the character is a recognised symbol for RNA secondary
+   * structure. Currently accepts a-z, A-Z, ()[]{}<>.
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isRnaSecondaryStructureSymbol(char c)
+  {
+    return isOpeningParenthesis(c) || isClosingParenthesis(c);
+  }
+
+  /**
+   * Answers true if the string is a recognised symbol for RNA secondary
+   * structure. Currently accepts a-z, A-Z, ()[]{}<>.
+   * 
+   * @param s
+   * @return
+   */
+  public static boolean isRnaSecondaryStructureSymbol(String s)
+  {
+    return isOpeningParenthesis(s) || isClosingParenthesis(s);
+  }
+
+  /**
+   * Translates a string to RNA secondary structure representation. Returns the
+   * string with any non-SS characters changed to spaces. Accepted characters
+   * are a-z, A-Z, and (){}[]<> brackets.
+   * 
+   * @param ssString
+   * @return
+   */
+  public static String getRNASecStrucState(String ssString)
+  {
+    if (ssString == null)
+    {
+      return null;
+    }
+    StringBuilder result = new StringBuilder(ssString.length());
+    for (int i = 0; i < ssString.length(); i++)
+    {
+      char c = ssString.charAt(i);
+      result.append(isRnaSecondaryStructureSymbol(c) ? c : " ");
+    }
+    return result.toString();
+  }
+
+  /**
+   * 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
+   * @return
+   */
+  public static boolean isCanonicalOrWobblePair(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 'C':
+      switch (second)
+      {
+      case 'G':
+        return true;
+      }
+      break;
+    case 'T':
+    case 'U':
+      switch (second)
+      {
+      case 'A':
+      case 'G':
+        return true;
+      }
+      break;
+    case 'G':
+      switch (second)
+      {
+      case 'C':
+      case 'T':
+      case 'U':
+        return true;
+      }
+      break;
+    }
+    return false;
+  }
+
+  /**
+   * 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.
+   * 
+   * @param c
+   * @return
+   */
+  public static char getMatchingClosingParenthesis(char c)
+  {
+    if ('A' <= c && c <= 'Z')
+    {
+      return (char) (c + 'a' - 'A');
+    }
+    switch (c)
+    {
+    case '(':
+      return ')';
+    case '[':
+      return ']';
+    case '{':
+      return '}';
+    case '<':
+      return '>';
+    default:
+      return c;
+    }
+  }
 }
index 40bedad..21ad1cc 100755 (executable)
@@ -59,13 +59,19 @@ public class SeqsetUtils
         sfeat.addElement(sfarray[i]);
       }
     }
-    sqinfo.put("SeqFeatures", sfeat);
-    sqinfo.put("PdbId",
-            (seq.getAllPDBEntries() != null) ? seq.getAllPDBEntries()
-                    : new Vector<PDBEntry>());
-    sqinfo.put("datasetSequence",
-            (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
-                    : new Sequence("THISISAPLACEHOLDER", ""));
+    if (seq.getDatasetSequence() == null)
+    {
+      sqinfo.put("SeqFeatures", sfeat);
+      sqinfo.put("PdbId",
+              (seq.getAllPDBEntries() != null) ? seq.getAllPDBEntries()
+                      : new Vector<PDBEntry>());
+    }
+    else
+    {
+      sqinfo.put("datasetSequence",
+              (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
+                      : new Sequence("THISISAPLACEHOLDER", ""));
+    }
     return sqinfo;
   }
 
@@ -129,6 +135,11 @@ public class SeqsetUtils
             && !(seqds.getName().equals("THISISAPLACEHOLDER") && seqds
                     .getLength() == 0))
     {
+      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.");
+      }
       sq.setDatasetSequence(seqds);
     }
 
index 70defb0..c12de4e 100755 (executable)
@@ -290,7 +290,7 @@ public class SequenceIdMatcher
     {
       if (s != null)
       {
-        id = new String(s);
+        id = s.toLowerCase();
       }
       else
       {
@@ -314,13 +314,13 @@ public class SequenceIdMatcher
       }
       if (s instanceof SeqIdName)
       {
-        return this.equals(((SeqIdName) s).id);
+        return this.stringequals(((SeqIdName) s).id);
       }
       else
       {
         if (s instanceof String)
         {
-          return this.equals((String) s);
+          return this.stringequals(((String) s).toLowerCase());
         }
       }
 
@@ -344,7 +344,7 @@ public class SequenceIdMatcher
      * @param s
      * @return boolean
      */
-    public boolean equals(String s)
+    private boolean stringequals(String s)
     {
       if (id.length() > s.length())
       {
@@ -357,5 +357,15 @@ public class SequenceIdMatcher
                 .indexOf(s.charAt(id.length())) > -1)) : false;
       }
     }
+
+    /**
+     * toString method returns the wrapped sequence id. For debugging purposes
+     * only, behaviour not guaranteed not to change.
+     */
+    @Override
+    public String toString()
+    {
+      return id;
+    }
   }
 }
index 88387dd..7b0858d 100644 (file)
@@ -24,6 +24,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 import jalview.util.Format;
 
 import java.util.ArrayList;
@@ -103,23 +104,24 @@ public class StructureFrequency
 
     SequenceFeature[] rna = rnaStruc._rnasecstr;
     char c, s, cEnd;
-    int count = 0, nonGap = 0, i, bpEnd = -1, j, jSize = sequences.length;
+    int bpEnd = -1;
+    int jSize = sequences.length;
     int[] values;
     int[][] pairs;
     float percentage;
-    boolean wooble = true;
-    for (i = start; i < end; i++) // foreach column
+
+    for (int i = start; i < end; i++) // foreach column
     {
-      residueHash = new Hashtable();
+      int canonicalOrWobblePairCount = 0, canonical = 0;
+      int otherPairCount = 0;
+      int nongap = 0;
       maxResidue = "-";
       values = new int[255];
       pairs = new int[255][255];
       bpEnd = -1;
-      // System.out.println("s="+struc[i]);
       if (i < struc.length)
       {
         s = struc[i];
-
       }
       else
       {
@@ -130,7 +132,7 @@ public class StructureFrequency
         s = '-';
       }
 
-      if (s != '(' && s != '[')
+      if (!Rna.isOpeningParenthesis(s))
       {
         if (s == '-')
         {
@@ -139,12 +141,11 @@ public class StructureFrequency
       }
       else
       {
-
         bpEnd = findPair(rna, i);
 
         if (bpEnd > -1)
         {
-          for (j = 0; j < jSize; j++) // foreach row
+          for (int j = 0; j < jSize; j++) // foreach row
           {
             if (sequences[j] == null)
             {
@@ -152,45 +153,45 @@ public class StructureFrequency
                       .println("WARNING: Consensus skipping null sequence - possible race condition.");
               continue;
             }
-            c = sequences[j].getCharAt(i);
-            // System.out.println("c="+c);
 
-            // standard representation for gaps in sequence and structure
-            if (c == '.' || c == ' ')
-            {
-              c = '-';
-            }
+            c = sequences[j].getCharAt(i);
+            cEnd = sequences[j].getCharAt(bpEnd);
 
-            if (c == '-')
+            if (Comparison.isGap(c) || Comparison.isGap(cEnd))
             {
               values['-']++;
               continue;
             }
-            cEnd = sequences[j].getCharAt(bpEnd);
-
-            // System.out.println("pairs ="+c+","+cEnd);
-            if (checkBpType(c, cEnd) == true)
+            nongap++;
+            /*
+             * ensure upper-case for counting purposes
+             */
+            if ('a' <= c && 'z' >= c)
             {
-              values['(']++; // H means it's a helix (structured)
-              maxResidue = "(";
-              wooble = true;
-              // System.out.println("It's a pair wc");
-
+              c += 'A' - 'a';
             }
-            if (checkBpType(c, cEnd) == false)
+            if ('a' <= cEnd && 'z' >= cEnd)
             {
-              wooble = false;
-              values['[']++; // H means it's a helix (structured)
-              maxResidue = "[";
-
+              cEnd += 'A' - 'a';
+            }
+            if (Rna.isCanonicalOrWobblePair(c, cEnd))
+            {
+              canonicalOrWobblePairCount++;
+              if (Rna.isCanonicalPair(c, cEnd))
+              {
+                canonical++;
+              }
+            }
+            else
+            {
+              otherPairCount++;
             }
             pairs[c][cEnd]++;
-
           }
         }
-        // nonGap++;
       }
-      // UPDATE this for new values
+
+      residueHash = new Hashtable();
       if (profile)
       {
         // TODO 1-dim array with jsize in [0], nongapped in [1]; or Pojo
@@ -199,13 +200,30 @@ public class StructureFrequency
 
         residueHash.put(PAIRPROFILE, pairs);
       }
-      if (wooble == true)
-      {
-        count = values['('];
-      }
-      if (wooble == false)
+      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)
+       */
+      int count = canonicalOrWobblePairCount;
+
+      /*
+       * display '(' if most pairs are canonical, or as
+       * '[' if there are more wobble pairs. 
+       */
+      if (canonicalOrWobblePairCount > 0 || otherPairCount > 0)
       {
-        count = values['['];
+        if (canonicalOrWobblePairCount >= otherPairCount)
+        {
+          maxResidue = (canonicalOrWobblePairCount - canonical) < canonical ? "("
+                  : "[";
+        }
+        else
+        {
+          maxResidue = "{";
+        }
       }
       residueHash.put(MAXCOUNT, new Integer(count));
       residueHash.put(MAXRESIDUE, maxResidue);
@@ -213,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;
@@ -223,19 +242,14 @@ public class StructureFrequency
       {
         values[')'] = values['('];
         values[']'] = values['['];
+        values['}'] = values['{'];
         values['('] = 0;
         values['['] = 0;
+        values['{'] = 0;
+        maxResidue = maxResidue.equals("(") ? ")"
+                : maxResidue.equals("[") ? "]" : "}";
+
         residueHash = new Hashtable();
-        if (wooble == true)
-        {
-          // System.out.println(maxResidue+","+wooble);
-          maxResidue = ")";
-        }
-        if (wooble == false)
-        {
-          // System.out.println(maxResidue+","+wooble);
-          maxResidue = "]";
-        }
         if (profile)
         {
           residueHash.put(PROFILE, new int[][] { values,
@@ -250,81 +264,12 @@ public class StructureFrequency
         percentage = ((float) count * 100) / jSize;
         residueHash.put(PID_GAPS, new Float(percentage));
 
-        result[bpEnd] = residueHash;
-
-      }
-    }
-  }
-
-  /**
-   * Method to check if a base-pair is a canonical or a wobble bp
-   * 
-   * @param up
-   *          5' base
-   * @param down
-   *          3' base
-   * @return True if it is a canonical/wobble bp
-   */
-  public static boolean checkBpType(char up, char down)
-  {
-    if (up > 'Z')
-    {
-      up -= 32;
-    }
-    if (down > 'Z')
-    {
-      down -= 32;
-    }
+        percentage = ((float) count * 100) / nongap;
+        residueHash.put(PID_NOGAPS, new Float(percentage));
 
-    switch (up)
-    {
-    case 'A':
-      switch (down)
-      {
-      case 'T':
-        return true;
-      case 'U':
-        return true;
-      }
-      break;
-    case 'C':
-      switch (down)
-      {
-      case 'G':
-        return true;
-      }
-      break;
-    case 'T':
-      switch (down)
-      {
-      case 'A':
-        return true;
-      case 'G':
-        return true;
-      }
-      break;
-    case 'G':
-      switch (down)
-      {
-      case 'C':
-        return true;
-      case 'T':
-        return true;
-      case 'U':
-        return true;
-      }
-      break;
-    case 'U':
-      switch (down)
-      {
-      case 'A':
-        return true;
-      case 'G':
-        return true;
+        result[bpEnd] = residueHash;
       }
-      break;
     }
-    return false;
   }
 
   /**
@@ -534,7 +479,7 @@ public class StructureFrequency
       for (String j : test)
       {
         System.out.println(i + "-" + j + ": "
-                + StructureFrequency.checkBpType(i.charAt(0), j.charAt(0)));
+                + Rna.isCanonicalOrWobblePair(i.charAt(0), j.charAt(0)));
       }
     }
   }
index 1ca3342..7c81912 100644 (file)
@@ -23,9 +23,8 @@ package jalview.analysis.scoremodels;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.ViewBasedAnalysisI;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.SeqCigar;
 import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceI;
-import jalview.util.Comparison;
 
 import java.util.ArrayList;
 import java.util.Hashtable;
@@ -48,13 +47,10 @@ public class FeatureScoreModel implements ScoreModelI, ViewBasedAnalysisI
   {
     int nofeats = 0;
     List<String> dft = fr.getDisplayedFeatureTypes();
-
     nofeats = dft.size();
-
-    SequenceI[] sequenceString = seqData.getVisibleAlignment(
-            Comparison.GapChars.charAt(0)).getSequencesArray();
-    int noseqs = sequenceString.length;
-    int cpwidth = seqData.getWidth();
+    SeqCigar[] seqs = seqData.getSequences();
+    int noseqs = seqs.length;
+    int cpwidth = 0;// = seqData.getWidth();
     float[][] distance = new float[noseqs][noseqs];
     if (nofeats == 0)
     {
@@ -67,54 +63,64 @@ public class FeatureScoreModel implements ScoreModelI, ViewBasedAnalysisI
       }
       return distance;
     }
-    float max = 0;
-    for (int cpos = 0; cpos < cpwidth; cpos++)
+    // need to get real position for view position
+    int[] viscont = seqData.getVisibleContigs();
+    for (int vc = 0; vc < viscont.length; vc += 2)
     {
-      // get visible features at cpos under view's display settings and compare
-      // them
-      List<Hashtable<String, SequenceFeature>> sfap = new ArrayList<Hashtable<String, SequenceFeature>>();
-      for (int i = 0; i < noseqs; i++)
-      {
-        Hashtable<String, SequenceFeature> types = new Hashtable<String, SequenceFeature>();
-        List<SequenceFeature> sfs = fr.findFeaturesAtRes(sequenceString[i],
-                sequenceString[i].findPosition(cpos));
-        for (SequenceFeature sf : sfs)
-        {
-          types.put(sf.getType(), sf);
-        }
-        sfap.add(types);
-      }
-      for (int i = 0; i < (noseqs - 1); i++)
+
+      for (int cpos = viscont[vc]; cpos <= viscont[vc + 1]; cpos++)
       {
-        if (cpos == 0)
-        {
-          distance[i][i] = 0f;
-        }
-        for (int j = i + 1; j < noseqs; j++)
+        cpwidth++;
+        // get visible features at cpos under view's display settings and
+        // compare them
+        List<Hashtable<String, SequenceFeature>> sfap = new ArrayList<Hashtable<String, SequenceFeature>>();
+        for (int i = 0; i < noseqs; i++)
         {
-          int sfcommon = 0;
-          // compare the two lists of features...
-          Hashtable<String, SequenceFeature> fi = sfap.get(i), fk, fj = sfap
-                  .get(j);
-          if (fi.size() > fj.size())
+          Hashtable<String, SequenceFeature> types = new Hashtable<String, SequenceFeature>();
+          int spos = seqs[i].findPosition(cpos);
+          if (spos != -1)
           {
-            fk = fj;
+            List<SequenceFeature> sfs = fr.findFeaturesAtRes(
+                    seqs[i].getRefSeq(), spos);
+            for (SequenceFeature sf : sfs)
+            {
+              types.put(sf.getType(), sf);
+            }
           }
-          else
+          sfap.add(types);
+        }
+        for (int i = 0; i < (noseqs - 1); i++)
+        {
+          if (cpos == 0)
           {
-            fk = fi;
-            fi = fj;
+            distance[i][i] = 0f;
           }
-          for (String k : fi.keySet())
+          for (int j = i + 1; j < noseqs; j++)
           {
-            SequenceFeature sfj = fk.get(k);
-            if (sfj != null)
+            int sfcommon = 0;
+            // compare the two lists of features...
+            Hashtable<String, SequenceFeature> fi = sfap.get(i), fk, fj = sfap
+                    .get(j);
+            if (fi.size() > fj.size())
+            {
+              fk = fj;
+            }
+            else
+            {
+              fk = fi;
+              fi = fj;
+            }
+            for (String k : fi.keySet())
             {
-              sfcommon++;
+              SequenceFeature sfj = fk.get(k);
+              if (sfj != null)
+              {
+                sfcommon++;
+              }
             }
+            distance[i][j] += (fi.size() + fk.size() - 2f * sfcommon);
+            distance[j][i] += distance[i][j];
           }
-          distance[i][j] += (fi.size() + fk.size() - 2f * sfcommon);
-          distance[j][i] += distance[i][j];
         }
       }
     }
index 66f4036..18605b8 100644 (file)
@@ -35,17 +35,12 @@ public interface AlignCalcManagerI
   void notifyStart(AlignCalcWorkerI worker);
 
   /**
-   * check if a calculation of this type is already active
-   * 
-   * @param worker
-   * @return
-   */
-  boolean alreadyDoing(AlignCalcWorkerI worker);
-
-  /**
-   * tell manager that worker is now processing data
+   * tell manager that a thread running worker's run() loop is ready to start
+   * processing data
    * 
    * @param worker
+   * @return true if worker should start processing, false if another thread is
+   *         in progress
    */
   boolean notifyWorking(AlignCalcWorkerI worker);
 
@@ -63,7 +58,7 @@ public interface AlignCalcManagerI
    * 
    * @param worker
    */
-  void workerCannotRun(AlignCalcWorkerI worker);
+  void disableWorker(AlignCalcWorkerI worker);
 
   /**
    * indicate that a worker like this may be run on the platform.
@@ -71,7 +66,15 @@ public interface AlignCalcManagerI
    * @param worker
    *          of class to be removed from the execution blacklist
    */
-  void workerMayRun(AlignCalcWorkerI worker);
+  void enableWorker(AlignCalcWorkerI worker);
+
+  /**
+   * Answers true if the worker is disabled from running
+   * 
+   * @param worker
+   * @return
+   */
+  boolean isDisabled(AlignCalcWorkerI worker);
 
   /**
    * launch a new worker
@@ -83,7 +86,7 @@ public interface AlignCalcManagerI
   /**
    * 
    * @param worker
-   * @return
+   * @return true if the worker is currently running
    */
   boolean isWorking(AlignCalcWorkerI worker);
 
@@ -120,7 +123,7 @@ public interface AlignCalcManagerI
    * 
    * @param workerClass
    */
-  void updateAnnotationFor(Class workerClass);
+  void updateAnnotationFor(Class<? extends AlignCalcWorkerI> workerClass);
 
   /**
    * return any registered workers of the given class
@@ -128,17 +131,8 @@ public interface AlignCalcManagerI
    * @param workerClass
    * @return null or one or more workers of the given class
    */
-  List<AlignCalcWorkerI> getRegisteredWorkersOfClass(Class workerClass);
-
-  /**
-   * start any workers of the given class
-   * 
-   * @param workerClass
-   * @return false if no workers of given class were registered (note -
-   *         blacklisted classes cannot be restarted, so this method will return
-   *         true for blacklisted workers)
-   */
-  boolean startRegisteredWorkersOfClass(Class workerClass);
+  List<AlignCalcWorkerI> getRegisteredWorkersOfClass(
+          Class<? extends AlignCalcWorkerI> workerClass);
 
   /**
    * work out if there is an instance of a worker that is *waiting* to start
@@ -156,6 +150,15 @@ public interface AlignCalcManagerI
    * 
    * @param typeToRemove
    */
-  void removeRegisteredWorkersOfClass(Class typeToRemove);
+  void removeRegisteredWorkersOfClass(
+          Class<? extends AlignCalcWorkerI> typeToRemove);
 
+  /**
+   * Removes the worker that produces the given annotation, provided it is
+   * marked as 'deletable'. Some workers may need to continue to run as the
+   * results of their calculations are needed, e.g. for colour schemes.
+   * 
+   * @param ann
+   */
+  void removeWorkerForAnnotation(AlignmentAnnotation ann);
 }
index 872528b..85157c4 100644 (file)
@@ -22,12 +22,39 @@ package jalview.api;
 
 import jalview.datamodel.AlignmentAnnotation;
 
+/**
+ * Interface describing a worker that calculates alignment annotation(s). The
+ * main (re-)calculation should be performed by the inherited run() method.
+ */
 public interface AlignCalcWorkerI extends Runnable
 {
+  /**
+   * Answers true if this worker updates the given annotation (regardless of its
+   * current state)
+   * 
+   * @param annot
+   * @return
+   */
+  boolean involves(AlignmentAnnotation annot);
 
-  public boolean involves(AlignmentAnnotation annot);
+  /**
+   * Updates the display of calculated annotation values (does not recalculate
+   * the values). This allows ÃŸquick redraw of annotations when display settings
+   * are changed.
+   */
+  void updateAnnotation();
 
-  public void updateAnnotation();
+  /**
+   * Removes any annotation(s) managed by this worker from the alignment
+   */
+  void removeAnnotation();
 
-  void removeOurAnnotation();
+  /**
+   * Answers true if the worker should be deleted entirely when its annotation
+   * is deleted from the display, or false if it should continue to run. Some
+   * workers are required to run for their side-effects.
+   * 
+   * @return
+   */
+  boolean isDeletable();
 }
index 17a1563..26966ba 100644 (file)
@@ -64,7 +64,7 @@ public interface AlignViewControllerI
    * @return true if operation affected state
    */
   boolean markColumnsContainingFeatures(boolean invert,
-          boolean extendCurrent, boolean clearColumns, String featureType);
+          boolean extendCurrent, boolean toggle, String featureType);
 
   /**
    * sort the alignment or current selection by average score over the given set
index 45e77ba..70463e7 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.api;
 
 import jalview.analysis.Conservation;
+import jalview.analysis.Profile;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
@@ -53,6 +54,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 +82,7 @@ public interface AlignViewportI extends ViewStyleI
 
   ColumnSelection getColumnSelection();
 
-  Hashtable[] getSequenceConsensusHash();
+  Profile[] getSequenceConsensusHash();
 
   /**
    * Get consensus data table for the cDNA complement of this alignment (if any)
@@ -110,6 +123,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 +145,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @param hconsensus
    */
-  void setSequenceConsensusHash(Hashtable[] hconsensus);
+  void setSequenceConsensusHash(Profile[] hconsensus);
 
   /**
    * Set the cDNA complement consensus for the viewport
@@ -235,11 +253,31 @@ public interface AlignViewportI extends ViewStyleI
    * 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
    * calculating trees, PCA, redundancy etc on views which contain hidden
+   * columns. This method doesn't exclude hidden sequences from the output.
+   *
+   * @param selectedRegionOnly
+   *          - determines if only the selected region or entire alignment is
+   *          exported
+   * @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
+   * calculating trees, PCA, redundancy etc on views which contain hidden
    * columns.
    * 
+   * @param selectedRegionOnly
+   *          - determines if only the selected region or entire alignment is
+   *          exported
+   * @param isExportHiddenSeqs
+   *          - determines if hidden sequences would be exported or not.
+   * 
    * @return String[]
    */
-  String[] getViewAsString(boolean selectedRegionOnly);
+  String[] getViewAsString(boolean selectedRegionOnly,
+          boolean isExportHiddenSeqs);
 
   void setSelectionGroup(SequenceGroup sg);
 
@@ -377,4 +415,12 @@ 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();
 }
index 9415745..51c35c5 100644 (file)
@@ -1,7 +1,28 @@
+/*
+ * 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;
 
+//JBPComment: this is a datamodel API - so it should be in datamodel (it's a peer of SequenceI)
 
 public interface DBRefEntryI
 {
@@ -47,30 +68,47 @@ public interface DBRefEntryI
   public void setVersion(String version);
 
   /**
+   * access a mapping, if present that can be used to map positions from the
+   * associated dataset sequence to the DBRef's sequence frame.
    * 
-   * @param startRes
-   *          index of start residue in the source DB
+   * @return null or a valid mapping.
    */
-  public void setStartRes(int startRes);
-
-  /**
-   * 
-   * @return index of start residue in the source DB
-   */
-  public int getStartRes();
+  public Mapping getMap();
 
   /**
+   * Answers true if this object is either equivalent to, or can be 'improved'
+   * by, the given entry. Specifically, answers true if
+   * <ul>
+   * <li>source and accession are identical</li>
+   * <li>version is identical, or this version is of the format "someSource:0",
+   * in which case the version for the other entry replaces it</li>
+   * <li>mappings are not compared but if this entry has no mapping, replace
+   * with that for the other entry</li>
+   * </ul>
    * 
-   * @param endRes
-   *          index of end residue in the source DB
+   * @param otherEntry
+   * @return
    */
-  public void setEndRes(int endRes);
+  public boolean updateFrom(DBRefEntryI otherEntry);
 
   /**
-   * 
-   * @return index of end residue in the source DB
+   * 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 int getEndRes();
-
-  public Mapping getMap();
+  public boolean isPrimaryCandidate();
 }
index d8363f4..01eb7fa 100644 (file)
@@ -1,13 +1,34 @@
+/*
+ * 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;
+
 import java.awt.Color;
 
 public interface FeatureColourI
 {
 
   /**
-   * Answers true when either isColourByLabel, isAboveThreshold or
-   * isBelowThreshold answers true
+   * Answers true when the feature colour varies across the score range
    * 
    * @return
    */
@@ -35,13 +56,22 @@ public interface FeatureColourI
   Color getMaxColour();
 
   /**
-   * Answers true if the feature is coloured by label (description); only
-   * applicable when isGraduatedColour answers true
+   * Answers true if the feature has a single colour, i.e. if isColourByLabel()
+   * and isGraduatedColour() both answer false
+   * 
+   * @return
+   */
+  boolean isSimpleColour();
+
+  /**
+   * Answers true if the feature is coloured by label (description)
    * 
    * @return
    */
   boolean isColourByLabel();
 
+  void setColourByLabel(boolean b);
+
   /**
    * Answers true if the feature is coloured below a threshold value; only
    * applicable when isGraduatedColour answers true
@@ -50,6 +80,8 @@ public interface FeatureColourI
    */
   boolean isBelowThreshold();
 
+  void setBelowThreshold(boolean b);
+
   /**
    * Answers true if the feature is coloured above a threshold value; only
    * applicable when isGraduatedColour answers true
@@ -58,14 +90,20 @@ public interface FeatureColourI
    */
   boolean isAboveThreshold();
 
+  void setAboveThreshold(boolean b);
+
   /**
-   * Answers true if the threshold is the min (or max) of the colour range; only
-   * applicable when isGraduatedColour answers true
+   * Answers true if the threshold is the minimum value (when
+   * isAboveThreshold()) or maximum value (when isBelowThreshold()) of the
+   * colour range; only applicable when isGraduatedColour and either
+   * isAboveThreshold() or isBelowThreshold() answers true
    * 
    * @return
    */
   boolean isThresholdMinMax();
 
+  void setThresholdMinMax(boolean b);
+
   /**
    * Returns the threshold value (if any), else zero
    * 
@@ -73,10 +111,71 @@ public interface FeatureColourI
    */
   float getThreshold();
 
+  void setThreshold(float f);
+
+  /**
+   * Answers true if the colour varies between the actual minimum and maximum
+   * score values of the feature, or false if between absolute minimum and
+   * maximum values (or if not a graduated colour).
+   * 
+   * @return
+   */
+  boolean isAutoScaled();
+
+  void setAutoScaled(boolean b);
+
+  /**
+   * Returns the maximum score of the graduated colour range
+   * 
+   * @return
+   */
+  float getMax();
+
+  /**
+   * Returns the minimum score of the graduated colour range
+   * 
+   * @return
+   */
+  float getMin();
+
+  /**
+   * Answers true if either isAboveThreshold or isBelowThreshold answers true
+   * 
+   * @return
+   */
+  boolean hasThreshold();
+
+  /**
+   * Returns the computed colour for the given sequence feature
+   * 
+   * @param feature
+   * @return
+   */
+  Color getColor(SequenceFeature feature);
+
+  /**
+   * Answers true if the feature has a simple colour, or is coloured by label,
+   * or has a graduated colour and the score of this feature instance is within
+   * the range to render (if any), i.e. does not lie below or above any
+   * threshold set.
+   * 
+   * @param feature
+   * @return
+   */
+  boolean isColored(SequenceFeature feature);
+
+  /**
+   * Update the min-max range for a graduated colour scheme
+   * 
+   * @param min
+   * @param max
+   */
+  void updateBounds(float min, float max);
+
   /**
-   * Answers true if ?
+   * Returns the colour in Jalview features file format
    * 
    * @return
    */
-  boolean isLowToHigh();
+  String toJalviewFormat(String featureType);
 }
index 5b15cad..dbc9880 100644 (file)
@@ -60,17 +60,15 @@ public interface FeatureRenderer
    * @param ft
    * @return display style for a feature
    */
-  Object getFeatureStyle(String ft);
+  FeatureColourI getFeatureStyle(String ft);
 
   /**
    * update the feature style for a particular feature
    * 
    * @param ft
    * @param ggc
-   *          - currently allows java.awt.Color and
-   *          jalview.schemes.GraduatedColor
    */
-  void setColour(String ft, Object ggc);
+  void setColour(String ft, FeatureColourI ggc);
 
   AlignViewportI getViewport();
 
@@ -85,7 +83,7 @@ public interface FeatureRenderer
    * 
    * @return
    */
-  Map<String, Object> getFeatureColours();
+  Map<String, FeatureColourI> getFeatureColours();
 
   /**
    * query the alignment view to find all features
@@ -100,7 +98,7 @@ public interface FeatureRenderer
    * 
    * @return
    */
-  Map<String, Object> getDisplayedFeatureCols();
+  Map<String, FeatureColourI> getDisplayedFeatureCols();
 
   /**
    * get all registered groups
@@ -143,12 +141,6 @@ public interface FeatureRenderer
   List<SequenceFeature> findFeaturesAtRes(SequenceI sequence, int res);
 
   /**
-   * 
-   * @return true if the rendering platform supports transparency
-   */
-  boolean isTransparencyAvailable();
-
-  /**
    * get current displayed types, in ordering of rendering (on top last)
    * 
    * @return a (possibly empty) list of feature types
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 e2fac14..c795f3f 100644 (file)
@@ -29,6 +29,8 @@ import jalview.xml.binding.sifts.Entry.Entity;
 import java.util.HashMap;
 import java.util.HashSet;
 
+// JBPComment: this isn't a top-level Jalview API - should be in its own package api
+
 public interface SiftsClientI
 {
   /**
@@ -46,13 +48,6 @@ public interface SiftsClientI
   public String getDbCoordSys();
 
   /**
-   * Get DB Evidence for the SIFTs Entry
-   * 
-   * @return
-   */
-  public String getDbEvidence();
-
-  /**
    * Get DB Source for the SIFTs Entry
    * 
    * @return
@@ -99,13 +94,6 @@ public interface SiftsClientI
   public boolean isAccessionMatched(String accessionId);
 
   /**
-   * Get the standard DB referenced by the SIFTs Entry
-   * 
-   * @return
-   */
-  public String[] getEntryDBs();
-
-  /**
    * 
    * @param mop
    *          MappingOutputPojo
@@ -128,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
    * 
@@ -140,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 7fc88bc..1544265 100644 (file)
@@ -43,7 +43,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;
@@ -70,8 +69,6 @@ import java.util.Vector;
 public class APopupMenu extends java.awt.PopupMenu implements
         ActionListener, ItemListener
 {
-  private static final String ALL_ANNOTATIONS = "All";
-
   Menu groupMenu = new Menu();
 
   MenuItem editGroupName = new MenuItem();
@@ -965,7 +962,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
             "label.represent_group_with", new Object[] { "" }));
     revealAll.setLabel(MessageManager.getString("action.reveal_all"));
     revealSeq.setLabel(MessageManager.getString("action.reveal_sequences"));
-    menu1.setLabel(MessageManager.getString("label.group") + ":");
+    menu1.setLabel(MessageManager.getString("label.group:"));
     add(groupMenu);
     this.add(seqMenu);
     this.add(hideSeqs);
@@ -1209,10 +1206,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", 3,
+              sg.getSequences(ap.av.getHiddenRepSequences()), 0, ap.av
+                      .getAlignment().getWidth(), false, ap.av
+                      .getConsPercGaps(), false));
       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
       SliderPanel.showConservationSlider();
     }
@@ -1301,35 +1298,7 @@ public class APopupMenu extends java.awt.PopupMenu implements
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { seq });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(seq, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs;
-
-    hseqs = new SequenceI[gsize];
-
-    int index = 0;
-    for (int i = 0; i < gsize; i++)
-    {
-      hseqs[index++] = sg.getSequenceAt(i);
-    }
-
-    ap.av.hideSequence(hseqs);
-    ap.av.sendSelection();
+    ap.av.hideSequences(seq, representGroup);
   }
 
   /**
@@ -1353,7 +1322,8 @@ public class APopupMenu extends java.awt.PopupMenu implements
     showMenu.removeAll();
     hideMenu.removeAll();
 
-    final List<String> all = Arrays.asList(ALL_ANNOTATIONS);
+    final List<String> all = Arrays.asList(new String[] { MessageManager
+            .getString("label.all") });
     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
             false);
index e5f0053..122afa8 100644 (file)
@@ -25,6 +25,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureRenderer;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SequenceStructureBinding;
@@ -101,7 +102,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;
@@ -218,6 +218,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       viewport.setColumnSelection(columnSelection);
     }
+    viewport.setScaleAboveWrapped(scaleAbove.getState());
 
     alignPanel = new AlignmentPanel(this, viewport);
     avc = new jalview.controller.AlignViewController(this, viewport,
@@ -367,7 +368,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     boolean featuresFile = false;
     try
     {
-      Map<String, Object> colours = alignPanel.seqPanel.seqCanvas
+      Map<String, FeatureColourI> colours = alignPanel.seqPanel.seqCanvas
               .getFeatureRenderer().getFeatureColours();
       boolean relaxedIdMatching = viewport.applet.getDefaultParameter(
               "relaxedidmatch", false);
@@ -701,9 +702,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()))
       {
@@ -731,8 +730,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();
       }
@@ -740,7 +738,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         viewport.hideSelectedColumns();
         if (!toggleSeqs)
@@ -927,11 +925,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);
@@ -1399,7 +1397,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     return annotation;
   }
 
-  private Map<String, Object> getDisplayedFeatureCols()
+  private Map<String, FeatureColourI> getDisplayedFeatureCols()
   {
     if (alignPanel.getFeatureRenderer() != null
             && viewport.getFeaturesDisplayed() != null)
@@ -1416,9 +1414,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
     {
@@ -2232,7 +2229,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
     viewport.setSelectionGroup(sg);
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2249,7 +2249,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     viewport.setSelectionGroup(null);
     alignPanel.idPanel.idCanvas.searchResults = null;
     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -3509,10 +3512,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     nucleotideColour.setLabel(MessageManager.getString("label.nucleotide"));
     nucleotideColour.addActionListener(this);
     modifyPID.setLabel(MessageManager
-            .getString("label.modify_identity_thereshold"));
+            .getString("label.modify_identity_threshold"));
     modifyPID.addActionListener(this);
     modifyConservation.setLabel(MessageManager
-            .getString("label.modify_conservation_thereshold"));
+            .getString("label.modify_conservation_threshold"));
     modifyConservation.addActionListener(this);
     annotationColour.setLabel(MessageManager
             .getString("action.by_annotation"));
@@ -4020,12 +4023,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());
-        }
-        pdbentry.getProperty().put("protocol", protocol);
+        pdbentry.setProperty("protocol", protocol);
         toaddpdb.addPDBId(pdbentry);
         alignPanel.getStructureSelectionManager()
                 .registerPDBEntry(pdbentry);
@@ -4076,7 +4074,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     if (protocol == null || protocol.trim().length() == 0
             || protocol.equals("null"))
     {
-      protocol = (String) pdb.getProperty().get("protocol");
+      protocol = (String) pdb.getProperty("protocol");
       if (protocol == null)
       {
         System.err.println("Couldn't work out protocol to open structure: "
index 34e0cc0..813ab84 100644 (file)
@@ -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"))
@@ -538,6 +542,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 +775,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     int oldX = av.getStartRes();
@@ -947,6 +953,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 +976,13 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     invalidate();
index 57b182c..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);
@@ -138,11 +144,11 @@ public class AnnotationColourChooser extends Panel implements
     }
 
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_no_thereshold"));
+            .getString("label.threshold_feature_no_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_above_thereshold"));
+            .getString("label.threshold_feature_above_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_below_thereshold"));
+            .getString("label.threshold_feature_below_threshold"));
 
     if (oldcs instanceof AnnotationColourGradient)
     {
@@ -162,7 +168,7 @@ public class AnnotationColourChooser extends Panel implements
       default:
         throw new Error(
                 MessageManager
-                        .getString("error.implementation_error_dont_know_thereshold_annotationcolourgradient"));
+                        .getString("error.implementation_error_dont_know_threshold_annotationcolourgradient"));
       }
       thresholdIsMin.setState(acg.thresholdIsMinMax);
       thresholdValue.setText("" + acg.getAnnotationThreshold());
@@ -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 5727e9c..b28ccc7 100755 (executable)
@@ -162,6 +162,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     return row;
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
@@ -261,6 +262,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
 
   boolean resizePanel = false;
 
+  @Override
   public void mouseMoved(MouseEvent evt)
   {
     resizePanel = evt.getY() < 10 && evt.getX() < 14;
@@ -306,6 +308,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     dragCancelled = true;
   }
 
+  @Override
   public void mouseDragged(MouseEvent evt)
   {
     if (dragCancelled)
@@ -365,10 +368,12 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     if (!resizePanel && !dragCancelled)
@@ -400,6 +405,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     ap.annotationPanel.repaint();
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
     if (evt.getY() < 10 && evt.getX() < 14)
@@ -409,6 +415,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
     dragCancelled = false;
@@ -427,6 +434,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     repaint();
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
     oldY = evt.getY();
@@ -522,6 +530,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
             final AlignmentAnnotation aaa = aa[selectedRow];
             cbmi.addItemListener(new ItemListener()
             {
+              @Override
               public void itemStateChanged(ItemEvent e)
               {
                 if (aaa.groupRef != null)
@@ -545,6 +554,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isShowConsensusHistogram());
               chist.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -564,6 +574,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isShowSequenceLogo());
               cprofl.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -585,6 +596,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       aa[selectedRow].groupRef.isNormaliseSequenceLogo());
               cprofn.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -608,6 +620,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isShowConsensusHistogram());
               chist.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -631,6 +644,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isShowSequenceLogo());
               cprof.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -655,6 +669,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
                       av.isNormaliseSequenceLogo());
               cprofn.addItemListener(new ItemListener()
               {
+                @Override
                 public void itemStateChanged(ItemEvent e)
                 {
                   // TODO: pass on reference
@@ -697,11 +712,47 @@ public class AnnotationLabels extends Panel implements ActionListener,
             // todo: make the ap scroll to the selection - not necessary, first
             // click highlights/scrolls, second selects
             ap.seqPanel.ap.idPanel.highlightSearchResults(null);
-            ap.av.setSelectionGroup(// new SequenceGroup(
-            aa[selectedRow].groupRef); // );
-            ap.av.sendSelection();
+            // process modifiers
+            SequenceGroup sg = ap.av.getSelectionGroup();
+            if (sg == null
+                    || sg == aa[selectedRow].groupRef
+                    || !(jalview.util.Platform.isControlDown(evt) || evt
+                            .isShiftDown()))
+            {
+              if (jalview.util.Platform.isControlDown(evt)
+                      || evt.isShiftDown())
+              {
+                // clone a new selection group from the associated group
+                ap.av.setSelectionGroup(new SequenceGroup(
+                        aa[selectedRow].groupRef));
+              }
+              else
+              {
+                // set selection to the associated group so it can be edited
+                ap.av.setSelectionGroup(aa[selectedRow].groupRef);
+              }
+            }
+            else
+            {
+              // modify current selection with associated group
+              int remainToAdd = aa[selectedRow].groupRef.getSize();
+              for (SequenceI sgs : aa[selectedRow].groupRef.getSequences())
+              {
+                if (jalview.util.Platform.isControlDown(evt))
+                {
+                  sg.addOrRemove(sgs, --remainToAdd == 0);
+                }
+                else
+                {
+                  // notionally, we should also add intermediate sequences from
+                  // last added sequence ?
+                  sg.addSequence(sgs, --remainToAdd == 0);
+                }
+              }
+            }
             ap.paintAlignment(false);
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
+            ap.av.sendSelection();
           }
           else
           {
@@ -728,7 +779,8 @@ public class AnnotationLabels extends Panel implements ActionListener,
               // we make a copy rather than edit the current selection if no
               // modifiers pressed
               // see Enhancement JAL-1557
-              if (!(evt.isControlDown() || evt.isShiftDown()))
+              if (!(jalview.util.Platform.isControlDown(evt) || evt
+                      .isShiftDown()))
               {
                 sg = new SequenceGroup(sg);
                 sg.clear();
@@ -736,7 +788,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
               }
               else
               {
-                if (evt.isControlDown())
+                if (jalview.util.Platform.isControlDown(evt))
                 {
                   sg.addOrRemove(aa[selectedRow].sequenceRef, true);
                 }
@@ -794,11 +846,13 @@ public class AnnotationLabels extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     int w = getSize().width;
index 77700d0..6012c1a 100755 (executable)
@@ -22,9 +22,13 @@ package jalview.appletgui;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -98,7 +102,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
   public AnnotationPanel(AlignmentPanel ap)
   {
-    MAC = new jalview.util.Platform().isAMac();
+    new jalview.util.Platform();
+    MAC = Platform.isAMac();
     this.ap = ap;
     av = ap.av;
     setLayout(null);
@@ -158,12 +163,12 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
 
     if (evt.getActionCommand().equals(REMOVE))
     {
-      for (int sel : av.getColumnSelection().getSelected())
+      for (int index : av.getColumnSelection().getSelected())
       {
-        // TODO: JAL-2001 check if applet has faulty 'REMOVE' selected columns
-        // of
-        // annotation if selection includes hidden columns
-        anot[sel] = null;
+        if (av.getColumnSelection().isVisible(index))
+        {
+          anot[index] = null;
+        }
       }
     }
     else if (evt.getActionCommand().equals(LABEL))
@@ -239,7 +244,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       else if (evt.getActionCommand().equals(STEM))
       {
         type = 'S';
-        symbol = "\u03C3";
+        int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+        symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
       }
 
       if (!aa[activeRow].hasIcons)
@@ -344,7 +350,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
     if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
             && activeRow != -1)
     {
-      if (av.getColumnSelection() == null)
+      if (av.getColumnSelection() == null
+              || av.getColumnSelection().isEmpty())
       {
         return;
       }
@@ -352,10 +359,8 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       PopupMenu pop = new PopupMenu(
               MessageManager.getString("label.structure_type"));
       MenuItem item;
-      /*
-       * Just display the needed structure options
-       */
-      if (av.getAlignment().isNucleotide() == true)
+
+      if (av.getAlignment().isNucleotide())
       {
         item = new MenuItem(STEM);
         item.addActionListener(this);
@@ -457,21 +462,67 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
       }
     }
 
-    int res = evt.getX() / av.getCharWidth() + av.getStartRes();
+    int column = evt.getX() / av.getCharWidth() + av.getStartRes();
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      column = av.getColumnSelection().adjustForHiddenColumns(column);
     }
 
-    if (row > -1 && res < aa[row].annotations.length
-            && aa[row].annotations[res] != null)
+    if (row > -1 && column < aa[row].annotations.length
+            && aa[row].annotations[column] != null)
     {
-      StringBuffer text = new StringBuffer("Sequence position " + (res + 1));
-      if (aa[row].annotations[res].description != null)
+      StringBuilder text = new StringBuilder();
+      text.append(MessageManager.getString("label.column")).append(" ")
+              .append(column + 1);
+      String description = aa[row].annotations[column].description;
+      if (description != null && description.length() > 0)
+      {
+        text.append("  ").append(description);
+      }
+
+      /*
+       * if the annotation is sequence-specific, show the sequence number
+       * in the alignment, and (if not a gap) the residue and position
+       */
+      SequenceI seqref = aa[row].sequenceRef;
+      if (seqref != null)
       {
-        text.append("  " + aa[row].annotations[res].description);
+        int seqIndex = av.getAlignment().findIndex(seqref);
+        if (seqIndex != -1)
+        {
+          text.append(", ")
+                  .append(MessageManager.getString("label.sequence"))
+                  .append(" ").append(seqIndex + 1);
+          char residue = seqref.getCharAt(column);
+          if (!Comparison.isGap(residue))
+          {
+            text.append(" ");
+            String name;
+            if (av.getAlignment().isNucleotide())
+            {
+              name = ResidueProperties.nucleotideName.get(String
+                      .valueOf(residue));
+              text.append(" Nucleotide: ").append(
+                      name != null ? name : residue);
+            }
+            else
+            {
+              name = 'X' == residue ? "X" : ('*' == residue ? "STOP"
+                      : ResidueProperties.aa2Triplet.get(String
+                              .valueOf(residue)));
+              text.append(" Residue: ").append(
+                      name != null ? name : residue);
+            }
+            int residuePos = seqref.findPosition(column);
+            text.append(" (").append(residuePos).append(")");
+            // int residuePos = seqref.findPosition(column);
+            // text.append(residue).append(" (")
+            // .append(residuePos).append(")");
+          }
+        }
       }
+
       ap.alignFrame.statusBar.setText(text.toString());
     }
   }
index 4cb5ede..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;
@@ -186,11 +147,11 @@ public abstract class AnnotationRowFilter extends Panel
   protected void populateThresholdComboBox(Choice threshold)
   {
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_no_thereshold"));
+            .getString("label.threshold_feature_no_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_above_thereshold"));
+            .getString("label.threshold_feature_above_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_below_thereshold"));
+            .getString("label.threshold_feature_below_threshold"));
   }
 
   public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
index 8374721..b925284 100644 (file)
@@ -60,7 +60,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;
 
@@ -290,11 +289,8 @@ public class AppletJmol extends EmbmenuFrame implements
         closeViewer();
       }
     });
-    if (pdbentry.getProperty() == null)
-    {
-      pdbentry.setProperty(new Hashtable());
-      pdbentry.getProperty().put("protocol", protocol);
-    }
+    pdbentry.setProperty("protocol", protocol);
+
     if (pdbentry.getFile() != null)
     {
       // import structure data from pdbentry.getFile based on given protocol
index 46a67c4..0e85017 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.GraphLine;
 import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.util.MessageManager;
 
 import java.awt.Checkbox;
@@ -60,9 +61,9 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   // AlignmentPanel ap;
 
-  GraduatedColor cs;
+  FeatureColourI cs;
 
-  Object oldcs;
+  FeatureColourI oldcs;
 
   Hashtable oldgroupColours;
 
@@ -91,29 +92,29 @@ public class FeatureColourChooser extends Panel implements ActionListener,
   {
     this.type = type;
     fr = frenderer;
-    float mm[] = ((float[][]) fr.getMinMax().get(type))[0];
+    float mm[] = fr.getMinMax().get(type)[0];
     min = mm[0];
     max = mm[1];
     oldcs = fr.getFeatureColours().get(type);
-    if (oldcs instanceof GraduatedColor)
+    if (oldcs.isGraduatedColour())
     {
-      cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
+      cs = new FeatureColour((FeatureColour) oldcs, min, max);
     }
     else
     {
       // promote original color to a graduated color
       Color bl = Color.black;
-      if (oldcs instanceof Color)
+      if (oldcs.isSimpleColour())
       {
-        bl = (Color) oldcs;
+        bl = oldcs.getColour();
       }
       // original colour becomes the maximum colour
-      cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
+      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
     }
-    minColour.setBackground(cs.getMinColor());
-    maxColour.setBackground(cs.getMaxColor());
-    minColour.setForeground(cs.getMinColor());
-    maxColour.setForeground(cs.getMaxColor());
+    minColour.setBackground(cs.getMinColour());
+    maxColour.setBackground(cs.getMaxColour());
+    minColour.setForeground(cs.getMinColour());
+    maxColour.setForeground(cs.getMaxColour());
     colourFromLabel.setState(cs.isColourByLabel());
     adjusting = true;
 
@@ -123,10 +124,8 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     } catch (Exception ex)
     {
     }
-    threshold
-            .select(cs.getThreshType() == AnnotationColourGradient.NO_THRESHOLD ? 0
-                    : cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
-                            : 2);
+    threshold.select(cs.isAboveThreshold() ? 1 : (cs.isBelowThreshold() ? 2
+            : 0));
 
     adjusting = false;
     changeColour();
@@ -192,11 +191,11 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     jPanel4.setBackground(Color.white);
     threshold.addItemListener(this);
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_no_thereshold"));
+            .getString("label.threshold_feature_no_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_above_thereshold"));
+            .getString("label.threshold_feature_above_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_below_thereshold"));
+            .getString("label.threshold_feature_below_threshold"));
     thresholdValue.addActionListener(this);
     slider.setBackground(Color.white);
     slider.setEnabled(false);
@@ -259,6 +258,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   private GraphLine threshline;
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     if (evt.getSource() == thresholdValue)
@@ -286,6 +286,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void itemStateChanged(ItemEvent evt)
   {
     maxColour.setEnabled(!colourFromLabel.getState());
@@ -293,19 +294,20 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     changeColour();
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (!adjusting)
     {
-      thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
+      thresholdValue.setText((slider.getValue() / 1000f) + "");
       valueChanged();
     }
   }
 
   protected void valueChanged()
   {
-    threshline.value = (float) slider.getValue() / 1000f;
-    cs.setThresh(threshline.value);
+    threshline.value = slider.getValue() / 1000f;
+    cs.setThreshold(threshline.value);
     changeColour();
     PaintRefresher.Refresh(this, fr.getViewport().getSequenceSetId());
     // ap.paintAlignment(false);
@@ -369,7 +371,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
-    GraduatedColor acg = new GraduatedColor(minColour.getBackground(),
+    FeatureColour acg = new FeatureColour(minColour.getBackground(),
             maxColour.getBackground(), min, max);
 
     acg.setColourByLabel(colourFromLabel.getState());
@@ -393,7 +395,7 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
     {
       adjusting = true;
-      acg.setThresh(threshline.value);
+      acg.setThreshold(threshline.value);
 
       float range = max * 1000f - min * 1000f;
 
@@ -406,17 +408,17 @@ public class FeatureColourChooser extends Panel implements ActionListener,
       adjusting = false;
     }
 
-    acg.setThreshType(aboveThreshold);
+    acg.setAboveThreshold(true);
     if (thresholdIsMin.getState()
             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
     {
       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
       {
-        acg = new GraduatedColor(acg, threshline.value, max);
+        acg = new FeatureColour(acg, threshline.value, max);
       }
       else
       {
-        acg = new GraduatedColor(acg, min, threshline.value);
+        acg = new FeatureColour(acg, min, threshline.value);
       }
     }
 
@@ -434,14 +436,17 @@ public class FeatureColourChooser extends Panel implements ActionListener,
 
   }
 
+  @Override
   public void mouseClicked(MouseEvent evt)
   {
   }
 
+  @Override
   public void mousePressed(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseReleased(MouseEvent evt)
   {
     if (evt.getSource() == minColour || evt.getSource() == maxColour)
@@ -456,10 +461,12 @@ public class FeatureColourChooser extends Panel implements ActionListener,
     // ap.paintAlignment(true);
   }
 
+  @Override
   public void mouseEntered(MouseEvent evt)
   {
   }
 
+  @Override
   public void mouseExited(MouseEvent evt)
   {
   }
index 4391fa2..82736d7 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.io.FeaturesFile;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
@@ -43,6 +45,9 @@ import java.awt.TextArea;
 import java.awt.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Hashtable;
 
 /**
  * DOCUMENT ME!
@@ -53,19 +58,20 @@ import java.awt.event.ActionListener;
 public class FeatureRenderer extends
         jalview.renderer.seqfeatures.FeatureRenderer
 {
+
+  // Holds web links for feature groups and feature types
+  // in the form label|link
+  Hashtable featureLinks = null;
+
   /**
    * Creates a new FeatureRenderer object.
    * 
    * @param av
-   *          DOCUMENT ME!
    */
   public FeatureRenderer(AlignmentViewport av)
   {
-    super();
-    this.av = av;
+    super(av);
 
-    setTransparencyAvailable(!System.getProperty("java.version")
-            .startsWith("1.1"));
   }
 
   static String lastFeatureAdded;
@@ -91,51 +97,35 @@ public class FeatureRenderer extends
     /**
      * render a feature style in the amend feature dialog box
      */
-    public void updateColor(Object newcol)
+    public void updateColor(FeatureColourI newcol)
     {
-
-      Color bg, col = null;
-      GraduatedColor gcol = null;
+      Color bg = null;
       String vlabel = "";
-      if (newcol instanceof Color)
-      {
-        isGcol = false;
-        col = (Color) newcol;
-        gcol = null;
-      }
-      else if (newcol instanceof GraduatedColor)
+      if (newcol.isSimpleColour())
       {
-        isGcol = true;
-        gcol = (GraduatedColor) newcol;
-        col = null;
+        bg = newcol.getColour();
+        setBackground(bg);
       }
       else
       {
-        throw new Error(
-                MessageManager
-                        .getString("error.invalid_colour_for_mycheckbox"));
-      }
-      if (col != null)
-      {
-        setBackground(bg = col);
-      }
-      else
-      {
-        if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+        if (newcol.isAboveThreshold())
         {
-          vlabel += " "
-                  + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
-                          : "(<)");
+          vlabel += " (>)";
         }
-        if (isColourByLabel = gcol.isColourByLabel())
+        else if (newcol.isBelowThreshold())
+        {
+          vlabel += " (<)";
+        }
+
+        if (isColourByLabel = newcol.isColourByLabel())
         {
           setBackground(bg = Color.white);
           vlabel += " (by Label)";
         }
         else
         {
-          setBackground(bg = gcol.getMinColor());
-          maxCol = gcol.getMaxColor();
+          setBackground(bg = newcol.getMinColour());
+          maxCol = newcol.getMaxColour();
         }
       }
       label = vlabel;
@@ -242,11 +232,12 @@ public class FeatureRenderer extends
             ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
 
           }
-          Object col = getFeatureStyle(name.getText());
+          FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            col = new jalview.schemes.UserColourScheme()
+            Color generatedColour = UserColourScheme
                     .createColourFromName(name.getText());
+            col = new FeatureColour(generatedColour);
           }
 
           colourPanel.updateColor(col);
@@ -260,23 +251,24 @@ public class FeatureRenderer extends
 
     tmp = new Panel();
     panel.add(tmp);
-    tmp.add(new Label("Name: ", Label.RIGHT));
+    tmp.add(new Label(MessageManager.getString("label.name:"), Label.RIGHT));
     tmp.add(name);
 
     tmp = new Panel();
     panel.add(tmp);
-    tmp.add(new Label("Group: ", Label.RIGHT));
+    tmp.add(new Label(MessageManager.getString("label.group:"), Label.RIGHT));
     tmp.add(source);
 
     tmp = new Panel();
     panel.add(tmp);
-    tmp.add(new Label("Colour: ", Label.RIGHT));
+    tmp.add(new Label(MessageManager.getString("label.colour"), Label.RIGHT));
     tmp.add(colourPanel);
 
     bigPanel.add(panel, BorderLayout.NORTH);
 
     panel = new Panel();
-    panel.add(new Label("Description: ", Label.RIGHT));
+    panel.add(new Label(MessageManager.getString("label.description:"),
+            Label.RIGHT));
     panel.add(new ScrollPane().add(description));
 
     if (!newFeatures)
@@ -284,9 +276,11 @@ public class FeatureRenderer extends
       bigPanel.add(panel, BorderLayout.SOUTH);
 
       panel = new Panel();
-      panel.add(new Label(" Start:", Label.RIGHT));
+      panel.add(new Label(MessageManager.getString("label.start"),
+              Label.RIGHT));
       panel.add(start);
-      panel.add(new Label("  End:", Label.RIGHT));
+      panel.add(new Label(MessageManager.getString("label.end"),
+              Label.RIGHT));
       panel.add(end);
       bigPanel.add(panel, BorderLayout.CENTER);
     }
@@ -354,21 +348,16 @@ public class FeatureRenderer extends
     start.setText(features[0].getBegin() + "");
     end.setText(features[0].getEnd() + "");
     description.setText(features[0].getDescription());
-    Color col = getColour(name.getText());
-    if (col == null)
-    {
-      col = new jalview.schemes.UserColourScheme()
-              .createColourFromName(name.getText());
-    }
-    Object fcol = getFeatureStyle(name.getText());
+    // lookup (or generate) the feature colour
+    FeatureColourI fcol = getFeatureStyle(name.getText());
     // simply display the feature color in a box
     colourPanel.updateColor(fcol);
     dialog.setResizable(true);
     // TODO: render the graduated color in the box.
-    colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
+    colourPanel.addMouseListener(new MouseAdapter()
     {
       @Override
-      public void mousePressed(java.awt.event.MouseEvent evt)
+      public void mousePressed(MouseEvent evt)
       {
         if (!colourPanel.isGcol)
         {
@@ -376,15 +365,14 @@ public class FeatureRenderer extends
         }
         else
         {
-          FeatureColourChooser fcc = new FeatureColourChooser(
-                  ap.alignFrame, name.getText());
+          new FeatureColourChooser(ap.alignFrame, name.getText());
           dialog.transferFocus();
         }
       }
     });
     dialog.setVisible(true);
 
-    jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
+    FeaturesFile ffile = new FeaturesFile();
 
     if (dialog.accept)
     {
@@ -413,7 +401,7 @@ public class FeatureRenderer extends
         if (!colourPanel.isGcol)
         {
           // update colour - otherwise its already done.
-          setColour(sf.type, colourPanel.getBackground());
+          setColour(sf.type, new FeatureColour(colourPanel.getBackground()));
         }
         try
         {
@@ -453,7 +441,7 @@ public class FeatureRenderer extends
         {
           setGroupVisibility(lastFeatureGroupAdded, true);
         }
-        setColour(lastFeatureAdded, newColour); // was fcol
+        setColour(lastFeatureAdded, new FeatureColour(newColour)); // was fcol
         setVisible(lastFeatureAdded);
         findAllFeatures(false); // different to original applet behaviour ?
         // findAllFeatures();
index 584a69a..2c454a4 100755 (executable)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -59,8 +58,8 @@ import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.Arrays;
 import java.util.Enumeration;
-import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import java.util.Vector;
 
 public class FeatureSettings extends Panel implements ItemListener,
@@ -95,14 +94,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     transparency = new Scrollbar(Scrollbar.HORIZONTAL,
             100 - (int) (fr.getTransparency() * 100), 1, 1, 100);
 
-    if (fr.isTransparencyAvailable())
-    {
-      transparency.addAdjustmentListener(this);
-    }
-    else
-    {
-      transparency.setEnabled(false);
-    }
+    transparency.addAdjustmentListener(this);
 
     java.net.URL url = getClass().getResource("/images/link.gif");
     if (url != null)
@@ -134,17 +126,8 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     Panel tPanel = new Panel(new BorderLayout());
 
-    if (fr.isTransparencyAvailable())
-    {
-      tPanel.add(transparency, BorderLayout.CENTER);
-      tPanel.add(new Label("Transparency"), BorderLayout.EAST);
-    }
-    else
-    {
-      tPanel.add(
-              new Label("Transparency not available in this web browser"),
-              BorderLayout.CENTER);
-    }
+    tPanel.add(transparency, BorderLayout.CENTER);
+    tPanel.add(new Label("Transparency"), BorderLayout.EAST);
 
     lowerPanel.add(tPanel, BorderLayout.SOUTH);
 
@@ -201,12 +184,12 @@ public class FeatureSettings extends Panel implements ItemListener,
             60);
   }
 
-  protected void popupSort(final MyCheckbox check, final Hashtable minmax,
-          int x, int y)
+  protected void popupSort(final MyCheckbox check,
+          final Map<String, float[][]> minmax, int x, int y)
   {
     final String type = check.type;
-    final Object typeCol = fr.getFeatureStyle(type);
-    java.awt.PopupMenu men = new PopupMenu(MessageManager.formatMessage(
+    final FeatureColourI typeCol = fr.getFeatureStyle(type);
+    PopupMenu men = new PopupMenu(MessageManager.formatMessage(
             "label.settings_for_type", new String[] { type }));
     java.awt.MenuItem scr = new MenuItem(
             MessageManager.getString("label.sort_by_score"));
@@ -237,9 +220,10 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     });
     men.add(dens);
+
     if (minmax != null)
     {
-      final Object typeMinMax = minmax.get(type);
+      final float[][] typeMinMax = minmax.get(type);
       /*
        * final java.awt.CheckboxMenuItem chb = new
        * java.awt.CheckboxMenuItem("Vary Height"); // this is broken at the
@@ -252,12 +236,12 @@ public class FeatureSettings extends Panel implements ItemListener,
        * 
        * }); men.add(chb);
        */
-      if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
+      if (typeMinMax != null && typeMinMax[0] != null)
       {
         // graduated colourschemes for those where minmax exists for the
         // positional features
         MenuItem mxcol = new MenuItem(
-                (typeCol instanceof Color) ? "Graduated Colour"
+                (typeCol.isSimpleColour()) ? "Graduated Colour"
                         : "Single Colour");
         men.add(mxcol);
         mxcol.addActionListener(new ActionListener()
@@ -266,7 +250,7 @@ public class FeatureSettings extends Panel implements ItemListener,
           @Override
           public void actionPerformed(ActionEvent e)
           {
-            if (typeCol instanceof Color)
+            if (typeCol.isSimpleColour())
             {
               new FeatureColourChooser(me, type);
               // write back the current colour object to update the table
@@ -274,14 +258,64 @@ public class FeatureSettings extends Panel implements ItemListener,
             }
             else
             {
-              new UserDefinedColours(me, check.type,
-                      ((GraduatedColor) typeCol));
+              new UserDefinedColours(me, check.type, typeCol);
             }
           }
 
         });
       }
     }
+
+    MenuItem selectContaining = new MenuItem(
+            MessageManager.getString("label.select_columns_containing"));
+    selectContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        me.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
+                false, type);
+      }
+    });
+    men.add(selectContaining);
+
+    MenuItem selectNotContaining = new MenuItem(
+            MessageManager.getString("label.select_columns_not_containing"));
+    selectNotContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        me.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
+                false, type);
+      }
+    });
+    men.add(selectNotContaining);
+
+    MenuItem hideContaining = new MenuItem(
+            MessageManager.getString("label.hide_columns_containing"));
+    hideContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hideFeatureColumns(type, true);
+      }
+    });
+    men.add(hideContaining);
+
+    MenuItem hideNotContaining = new MenuItem(
+            MessageManager.getString("label.hide_columns_not_containing"));
+    hideNotContaining.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hideFeatureColumns(type, false);
+      }
+    });
+    men.add(hideNotContaining);
+
     this.featurePanel.add(men);
     men.show(this.featurePanel, x, y);
   }
@@ -338,7 +372,7 @@ public class FeatureSettings extends Panel implements ItemListener,
   {
     SequenceFeature[] tmpfeatures;
     String group = null, type;
-    Vector visibleChecks = new Vector();
+    Vector<String> visibleChecks = new Vector<String>();
     AlignmentI alignment = av.getAlignment();
     for (int i = 0; i < alignment.getHeight(); i++)
     {
@@ -404,7 +438,7 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     // now add checkboxes which should be visible,
     // if they have not already been added
-    Enumeration en = visibleChecks.elements();
+    Enumeration<String> en = visibleChecks.elements();
 
     while (en.hasMoreElements())
     {
@@ -600,19 +634,9 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
   }
 
-  public void setUserColour(String feature, Object originalColour)
+  public void setUserColour(String feature, FeatureColourI originalColour)
   {
-    if (originalColour instanceof Color
-            || originalColour instanceof GraduatedColor)
-    {
-      fr.setColour(feature, originalColour);
-    }
-    else
-    {
-      throw new Error(
-              MessageManager
-                      .getString("error.implementation_error_unsupported_feature_colour_object"));
-    }
+    fr.setColour(feature, originalColour);
     refreshTable();
   }
 
@@ -649,10 +673,10 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     if (evt.getClickCount() > 1)
     {
-      Object fcol = fr.getFeatureStyle(check.type);
-      if (fcol instanceof Color)
+      FeatureColourI fcol = fr.getFeatureStyle(check.type);
+      if (fcol.isSimpleColour())
       {
-        new UserDefinedColours(this, check.type, (Color) fcol);
+        new UserDefinedColours(this, check.type, fcol.getColour());
       }
       else
       {
@@ -684,49 +708,34 @@ public class FeatureSettings extends Panel implements ItemListener,
 
     boolean hasLink;
 
-    GraduatedColor gcol;
-
-    Color col;
+    FeatureColourI col;
 
-    public void updateColor(Object newcol)
+    public void updateColor(FeatureColourI newcol)
     {
-      if (newcol instanceof Color)
+      col = newcol;
+      if (col.isSimpleColour())
       {
-        col = (Color) newcol;
-        gcol = null;
-      }
-      else if (newcol instanceof GraduatedColor)
-      {
-        gcol = (GraduatedColor) newcol;
-        col = null;
-      }
-      else
-      {
-        throw new Error(
-                MessageManager
-                        .getString("error.invalid_colour_for_mycheckbox"));
-      }
-      if (col != null)
-      {
-        setBackground(col);
+        setBackground(col.getColour());
       }
       else
       {
         String vlabel = type;
-        if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+        if (col.isAboveThreshold())
+        {
+          vlabel += " (>)";
+        }
+        else if (col.isBelowThreshold())
         {
-          vlabel += " "
-                  + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
-                          : "(<)");
+          vlabel += " (<)";
         }
-        if (gcol.isColourByLabel())
+        if (col.isColourByLabel())
         {
           setBackground(Color.white);
           vlabel += " (by Label)";
         }
         else
         {
-          setBackground(gcol.getMinColor());
+          setBackground(col.getMinColour());
         }
         this.setLabel(vlabel);
       }
@@ -743,7 +752,7 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
 
     public MyCheckbox(String type, boolean selected, boolean b,
-            Object featureStyle)
+            FeatureColourI featureStyle)
     {
       this(type, selected, b);
       updateColor(featureStyle);
@@ -753,9 +762,9 @@ public class FeatureSettings extends Panel implements ItemListener,
     public void paint(Graphics g)
     {
       Dimension d = getSize();
-      if (gcol != null)
+      if (col != null)
       {
-        if (gcol.isColourByLabel())
+        if (col.isColourByLabel())
         {
           g.setColor(Color.white);
           g.fillRect(d.width / 2, 0, d.width / 2, d.height);
@@ -771,9 +780,9 @@ public class FeatureSettings extends Panel implements ItemListener,
            */
 
         }
-        else
+        else if (col.isGraduatedColour())
         {
-          Color maxCol = gcol.getMaxColor();
+          Color maxCol = col.getMaxColour();
           g.setColor(maxCol);
           g.fillRect(d.width / 2, 0, d.width / 2, d.height);
 
@@ -788,9 +797,30 @@ public class FeatureSettings extends Panel implements ItemListener,
     }
   }
 
+  /**
+   * Hide columns containing (or not containing) a given feature type
+   * 
+   * @param type
+   * @param 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))
+      {
+        ap.alignFrame.viewport.hideSelectedColumns();
+      }
+    }
+  }
+
   @Override
   public void mousePressed(MouseEvent e)
   {
+    // TODO Auto-generated method stub
+
   }
 
 }
index 16bba0b..d72e91f 100755 (executable)
@@ -138,11 +138,13 @@ public class IdCanvas extends Panel
     repaint();
   }
 
+  @Override
   public void update(Graphics g)
   {
     paint(g);
   }
 
+  @Override
   public void paint(Graphics g)
   {
     if (getSize().height < 0 || getSize().width < 0)
@@ -378,7 +380,7 @@ public class IdCanvas extends Panel
     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
             .getSize());
 
-    if (av.isHiddenRepSequence(seq))
+    if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
     {
       gg.setFont(bold);
       return true;
index 8f24f11..2cb3060 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,24 +85,22 @@ 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);
     }
   }
 
   Tooltip tooltip;
 
+  @Override
   public void mouseMoved(MouseEvent e)
   {
     int seq = alignPanel.seqPanel.findSeq(e);
@@ -188,6 +189,7 @@ public class IdPanel extends Panel implements MouseListener,
     tooltiptext = null;
   }
 
+  @Override
   public void mouseDragged(MouseEvent e)
   {
     mouseDragging = true;
@@ -207,6 +209,7 @@ public class IdPanel extends Panel implements MouseListener,
     alignPanel.paintAlignment(false);
   }
 
+  @Override
   public void mouseClicked(MouseEvent e)
   {
     if (e.getClickCount() < 2)
@@ -270,6 +273,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mouseEntered(MouseEvent e)
   {
     if (scrollThread != null)
@@ -278,6 +282,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mouseExited(MouseEvent e)
   {
     if (av.getWrapAlignment())
@@ -297,6 +302,7 @@ public class IdPanel extends Panel implements MouseListener,
     }
   }
 
+  @Override
   public void mousePressed(MouseEvent e)
   {
     if (e.getClickCount() > 1)
@@ -345,8 +351,8 @@ public class IdPanel extends Panel implements MouseListener,
     }
 
     if ((av.getSelectionGroup() == null)
-            || ((!e.isControlDown() && !e.isShiftDown()) && av
-                    .getSelectionGroup() != null))
+            || ((!jalview.util.Platform.isControlDown(e) && !e
+                    .isShiftDown()) && av.getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
       av.getSelectionGroup().setStartRes(0);
@@ -401,6 +407,7 @@ public class IdPanel extends Panel implements MouseListener,
 
   }
 
+  @Override
   public void mouseReleased(MouseEvent e)
   {
     if (scrollThread != null)
@@ -455,6 +462,7 @@ public class IdPanel extends Panel implements MouseListener,
       running = false;
     }
 
+    @Override
     public void run()
     {
       running = true;
index bc64728..9b2be4c 100755 (executable)
@@ -265,7 +265,8 @@ public class OverviewPanel extends Panel implements Runnable,
   {
     miniMe = null;
     int alwidth = av.getAlignment().getWidth();
-    int alheight = av.getAlignment().getHeight();
+    int alheight = av.getAlignment().getHeight()
+            + av.getAlignment().getHiddenSequences().getSize();
 
     if (av.isShowSequenceFeatures())
     {
@@ -304,6 +305,10 @@ public class OverviewPanel extends Panel implements Runnable,
     AlignmentI alignment = av.getAlignment();
     for (row = 0; row <= sequencesHeight; row++)
     {
+      if (resizeAgain)
+      {
+        break;
+      }
       if ((int) (row * sampleRow) == lastrow)
       {
         sameRow++;
@@ -385,6 +390,10 @@ public class OverviewPanel extends Panel implements Runnable,
     {
       for (col = 0; col < width; col++)
       {
+        if (resizeAgain)
+        {
+          break;
+        }
         lastcol = (int) (col * sampleCol);
         {
           mg.translate(col, sequencesHeight);
index 71ecb13..5a156fa 100755 (executable)
@@ -22,6 +22,8 @@ package jalview.appletgui;
 
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SequenceGroup;
+import jalview.renderer.ScaleRenderer;
+import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -36,6 +38,7 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.List;
 
 public class ScalePanel extends Panel implements MouseMotionListener,
         MouseListener
@@ -149,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
@@ -202,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);
           }
@@ -406,64 +408,69 @@ public class ScalePanel extends Panel implements MouseMotionListener,
 
     // Fill the selected columns
     ColumnSelection cs = av.getColumnSelection();
-    gg.setColor(new Color(220, 0, 0));
-    int avcharWidth = av.getCharWidth(), avcharHeight = av.getCharHeight();
-    for (int sel : cs.getSelected())
+    int avCharWidth = av.getCharWidth();
+    int avcharHeight = av.getCharHeight();
+    if (cs != null)
     {
-      // TODO: JAL-2001 - provide a fast method to list visible selected in a
-      // given range
-      if (av.hasHiddenColumns())
+      gg.setColor(new Color(220, 0, 0));
+      boolean hasHiddenColumns = cs.hasHiddenColumns();
+      for (int sel : cs.getSelected())
       {
-        sel = av.getColumnSelection().findColumnPosition(sel);
-      }
+        // TODO: JAL-2001 - provide a fast method to list visible selected in a
+        // given range
+        if (hasHiddenColumns)
+        {
+          if (cs.isVisible(sel))
+          {
+            sel = cs.findColumnPosition(sel);
+          }
+          else
+          {
+            continue;
+          }
+        }
 
-      if ((sel >= startx) && (sel <= endx))
-      {
-        gg.fillRect((sel - startx) * avcharWidth, 0, avcharWidth,
-                getSize().height);
+        if ((sel >= startx) && (sel <= endx))
+        {
+          gg.fillRect((sel - startx) * avCharWidth, 0, avCharWidth,
+                  getSize().height);
+        }
       }
     }
 
     // Draw the scale numbers
     gg.setColor(Color.black);
 
-    int scalestartx = (startx / 10) * 10;
-    int widthx = 1 + endx - startx;
-
-    FontMetrics fm = gg.getFontMetrics(av.getFont());
-    int y = avcharHeight - fm.getDescent();
-
-    if ((scalestartx % 10) == 0)
-    {
-      scalestartx += 5;
-    }
-
-    String string;
     int maxX = 0;
+    List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, startx,
+            endx);
 
-    for (int i = scalestartx; i < endx; i += 5)
+    FontMetrics fm = gg.getFontMetrics(av.getFont());
+    int y = avcharHeight;
+    int yOf = fm.getDescent();
+    y -= yOf;
+    for (ScaleMark mark : marks)
     {
-      if ((i % 10) == 0)
+      boolean major = mark.major;
+      int mpos = mark.column; // (i - startx - 1)
+      String mstring = mark.text;
+      if (mstring != null)
       {
-        string = String.valueOf(av.getColumnSelection()
-                .adjustForHiddenColumns(i));
-        if ((i - startx - 1) * avcharWidth > maxX)
+        if (mpos * avCharWidth > maxX)
         {
-          gg.drawString(string, (i - startx - 1) * avcharWidth, y);
-          maxX = (i - startx + 1) * avcharWidth + fm.stringWidth(string);
+          gg.drawString(mstring, mpos * avCharWidth, y);
+          maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring);
         }
-
-        gg.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2),
-                y + 2,
-                ((i - startx - 1) * avcharWidth) + (avcharWidth / 2), y
-                        + (fm.getDescent() * 2));
-
+      }
+      if (major)
+      {
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
       }
       else
       {
-        gg.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2), y
-                + fm.getDescent(), ((i - startx - 1) * avcharWidth)
-                + (avcharWidth / 2), y + (fm.getDescent() * 2));
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
       }
     }
 
@@ -473,33 +480,24 @@ public class ScalePanel extends Panel implements MouseMotionListener,
       int res;
       if (av.getShowHiddenMarkers())
       {
-        for (int i = 0; i < av.getColumnSelection().getHiddenColumns()
-                .size(); i++)
+        int widthx = 1 + endx - startx;
+        for (int i = 0; i < cs.getHiddenColumns().size(); i++)
         {
 
-          res = av.getColumnSelection().findHiddenRegionPosition(i)
-                  - startx;
+          res = cs.findHiddenRegionPosition(i) - startx;
 
           if (res < 0 || res > widthx)
           {
             continue;
           }
 
-          gg.fillPolygon(new int[] { res * avcharWidth - avcharHeight / 4,
-              res * avcharWidth + avcharHeight / 4, res * avcharWidth },
-                  new int[] { y - avcharHeight / 2, y - avcharHeight / 2,
-                      y + 8 }, 3);
-
+          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);
         }
       }
-
-      if (reveal != null && reveal[0] > startx && reveal[0] < endx)
-      {
-        gg.drawString(MessageManager.getString("label.reveal_columns"),
-                reveal[0] * avcharWidth, 0);
-      }
     }
-
   }
 
 }
index 024fdc7..7216bfe 100755 (executable)
@@ -24,6 +24,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.renderer.ScaleRenderer;
+import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.Color;
@@ -90,26 +92,29 @@ public class SeqCanvas extends Panel
 
   private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
   {
-    int scalestartx = startx - startx % 10 + 10;
-
+    updateViewport();
     g.setColor(Color.black);
-
-    // NORTH SCALE
-    for (int i = scalestartx; i < endx; i += 10)
+    for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx,
+            endx))
     {
-      int value = i;
-      if (av.hasHiddenColumns())
+      int mpos = mark.column; // (i - startx - 1)
+      if (mpos < 0)
       {
-        value = av.getColumnSelection().adjustForHiddenColumns(value);
+        continue;
       }
+      String mstring = mark.text;
 
-      g.drawString(String.valueOf(value), (i - startx - 1) * avcharWidth,
-              ypos - (avcharHeight / 2));
-
-      g.drawLine(((i - startx - 1) * avcharWidth) + (avcharWidth / 2),
-              (ypos + 2) - (avcharHeight / 2),
-              ((i - startx - 1) * avcharWidth) + (avcharWidth / 2),
-              ypos - 2);
+      if (mark.major)
+      {
+        if (mstring != null)
+        {
+          g.drawString(mstring, mpos * avcharWidth, ypos
+                  - (avcharHeight / 2));
+        }
+        g.drawLine((mpos * avcharWidth) + (avcharWidth / 2), (ypos + 2)
+                - (avcharHeight / 2), (mpos * avcharWidth)
+                + (avcharWidth / 2), ypos - 2);
+      }
     }
   }
 
index 479b746..6ca9499 100644 (file)
@@ -919,6 +919,14 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
   Tooltip tooltip;
 
+  /**
+   * set when the current UI interaction has resulted in a change that requires
+   * overview shading to be recalculated. this could be changed to something
+   * more expressive that indicates what actually has changed, so selective
+   * redraws can be applied
+   */
+  private boolean needOverviewUpdate; // TODO: refactor to avcontroller
+
   @Override
   public void mouseDragged(MouseEvent evt)
   {
@@ -1521,9 +1529,11 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     {
       return;
     }
-
-    stretchGroup.recalcConservation(); // always do this - annotation has own
-                                       // state
+    // always do this - annotation has own state
+    // but defer colourscheme update until hidden sequences are passed in
+    boolean vischange = stretchGroup.recalcConservation(true);
+    // here we rely on stretchGroup == av.getSelection()
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1540,11 +1550,12 @@ public class SeqPanel extends Panel implements MouseMotionListener,
                 stretchGroup.getName());
       }
     }
+    PaintRefresher.Refresh(ap, av.getSequenceSetId());
+    ap.paintAlignment(needOverviewUpdate);
+    needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
-    PaintRefresher.Refresh(ap, av.getSequenceSetId());
-    ap.paintAlignment(true);
     av.sendSelection();
   }
 
@@ -1596,6 +1607,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1603,6 +1615,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1636,6 +1649,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1645,6 +1659,7 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
 
         stretchGroup.addSequence(nextSeq, false);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1813,9 +1828,12 @@ public class SeqPanel extends Panel implements MouseMotionListener,
 
     // do we want to thread this ? (contention with seqsel and colsel locks, I
     // suspect)
-    // rules are: colsel is copied if there is a real intersection between
-    // sequence selection
-    boolean repaint = false, copycolsel = true;
+    /*
+     * only copy colsel if there is a real intersection between
+     * sequence selection and this panel's alignment
+     */
+    boolean repaint = false;
+    boolean copycolsel = false;
     if (av.getSelectionGroup() == null || !av.isSelectionGroupChanged(true))
     {
       SequenceGroup sgroup = null;
@@ -1832,11 +1850,9 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         }
         sgroup = seqsel.intersect(av.getAlignment(),
                 (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
-        if ((sgroup == null || sgroup.getSize() == 0)
-                && (colsel == null || colsel.isEmpty()))
+        if ((sgroup != null && sgroup.getSize() > 0))
         {
-          // don't copy columns if the region didn't intersect.
-          copycolsel = false;
+          copycolsel = true;
         }
       }
       if (sgroup != null && sgroup.getSize() > 0)
@@ -1964,7 +1980,6 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
             av);
     av.setColumnSelection(cs);
-    av.isColSelChanged(true);
 
     ap.scalePanelHolder.repaint();
     ap.repaint();
index 09b50c4..970d20e 100755 (executable)
@@ -32,6 +32,8 @@ import java.awt.Graphics;
 
 public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
+  final static int CHAR_TO_UPPER = 'A' - 'a';
+
   AlignViewport av;
 
   FontMetrics fm;
@@ -67,6 +69,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
     this.renderGaps = renderGaps;
   }
 
+  @Override
   public Color getResidueBoxColour(SequenceI seq, int i)
   {
     allGroups = av.getAlignment().findAllGroups(seq);
@@ -256,7 +259,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         }
         if (currentSequenceGroup.getShowNonconserved())
         {
-          s = getDisplayChar(srep, i, s, '.');
+          s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
         }
       }
       else
@@ -280,7 +283,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
         }
         if (av.getShowUnconserved())
         {
-          s = getDisplayChar(srep, i, s, '.');
+          s = getDisplayChar(srep, i, s, '.', null);
 
         }
       }
@@ -312,20 +315,43 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
 
   }
 
-  private char getDisplayChar(final boolean usesrep, int position, char s,
-          char c)
+  /**
+   * Returns 'conservedChar' to represent the given position if the sequence
+   * character at that position is equal to the consensus (ignoring case), else
+   * returns the sequence character
+   * 
+   * @param usesrep
+   * @param position
+   * @param sequenceChar
+   * @param conservedChar
+   * @return
+   */
+  private char getDisplayChar(final boolean usesrep, int position,
+          char sequenceChar, char conservedChar, SequenceGroup currentGroup)
   {
     // TODO - use currentSequenceGroup rather than alignment
     // currentSequenceGroup.getConsensus()
-    char conschar = (usesrep) ? av.getAlignment().getSeqrep()
-            .getCharAt(position)
-            : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
-                    .charAt(0);
-    if (!jalview.util.Comparison.isGap(conschar) && s == conschar)
+    char conschar = (usesrep) ? (currentGroup == null
+            || position < currentGroup.getStartRes()
+            || position > currentGroup.getEndRes() ? av.getAlignment()
+            .getSeqrep().getCharAt(position)
+            : (currentGroup.getSeqrep() != null ? currentGroup.getSeqrep()
+                    .getCharAt(position) : av.getAlignment().getSeqrep()
+                    .getCharAt(position)))
+            : (currentGroup != null && currentGroup.getConsensus() != null
+                    && position >= currentGroup.getStartRes()
+                    && position <= currentGroup.getEndRes() && currentGroup
+                    .getConsensus().annotations.length > position) ? currentGroup
+                    .getConsensus().annotations[position].displayCharacter
+                    .charAt(0)
+                    : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
+                            .charAt(0);
+    if (!jalview.util.Comparison.isGap(conschar)
+            && (sequenceChar == conschar || sequenceChar + CHAR_TO_UPPER == conschar))
     {
-      s = c;
+      sequenceChar = conservedChar;
     }
-    return s;
+    return sequenceChar;
   }
 
   boolean inCurrentSequenceGroup(int res)
index 2fc15d0..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_thereshold",
+    PIDSlider
+            .setTitle(MessageManager.formatMessage(
+                    "label.percentage_identity_threshold",
                     new String[] { source }));
 
     if (ap.av.getAlignment().getGroups() != null)
index edcd961..3b509e5 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,9 +676,8 @@ 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),
-                sg.getStartRes(), sg.getEndRes());
+        Conservation c = new Conservation("Group", 3,
+                sg.getSequences(null), sg.getStartRes(), sg.getEndRes());
 
         c.calculate();
         c.verdict(false, av.getConsPercGaps());
index 57cf669..88098a9 100644 (file)
  */
 package jalview.appletgui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SequenceGroup;
 import jalview.schemes.ColourSchemeI;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
@@ -59,7 +60,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   Button selectedButton;
 
-  Vector oldColours = new Vector();
+  Vector<Color> oldColours = new Vector<Color>();
 
   ColourSchemeI oldColourScheme;
 
@@ -75,7 +76,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   String originalLabel;
 
-  Object originalColour;
+  FeatureColourI originalColour;
 
   int R = 0, G = 0, B = 0;
 
@@ -117,7 +118,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
   public UserDefinedColours(FeatureRenderer fr, Frame alignframe)
   {
     caller = fr;
-    originalColour = fr.colourPanel.getBackground();
+    originalColour = new FeatureColour(fr.colourPanel.getBackground());
     originalLabel = "Feature Colour";
     setForDialog("Select Feature Colour", alignframe);
     setTargetColour(fr.colourPanel.getBackground());
@@ -134,21 +135,21 @@ public class UserDefinedColours extends Panel implements ActionListener,
    * 
    * @param caller
    *          - handles events
-   * @param col1
+   * @param col
    *          - original colour
    * @param alignframe
    *          - the parent Frame for the dialog
    * @param title
    *          - window title
    */
-  public UserDefinedColours(Component caller, Color col1, Frame alignframe,
+  public UserDefinedColours(Component caller, Color col, Frame alignframe,
           String title)
   {
     this.caller = caller;
-    originalColour = col1;
+    originalColour = new FeatureColour(col);
     originalLabel = title;
     setForDialog(title, alignframe);
-    setTargetColour(col1);
+    setTargetColour(col);
     dialog.setVisible(true);
   }
 
@@ -161,7 +162,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
    */
   public UserDefinedColours(Object caller, String label, Color colour)
   {
-    this(caller, label, colour, colour);
+    this(caller, label, new FeatureColour(colour), colour);
   }
 
   /**
@@ -172,13 +173,13 @@ public class UserDefinedColours extends Panel implements ActionListener,
    * @param graduatedColor
    */
   public UserDefinedColours(FeatureSettings me, String type,
-          GraduatedColor graduatedColor)
+          FeatureColourI graduatedColor)
   {
-    this(me, type, graduatedColor, graduatedColor.getMaxColor());
+    this(me, type, graduatedColor, graduatedColor.getMaxColour());
   }
 
-  private UserDefinedColours(Object caller, String label, Object ocolour,
-          Color colour)
+  private UserDefinedColours(Object caller, String label,
+          FeatureColourI ocolour, Color colour)
   {
     this.caller = caller;
     originalColour = ocolour;
@@ -228,6 +229,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   }
 
+  @Override
   public void actionPerformed(ActionEvent evt)
   {
     final Object source = evt.getSource();
@@ -257,6 +259,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     }
   }
 
+  @Override
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
     if (evt.getSource() == rScroller)
@@ -420,6 +423,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     button.setFont(new java.awt.Font("Verdana", 1, 10));
     button.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         colourButtonPressed(e);
@@ -451,7 +455,8 @@ public class UserDefinedColours extends Panel implements ActionListener,
     {
       if (caller instanceof FeatureSettings)
       {
-        ((FeatureSettings) caller).setUserColour(originalLabel, getColor());
+        ((FeatureSettings) caller).setUserColour(originalLabel,
+                new FeatureColour(getColor()));
       }
       else if (caller instanceof AnnotationColourChooser)
       {
@@ -468,7 +473,8 @@ public class UserDefinedColours extends Panel implements ActionListener,
       }
       else if (caller instanceof FeatureRenderer)
       {
-        ((FeatureRenderer) caller).colourPanel.updateColor(getColor());
+        ((FeatureRenderer) caller).colourPanel
+                .updateColor(new FeatureColour(getColor()));
       }
       else if (caller instanceof FeatureColourChooser)
       {
@@ -537,12 +543,12 @@ public class UserDefinedColours extends Panel implements ActionListener,
         if (originalLabel.equals("Min Colour"))
         {
           ((AnnotationColourChooser) caller)
-                  .minColour_actionPerformed((Color) originalColour);
+                  .minColour_actionPerformed(originalColour.getColour());
         }
         else
         {
           ((AnnotationColourChooser) caller)
-                  .maxColour_actionPerformed((Color) originalColour);
+                  .maxColour_actionPerformed(originalColour.getColour());
         }
       }
       else if (caller instanceof FeatureRenderer)
@@ -556,12 +562,12 @@ public class UserDefinedColours extends Panel implements ActionListener,
         if (originalLabel.indexOf("inimum") > -1)
         {
           ((FeatureColourChooser) caller)
-                  .minColour_actionPerformed((Color) originalColour);
+                  .minColour_actionPerformed(originalColour.getColour());
         }
         else
         {
           ((FeatureColourChooser) caller)
-                  .maxColour_actionPerformed((Color) originalColour);
+                  .maxColour_actionPerformed(originalColour.getColour());
         }
       }
       if (dialog != null)
@@ -576,7 +582,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
     Color[] newColours = new Color[24];
     for (int i = 0; i < 24; i++)
     {
-      newColours[i] = (Color) oldColours.elementAt(i);
+      newColours[i] = oldColours.elementAt(i);
       buttonPanel.getComponent(i).setBackground(newColours[i]);
     }
 
diff --git a/src/jalview/bin/ArgsParser.java b/src/jalview/bin/ArgsParser.java
new file mode 100644 (file)
index 0000000..c927f1f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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;
+import java.util.Vector;
+
+/**
+ * Notes: this argParser does not distinguish between parameter switches,
+ * parameter values and argument text. If an argument happens to be identical to
+ * a parameter, it will be taken as such (even though it didn't have a '-'
+ * prefixing it).
+ * 
+ * @author Andrew Waterhouse and JBP documented.
+ * 
+ */
+public class ArgsParser
+{
+  Vector<String> vargs = null;
+
+  public ArgsParser(String[] args)
+  {
+    vargs = new Vector<String>();
+    for (int i = 0; i < args.length; i++)
+    {
+      String arg = args[i].trim();
+      if (arg.charAt(0) == '-')
+      {
+        arg = arg.substring(1);
+      }
+      vargs.addElement(arg);
+    }
+  }
+
+  /**
+   * check for and remove first occurence of arg+parameter in arglist.
+   * 
+   * @param arg
+   * @return return the argument following the given arg if arg was in list.
+   */
+  public String getValue(String arg)
+  {
+    return getValue(arg, false);
+  }
+
+  public String getValue(String arg, boolean utf8decode)
+  {
+    int index = vargs.indexOf(arg);
+    String dc = null, ret = null;
+    if (index != -1)
+    {
+      ret = vargs.elementAt(index + 1).toString();
+      vargs.removeElementAt(index);
+      vargs.removeElementAt(index);
+      if (utf8decode && ret != null)
+      {
+        try
+        {
+          dc = URLDecoder.decode(ret, "UTF-8");
+          ret = dc;
+        } catch (Exception e)
+        {
+          // TODO: log failure to decode
+        }
+      }
+    }
+    return ret;
+  }
+
+  /**
+   * check for and remove first occurence of arg in arglist.
+   * 
+   * @param arg
+   * @return true if arg was present in argslist.
+   */
+  public boolean contains(String arg)
+  {
+    if (vargs.contains(arg))
+    {
+      vargs.removeElement(arg);
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  public String nextValue()
+  {
+    return vargs.remove(0);
+  }
+
+  public int getSize()
+  {
+    return vargs.size();
+  }
+
+}
index 7911cd5..8412dab 100755 (executable)
@@ -20,8 +20,8 @@
  */
 package jalview.bin;
 
-import jalview.datamodel.DBRefSource;
-import jalview.ws.dbsources.Pdb;
+import jalview.datamodel.PDBEntry;
+import jalview.structure.StructureImportSettings;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
 import jalview.ws.dbsources.das.datamodel.DasSourceRegistry;
 import jalview.ws.sifts.SiftsSettings;
@@ -38,6 +38,7 @@ import java.text.SimpleDateFormat;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
+import java.util.Locale;
 import java.util.Properties;
 import java.util.TreeSet;
 
@@ -228,7 +229,23 @@ public class Cache
 
   private final static String DEFAULT_FAIL_SAFE_PID_THRESHOLD = "30";
 
-  private final static String DEFAULT_STRUCTURE_FORMAT = DBRefSource.PDB;
+  /**
+   * Allowed values are PDB or mmCIF
+   */
+  private final static String PDB_DOWNLOAD_FORMAT = PDBEntry.Type.MMCIF
+          .toString();
+
+  private final static String DEFAULT_PDB_FILE_PARSER = StructureImportSettings.StructureParser.JMOL_PARSER
+          .toString();
+
+  /*
+   * a date formatter using a fixed (rather than the user's) locale; 
+   * this ensures that date properties can be written and re-read successfully
+   * even if the user changes their locale setting
+   */
+  private static final DateFormat date_format = SimpleDateFormat
+          .getDateTimeInstance(SimpleDateFormat.MEDIUM,
+                  SimpleDateFormat.MEDIUM, Locale.UK);
 
   /**
    * Initialises the Jalview Application Log
@@ -426,8 +443,13 @@ public class Cache
     System.out
             .println("Jalview Version: " + codeVersion + codeInstallation);
 
-    Pdb.setCurrentDefaultFomart(jalview.bin.Cache.getDefault(
-            "DEFAULT_STRUCTURE_FORMAT", DEFAULT_STRUCTURE_FORMAT));
+    StructureImportSettings.setDefaultStructureFileFormat(jalview.bin.Cache
+            .getDefault("PDB_DOWNLOAD_FORMAT", PDB_DOWNLOAD_FORMAT));
+    StructureImportSettings
+            .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
@@ -874,30 +896,31 @@ public class Cache
     setProperty(property, jalview.util.Format.getHexString(colour));
   }
 
-  public static final DateFormat date_format = SimpleDateFormat
-          .getDateTimeInstance();
-
   /**
-   * store a date in a jalview property
+   * Stores a formatted date in a jalview property, using a fixed locale.
    * 
-   * @param string
-   * @param time
+   * @param propertyName
+   * @param date
+   * @return the formatted date string
    */
-  public static void setDateProperty(String property, Date time)
+  public static String setDateProperty(String propertyName, Date date)
   {
-    setProperty(property, date_format.format(time));
+    String formatted = date_format.format(date);
+    setProperty(propertyName, formatted);
+    return formatted;
   }
 
   /**
-   * read a date stored in a jalview property
+   * Reads a date stored in a Jalview property, parses it (using a fixed locale
+   * format) and returns as a Date, or null if parsing fails
    * 
-   * @param property
-   * @return valid date as stored by setDateProperty, or null
+   * @param propertyName
+   * @return
    * 
    */
-  public static Date getDateProperty(String property)
+  public static Date getDateProperty(String propertyName)
   {
-    String val = getProperty(property);
+    String val = getProperty(propertyName);
     if (val != null)
     {
       try
@@ -906,7 +929,7 @@ public class Cache
       } catch (Exception ex)
       {
         System.err.println("Invalid or corrupt date in property '"
-                + property + "' : value was '" + val + "'");
+                + propertyName + "' : value was '" + val + "'");
       }
     }
     return null;
index 8fe3bca..164ba27 100755 (executable)
  */
 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;
+import jalview.io.AppletFormatAdapter;
 import jalview.io.BioJsHTMLOutput;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
 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;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.jws2.Jws2Discoverer;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
-import java.net.URLDecoder;
 import java.security.AllPermission;
 import java.security.CodeSource;
 import java.security.PermissionCollection;
@@ -51,7 +62,6 @@ import java.util.Map;
 import java.util.Vector;
 
 import javax.swing.UIManager;
-import javax.swing.UnsupportedLookAndFeelException;
 
 /**
  * Main class for Jalview Application <br>
@@ -63,11 +73,21 @@ import javax.swing.UnsupportedLookAndFeelException;
  */
 public class Jalview
 {
+  /*
+   * singleton instance of this class
+   */
+  private static Jalview instance;
+
+  private Desktop desktop;
+
+  public static AlignFrame currentAlignFrame;
+
   static
   {
     // grab all the rights we can the JVM
     Policy.setPolicy(new Policy()
     {
+      @Override
       public PermissionCollection getPermissions(CodeSource codesource)
       {
         Permissions perms = new Permissions();
@@ -75,6 +95,7 @@ public class Jalview
         return (perms);
       }
 
+      @Override
       public void refresh()
       {
       }
@@ -82,6 +103,71 @@ public class Jalview
   }
 
   /**
+   * keep track of feature fetching tasks.
+   * 
+   * @author JimP
+   * 
+   */
+  class FeatureFetcher
+  {
+    /*
+     * TODO: generalise to track all jalview events to orchestrate batch
+     * processing events.
+     */
+
+    private int queued = 0;
+
+    private int running = 0;
+
+    public FeatureFetcher()
+    {
+
+    }
+
+    public void addFetcher(final AlignFrame af,
+            final Vector<String> dasSources)
+    {
+      final long id = System.currentTimeMillis();
+      queued++;
+      final FeatureFetcher us = this;
+      new Thread(new Runnable()
+      {
+
+        @Override
+        public void run()
+        {
+          synchronized (us)
+          {
+            queued--;
+            running++;
+          }
+
+          af.setProgressBar(MessageManager
+                  .getString("status.das_features_being_retrived"), id);
+          af.featureSettings_actionPerformed(null);
+          af.featureSettings.fetchDasFeatures(dasSources, true);
+          af.setProgressBar(null, id);
+          synchronized (us)
+          {
+            running--;
+          }
+        }
+      }).start();
+    }
+
+    public synchronized boolean allFinished()
+    {
+      return queued == 0 && running == 0;
+    }
+
+  }
+
+  public static Jalview getInstance()
+  {
+    return instance;
+  }
+
+  /**
    * main class for Jalview application
    * 
    * @param args
@@ -89,6 +175,16 @@ public class Jalview
    */
   public static void main(String[] args)
   {
+    instance = new Jalview();
+    instance.doMain(args);
+  }
+
+  /**
+   * @param args
+   */
+  void doMain(String[] args)
+  {
+    System.setSecurityManager(null);
     System.out.println("Java version: "
             + System.getProperty("java.version"));
     System.out.println(System.getProperty("os.arch") + " "
@@ -161,7 +257,7 @@ public class Jalview
     try
     {
       Cache.initLogger();
-    } catch (java.lang.NoClassDefFoundError error)
+    } catch (NoClassDefFoundError error)
     {
       error.printStackTrace();
       System.out
@@ -170,7 +266,7 @@ public class Jalview
       System.exit(0);
     }
 
-    Desktop desktop = null;
+    desktop = null;
 
     try
     {
@@ -178,7 +274,7 @@ public class Jalview
     } catch (Exception ex)
     {
     }
-    if (new Platform().isAMac())
+    if (Platform.isAMac())
     {
       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
               "Jalview");
@@ -187,13 +283,22 @@ public class Jalview
       {
         UIManager.setLookAndFeel(ch.randelshofer.quaqua.QuaquaManager
                 .getLookAndFeel());
-      } catch (UnsupportedLookAndFeelException e)
+      } catch (Throwable e)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
+        System.err.println("Failed to set QuaQua look and feel: "
+                + e.toString());
       }
     }
 
+    /*
+     * 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();
@@ -234,7 +339,6 @@ public class Jalview
             Cache.log.debug("Starting questionnaire with default url: "
                     + defurl);
             desktop.checkForQuestionnaire(defurl);
-
           }
         }
       }
@@ -242,17 +346,19 @@ public class Jalview
       {
         System.err.println("CMD [-noquestionnaire] executed successfully!");
       }
-      desktop.checkForNews();
-    }
 
-    if (!isHeadlessMode())
-    {
+      if (!aparser.contains("nonews"))
+      {
+        desktop.checkForNews();
+      }
+
       BioJsHTMLOutput.updateBioJS();
     }
 
     String file = null, protocol = null, format = null, data = null;
-    jalview.io.FileLoader fileLoader = new jalview.io.FileLoader(!headless);
-    Vector getFeatures = null; // vector of das source nicknames to fetch
+    FileLoader fileLoader = new FileLoader(!headless);
+    Vector<String> getFeatures = null; // vector of das source nicknames to
+                                       // fetch
     // features from
     // loading is done.
     String groovyscript = null; // script to execute after all loading is
@@ -266,8 +372,8 @@ public class Jalview
       System.out.println("No files to open!");
       System.exit(1);
     }
-    String vamsasImport = aparser.getValue("vdoc"), vamsasSession = aparser
-            .getValue("vsess");
+    String vamsasImport = aparser.getValue("vdoc");
+    String vamsasSession = aparser.getValue("vsess");
     if (vamsasImport != null || vamsasSession != null)
     {
       if (desktop == null || headless)
@@ -282,13 +388,13 @@ public class Jalview
       {
         try
         {
-          String viprotocol = jalview.io.AppletFormatAdapter
+          String viprotocol = AppletFormatAdapter
                   .checkProtocol(vamsasImport);
           if (viprotocol == jalview.io.FormatAdapter.FILE)
           {
             inSession = desktop.vamsasImport(new File(vamsasImport));
           }
-          else if (viprotocol == jalview.io.FormatAdapter.URL)
+          else if (viprotocol == FormatAdapter.URL)
           {
             inSession = desktop.vamsasImport(new URL(vamsasImport));
           }
@@ -365,7 +471,7 @@ public class Jalview
 
       if (!file.startsWith("http://"))
       {
-        if (!(new java.io.File(file)).exists())
+        if (!(new File(file)).exists())
         {
           System.out.println("Can't find " + file);
           if (headless)
@@ -375,9 +481,9 @@ public class Jalview
         }
       }
 
-      protocol = jalview.io.AppletFormatAdapter.checkProtocol(file);
+      protocol = AppletFormatAdapter.checkProtocol(file);
 
-      format = new jalview.io.IdentifyFile().identify(file, protocol);
+      format = new IdentifyFile().identify(file, protocol);
 
       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
               format);
@@ -387,19 +493,18 @@ public class Jalview
       }
       else
       {
-        Desktop.setCurrentAlignFrame(af);
+        setCurrentAlignFrame(af);
         data = aparser.getValue("colour", true);
         if (data != null)
         {
           data.replaceAll("%20", " ");
 
-          jalview.schemes.ColourSchemeI cs = jalview.schemes.ColourSchemeProperty
-                  .getColour(af.getViewport().getAlignment(), data);
+          ColourSchemeI cs = ColourSchemeProperty.getColour(af
+                  .getViewport().getAlignment(), data);
 
           if (cs == null)
           {
-            jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme(
-                    "white");
+            UserColourScheme ucs = new UserColourScheme("white");
             ucs.parseAppletParameter(data);
             cs = ucs;
           }
@@ -416,7 +521,7 @@ public class Jalview
         if (data != null)
         {
           af.parseFeaturesFile(data,
-                  jalview.io.AppletFormatAdapter.checkProtocol(data));
+                  AppletFormatAdapter.checkProtocol(data));
           // System.out.println("Added " + data);
           System.out.println("CMD groups[-" + data
                   + "]  executed successfully!");
@@ -425,7 +530,7 @@ public class Jalview
         if (data != null)
         {
           af.parseFeaturesFile(data,
-                  jalview.io.AppletFormatAdapter.checkProtocol(data));
+                  AppletFormatAdapter.checkProtocol(data));
           // System.out.println("Added " + data);
           System.out.println("CMD [-features " + data
                   + "]  executed successfully!");
@@ -473,8 +578,8 @@ public class Jalview
           {
             System.out.println("CMD [-tree " + data
                     + "] executed successfully!");
-            fin = new jalview.io.NewickFile(data,
-                    jalview.io.AppletFormatAdapter.checkProtocol(data));
+            fin = new NewickFile(data,
+                    AppletFormatAdapter.checkProtocol(data));
             if (fin != null)
             {
               af.getViewport().setCurrentTree(
@@ -514,20 +619,10 @@ public class Jalview
         {
           // Execute the groovy script after we've done all the rendering stuff
           // and before any images or figures are generated.
-          if (jalview.bin.Cache.groovyJarsPresent())
-          {
-            System.out.println("Executing script " + groovyscript);
-            executeGroovyScript(groovyscript, new Object[] { desktop, af });
-
-            System.out.println("CMD groovy[" + groovyscript
-                    + "] executed successfully!");
-          }
-          else
-          {
-            System.err
-                    .println("Sorry. Groovy Support is not available, so ignoring the provided groovy script "
-                            + groovyscript);
-          }
+          System.out.println("Executing script " + groovyscript);
+          executeGroovyScript(groovyscript, af);
+          System.out.println("CMD groovy[" + groovyscript
+                  + "] executed successfully!");
           groovyscript = null;
         }
         String imageName = "unnamed.png";
@@ -538,14 +633,14 @@ public class Jalview
 
           if (format.equalsIgnoreCase("png"))
           {
-            af.createPNG(new java.io.File(file));
-            imageName = (new java.io.File(file)).getName();
+            af.createPNG(new File(file));
+            imageName = (new File(file)).getName();
             System.out.println("Creating PNG image: " + file);
             continue;
           }
           else if (format.equalsIgnoreCase("svg"))
           {
-            File imageFile = new java.io.File(file);
+            File imageFile = new File(file);
             imageName = imageFile.getName();
             af.createSVG(imageFile);
             System.out.println("Creating SVG image: " + file);
@@ -553,21 +648,37 @@ public class Jalview
           }
           else if (format.equalsIgnoreCase("html"))
           {
-            File imageFile = new java.io.File(file);
+            File imageFile = new File(file);
             imageName = imageFile.getName();
-            new HtmlSvgOutput(new java.io.File(file), af.alignPanel);
+            new HtmlSvgOutput(new File(file), af.alignPanel);
             System.out.println("Creating HTML image: " + file);
             continue;
           }
+          else if (format.equalsIgnoreCase("biojsmsa"))
+          {
+            BioJsHTMLOutput.updateBioJS();
+            try
+            {
+              Thread.sleep(1500);
+            } catch (InterruptedException e)
+            {
+              e.printStackTrace();
+            }
+            BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel, af);
+            bjs.exportJalviewAlignmentAsBioJsHtmlFile(file);
+            System.out.println("Creating BioJS MSA Viwer HTML file: "
+                    + file);
+            continue;
+          }
           else if (format.equalsIgnoreCase("imgMap"))
           {
-            af.createImageMap(new java.io.File(file), imageName);
+            af.createImageMap(new File(file), imageName);
             System.out.println("Creating image map: " + file);
             continue;
           }
           else if (format.equalsIgnoreCase("eps"))
           {
-            File outputFile = new java.io.File(file);
+            File outputFile = new File(file);
             System.out.println("Creating EPS file: "
                     + outputFile.getAbsolutePath());
             af.createEPS(outputFile);
@@ -627,7 +738,7 @@ public class Jalview
       }
       else
       {
-        format = new jalview.io.IdentifyFile().identify(file, protocol);
+        format = new IdentifyFile().identify(file, protocol);
       }
 
       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
@@ -649,11 +760,10 @@ public class Jalview
     // Once all other stuff is done, execute any groovy scripts (in order)
     if (groovyscript != null)
     {
-      if (jalview.bin.Cache.groovyJarsPresent())
+      if (Cache.groovyJarsPresent())
       {
         System.out.println("Executing script " + groovyscript);
-        executeGroovyScript(groovyscript, new Object[] { desktop,
-            startUpAlframe });
+        executeGroovyScript(groovyscript, startUpAlframe);
       }
       else
       {
@@ -695,10 +805,12 @@ 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"
                     + "-noquestionnaire\tTurn off questionnaire check.\n"
+                    + "-nonews\tTurn off check for Jalview news.\n"
                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
                     // +
@@ -720,8 +832,8 @@ public class Jalview
     /**
      * start a User Config prompt asking if we can log usage statistics.
      */
-    jalview.gui.PromptUserConfig prompter = new jalview.gui.PromptUserConfig(
-            desktop.desktop,
+    PromptUserConfig prompter = new PromptUserConfig(
+            Desktop.desktop,
             "USAGESTATS",
             "Jalview Usage Statistics",
             "Do you want to help make Jalview better by enabling "
@@ -729,6 +841,7 @@ public class Jalview
                     + "\n\n(you can enable or disable usage tracking in the preferences)",
             new Runnable()
             {
+              @Override
               public void run()
               {
                 Cache.log
@@ -738,6 +851,7 @@ public class Jalview
               }
             }, new Runnable()
             {
+              @Override
               public void run()
               {
                 Cache.log.debug("Not enabling Google Tracking.");
@@ -755,14 +869,8 @@ public class Jalview
    *          the Jalview Desktop object passed in to the groovy binding as the
    *          'Jalview' object.
    */
-  private static void executeGroovyScript(String groovyscript,
-          Object[] jalviewContext)
+  private void executeGroovyScript(String groovyscript, AlignFrame af)
   {
-    if (jalviewContext == null)
-    {
-      System.err
-              .println("Sorry. Groovy support is currently only available when running with the Jalview GUI enabled.");
-    }
     /**
      * for scripts contained in files
      */
@@ -779,8 +887,8 @@ public class Jalview
         tfile = File.createTempFile("jalview", "groovy");
         PrintWriter outfile = new PrintWriter(new OutputStreamWriter(
                 new FileOutputStream(tfile)));
-        BufferedReader br = new BufferedReader(
-                new java.io.InputStreamReader(System.in));
+        BufferedReader br = new BufferedReader(new InputStreamReader(
+                System.in));
         String line = null;
         while ((line = br.readLine()) != null)
         {
@@ -844,75 +952,23 @@ public class Jalview
         }
       }
     }
-    boolean success = false;
     try
     {
-      /*
-       * The following code performs the GroovyScriptEngine invocation using
-       * reflection, and is equivalent to this fragment from the embedding
-       * groovy documentation on the groovy site: <code> import
-       * groovy.lang.Binding; import groovy.util.GroovyScriptEngine;
-       * 
-       * String[] roots = new String[] { "/my/groovy/script/path" };
-       * GroovyScriptEngine gse = new GroovyScriptEngine(roots); Binding binding
-       * = new Binding(); binding.setVariable("input", "world");
-       * gse.run("hello.groovy", binding); </code>
-       */
-      Class<?>[] bspec;
-      Object[] binding;
-      int blen = ((jalviewContext[0] == null) ? 0 : 1)
-              + ((jalviewContext[1] == null) ? 0 : 1);
-      String cnames[] = new String[] { "Jalview", "currentAlFrame" };
-      bspec = new Class[blen * 2];
-      binding = new Object[blen * 2];
-      blen = 0;
-      ClassLoader cl = null;
       Map<String, Object> vbinding = new HashMap<String, Object>();
-      for (int jc = 0; jc < jalviewContext.length; jc++)
+      vbinding.put("Jalview", this);
+      if (af != null)
       {
-        if (jalviewContext[jc] != null)
-        {
-          if (cl == null)
-          {
-            cl = jalviewContext[jc].getClass().getClassLoader();
-          }
-          bspec[blen * 2] = String.class;
-          bspec[blen * 2 + 1] = Object.class;
-          binding[blen * 2] = cnames[jc];
-          binding[blen * 2 + 1] = jalviewContext[jc];
-          vbinding.put(cnames[jc], jalviewContext[jc]);
-          blen++;
-        }
+        vbinding.put("currentAlFrame", af);
       }
-      Class<?> gbindingc = cl.loadClass("groovy.lang.Binding");
-      Constructor<?> gbcons;
-      Object gbinding;
-      try
-      {
-        gbcons = gbindingc.getConstructor(Map.class);
-        gbinding = gbcons.newInstance(vbinding);
-      } catch (NoSuchMethodException x)
+      Binding gbinding = new Binding(vbinding);
+      GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
+      gse.run(sfile.toString(), gbinding);
+      if ("STDIN".equals(groovyscript))
       {
-        // old style binding config - using series of string/object values to
-        // setVariable.
-        gbcons = gbindingc.getConstructor();
-        gbinding = gbcons.newInstance();
-        java.lang.reflect.Method setvar = gbindingc.getMethod(
-                "setVariable", bspec);
-        setvar.invoke(gbinding, binding);
+        // delete temp file that we made -
+        // only if it was successfully executed
+        tfile.delete();
       }
-
-      Class<?> gsec = cl.loadClass("groovy.util.GroovyScriptEngine");
-      Constructor<?> gseccons = gsec
-              .getConstructor(new Class[] { URL[].class }); // String[].class
-                                                            // });
-      Object gse = gseccons
-              .newInstance(new Object[] { new URL[] { sfile } }); // .toString()
-                                                                  // } });
-      java.lang.reflect.Method run = gsec.getMethod("run", new Class[] {
-          String.class, gbindingc });
-      run.invoke(gse, new Object[] { sfile.toString(), gbinding });
-      success = true;
     } catch (Exception e)
     {
       System.err.println("Exception Whilst trying to execute file " + sfile
@@ -920,12 +976,6 @@ public class Jalview
       e.printStackTrace(System.err);
 
     }
-    if (success && groovyscript.equals("STDIN"))
-    {
-      // delete temp file that we made - but only if it was successfully
-      // executed
-      tfile.delete();
-    }
   }
 
   /**
@@ -933,16 +983,15 @@ public class Jalview
    * 
    * @return vector of DAS source nicknames to retrieve from
    */
-  private static Vector checkDasArguments(ArgsParser aparser)
+  private static Vector<String> checkDasArguments(ArgsParser aparser)
   {
-    Vector source = null;
+    Vector<String> source = null;
     String data;
     String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
     while ((data = aparser.getValue("dasserver", true)) != null)
     {
       String nickname = null;
       String url = null;
-      boolean seq = false, feat = true;
       int pos = data.indexOf('=');
       // determine capabilities
       if (pos > 0)
@@ -972,7 +1021,7 @@ public class Jalview
                         + nickname + "|" + url);
         if (source == null)
         {
-          source = new Vector();
+          source = new Vector<String>();
         }
         source.addElement(nickname);
       }
@@ -990,7 +1039,7 @@ public class Jalview
       System.out.println("adding source '" + data + "'");
       if (source == null)
       {
-        source = new Vector();
+        source = new Vector<String>();
       }
       source.addElement(data);
     }
@@ -1002,7 +1051,8 @@ public class Jalview
    * 
    * @param dasSources
    */
-  private static FeatureFetcher startFeatureFetching(final Vector dasSources)
+  private FeatureFetcher startFeatureFetching(
+          final Vector<String> dasSources)
   {
     FeatureFetcher ff = new FeatureFetcher();
     AlignFrame afs[] = Desktop.getAlignFrames();
@@ -1026,173 +1076,37 @@ public class Jalview
     }
     return false;
   }
-}
-
-/**
- * Notes: this argParser does not distinguish between parameter switches,
- * parameter values and argument text. If an argument happens to be identical to
- * a parameter, it will be taken as such (even though it didn't have a '-'
- * prefixing it).
- * 
- * @author Andrew Waterhouse and JBP documented.
- * 
- */
-
-class rnabuttonlistener implements ActionListener
-{
-  public void actionPerformed(ActionEvent arg0)
-  {
-    System.out.println("Good idea ! ");
-
-  }
-}
 
-class pbuttonlistener implements ActionListener
-{
-  public void actionPerformed(ActionEvent arg0)
+  public AlignFrame[] getAlignFrames()
   {
+    return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
+            : Desktop.getAlignFrames();
 
   }
-}
-
-class ArgsParser
-{
-  Vector vargs = null;
-
-  public ArgsParser(String[] args)
-  {
-    vargs = new Vector();
-    for (int i = 0; i < args.length; i++)
-    {
-      String arg = args[i].trim();
-      if (arg.charAt(0) == '-')
-      {
-        arg = arg.substring(1);
-      }
-      vargs.addElement(arg);
-    }
-  }
-
-  /**
-   * check for and remove first occurence of arg+parameter in arglist.
-   * 
-   * @param arg
-   * @return return the argument following the given arg if arg was in list.
-   */
-  public String getValue(String arg)
-  {
-    return getValue(arg, false);
-  }
-
-  public String getValue(String arg, boolean utf8decode)
-  {
-    int index = vargs.indexOf(arg);
-    String dc = null, ret = null;
-    if (index != -1)
-    {
-      ret = vargs.elementAt(index + 1).toString();
-      vargs.removeElementAt(index);
-      vargs.removeElementAt(index);
-      if (utf8decode && ret != null)
-      {
-        try
-        {
-          dc = URLDecoder.decode(ret, "UTF-8");
-          ret = dc;
-        } catch (Exception e)
-        {
-          // TODO: log failure to decode
-        }
-      }
-    }
-    return ret;
-  }
 
   /**
-   * check for and remove first occurence of arg in arglist.
-   * 
-   * @param arg
-   * @return true if arg was present in argslist.
+   * Quit method delegates to Desktop.quit - unless running in headless mode
+   * when it just ends the JVM
    */
-  public boolean contains(String arg)
+  public void quit()
   {
-    if (vargs.contains(arg))
+    if (desktop != null)
     {
-      vargs.removeElement(arg);
-      return true;
+      desktop.quit();
     }
     else
     {
-      return false;
+      System.exit(0);
     }
   }
 
-  public String nextValue()
+  public static AlignFrame getCurrentAlignFrame()
   {
-    return vargs.remove(0).toString();
+    return Jalview.currentAlignFrame;
   }
 
-  public int getSize()
+  public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
   {
-    return vargs.size();
+    Jalview.currentAlignFrame = currentAlignFrame;
   }
-
-}
-
-/**
- * keep track of feature fetching tasks.
- * 
- * @author JimP
- * 
- */
-class FeatureFetcher
-{
-  /*
-   * TODO: generalise to track all jalview events to orchestrate batch
-   * processing events.
-   */
-
-  private int queued = 0;
-
-  private int running = 0;
-
-  public FeatureFetcher()
-  {
-
-  }
-
-  public void addFetcher(final AlignFrame af, final Vector dasSources)
-  {
-    final long id = System.currentTimeMillis();
-    queued++;
-    final FeatureFetcher us = this;
-    new Thread(new Runnable()
-    {
-
-      public void run()
-      {
-        synchronized (us)
-        {
-          queued--;
-          running++;
-        }
-
-        af.setProgressBar(MessageManager
-                .getString("status.das_features_being_retrived"), id);
-        af.featureSettings_actionPerformed(null);
-        af.featureSettings.fetchDasFeatures(dasSources, true);
-        af.setProgressBar(null, id);
-        synchronized (us)
-        {
-          running--;
-        }
-      }
-    }).start();
-  }
-
-  public synchronized boolean allFinished()
-  {
-    return queued == 0 && running == 0;
-  }
-
 }
index 13e4b7e..b30ad41 100644 (file)
@@ -466,17 +466,11 @@ public class JalviewLite extends Applet implements
         SequenceI rs = sel.getSequenceAt(0);
         start = rs.findIndex(start);
         end = rs.findIndex(end);
-        if (csel != null)
-        {
-          List<Integer> cs = csel.getSelected();
-          // note - the following actually clears cs as well, since
-          // csel.getSelected returns a reference. Need to check if we need to
-          // have a concurrentModification exception thrown here
-          csel.clear();
-          for (Integer selectedCol : cs)
-          {
-            csel.addElement(rs.findIndex(selectedCol));
-          }
+        List<Integer> cs = new ArrayList<Integer>(csel.getSelected());
+        csel.clear();
+        for (Integer selectedCol : cs)
+        {
+          csel.addElement(rs.findIndex(selectedCol));
         }
       }
       sel.setStartRes(start);
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 ca2ae6d..f508bc3 100644 (file)
@@ -169,150 +169,136 @@ public class AlignViewController implements AlignViewControllerI
     // JBPNote this routine could also mark rows, not just columns.
     // need a decent query structure to allow all types of feature searches
     BitSet bs = new BitSet();
-    int alw, alStart;
-    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null ? viewport
-            .getAlignment() : viewport.getSelectionGroup());
-    alStart = sqcol.getStartRes();
-    alw = sqcol.getEndRes() + 1;
+    SequenceCollectionI sqcol = (viewport.getSelectionGroup() == null || extendCurrent) ? viewport
+            .getAlignment() : viewport.getSelectionGroup();
+
+    int nseq = findColumnsWithFeature(featureType, 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"),
+                    featureType, Integer.valueOf(nseq).toString() }));
+        return true;
+      }
+    }
+    else
+    {
+      avcg.setStatus(MessageManager.formatMessage(
+              "label.no_feature_of_type_found",
+              new String[] { featureType }));
+      if (!extendCurrent)
+      {
+        cs.clear();
+        alignPanel.paintAlignment(true);
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Sets a bit in the BitSet for each column (base 0) in the sequence
+   * collection which includes the specified feature type. Returns the number of
+   * sequences which have the feature in the selected range.
+   * 
+   * @param featureType
+   * @param sqcol
+   * @param bs
+   * @return
+   */
+  static int findColumnsWithFeature(String featureType,
+          SequenceCollectionI sqcol, BitSet bs)
+  {
+    final int startPosition = sqcol.getStartRes() + 1; // converted to base 1
+    final int endPosition = sqcol.getEndRes() + 1;
     List<SequenceI> seqs = sqcol.getSequences();
     int nseq = 0;
     for (SequenceI sq : seqs)
     {
-      int tfeat = 0;
+      boolean sequenceHasFeature = false;
       if (sq != null)
       {
-        SequenceFeature[] sf = sq.getSequenceFeatures();
-        if (sf != null)
+        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 < alStart || ist > alw)
+          if (iend < startPosition || ist > endPosition)
           {
             // sequence not in region
             continue;
           }
-          for (SequenceFeature sfpos : sf)
+          for (SequenceFeature sf : sfs)
           {
-            // future functionalty - featureType == null means mark columns
+            // future functionality - featureType == null means mark columns
             // containing all displayed features
-            if (sfpos != null && (featureType.equals(sfpos.getType())))
+            if (sf != null && (featureType.equals(sf.getType())))
             {
-              tfeat++;
               // optimisation - could consider 'spos,apos' like cursor argument
               // - findIndex wastes time by starting from first character and
               // counting
 
-              int i = sq.findIndex(sfpos.getBegin());
-              int j = sq.findIndex(sfpos.getEnd());
-              if (j < alStart || i > alw)
+              int i = sq.findIndex(sf.getBegin());
+              int j = sq.findIndex(sf.getEnd());
+              if (j < startPosition || i > endPosition)
               {
                 // feature is outside selected region
                 continue;
               }
-              if (i < alStart)
+              sequenceHasFeature = true;
+              if (i < startPosition)
               {
-                i = alStart;
+                i = startPosition;
               }
               if (i < ist)
               {
                 i = ist;
               }
-              if (j > alw)
+              if (j > endPosition)
               {
-                j = alw;
+                j = endPosition;
               }
               for (; i <= j; i++)
               {
-                bs.set(i - 1);
+                bs.set(i - 1); // convert to base 0
               }
             }
           }
         }
 
-        if (tfeat > 0)
+        if (sequenceHasFeature)
         {
           nseq++;
         }
       }
     }
-    ColumnSelection cs = viewport.getColumnSelection();
-    if (bs.cardinality() > 0 || invert)
-    {
-      if (cs == null)
-      {
-        cs = new ColumnSelection();
-      }
-      else
-      {
-        if (!extendCurrent)
-        {
-          cs.clear();
-        }
-      }
-      if (invert)
-      {
-        // invert only in the currently selected sequence region
-        for (int i = bs.nextClearBit(alStart), ibs = bs.nextSetBit(alStart); i >= alStart
-                && i < (alw);)
-        {
-          if (ibs < 0 || i < ibs)
-          {
-            if (toggle && cs.contains(i))
-            {
-              cs.removeElement(i++);
-            }
-            else
-            {
-              cs.addElement(i++);
-            }
-          }
-          else
-          {
-            i = bs.nextClearBit(ibs);
-            ibs = bs.nextSetBit(i);
-          }
-        }
-      }
-      else
-      {
-        for (int i = bs.nextSetBit(alStart); i >= alStart; i = bs
-                .nextSetBit(i + 1))
-        {
-          if (toggle && cs.contains(i))
-          {
-            cs.removeElement(i);
-          }
-          else
-          {
-            cs.addElement(i);
-          }
-        }
-      }
-      viewport.setColumnSelection(cs);
-      alignPanel.paintAlignment(true);
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.view_controller_toggled_marked",
-              new String[] {
-                  (toggle ? MessageManager.getString("label.toggled")
-                          : MessageManager.getString("label.marked")),
-                  (invert ? (Integer.valueOf((alw - alStart)
-                          - bs.cardinality()).toString()) : (Integer
-                          .valueOf(bs.cardinality()).toString())),
-                  featureType, Integer.valueOf(nseq).toString() }));
-      return true;
-    }
-    else
-    {
-      avcg.setStatus(MessageManager.formatMessage(
-              "label.no_feature_of_type_found",
-              new String[] { featureType }));
-      if (!extendCurrent && cs != null)
-      {
-        cs.clear();
-        alignPanel.paintAlignment(true);
-      }
-      return false;
-    }
+    return nseq;
   }
 
   @Override
index 6d6cdb5..c5204eb 100644 (file)
@@ -23,6 +23,7 @@ package jalview.datamodel;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 
+import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -36,7 +37,7 @@ public class AlignedCodonFrame
   /*
    * Data bean to hold mappings from one sequence to another
    */
-  private class SequenceToSequenceMapping
+  public class SequenceToSequenceMapping
   {
     private SequenceI fromSeq;
 
@@ -57,6 +58,54 @@ public class AlignedCodonFrame
       return String.format("From %s %s", fromSeq.getName(),
               mapping.toString());
     }
+
+    /**
+     * Returns a hashCode derived from the hashcodes of the mappings and fromSeq
+     * 
+     * @see SequenceToSequenceMapping#hashCode()
+     */
+    @Override
+    public int hashCode()
+    {
+      return (fromSeq == null ? 0 : fromSeq.hashCode() * 31)
+              + mapping.hashCode();
+    }
+
+    /**
+     * Answers true if the objects hold the same mapping between the same two
+     * sequences
+     * 
+     * @see Mapping#equals
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+      if (!(obj instanceof SequenceToSequenceMapping))
+      {
+        return false;
+      }
+      SequenceToSequenceMapping that = (SequenceToSequenceMapping) obj;
+      if (this.mapping == null)
+      {
+        return that.mapping == null;
+      }
+      // TODO: can simplify by asserting fromSeq is a dataset sequence
+      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);
+    }
+
+    public SequenceI getFromSeq()
+    {
+      return fromSeq;
+    }
+
+    public Mapping getMapping()
+    {
+      return mapping;
+    }
   }
 
   private List<SequenceToSequenceMapping> mappings;
@@ -79,6 +128,21 @@ public class AlignedCodonFrame
    */
   public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map)
   {
+    addMap(dnaseq, aaseq, map, null);
+  }
+
+  /**
+   * Adds a mapping between the dataset sequences for the associated dna and
+   * protein sequence objects
+   * 
+   * @param dnaseq
+   * @param aaseq
+   * @param map
+   * @param mapFromId
+   */
+  public void addMap(SequenceI dnaseq, SequenceI aaseq, MapList map,
+          String mapFromId)
+  {
     // JBPNote DEBUG! THIS !
     // dnaseq.transferAnnotation(aaseq, mp);
     // aaseq.transferAnnotation(dnaseq, new Mapping(map.getInverse()));
@@ -90,6 +154,8 @@ public class AlignedCodonFrame
 
     /*
      * if we already hold a mapping between these sequences, just add to it 
+     * note that 'adding' a duplicate map does nothing; this protects against
+     * creating duplicate mappings in AlignedCodonFrame
      */
     for (SequenceToSequenceMapping ssm : mappings)
     {
@@ -104,6 +170,7 @@ public class AlignedCodonFrame
      * otherwise, add a new sequence mapping
      */
     Mapping mp = new Mapping(toSeq, map);
+    mp.setMappedFromId(mapFromId);
     mappings.add(new SequenceToSequenceMapping(fromSeq, mp));
   }
 
@@ -421,7 +488,8 @@ public class AlignedCodonFrame
 
     for (SequenceToSequenceMapping ssm : mappings)
     {
-      if (ssm.mapping.to == protein)
+      if (ssm.mapping.to == protein
+              && ssm.mapping.getMap().getFromRatio() == 3)
       {
         ml = ssm.mapping.map;
         dnaSeq = ssm.fromSeq;
@@ -651,8 +719,8 @@ public class AlignedCodonFrame
   }
 
   /**
-   * Returns the first mapping found that is from 'fromSeq' to '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
@@ -662,16 +730,54 @@ public class AlignedCodonFrame
    */
   public Mapping getMappingBetween(SequenceI fromSeq, SequenceI toSeq)
   {
+    SequenceI dssFrom = fromSeq.getDatasetSequence() == null ? fromSeq
+            : fromSeq.getDatasetSequence();
+    SequenceI dssTo = toSeq.getDatasetSequence() == null ? toSeq : toSeq
+            .getDatasetSequence();
+
     for (SequenceToSequenceMapping mapping : mappings)
     {
       SequenceI from = mapping.fromSeq;
       SequenceI to = mapping.mapping.to;
-      if ((from == fromSeq || from == fromSeq.getDatasetSequence())
-              && (to == toSeq || to == toSeq.getDatasetSequence()))
+      if ((from == dssFrom && to == dssTo)
+              || (from == dssTo && to == dssFrom))
       {
         return mapping.mapping;
       }
     }
     return null;
   }
+
+  /**
+   * Returns a hashcode derived from the list of sequence mappings
+   * 
+   * @see SequenceToSequenceMapping#hashCode()
+   * @see AbstractList#hashCode()
+   */
+  @Override
+  public int hashCode()
+  {
+    return this.mappings.hashCode();
+  }
+
+  /**
+   * Two AlignedCodonFrame objects are equal if they hold the same ordered list
+   * of mappings
+   * 
+   * @see SequenceToSequenceMapping#
+   */
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof AlignedCodonFrame))
+    {
+      return false;
+    }
+    return this.mappings.equals(((AlignedCodonFrame) obj).mappings);
+  }
+
+  public List<SequenceToSequenceMapping> getMappings()
+  {
+    return mappings;
+  }
 }
index a9b0d53..2289ac6 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;
@@ -44,7 +46,7 @@ import java.util.Vector;
  */
 public class Alignment implements AlignmentI
 {
-  protected Alignment dataset;
+  private Alignment dataset;
 
   protected List<SequenceI> sequences;
 
@@ -109,7 +111,10 @@ public class Alignment implements AlignmentI
     /*
      * Share the same dataset sequence mappings (if any). 
      */
-    this.setCodonFrames(al.getCodonFrames());
+    if (dataset == null && al.getDataset() == null)
+    {
+      this.setCodonFrames(al.getCodonFrames());
+    }
   }
 
   /**
@@ -222,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)
     {
@@ -252,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;
     }
   }
 
@@ -279,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;
@@ -294,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();
     }
   }
 
@@ -986,7 +1010,7 @@ public class Alignment implements AlignmentI
   }
 
   @Override
-  public void setDataset(Alignment data)
+  public void setDataset(AlignmentI data)
   {
     if (dataset == null && data == null)
     {
@@ -994,7 +1018,12 @@ public class Alignment implements AlignmentI
     }
     else if (dataset == null && data != null)
     {
-      dataset = data;
+      if (!(data instanceof Alignment))
+      {
+        throw new Error(
+                "Implementation Error: jalview.datamodel.Alignment does not yet support other implementations of AlignmentI as its dataset reference");
+      }
+      dataset = (Alignment) data;
       for (int i = 0; i < getHeight(); i++)
       {
         SequenceI currentSeq = getSequenceAt(i);
@@ -1021,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.
    */
@@ -1030,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;
@@ -1340,6 +1443,10 @@ public class Alignment implements AlignmentI
   @Override
   public List<AlignedCodonFrame> getCodonFrames()
   {
+    // TODO: Fix this method to fix failing AlignedCodonFrame tests
+    // this behaviour is currently incorrect. method should return codon frames
+    // for just the alignment,
+    // selected from dataset
     return dataset != null ? dataset.getCodonFrames() : codonFrameList;
   }
 
@@ -1361,11 +1468,7 @@ public class Alignment implements AlignmentI
   @Override
   public void append(AlignmentI toappend)
   {
-    if (toappend == this)
-    {
-      System.err.println("Self append may cause a deadlock.");
-    }
-    // TODO test this method for a future 2.5 release
+    // TODO JAL-1270 needs test coverage
     // currently tested for use in jalview.gui.SequenceFetcher
     boolean samegap = toappend.getGapCharacter() == getGapCharacter();
     char oldc = toappend.getGapCharacter();
@@ -1376,6 +1479,8 @@ public class Alignment implements AlignmentI
             .getFullAlignment().getSequences() : toappend.getSequences();
     if (sqs != null)
     {
+      // avoid self append deadlock by
+      List<SequenceI> toappendsq = new ArrayList<SequenceI>();
       synchronized (sqs)
       {
         for (SequenceI addedsq : sqs)
@@ -1391,9 +1496,13 @@ public class Alignment implements AlignmentI
               }
             }
           }
-          addSequence(addedsq);
+          toappendsq.add(addedsq);
         }
       }
+      for (SequenceI addedsq : toappendsq)
+      {
+        addSequence(addedsq);
+      }
     }
     AlignmentAnnotation[] alan = toappend.getAlignmentAnnotation();
     for (int a = 0; alan != null && a < alan.length; a++)
@@ -1401,6 +1510,7 @@ public class Alignment implements AlignmentI
       addAnnotation(alan[a]);
     }
 
+    // use add method
     getCodonFrames().addAll(toappend.getCodonFrames());
 
     List<SequenceGroup> sg = toappend.getGroups();
@@ -1691,9 +1801,11 @@ public class Alignment implements AlignmentI
    * Parameters control whether gaps in exon (mapped) and intron (unmapped)
    * regions are preserved. Gaps that connect introns to exons are treated
    * conservatively, i.e. only preserved if both intron and exon gaps are
-   * preserved.
+   * preserved. TODO: check caveats below where the implementation fails
    * 
    * @param al
+   *          - must have same dataset, and sequences in al must have equivalent
+   *          dataset sequence and start/end bounds under given mapping
    * @param preserveMappedGaps
    *          if true, gaps within and between mapped codons are preserved
    * @param preserveUnmappedGaps
@@ -1704,12 +1816,17 @@ public class Alignment implements AlignmentI
           boolean preserveUnmappedGaps)
   {
     // TODO should this method signature be the one in the interface?
+    // JBPComment - yes - neither flag is used, so should be deleted.
     boolean thisIsNucleotide = this.isNucleotide();
     boolean thatIsProtein = !al.isNucleotide();
     if (!thatIsProtein && !thisIsNucleotide)
     {
       return AlignmentUtils.alignProteinAsDna(this, al);
     }
+    else if (thatIsProtein && thisIsNucleotide)
+    {
+      return AlignmentUtils.alignCdsAsProtein(this, al);
+    }
     return AlignmentUtils.alignAs(this, al);
   }
 
index 7990a5c..05688cb 100755 (executable)
@@ -24,11 +24,11 @@ import jalview.analysis.Rna;
 import jalview.analysis.SecStrConsensus.SimpleBP;
 import jalview.analysis.WUSSParseException;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
@@ -79,7 +79,7 @@ public class AlignmentAnnotation
   /** Array of annotations placed in the current coordinate system */
   public Annotation[] annotations;
 
-  public ArrayList<SimpleBP> bps = null;
+  public List<SimpleBP> bps = null;
 
   /**
    * RNA secondary structure contact positions
@@ -102,8 +102,8 @@ public class AlignmentAnnotation
   {
     try
     {
-      _rnasecstr = Rna.GetBasePairs(RNAannot);
-      bps = Rna.GetModeleBP(RNAannot);
+      bps = Rna.getModeleBP(RNAannot);
+      _rnasecstr = Rna.getBasePairs(bps);
       invalidrnastruc = -1;
     } catch (WUSSParseException px)
     {
@@ -272,7 +272,7 @@ public class AlignmentAnnotation
   // JBPNote: what does this do ?
   public void ConcenStru(CharSequence RNAannot) throws WUSSParseException
   {
-    bps = Rna.GetModeleBP(RNAannot);
+    bps = Rna.getModeleBP(RNAannot);
   }
 
   /**
@@ -485,7 +485,7 @@ public class AlignmentAnnotation
       this(0, annotations.length);
     }
 
-    public AnnotCharSequence(int start, int end)
+    AnnotCharSequence(int start, int end)
     {
       offset = start;
       max = end;
@@ -593,6 +593,7 @@ public class AlignmentAnnotation
     if (annotations == null)
     {
       visible = false; // try to prevent renderer from displaying.
+      invalidrnastruc = -1;
       return; // this is a non-annotation row annotation - ie a sequence score.
     }
 
@@ -1306,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)
     {
@@ -1411,6 +1411,77 @@ public class AlignmentAnnotation
     this.annotationId = ANNOTATION_ID_PREFIX + Long.toString(nextId());
   }
 
+  /**
+   * Returns the match for the last unmatched opening RNA helix pair symbol
+   * preceding the given column, or '(' if nothing found to match.
+   * 
+   * @param column
+   * @return
+   */
+  public String getDefaultRnaHelixSymbol(int column)
+  {
+    String result = "(";
+    if (annotations == null)
+    {
+      return result;
+    }
+
+    /*
+     * for each preceding column, if it contains an open bracket, 
+     * count whether it is still unmatched at column, if so return its pair
+     * (likely faster than the fancy alternative using stacks)
+     */
+    for (int col = column - 1; col >= 0; col--)
+    {
+      Annotation annotation = annotations[col];
+      if (annotation == null)
+      {
+        continue;
+      }
+      String displayed = annotation.displayCharacter;
+      if (displayed == null || displayed.length() != 1)
+      {
+        continue;
+      }
+      char symbol = displayed.charAt(0);
+      if (!Rna.isOpeningParenthesis(symbol))
+      {
+        continue;
+      }
+
+      /*
+       * found an opening bracket symbol
+       * count (closing-opening) symbols of this type that follow it,
+       * up to and excluding the target column; if the count is less
+       * than 1, the opening bracket is unmatched, so return its match
+       */
+      String closer = String.valueOf(Rna
+              .getMatchingClosingParenthesis(symbol));
+      String opener = String.valueOf(symbol);
+      int count = 0;
+      for (int j = col + 1; j < column; j++)
+      {
+        if (annotations[j] != null)
+        {
+          String s = annotations[j].displayCharacter;
+          if (closer.equals(s))
+          {
+            count++;
+          }
+          else if (opener.equals(s))
+          {
+            count--;
+          }
+        }
+      }
+      if (count < 1)
+      {
+        return closer;
+      }
+    }
+    return result;
+  }
+
   protected static synchronized long nextId()
   {
     return counter++;
index 76d1a48..1d37fa6 100755 (executable)
@@ -41,7 +41,8 @@ public interface AlignmentI extends AnnotatedCollectionI
    * 
    * Calculates the maximum width of the alignment, including gaps.
    * 
-   * @return Greatest sequence length within alignment.
+   * @return Greatest sequence length within alignment, or -1 if no sequences
+   *         present
    */
   @Override
   int getWidth();
@@ -107,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
@@ -305,7 +309,7 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @return Alignment containing dataset sequences or null of this is a
    *         dataset.
    */
-  Alignment getDataset();
+  AlignmentI getDataset();
 
   /**
    * Set the associated dataset for the alignment, or create one.
@@ -313,7 +317,7 @@ public interface AlignmentI extends AnnotatedCollectionI
    * @param dataset
    *          The dataset alignment or null to construct one.
    */
-  void setDataset(Alignment dataset);
+  void setDataset(AlignmentI dataset);
 
   /**
    * pads sequences with gaps (to ensure the set looks like an alignment)
index 756a116..9db9f38 100644 (file)
@@ -26,7 +26,6 @@ import jalview.util.ShiftList;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Vector;
 
 /**
  * Transient object compactly representing a 'view' of an alignment - with
@@ -69,13 +68,51 @@ public class AlignmentView
    */
   private class ScGroup
   {
-    public Vector seqs;
+    public List<SeqCigar> seqs;
 
     public SequenceGroup sg;
 
     ScGroup()
     {
-      seqs = new Vector();
+      seqs = new ArrayList<SeqCigar>();
+    }
+
+    /**
+     * @param seq
+     * @return true if seq was not a member before and was added to group
+     */
+    public boolean add(SeqCigar seq)
+    {
+      if (!seq.isMemberOf(this))
+      {
+        seqs.add(seq);
+        seq.setGroupMembership(this);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+    /**
+     * 
+     * @param seq
+     * @return true if seq was a member and was removed from group
+     */
+    public boolean remove(SeqCigar seq)
+    {
+      if (seq.removeGroupMembership(this))
+      {
+        seqs.remove(seq);
+        return true;
+      }
+      return false;
+    }
+
+    public int size()
+    {
+      return seqs.size();
     }
   }
 
@@ -83,7 +120,7 @@ public class AlignmentView
    * vector of selected seqCigars. This vector is also referenced by each
    * seqCigar contained in it.
    */
-  private Vector selected;
+  private ScGroup selected;
 
   /**
    * Construct an alignmentView from a live jalview alignment view. Note -
@@ -124,7 +161,7 @@ public class AlignmentView
     if (selection != null && selection.getSize() > 0)
     {
       List<SequenceI> sel = selection.getSequences(null);
-      this.selected = new Vector();
+      this.selected = new ScGroup();
       selseqs = selection
               .getSequencesInOrder(alignment, selectedRegionOnly);
     }
@@ -194,8 +231,7 @@ public class AlignmentView
         if (selection != null && selection.getSize() > 0
                 && !selectedRegionOnly)
         {
-          sequences[csi].setGroupMembership(selected);
-          selected.addElement(sequences[csi]);
+          selected.add(sequences[csi]);
         }
         if (seqsets != null)
         {
@@ -203,9 +239,8 @@ public class AlignmentView
           {
             if ((seqsets.get(sg)).contains(selseqs[i]))
             {
-              sequences[csi].setGroupMembership(sgrps[sg]);
               sgrps[sg].sg.deleteSequence(selseqs[i], false);
-              sgrps[sg].seqs.addElement(sequences[csi]);
+              sgrps[sg].add(sequences[csi]);
               if (!addedgps[sg])
               {
                 if (scGroups == null)
@@ -242,8 +277,7 @@ public class AlignmentView
     if (!seqcigararray.isSeqCigarArray())
     {
       throw new Error(
-              MessageManager
-                      .getString("error.implementation_error_can_only_make_alignmnet_from_cigararray"));
+              "Implementation Error - can only make an alignment view from a CigarArray of sequences.");
     }
     // contigs = seqcigararray.applyDeletions();
     contigs = seqcigararray.getDeletedRegions();
@@ -1073,10 +1107,10 @@ public class AlignmentView
                 + sgr.sg.getEndRes());
         for (int s = 0; s < sgr.seqs.size(); s++)
         {
-          if (!((SeqCigar) sgr.seqs.elementAt(s)).isMemberOf(sgr))
+          // JBPnote this should be a unit test for ScGroup
+          if (!sgr.seqs.get(s).isMemberOf(sgr))
           {
-            os.println("** WARNING: sequence "
-                    + ((SeqCigar) sgr.seqs.elementAt(s)).toString()
+            os.println("** WARNING: sequence " + sgr.seqs.get(s).toString()
                     + " is not marked as member of group.");
           }
         }
index bcf8596..5fb507a 100644 (file)
@@ -533,6 +533,7 @@ public abstract class CigarBase
       {
       case M:
         cursor += range[i];
+        break;
       case I:
         vcursor += range[i];
         break;
index c23b772..d651c0b 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.datamodel;
 
+import jalview.util.Comparison;
 import jalview.util.ShiftList;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
 import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField;
@@ -31,28 +32,65 @@ import java.util.List;
 import java.util.Vector;
 
 /**
- * NOTE: Columns are zero based.
+ * Data class holding the selected columns and hidden column ranges for a view.
+ * Ranges are base 1.
  */
 public class ColumnSelection
 {
+  /**
+   * A class to hold an efficient representation of selected columns
+   */
   private class IntList
   {
     /*
      * 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))
       {
@@ -61,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);
@@ -82,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();
     }
@@ -108,7 +151,7 @@ public class ColumnSelection
      * @param i
      * @return
      */
-    public int elementAt(int i)
+    int elementAt(int i)
     {
       return order.get(i);
     }
@@ -151,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++)
@@ -170,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);
     }
@@ -188,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())
@@ -204,9 +247,27 @@ public class ColumnSelection
       }
       return rlist;
     }
+
+    @Override
+    public int hashCode()
+    {
+      // TODO Auto-generated method stub
+      return selected.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+      if (obj instanceof IntList)
+      {
+        return ((IntList) obj).selected.equals(selected);
+      }
+      return false;
+    }
   }
 
-  IntList selected = new IntList();
+  IntList selection = new IntList();
+
   /*
    * list of hidden column [start, end] ranges; the list is maintained in
    * ascending start column order
@@ -221,7 +282,7 @@ public class ColumnSelection
    */
   public void addElement(int col)
   {
-    selected.add(col);
+    selection.add(col);
   }
 
   /**
@@ -229,7 +290,7 @@ public class ColumnSelection
    */
   public void clear()
   {
-    selected.clear();
+    selection.clear();
   }
 
   /**
@@ -240,7 +301,7 @@ public class ColumnSelection
    */
   public void removeElement(int col)
   {
-    selected.remove(col);
+    selection.remove(col);
   }
 
   /**
@@ -257,21 +318,26 @@ public class ColumnSelection
     for (int i = start; i < end; i++)
     {
       colInt = new Integer(i);
-      if (selected.contains(colInt))
+      if (selection.contains(colInt))
       {
-        selected.remove(colInt);
+        selection.remove(colInt);
       }
     }
   }
 
   /**
-   * 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
+   * 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 selected.getList();
+    return selection.getList();
   }
 
   /**
@@ -280,7 +346,7 @@ public class ColumnSelection
    */
   public List<int[]> getSelectedRanges()
   {
-    return selected.getRanges();
+    return selection.getRanges();
   }
 
   /**
@@ -292,7 +358,7 @@ public class ColumnSelection
    */
   public boolean contains(int col)
   {
-    return (col > -1) ? selected.isSelected(col) : false;
+    return (col > -1) ? selection.isSelected(col) : false;
   }
 
   /**
@@ -300,7 +366,7 @@ public class ColumnSelection
    */
   public boolean isEmpty()
   {
-    return selected == null || selected.isEmpty();
+    return selection == null || selection.isEmpty();
   }
 
   /**
@@ -310,11 +376,11 @@ public class ColumnSelection
    */
   public int getMax()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return -1;
     }
-    return selected.getMaxColumn();
+    return selection.getMaxColumn();
   }
 
   /**
@@ -324,11 +390,11 @@ public class ColumnSelection
    */
   public int getMin()
   {
-    if (selected.isEmpty())
+    if (selection.isEmpty())
     {
       return 1000000000;
     }
-    return selected.getMinColumn();
+    return selection.getMinColumn();
   }
 
   /**
@@ -342,7 +408,7 @@ public class ColumnSelection
   public List<int[]> compensateForEdit(int start, int change)
   {
     List<int[]> deletedHiddenColumns = null;
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -392,7 +458,7 @@ public class ColumnSelection
   private void compensateForDelEdits(int start, int change)
   {
 
-    selected.compensateForEdits(start, change);
+    selection.compensateForEdits(start, change);
 
     if (hiddenColumns != null)
     {
@@ -569,12 +635,12 @@ public class ColumnSelection
             hiddenColumns = null;
           }
         }
-        if (selected != null && selected.size() > 0)
+        if (selection != null && selection.size() > 0)
         {
-          selected.pruneColumnList(shifts);
-          if (selected != null && selected.size() == 0)
+          selection.pruneColumnList(shifts);
+          if (selection != null && selection.size() == 0)
           {
-            selected = null;
+            selection = null;
           }
         }
         // and shift the rest.
@@ -598,7 +664,7 @@ public class ColumnSelection
    * Return absolute column index for a visible column index
    * 
    * @param column
-   *          int column index in alignment view
+   *          int column index in alignment view (count from zero)
    * @return alignment column index for column
    */
   public int adjustForHiddenColumns(int column)
@@ -741,12 +807,13 @@ public class ColumnSelection
 
   public void hideSelectedColumns()
   {
-    synchronized (selected) {
-      for (int[] selregions:selected.getRanges())
+    synchronized (selection)
+    {
+      for (int[] selregions : selection.getRanges())
       {
         hideColumns(selregions[0], selregions[1]);
       }
-      selected.clear();
+      selection.clear();
     }
 
   }
@@ -806,7 +873,7 @@ public class ColumnSelection
     /*
      * remaining case is that the new range follows everything else
      */
-      hiddenColumns.addElement(new int[] { start, end });
+    hiddenColumns.addElement(new int[] { start, end });
   }
 
   /**
@@ -924,14 +991,7 @@ public class ColumnSelection
   {
     if (copy != null)
     {
-      if (copy.selected != null)
-      {
-        selected = new IntList();
-        for (int i = 0, j = copy.selected.size(); i < j; i++)
-        {
-          selected.add(copy.selected.elementAt(i));
-        }
-      }
+      selection = new IntList(copy.selection);
       if (copy.hiddenColumns != null)
       {
         hiddenColumns = new Vector<int[]>(copy.hiddenColumns.size());
@@ -961,7 +1021,7 @@ public class ColumnSelection
           SequenceI[] seqs)
   {
     int i, iSize = seqs.length;
-    String selection[] = new String[iSize];
+    String selections[] = new String[iSize];
     if (hiddenColumns != null && hiddenColumns.size() > 0)
     {
       for (i = 0; i < iSize; i++)
@@ -1003,18 +1063,18 @@ public class ColumnSelection
           visibleSeq.append(seqs[i].getSequence(blockStart, end));
         }
 
-        selection[i] = visibleSeq.toString();
+        selections[i] = visibleSeq.toString();
       }
     }
     else
     {
       for (i = 0; i < iSize; i++)
       {
-        selection[i] = seqs[i].getSequenceAsString(start, end);
+        selections[i] = seqs[i].getSequenceAsString(start, end);
       }
     }
 
-    return selection;
+    return selections;
   }
 
   /**
@@ -1077,6 +1137,84 @@ public class ColumnSelection
   }
 
   /**
+   * Locate the first and last position visible for this sequence. if seq isn't
+   * visible then return the position of the left and right of the hidden
+   * boundary region, and the corresponding alignment column indices for the
+   * extent of the sequence
+   * 
+   * @param seq
+   * @return int[] { visible start, visible end, first seqpos, last seqpos,
+   *         alignment index for seq start, alignment index for seq end }
+   */
+  public int[] locateVisibleBoundsOfSequence(SequenceI seq)
+  {
+    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;
+      return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+    }
+
+    // Simply walk along the sequence whilst watching for hidden column
+    // boundaries
+    List<int[]> regions = getHiddenColumns();
+    int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
+            .getLength(), hideEnd = -1;
+    int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
+    boolean foundStart = false;
+    for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+            && p < pLen; p++)
+    {
+      if (!Comparison.isGap(seq.getCharAt(p)))
+      {
+        // keep track of first/last column
+        // containing sequence data regardless of visibility
+        if (firstP == -1)
+        {
+          firstP = p;
+        }
+        lastP = p;
+        // update hidden region start/end
+        while (hideEnd < p && rcount < regions.size())
+        {
+          int[] region = regions.get(rcount++);
+          visPrev = visNext;
+          visNext += region[0] - visPrev;
+          hideStart = region[0];
+          hideEnd = region[1];
+        }
+        if (hideEnd < p)
+        {
+          hideStart = seq.getLength();
+        }
+        // update visible boundary for sequence
+        if (p < hideStart)
+        {
+          if (!foundStart)
+          {
+            fpos = spos;
+            start = p;
+            foundStart = true;
+          }
+          lastvispos = p;
+          lpos = spos;
+        }
+        // look for next sequence position
+        spos++;
+      }
+    }
+    if (foundStart)
+    {
+      return new int[] { findColumnPosition(start),
+          findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+    }
+    // otherwise, sequence was completely hidden
+    return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+  }
+
+  /**
    * delete any columns in alignmentAnnotation that are hidden (including
    * sequence associated annotation).
    * 
@@ -1226,7 +1364,7 @@ public class ColumnSelection
       {
         if (hiddenColumns != null && isVisible(col.intValue()))
         {
-          selected.add(col);
+          selection.add(col);
         }
       }
     }
@@ -1240,8 +1378,8 @@ public class ColumnSelection
    */
   public void setElementsFrom(ColumnSelection colsel)
   {
-    selected = new IntList();
-    if (colsel.selected != null && colsel.selected.size() > 0)
+    selection = new IntList();
+    if (colsel.selection != null && colsel.selection.size() > 0)
     {
       if (hiddenColumns != null && hiddenColumns.size() > 0)
       {
@@ -1408,7 +1546,7 @@ public class ColumnSelection
    */
   public boolean hasSelectedColumns()
   {
-    return (selected != null && selected.size() > 0);
+    return (selection != null && selection.size() > 0);
   }
 
   /**
@@ -1447,6 +1585,8 @@ public class ColumnSelection
   public boolean filterAnnotations(Annotation[] annotations,
           AnnotationFilterParameter filterParams)
   {
+    // JBPNote - this method needs to be refactored to become independent of
+    // viewmodel package
     this.revealAllHiddenColumns();
     this.clear();
     int count = 0;
@@ -1528,4 +1668,149 @@ public class ColumnSelection
     } while (count < annotations.length);
     return false;
   }
+
+  /**
+   * Returns a hashCode built from selected columns and hidden column ranges
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = selection.hashCode();
+    if (hiddenColumns != null)
+    {
+      for (int[] hidden : hiddenColumns)
+      {
+        hashCode = 31 * hashCode + hidden[0];
+        hashCode = 31 * hashCode + hidden[1];
+      }
+    }
+    return hashCode;
+  }
+
+  /**
+   * Answers true if comparing to a ColumnSelection with the same selected
+   * columns and hidden columns, else false
+   */
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof ColumnSelection))
+    {
+      return false;
+    }
+    ColumnSelection that = (ColumnSelection) obj;
+
+    /*
+     * check columns selected are either both null, or match
+     */
+    if (this.selection == null)
+    {
+      if (that.selection != null)
+      {
+        return false;
+      }
+    }
+    if (!this.selection.equals(that.selection))
+    {
+      return false;
+    }
+
+    /*
+     * check hidden columns are either both null, or match
+     */
+    if (this.hiddenColumns == null)
+    {
+      return (that.hiddenColumns == null);
+    }
+    if (that.hiddenColumns == null
+            || that.hiddenColumns.size() != this.hiddenColumns.size())
+    {
+      return false;
+    }
+    int i = 0;
+    for (int[] thisRange : hiddenColumns)
+    {
+      int[] thatRange = that.hiddenColumns.get(i++);
+      if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+      {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Updates the column selection depending on the parameters, and returns true
+   * if any change was made to the selection
+   * 
+   * @param markedColumns
+   *          a set identifying marked columns (base 0)
+   * @param startCol
+   *          the first column of the range to operate over (base 0)
+   * @param endCol
+   *          the last column of the range to operate over (base 0)
+   * @param invert
+   *          if true, deselect marked columns and select unmarked
+   * @param extendCurrent
+   *          if true, extend rather than replacing the current column selection
+   * @param toggle
+   *          if true, toggle the selection state of marked columns
+   * 
+   * @return
+   */
+  public boolean markColumns(BitSet markedColumns, int startCol,
+          int endCol, boolean invert, boolean extendCurrent, boolean toggle)
+  {
+    boolean changed = false;
+    if (!extendCurrent && !toggle)
+    {
+      changed = !this.isEmpty();
+      clear();
+    }
+    if (invert)
+    {
+      // invert only in the currently selected sequence region
+      int i = markedColumns.nextClearBit(startCol);
+      int ibs = markedColumns.nextSetBit(startCol);
+      while (i >= startCol && i <= endCol)
+      {
+        if (ibs < 0 || i < ibs)
+        {
+          changed = true;
+          if (toggle && contains(i))
+          {
+            removeElement(i++);
+          }
+          else
+          {
+            addElement(i++);
+          }
+        }
+        else
+        {
+          i = markedColumns.nextClearBit(ibs);
+          ibs = markedColumns.nextSetBit(i);
+        }
+      }
+    }
+    else
+    {
+      int i = markedColumns.nextSetBit(startCol);
+      while (i >= startCol && i <= endCol)
+      {
+        changed = true;
+        if (toggle && contains(i))
+        {
+          removeElement(i);
+        }
+        else
+        {
+          addElement(i);
+        }
+        i = markedColumns.nextSetBit(i + 1);
+      }
+    }
+    return changed;
+  }
+
 }
index 53642b5..ec6dcf8 100755 (executable)
@@ -22,11 +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 = "";
 
-  private int startRes, endRes;
   /**
    * maps from associated sequence to the database sequence's coordinate system
    */
@@ -37,7 +39,6 @@ public class DBRefEntry implements DBRefEntryI
 
   }
 
-
   public DBRefEntry(String source, String version, String accessionId)
   {
     this(source, version, accessionId, null);
@@ -98,6 +99,86 @@ public class DBRefEntry implements DBRefEntryI
   }
 
   /**
+   * Answers true if this object is either equivalent to, or can be 'improved'
+   * by, the given entry. Specifically, answers true if
+   * <ul>
+   * <li>source and accession are identical (ignoring case)</li>
+   * <li>version is identical (ignoring case), or this version is of the format
+   * "someSource:0", in which case the version for the other entry replaces it</li>
+   * <li>mappings are not compared but if this entry has no mapping, replace
+   * with that for the other entry</li>
+   * </ul>
+   * 
+   * @param other
+   * @return
+   */
+  @Override
+  public boolean updateFrom(DBRefEntryI other)
+  {
+    if (other == null)
+    {
+      return false;
+    }
+    if (other == this)
+    {
+      return true;
+    }
+
+    /*
+     * source must either match or be both null
+     */
+    String otherSource = other.getSource();
+    if ((source == null && otherSource != null)
+            || (source != null && otherSource == null)
+            || (source != null && !source.equalsIgnoreCase(otherSource)))
+    {
+      return false;
+    }
+
+    /*
+     * accession id must either match or be both null
+     */
+    String otherAccession = other.getAccessionId();
+    if ((accessionId == null && otherAccession != null)
+            || (accessionId != null && otherAccession == null)
+            || (accessionId != null && !accessionId
+                    .equalsIgnoreCase(otherAccession)))
+    {
+      return false;
+    }
+
+    /*
+     * if my version is null, "0" or "source:0" then replace with other version,
+     * otherwise the versions have to match
+     */
+    String otherVersion = other.getVersion();
+
+    if ((version == null || version.equals("0") || version.endsWith(":0"))
+            && otherVersion != null)
+    {
+      setVersion(otherVersion);
+    }
+    else
+    {
+      if (version != null
+              && (otherVersion == null || !version
+                      .equalsIgnoreCase(otherVersion)))
+      {
+        return false;
+      }
+    }
+
+    /*
+     * if I have no mapping, take that of the other dbref
+     */
+    if (map == null)
+    {
+      setMap(other.getMap());
+    }
+    return true;
+  }
+
+  /**
    * test for similar DBRef attributes, except for the map object.
    * 
    * @param entry
@@ -106,6 +187,7 @@ public class DBRefEntry implements DBRefEntryI
   @Override
   public boolean equalRef(DBRefEntryI entry)
   {
+    // TODO is this method and equals() not needed?
     if (entry == null)
     {
       return false;
@@ -145,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()
   {
@@ -204,26 +282,54 @@ public class DBRefEntry implements DBRefEntryI
   }
 
   @Override
-  public int getStartRes()
+  public boolean isPrimaryCandidate()
   {
-    return startRes;
-  }
-
-  @Override
-  public void setStartRes(int startRes)
-  {
-    this.startRes = startRes;
-  }
-
-  @Override
-  public int getEndRes()
-  {
-    return endRes;
-  }
-
-  @Override
-  public void setEndRes(int endRes)
-  {
-    this.endRes = endRes;
+    /*
+     * 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 91b49eb..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
- * jalview.ws.DbSourcProxy)
+ * jalview.ws.DbSourcProxy) <br/>
+ * TODO: replace with ontology to allow recognition of particular attributes
+ * (e.g. protein coding, alignment (ortholog db, paralog db, domain db),
+ * genomic, transcriptomic, 3D structure providing (PDB, MODBASE, etc) ..).
  * 
  * @author JimP
  * 
@@ -33,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.
@@ -51,32 +58,27 @@ public class DBRefSource
   /**
    * PDB Entry Code
    */
-  public static String PDB = "PDB";
-
-  /**
-   * mmCIF Entry Code
-   */
-  public static String MMCIF = "mmCIF";
+  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
@@ -88,6 +90,8 @@ public class DBRefSource
    */
   public static final String ENSEMBL = "ENSEMBL";
 
+  public static final String ENSEMBLGENOMES = "ENSEMBLGENOMES";
+
   /**
    * List of databases whose sequences might have coding regions annotated
    */
@@ -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 d25eb96..2306bec 100644 (file)
@@ -28,8 +28,7 @@ package jalview.datamodel;
  */
 public class FeatureProperties
 {
-
-  private static final String EMBL_CODING_FEATURE = "CDS";
+  public static final String EMBL_CODING_FEATURE = "CDS";
 
   public static final String EXONPOS = "exon number";
 
index dcc5f26..9e2cf72 100755 (executable)
@@ -33,11 +33,21 @@ public class HiddenSequences
 
   AlignmentI alignment;
 
+  /**
+   * Constructor given a reference to an alignment (with no hidden sequences)
+   * 
+   * @param al
+   */
   public HiddenSequences(AlignmentI al)
   {
     alignment = al;
   }
 
+  /**
+   * Answers the number of hidden sequences
+   * 
+   * @return
+   */
   public int getSize()
   {
     if (hiddenSequences == null)
@@ -45,9 +55,9 @@ public class HiddenSequences
       return 0;
     }
     int count = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null)
+      if (seq != null)
       {
         count++;
       }
@@ -56,15 +66,23 @@ public class HiddenSequences
     return count;
   }
 
+  /**
+   * Answers the length of the longest hidden sequence
+   * 
+   * @return
+   */
   public int getWidth()
   {
+    if (hiddenSequences == null)
+    {
+      return 0;
+    }
     int width = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    for (SequenceI seq : hiddenSequences)
     {
-      if (hiddenSequences[i] != null
-              && hiddenSequences[i].getLength() > width)
+      if (seq != null && seq.getLength() > width)
       {
-        width = hiddenSequences[i].getLength();
+        width = seq.getLength();
       }
     }
 
@@ -72,7 +90,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are removed from the main alignment
+   * Call this method after a sequence is removed from the main alignment
    */
   public void adjustHeightSequenceDeleted(int seqIndex)
   {
@@ -108,8 +126,7 @@ public class HiddenSequences
   }
 
   /**
-   * Call this method if sequences are added to or removed from the main
-   * alignment
+   * Call this method after a sequence is added to the main alignment
    */
   public void adjustHeightSequenceAdded()
   {
@@ -125,6 +142,11 @@ public class HiddenSequences
     hiddenSequences = tmp;
   }
 
+  /**
+   * Mark the specified sequence as hidden
+   * 
+   * @param sequence
+   */
   public void hideSequence(SequenceI sequence)
   {
     if (hiddenSequences == null)
@@ -163,6 +185,17 @@ public class HiddenSequences
     return revealedSeqs;
   }
 
+  /**
+   * Reveals (unhides) consecutive hidden sequences just above the given
+   * alignment index. The revealed sequences are selected (including their
+   * visible representative sequence if there was one and 'reveal' is being
+   * performed on it).
+   * 
+   * @param alignmentIndex
+   * @param hiddenRepSequences
+   *          a map of representative sequences to the sequences they represent
+   * @return
+   */
   public List<SequenceI> showSequence(int alignmentIndex,
           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
   {
@@ -203,20 +236,22 @@ public class HiddenSequences
                     + " has been deleted whilst hidden");
           }
         }
-
       }
     }
-
     return revealedSeqs;
   }
 
   public SequenceI getHiddenSequence(int alignmentIndex)
   {
-    return hiddenSequences[alignmentIndex];
+    return hiddenSequences == null ? null : hiddenSequences[alignmentIndex];
   }
 
   public int findIndexWithoutHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hiddenSeqs = 0;
     if (hiddenSequences.length <= alignmentIndex)
@@ -232,13 +267,16 @@ public class HiddenSequences
       }
       index++;
     }
-    ;
 
     return (alignmentIndex - hiddenSeqs);
   }
 
   public int adjustForHiddenSeqs(int alignmentIndex)
   {
+    if (hiddenSequences == null)
+    {
+      return alignmentIndex;
+    }
     int index = 0;
     int hSize = hiddenSequences.length;
     while (index <= alignmentIndex && index < hSize)
@@ -254,22 +292,37 @@ public class HiddenSequences
     return alignmentIndex;
   }
 
+  /**
+   * 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()
   {
-    int isize = hiddenSequences.length;
-    SequenceI[] seq = new Sequence[isize];
-
-    int index = 0;
-    for (int i = 0; i < hiddenSequences.length; i++)
+    SequenceI[] seq;
+    if (hiddenSequences == null)
     {
-      if (hiddenSequences[i] != null)
-      {
-        seq[i] = hiddenSequences[i];
-      }
-      else
+      seq = alignment.getSequencesArray();
+    }
+    else
+    {
+      int isize = hiddenSequences.length;
+      seq = new Sequence[isize];
+
+      int index = 0;
+      for (int i = 0; i < hiddenSequences.length; i++)
       {
-        seq[i] = alignment.getSequenceAt(index);
-        index++;
+        if (hiddenSequences[i] != null)
+        {
+          seq[i] = hiddenSequences[i];
+        }
+        else
+        {
+          seq[i] = alignment.getSequenceAt(index);
+          index++;
+        }
       }
     }
     Alignment fAlignmt = new Alignment(seq);
@@ -277,6 +330,7 @@ public class HiddenSequences
     fAlignmt.alignmentProperties = alignment.getProperties();
     fAlignmt.groups = alignment.getGroups();
     fAlignmt.hasRNAStructure = alignment.hasRNAStructure();
+    fAlignmt.setSeqrep(alignment.getSeqrep());
 
     return fAlignmt;
   }
index bd83fe9..1c196be 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.datamodel;
 
+import jalview.util.Comparison;
 import jalview.util.MapList;
 
 import java.util.Iterator;
@@ -258,7 +259,8 @@ public class Mapping
       int truePos = sequencePos - (start - 1);
       while (alignedBases < truePos && alignedColumn < alignedSeq.length)
       {
-        if (alignedSeq[alignedColumn++] != gap)
+        char c = alignedSeq[alignedColumn++];
+        if (c != gap && !Comparison.isGap(c))
         {
           alignedBases++;
         }
@@ -274,18 +276,23 @@ public class Mapping
 
   }
 
-  /**
+  /*
    * Contains the start-end pairs mapping from the associated sequence to the
    * sequence in the database coordinate system. It also takes care of step
    * difference between coordinate systems.
    */
   MapList map = null;
 
-  /**
+  /*
    * The sequence that map maps the associated sequence to (if any).
    */
   SequenceI to = null;
 
+  /*
+   * optional sequence id for the 'from' ranges
+   */
+  private String mappedFromId;
+
   public Mapping(MapList map)
   {
     super();
@@ -333,6 +340,7 @@ public class Mapping
         map = new MapList(map2.map);
       }
       to = map2.to;
+      mappedFromId = map2.mappedFromId;
     }
   }
 
@@ -356,14 +364,13 @@ public class Mapping
   /**
    * Equals that compares both the to references and MapList mappings.
    * 
-   * @param other
+   * @param o
    * @return
+   * @see MapList#equals
    */
   @Override
   public boolean equals(Object o)
   {
-    // TODO should override Object.hashCode() to ensure that equal objects have
-    // equal hashcodes
     if (o == null || !(o instanceof Mapping))
     {
       return false;
@@ -390,6 +397,21 @@ public class Mapping
   }
 
   /**
+   * Returns a hashCode made from the sequence and maplist
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = (this.to == null ? 1 : this.to.hashCode());
+    if (this.map != null)
+    {
+      hashCode = hashCode * 31 + this.map.hashCode();
+    }
+
+    return hashCode;
+  }
+
+  /**
    * get the 'initial' position in the associated sequence for a position in the
    * mapped reference frame
    * 
@@ -728,4 +750,22 @@ public class Mapping
             : this.to.getName());
   }
 
+  /**
+   * Returns the identifier for the 'from' range sequence, or null if not set
+   * 
+   * @return
+   */
+  public String getMappedFromId()
+  {
+    return mappedFromId;
+  }
+
+  /**
+   * Sets the identifier for the 'from' range sequence
+   */
+  public void setMappedFromId(String mappedFromId)
+  {
+    this.mappedFromId = mappedFromId;
+  }
+
 }
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 1c7df49..6a6ccd0 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
   {
-    PDB, MMCIF, FILE
+    PDB, MMCIF, FILE;
+    /**
+     * 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;
+    }
+
+    /**
+     * case insensitive equivalence for strings resolving to PDBEntry type
+     * 
+     * @param t
+     * @return
+     */
+    public boolean matches(String t)
+    {
+      return (this.toString().equalsIgnoreCase(t));
+    }
   }
 
-  Hashtable properties;
 
-  /*
-   * (non-Javadoc)
-   * 
-   * @see java.lang.Object#equals(java.lang.Object)
+  /**
+   * 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)
@@ -56,17 +94,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;
   }
 
   /**
@@ -90,10 +135,21 @@ public class PDBEntry
   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);
   }
 
   /**
@@ -106,16 +162,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();
+    }
+  }
+
+  /**
+   * 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)
+  {
+    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 file)
+  public void setFile(String f)
   {
-    this.file = file;
+    this.file = f;
   }
 
   public String getFile()
@@ -148,24 +232,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 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
@@ -173,4 +309,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;
+  }
 }
index d279a26..98b0de5 100644 (file)
@@ -68,10 +68,49 @@ public class SeqCigar extends CigarSimple
   }
 
   /**
+   * 
+   * @param column
+   * @return position in sequence for column (or -1 if no match state exists)
+   */
+  public int findPosition(int column)
+  {
+    int w = 0, ew, p = refseq.findPosition(start);
+    if (column < 0)
+    {
+      return -1;
+    }
+    if (range != null)
+    {
+      for (int i = 0; i < length; i++)
+      {
+        if (operation[i] == M || operation[i] == D)
+        {
+          p += range[i];
+        }
+        if (operation[i] == M || operation[i] == I)
+        {
+          ew = w + range[i];
+          if (column < ew)
+          {
+            if (operation[i] == I)
+            {
+              return -1;
+            }
+            return p - (ew - column);
+          }
+          w = ew;
+        }
+      }
+    }
+    return -1;
+  }
+
+  /**
    * Returns sequence as a string with cigar operations applied to it
    * 
    * @return String
    */
+  @Override
   public String getSequenceString(char GapChar)
   {
     return (length == 0) ? "" : (String) getSequenceAndDeletions(
index 6c8cbc0..c8b94ce 100755 (executable)
@@ -22,9 +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;
@@ -56,8 +61,6 @@ public class Sequence extends ASequence implements SequenceI
 
   String vamsasId;
 
-  DBRefEntryI sourceDBRef;
-
   DBRefEntry[] dbrefs;
 
   RNA rna;
@@ -185,12 +188,13 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   /**
-   * Creates a new Sequence object with new features, DBRefEntries,
-   * AlignmentAnnotations, and PDBIds but inherits any existing dataset sequence
-   * reference.
+   * Creates a new Sequence object with new AlignmentAnnotations but inherits
+   * any existing dataset sequence reference. If non exists, everything is
+   * copied.
    * 
    * @param seq
-   *          DOCUMENT ME!
+   *          if seq is a dataset sequence, behaves like a plain old copy
+   *          constructor
    */
   public Sequence(SequenceI seq)
   {
@@ -213,31 +217,45 @@ public class Sequence extends ASequence implements SequenceI
 
   }
 
+  /**
+   * does the heavy lifting when cloning a dataset sequence, or coping data from
+   * dataset to a new derived sequence.
+   * 
+   * @param seq
+   *          - source of attributes.
+   * @param alAnnotation
+   *          - alignment annotation present on seq that should be copied onto
+   *          this sequence
+   */
   protected void initSeqFrom(SequenceI seq,
           AlignmentAnnotation[] alAnnotation)
   {
-    initSeqAndName(seq.getName(), seq.getSequence(), seq.getStart(),
-            seq.getEnd());
+    {
+      char[] oseq = seq.getSequence();
+      initSeqAndName(seq.getName(), Arrays.copyOf(oseq, oseq.length),
+              seq.getStart(), seq.getEnd());
+    }
     description = seq.getDescription();
-    sourceDBRef = seq.getSourceDBRef() == null ? null : new DBRefEntry(
-            seq.getSourceDBRef());
-    if (seq.getSequenceFeatures() != null)
+    if (seq != datasetSequence)
     {
-      SequenceFeature[] sf = seq.getSequenceFeatures();
-      for (int i = 0; i < sf.length; i++)
-      {
-        addSequenceFeature(new SequenceFeature(sf[i]));
-      }
+      setDatasetSequence(seq.getDatasetSequence());
     }
-    setDatasetSequence(seq.getDatasetSequence());
     if (datasetSequence == null && seq.getDBRefs() != null)
     {
-      // only copy DBRefs if we really are a dataset sequence
+      // only copy DBRefs and seqfeatures if we really are a dataset sequence
       DBRefEntry[] dbr = seq.getDBRefs();
       for (int i = 0; i < dbr.length; i++)
       {
         addDBRef(new DBRefEntry(dbr[i]));
       }
+      if (seq.getSequenceFeatures() != null)
+      {
+        SequenceFeature[] sf = seq.getSequenceFeatures();
+        for (int i = 0; i < sf.length; i++)
+        {
+          addSequenceFeature(new SequenceFeature(sf[i]));
+        }
+      }
     }
     if (seq.getAnnotation() != null)
     {
@@ -274,22 +292,35 @@ public class Sequence extends ASequence implements SequenceI
     }
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param v
-   *          DOCUMENT ME!
-   */
   @Override
   public void setSequenceFeatures(SequenceFeature[] features)
   {
-    sequenceFeatures = features;
+    if (datasetSequence == null)
+    {
+      sequenceFeatures = features;
+    }
+    else
+    {
+      if (datasetSequence.getSequenceFeatures() != features
+              && datasetSequence.getSequenceFeatures() != null
+              && datasetSequence.getSequenceFeatures().length > 0)
+      {
+        new Exception(
+                "Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment")
+                .printStackTrace();
+      }
+      datasetSequence.setSequenceFeatures(features);
+    }
   }
 
   @Override
   public synchronized void addSequenceFeature(SequenceFeature sf)
   {
-    // TODO add to dataset sequence instead if there is one?
+    if (sequenceFeatures == null && datasetSequence != null)
+    {
+      datasetSequence.addSequenceFeature(sf);
+      return;
+    }
     if (sequenceFeatures == null)
     {
       sequenceFeatures = new SequenceFeature[0];
@@ -315,6 +346,10 @@ public class Sequence extends ASequence implements SequenceI
   {
     if (sequenceFeatures == null)
     {
+      if (datasetSequence != null)
+      {
+        datasetSequence.deleteFeature(sf);
+      }
       return;
     }
 
@@ -377,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;
   }
 
   /**
@@ -913,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
@@ -930,41 +971,56 @@ 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];
     }
 
-    int i, iSize = dbrefs.length;
-
-    for (i = 0; i < iSize; i++)
+    for (DBRefEntryI dbr : dbrefs)
     {
-      if (dbrefs[i].equalRef(entry))
+      if (dbr.updateFrom(entry))
       {
-        if (entry.getMap() != null)
-        {
-          if (dbrefs[i].getMap() == null)
-          {
-            // overwrite with 'superior' entry that contains a mapping.
-            dbrefs[i] = entry;
-          }
-        }
+        /*
+         * found a dbref that either matched, or could be
+         * updated from, the new entry - no need to add it
+         */
         return;
       }
     }
 
-    DBRefEntry[] temp = new DBRefEntry[iSize + 1];
-    System.arraycopy(dbrefs, 0, temp, 0, iSize);
+    /*
+     * extend the array to make room for one more
+     */
+    // TODO use an ArrayList instead
+    int j = dbrefs.length;
+    DBRefEntry[] temp = new DBRefEntry[j + 1];
+    System.arraycopy(dbrefs, 0, temp, 0, j);
     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;
   }
 
@@ -1037,33 +1093,49 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public SequenceI deriveSequence()
   {
-    SequenceI seq = new Sequence(this);
-    if (datasetSequence != null)
-    {
-      // duplicate current sequence with same dataset
-      seq.setDatasetSequence(datasetSequence);
-    }
-    else
+    Sequence seq = null;
+    if (datasetSequence == null)
     {
       if (isValidDatasetSequence())
       {
         // Use this as dataset sequence
+        seq = new Sequence(getName(), "", 1, -1);
         seq.setDatasetSequence(this);
+        seq.initSeqFrom(this, getAnnotation());
+        return seq;
       }
       else
       {
         // Create a new, valid dataset sequence
-        SequenceI ds = seq;
-        ds.setSequence(AlignSeq.extractGaps(
-                jalview.util.Comparison.GapChars, new String(sequence)));
-        setDatasetSequence(ds);
-        ds.setSequenceFeatures(getSequenceFeatures());
-        seq = this; // and return this sequence as the derived sequence.
+        createDatasetSequence();
       }
     }
-    return seq;
+    return new Sequence(this);
   }
 
+  private boolean _isNa;
+
+  private long _seqhash = 0;
+
+  /**
+   * Answers false if the sequence is more than 85% nucleotide (ACGTU), else
+   * true
+   */
+  @Override
+  public boolean isProtein()
+  {
+    if (datasetSequence != null)
+    {
+      return datasetSequence.isProtein();
+    }
+    if (_seqhash != sequence.hashCode())
+    {
+      _seqhash = sequence.hashCode();
+      _isNa = Comparison.isNucleotide(this);
+    }
+    return !_isNa;
+  };
+
   /*
    * (non-Javadoc)
    * 
@@ -1074,20 +1146,27 @@ public class Sequence extends ASequence implements SequenceI
   {
     if (datasetSequence == null)
     {
-      datasetSequence = new Sequence(getName(), AlignSeq.extractGaps(
+      Sequence dsseq = new Sequence(getName(), AlignSeq.extractGaps(
               jalview.util.Comparison.GapChars, getSequenceAsString()),
               getStart(), getEnd());
-      datasetSequence.setSequenceFeatures(getSequenceFeatures());
-      datasetSequence.setDescription(getDescription());
-      setSequenceFeatures(null);
-      // move database references onto dataset sequence
-      datasetSequence.setDBRefs(getDBRefs());
-      setDBRefs(null);
-      datasetSequence.setPDBId(getAllPDBEntries());
-      setPDBId(null);
+
+      datasetSequence = dsseq;
+
+      dsseq.setDescription(description);
+      // move features and database references onto dataset sequence
+      dsseq.sequenceFeatures = sequenceFeatures;
+      sequenceFeatures = null;
+      dsseq.dbrefs = dbrefs;
+      dbrefs = null;
+      // TODO: search and replace any references to this sequence with
+      // references to the dataset sequence in Mappings on dbref
+      dsseq.pdbIds = pdbIds;
+      pdbIds = null;
       datasetSequence.updatePDBIds();
       if (annotation != null)
       {
+        // annotation is cloned rather than moved, to preserve what's currently
+        // on the alignment
         for (AlignmentAnnotation aa : annotation)
         {
           AlignmentAnnotation _aa = new AlignmentAnnotation(aa);
@@ -1172,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
@@ -1341,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))
@@ -1358,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 4a7706f..c75d6f2 100755 (executable)
@@ -39,6 +39,13 @@ public class SequenceFeature
   // private key for Phase designed not to conflict with real GFF data
   private static final String PHASE = "!Phase";
 
+  // private key for ENA location designed not to conflict with real GFF data
+  private static final String LOCATION = "!Location";
+
+  /*
+   * ATTRIBUTES is reserved for the GFF 'column 9' data, formatted as
+   * name1=value1;name2=value2,value3;...etc
+   */
   private static final String ATTRIBUTES = "ATTRIBUTES";
 
   public int begin;
@@ -51,6 +58,10 @@ public class SequenceFeature
 
   public String description;
 
+  /*
+   * a map of key-value pairs; may be populated from GFF 'column 9' data,
+   * other data sources (e.g. GenBank file), or programmatically
+   */
   public Map<String, Object> otherDetails;
 
   public Vector<String> links;
@@ -111,26 +122,57 @@ public class SequenceFeature
     }
   }
 
+  /**
+   * Constructor including a Status value
+   * 
+   * @param type
+   * @param desc
+   * @param status
+   * @param begin
+   * @param end
+   * @param featureGroup
+   */
   public SequenceFeature(String type, String desc, String status,
           int begin, int end, String featureGroup)
   {
+    this(type, desc, begin, end, featureGroup);
+    setStatus(status);
+  }
+
+  /**
+   * Constructor
+   * 
+   * @param type
+   * @param desc
+   * @param begin
+   * @param end
+   * @param featureGroup
+   */
+  SequenceFeature(String type, String desc, int begin, int end,
+          String featureGroup)
+  {
     this.type = type;
     this.description = desc;
-    setValue(STATUS, status);
     this.begin = begin;
     this.end = end;
     this.featureGroup = featureGroup;
   }
 
+  /**
+   * Constructor including a score value
+   * 
+   * @param type
+   * @param desc
+   * @param begin
+   * @param end
+   * @param score
+   * @param featureGroup
+   */
   public SequenceFeature(String type, String desc, int begin, int end,
           float score, String featureGroup)
   {
-    this.type = type;
-    this.description = desc;
-    this.begin = begin;
-    this.end = end;
+    this(type, desc, begin, end, featureGroup);
     this.score = score;
-    this.featureGroup = featureGroup;
   }
 
   /**
@@ -445,6 +487,26 @@ public class SequenceFeature
   }
 
   /**
+   * Sets the 'raw' ENA format location specifier e.g. join(12..45,89..121)
+   * 
+   * @param loc
+   */
+  public void setEnaLocation(String loc)
+  {
+    setValue(LOCATION, loc);
+  }
+
+  /**
+   * Gets the 'raw' ENA format location specifier e.g. join(12..45,89..121)
+   * 
+   * @param loc
+   */
+  public String getEnaLocation()
+  {
+    return (String) getValue(LOCATION);
+  }
+
+  /**
    * Readable representation, for debug only, not guaranteed not to change
    * between versions
    */
index 0e8fa17..98fd8f2 100755 (executable)
@@ -22,15 +22,13 @@ package jalview.datamodel;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.Conservation;
+import jalview.analysis.Profile;
 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 +44,6 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   Conservation conserve;
 
-  Vector aaFrequency;
-
   boolean displayBoxes = true;
 
   boolean displayText = true;
@@ -504,33 +500,52 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * calculate residue conservation for group - but only if necessary.
+   * calculate residue conservation and colourschemes for group - but only if
+   * necessary. returns true if the calculation resulted in a visible change to
+   * group
+   */
+  public boolean recalcConservation()
+  {
+    return recalcConservation(false);
+  }
+
+  /**
+   * calculate residue conservation for group - but only if necessary. returns
+   * true if the calculation resulted in a visible change to group
+   * 
+   * @param defer
+   *          when set, colourschemes for this group are not refreshed after
+   *          recalculation
    */
-  public void recalcConservation()
+  public boolean recalcConservation(boolean defer)
   {
     if (cs == null && consensus == null && conservation == null)
     {
-      return;
+      return false;
     }
+    // TODO: try harder to detect changes in state in order to minimise
+    // recalculation effort
+    boolean upd = false;
     try
     {
-      Hashtable cnsns[] = AAFrequency.calculate(sequences, startRes,
+      Profile[] 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,
-                endRes + 1);
+        Conservation c = new Conservation(groupName, 3, sequences,
+                startRes, endRes + 1);
         c.calculate();
         c.verdict(false, consPercGaps);
         if (conservation != null)
@@ -544,17 +559,25 @@ public class SequenceGroup implements AnnotatedCollectionI
             cs.setConservation(c);
           }
         }
+        // eager update - will cause a refresh of overview regardless
+        upd = true;
       }
-      if (cs != null)
+      if (cs != null && !defer)
       {
+        // TODO: JAL-2034 should cs.alignmentChanged modify return state
         cs.alignmentChanged(context != null ? context : this, null);
+        return true;
+      }
+      else
+      {
+        return upd;
       }
     } catch (java.lang.OutOfMemoryError err)
     {
       // TODO: catch OOM
       System.out.println("Out of memory loading groups: " + err);
     }
-
+    return upd;
   }
 
   private void _updateConservationRow(Conservation c)
@@ -577,9 +600,9 @@ public class SequenceGroup implements AnnotatedCollectionI
     c.completeAnnotations(conservation, null, startRes, endRes + 1);
   }
 
-  public Hashtable[] consensusData = null;
+  public Profile[] consensusData = null;
 
-  private void _updateConsensusRow(Hashtable[] cnsns, long nseq)
+  private void _updateConsensusRow(Profile[] cnsns, long nseq)
   {
     if (consensus == null)
     {
@@ -894,6 +917,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * @return the representative sequence for this group
    */
+  @Override
   public SequenceI getSeqrep()
   {
     return seqrep;
@@ -906,6 +930,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * @param seqrep
    *          the seqrep to set (null means no sequence representative)
    */
+  @Override
   public void setSeqrep(SequenceI seqrep)
   {
     this.seqrep = seqrep;
@@ -915,6 +940,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * 
    * @return true if group has a sequence representative
    */
+  @Override
   public boolean hasSeqrep()
   {
     return seqrep != null;
@@ -1036,7 +1062,8 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   /**
    * 
-   * @return automatically calculated consensus row
+   * @return automatically calculated consensus row note: the row is a stub if a
+   *         consensus calculation has not yet been performed on the group
    */
   public AlignmentAnnotation getConsensus()
   {
index f1cba43..aec68ab 100755 (executable)
@@ -20,8 +20,6 @@
  */
 package jalview.datamodel;
 
-import jalview.api.DBRefEntryI;
-
 import java.util.List;
 import java.util.Vector;
 
@@ -219,6 +217,15 @@ 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
+   */
+  public boolean isProtein();
+
+  /**
    * Delete a range of aligned sequence columns, creating a new dataset sequence
    * if necessary and adjusting start and end positions accordingly.
    * 
@@ -233,34 +240,39 @@ public interface SequenceI extends ASequenceI
    * DOCUMENT ME!
    * 
    * @param i
-   *          DOCUMENT ME!
+   *          alignment column number
    * @param c
-   *          DOCUMENT ME!
+   *          character to insert
    */
   public void insertCharAt(int i, char c);
 
   /**
-   * DOCUMENT ME!
+   * insert given character at alignment column position
    * 
    * @param position
-   *          DOCUMENT ME!
+   *          alignment column number
+   * @param count
+   *          length of insert
    * @param ch
-   *          DOCUMENT ME!
+   *          character to insert
    */
   public void insertCharAt(int position, int count, char ch);
 
   /**
-   * DOCUMENT ME!
+   * Gets array holding sequence features associated with this sequence. The
+   * array may be held by the sequence's dataset sequence if that is defined.
    * 
-   * @return DOCUMENT ME!
+   * @return hard reference to array
    */
   public SequenceFeature[] getSequenceFeatures();
 
   /**
-   * DOCUMENT ME!
+   * Replaces the array of sequence features associated with this sequence with
+   * a new array reference. If this sequence has a dataset sequence, then this
+   * method will update the dataset sequence's feature array
    * 
-   * @param v
-   *          DOCUMENT ME!
+   * @param features
+   *          New array of sequence features
    */
   public void setSequenceFeatures(SequenceFeature[] features);
 
@@ -280,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
@@ -298,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();
@@ -432,7 +459,13 @@ public interface SequenceI extends ASequenceI
    */
   public PDBEntry getPDBEntry(String pdbId);
 
-  public void setSourceDBRef(DBRefEntryI dbRef);
-
-  public DBRefEntryI getSourceDBRef();
+  /**
+   * 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.
+   * 
+   * @return just the primary references (if any) for this sequence, or an empty
+   *         list
+   */
+  public List<DBRefEntry> getPrimaryDBRefs();
 }
index 691a4c9..4d09bdc 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.datamodel.xdb.embl;
 
 import jalview.analysis.SequenceIdMatcher;
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.FeatureProperties;
@@ -29,10 +30,12 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.util.DBRefUtils;
+import jalview.util.DnaUtils;
 import jalview.util.MapList;
 import jalview.util.MappingUtils;
 import jalview.util.StringUtils;
 
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.List;
@@ -45,9 +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/Tools/dbfetch/dbfetch?db=ena_sequence&id=J03321
- * &format=emblxml
+ * For example: http://www.ebi.ac.uk/ena/data/view/J03321&display=xml
  * 
  * @see embl_mapping.xml
  */
@@ -57,17 +58,29 @@ public class EmblEntry
 
   String accession;
 
-  String version;
+  String entryVersion;
 
-  String taxDivision;
+  String sequenceVersion;
 
-  String desc;
+  String dataClass;
 
-  String rCreated;
+  String moleculeType;
 
-  String rLastUpdated;
+  String topology;
 
-  String lastUpdated;
+  String sequenceLength;
+
+  String taxonomicDivision;
+
+  String description;
+
+  String firstPublicDate;
+
+  String firstPublicRelease;
+
+  String lastUpdatedDate;
+
+  String lastUpdatedRelease;
 
   Vector<String> keywords;
 
@@ -112,23 +125,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the desc
-   */
-  public String getDesc()
-  {
-    return desc;
-  }
-
-  /**
-   * @param desc
-   *          the desc to set
-   */
-  public void setDesc(String desc)
-  {
-    this.desc = desc;
-  }
-
-  /**
    * @return the features
    */
   public Vector<EmblFeature> getFeatures()
@@ -163,57 +159,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the lastUpdated
-   */
-  public String getLastUpdated()
-  {
-    return lastUpdated;
-  }
-
-  /**
-   * @param lastUpdated
-   *          the lastUpdated to set
-   */
-  public void setLastUpdated(String lastUpdated)
-  {
-    this.lastUpdated = lastUpdated;
-  }
-
-  /**
-   * @return the releaseCreated
-   */
-  public String getRCreated()
-  {
-    return rCreated;
-  }
-
-  /**
-   * @param releaseCreated
-   *          the releaseCreated to set
-   */
-  public void setRCreated(String releaseCreated)
-  {
-    this.rCreated = releaseCreated;
-  }
-
-  /**
-   * @return the releaseLastUpdated
-   */
-  public String getRLastUpdated()
-  {
-    return rLastUpdated;
-  }
-
-  /**
-   * @param releaseLastUpdated
-   *          the releaseLastUpdated to set
-   */
-  public void setRLastUpdated(String releaseLastUpdated)
-  {
-    this.rLastUpdated = releaseLastUpdated;
-  }
-
-  /**
    * @return the sequence
    */
   public EmblSequence getSequence()
@@ -231,40 +176,6 @@ public class EmblEntry
   }
 
   /**
-   * @return the taxDivision
-   */
-  public String getTaxDivision()
-  {
-    return taxDivision;
-  }
-
-  /**
-   * @param taxDivision
-   *          the taxDivision to set
-   */
-  public void setTaxDivision(String taxDivision)
-  {
-    this.taxDivision = taxDivision;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
-  }
-
-  /**
    * Recover annotated sequences from EMBL file
    * 
    * @param sourceDb
@@ -274,38 +185,40 @@ public class EmblEntry
    */
   public SequenceI getSequence(String sourceDb, List<SequenceI> peptides)
   {
-    SequenceI dna = new Sequence(sourceDb + "|" + accession,
-            sequence.getSequence());
-    dna.setDescription(desc);
-    DBRefEntry retrievedref = new DBRefEntry(sourceDb, version, accession);
+    SequenceI dna = makeSequence(sourceDb);
+    if (dna == null)
+    {
+      return null;
+    }
+    dna.setDescription(description);
+    DBRefEntry retrievedref = new DBRefEntry(sourceDb,
+            getSequenceVersion(), accession);
     dna.addDBRef(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));
-    // TODO: transform EMBL Database refs to canonical form
+
+    /*
+     * transform EMBL Database refs to canonical form
+     */
     if (dbRefs != null)
     {
       for (DBRefEntry dbref : dbRefs)
       {
+        dbref.setSource(DBRefUtils.getCanonicalName(dbref.getSource()));
         dna.addDBRef(dbref);
       }
     }
 
+    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
     try
     {
       for (EmblFeature feature : features)
       {
-        if (feature.dbRefs != null)
-        {
-          for (DBRefEntry dbref : feature.dbRefs)
-          {
-            dna.addDBRef(dbref);
-          }
-        }
         if (FeatureProperties.isCodingFeature(sourceDb, feature.getName()))
         {
-          parseCodingFeature(feature, sourceDb, dna, peptides);
+          parseCodingFeature(feature, sourceDb, dna, peptides, matcher);
         }
       }
     } catch (Exception e)
@@ -322,6 +235,23 @@ public class EmblEntry
   }
 
   /**
+   * @param sourceDb
+   * @return
+   */
+  SequenceI makeSequence(String sourceDb)
+  {
+    if (sequence == null)
+    {
+      System.err.println("No sequence was returned for ENA accession "
+              + accession);
+      return null;
+    }
+    SequenceI dna = new Sequence(sourceDb + "|" + accession,
+            sequence.getSequence());
+    return dna;
+  }
+
+  /**
    * Extracts coding region and product from a CDS feature and properly decorate
    * it with annotations.
    * 
@@ -333,19 +263,20 @@ public class EmblEntry
    *          parent dna sequence for this record
    * @param peptides
    *          list of protein product sequences for Embl entry
+   * @param matcher
+   *          helper to match xrefs in already retrieved sequences
    */
   void parseCodingFeature(EmblFeature feature, String sourceDb,
-          SequenceI dna, List<SequenceI> peptides)
+          SequenceI dna, List<SequenceI> peptides, SequenceIdMatcher matcher)
   {
     boolean isEmblCdna = sourceDb.equals(DBRefSource.EMBLCDS);
 
-    int[] exon = getCdsRanges(feature);
+    int[] exons = getCdsRanges(feature);
 
-    String prseq = null;
-    String prname = "";
-    String prid = null;
+    String translation = null;
+    String proteinName = "";
+    String proteinId = null;
     Map<String, String> vals = new Hashtable<String, String>();
-    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
 
     /*
      * codon_start 1/2/3 in EMBL corresponds to phase 0/1/2 in CDS
@@ -365,17 +296,18 @@ public class EmblEntry
         if (qname.equals("translation"))
         {
           // remove all spaces (precompiled String.replaceAll(" ", ""))
-          prseq = SPACE_PATTERN.matcher(q.getValues()[0]).replaceAll("");
+          translation = SPACE_PATTERN.matcher(q.getValues()[0]).replaceAll(
+                  "");
         }
         else if (qname.equals("protein_id"))
         {
-          prid = q.getValues()[0];
+          proteinId = q.getValues()[0].trim();
         }
         else if (qname.equals("codon_start"))
         {
           try
           {
-            codonStart = Integer.parseInt(q.getValues()[0]);
+            codonStart = Integer.parseInt(q.getValues()[0].trim());
           } catch (NumberFormatException e)
           {
             System.err.println("Invalid codon_start in XML for "
@@ -385,7 +317,7 @@ public class EmblEntry
         else if (qname.equals("product"))
         {
           // sometimes name is returned e.g. for V00488
-          prname = q.getValues()[0];
+          proteinName = q.getValues()[0].trim();
         }
         else
         {
@@ -401,54 +333,59 @@ public class EmblEntry
       }
     }
 
-    DBRefEntry protEMBLCDS = null;
-    exon = MappingUtils.removeStartPositions(codonStart - 1, exon);
-    boolean noProteinDbref = true;
+    DBRefEntry proteinToEmblProteinRef = null;
+    exons = MappingUtils.removeStartPositions(codonStart - 1, exons);
 
     SequenceI product = null;
-    Mapping map = null;
-    if (prseq != null && prname != null && prid != null)
+    Mapping dnaToProteinMapping = null;
+    if (translation != null && proteinName != null && proteinId != null)
     {
+      int translationLength = translation.length();
+
       /*
        * look for product in peptides list, if not found, add it
        */
-      product = matcher.findIdMatch(prid);
+      product = matcher.findIdMatch(proteinId);
       if (product == null)
       {
-        product = new Sequence(prid, prseq, 1, prseq.length());
-        product.setDescription(((prname.length() == 0) ? "Protein Product from "
+        product = new Sequence(proteinId, translation, 1, translationLength);
+        product.setDescription(((proteinName.length() == 0) ? "Protein Product from "
                 + sourceDb
-                : prname));
+                : proteinName));
         peptides.add(product);
         matcher.add(product);
       }
 
       // we have everything - create the mapping and perhaps the protein
       // sequence
-      if (exon == null || exon.length == 0)
+      if (exons == null || exons.length == 0)
       {
+        /*
+         * workaround until we handle dna location for CDS sequence
+         * e.g. location="X53828.1:60..1058" correctly
+         */
         System.err
                 .println("Implementation Notice: EMBLCDS records not properly supported yet - Making up the CDNA region of this sequence... may be incorrect ("
                         + sourceDb + ":" + getAccession() + ")");
-        if (prseq.length() * 3 == (1 - codonStart + dna.getSequence().length))
+        if (translationLength * 3 == (1 - codonStart + dna.getSequence().length))
         {
           System.err
                   .println("Not allowing for additional stop codon at end of cDNA fragment... !");
-          // this might occur for CDS sequences where no features are
-          // marked.
-          exon = new int[] { dna.getStart() + (codonStart - 1),
+          // this might occur for CDS sequences where no features are marked
+          exons = new int[] { dna.getStart() + (codonStart - 1),
               dna.getEnd() };
-          map = new Mapping(product, exon, new int[] { 1, prseq.length() },
-                  3, 1);
+          dnaToProteinMapping = new Mapping(product, exons, new int[] { 1,
+              translationLength }, 3, 1);
         }
-        if ((prseq.length() + 1) * 3 == (1 - codonStart + dna.getSequence().length))
+        if ((translationLength + 1) * 3 == (1 - codonStart + dna
+                .getSequence().length))
         {
           System.err
                   .println("Allowing for additional stop codon at end of cDNA fragment... will probably cause an error in VAMSAs!");
-          exon = new int[] { dna.getStart() + (codonStart - 1),
+          exons = new int[] { dna.getStart() + (codonStart - 1),
               dna.getEnd() - 3 };
-          map = new Mapping(product, exon, new int[] { 1, prseq.length() },
-                  3, 1);
+          dnaToProteinMapping = new Mapping(product, exons, new int[] { 1,
+              translationLength }, 3, 1);
         }
       }
       else
@@ -467,57 +404,78 @@ public class EmblEntry
         else
         {
           // final product length truncation check
-          // TODO should from range include stop codon even if not in protein
-          // in order to include stop codon in CDS sequence (as done for
-          // Ensembl)?
-          int[] cdsRanges = adjustForProteinLength(prseq.length(), exon);
-          map = new Mapping(product, cdsRanges, new int[] { 1,
-              prseq.length() }, 3, 1);
-          // reconstruct the EMBLCDS entry
-          // TODO: this is only necessary when there codon annotation is
-          // complete (I think JBPNote)
-          DBRefEntry pcdnaref = new DBRefEntry();
-          pcdnaref.setAccessionId(prid);
-          pcdnaref.setSource(DBRefSource.EMBLCDS);
-          pcdnaref.setVersion(getVersion()); // same as parent EMBL version.
-          MapList mp = new MapList(new int[] { 1, prseq.length() },
-                  new int[] { 1 + (codonStart - 1),
-                      (codonStart - 1) + 3 * prseq.length() }, 1, 3);
-          pcdnaref.setMap(new Mapping(mp));
+          int[] cdsRanges = adjustForProteinLength(translationLength, exons);
+          dnaToProteinMapping = new Mapping(product, cdsRanges, new int[] {
+              1, translationLength }, 3, 1);
           if (product != null)
           {
-            product.addDBRef(pcdnaref);
-            protEMBLCDS = new DBRefEntry(pcdnaref);
-            protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
-            product.addDBRef(protEMBLCDS);
+            /*
+             * make xref with mapping from protein to EMBL dna
+             */
+            DBRefEntry proteinToEmblRef = new DBRefEntry(DBRefSource.EMBL,
+                    getSequenceVersion(), proteinId, new Mapping(
+                            dnaToProteinMapping.getMap().getInverse()));
+            product.addDBRef(proteinToEmblRef);
+
+            /*
+             * make xref from protein to EMBLCDS; we assume here that the 
+             * CDS sequence version is same as dna sequence (?!)
+             */
+            MapList proteinToCdsMapList = new MapList(new int[] { 1,
+                translationLength }, new int[] { 1 + (codonStart - 1),
+                (codonStart - 1) + 3 * translationLength }, 1, 3);
+            DBRefEntry proteinToEmblCdsRef = new DBRefEntry(
+                    DBRefSource.EMBLCDS, getSequenceVersion(), proteinId,
+                    new Mapping(proteinToCdsMapList));
+            product.addDBRef(proteinToEmblCdsRef);
+
+            /*
+             * make 'direct' xref from protein to EMBLCDSPROTEIN
+             */
+            proteinToEmblProteinRef = new DBRefEntry(proteinToEmblCdsRef);
+            proteinToEmblProteinRef.setSource(DBRefSource.EMBLCDSProduct);
+            proteinToEmblProteinRef.setMap(null);
+            product.addDBRef(proteinToEmblProteinRef);
           }
         }
       }
-      // add cds feature to dna seq - this may include the stop codon
-      for (int xint = 0; exon != null && xint < exon.length; xint += 2)
+
+      /*
+       * add cds features to dna sequence
+       */
+      for (int xint = 0; exons != null && xint < exons.length; xint += 2)
       {
-        SequenceFeature sf = makeCdsFeature(exon, xint, prname, prid, vals,
-                codonStart);
+        SequenceFeature sf = makeCdsFeature(exons, xint, proteinName,
+                proteinId, vals, codonStart);
         sf.setType(feature.getName()); // "CDS"
+        sf.setEnaLocation(feature.getLocation());
         sf.setFeatureGroup(sourceDb);
         dna.addSequenceFeature(sf);
       }
     }
 
     /*
-     * add dbRefs to sequence, and mappings for Uniprot xrefs
+     * add feature dbRefs to sequence, and mappings for Uniprot xrefs
      */
+    boolean hasUniprotDbref = false;
     if (feature.dbRefs != null)
     {
       boolean mappingUsed = false;
       for (DBRefEntry ref : feature.dbRefs)
       {
-        ref.setSource(DBRefUtils.getCanonicalName(ref.getSource()));
-        if (ref.getSource().equals(DBRefSource.UNIPROT))
+        /*
+         * ensure UniProtKB/Swiss-Prot converted to UNIPROT
+         */
+        String source = DBRefUtils.getCanonicalName(ref.getSource());
+        ref.setSource(source);
+        DBRefEntry proteinDbRef = new DBRefEntry(ref.getSource(),
+                ref.getVersion(), ref.getAccessionId());
+        if (source.equals(DBRefSource.UNIPROT))
         {
           String proteinSeqName = DBRefSource.UNIPROT + "|"
                   + ref.getAccessionId();
-          if (map != null && map.getTo() != null)
+          if (dnaToProteinMapping != null
+                  && dnaToProteinMapping.getTo() != null)
           {
             if (mappingUsed)
             {
@@ -525,13 +483,14 @@ public class EmblEntry
                * two or more Uniprot xrefs for the same CDS - 
                * each needs a distinct Mapping (as to a different sequence)
                */
-              map = new Mapping(map);
+              dnaToProteinMapping = new Mapping(dnaToProteinMapping);
             }
             mappingUsed = true;
 
             /*
              * try to locate the protein mapped to (possibly by a 
-             * previous CDS feature)
+             * previous CDS feature); if not found, construct it from
+             * the EMBL translation
              */
             SequenceI proteinSeq = matcher.findIdMatch(proteinSeqName);
             if (proteinSeq == null)
@@ -541,61 +500,62 @@ public class EmblEntry
               matcher.add(proteinSeq);
               peptides.add(proteinSeq);
             }
-            map.setTo(proteinSeq);
-            map.getTo().addDBRef(
-                    new DBRefEntry(ref.getSource(), ref.getVersion(), ref
-                            .getAccessionId()));
-            ref.setMap(map);
+            dnaToProteinMapping.setTo(proteinSeq);
+            dnaToProteinMapping.setMappedFromId(proteinId);
+            proteinSeq.addDBRef(proteinDbRef);
+            ref.setMap(dnaToProteinMapping);
           }
-          noProteinDbref = false;
+          hasUniprotDbref = true;
         }
         if (product != null)
         {
-          DBRefEntry pref = new DBRefEntry(ref.getSource(),
-                  ref.getVersion(), ref.getAccessionId());
+          /*
+           * copy feature dbref to our protein product
+           */
+          DBRefEntry pref = proteinDbRef;
           pref.setMap(null); // reference is direct
           product.addDBRef(pref);
           // Add converse mapping reference
-          if (map != null)
+          if (dnaToProteinMapping != null)
           {
-            Mapping pmap = new Mapping(dna, map.getMap().getInverse());
-            pref = new DBRefEntry(sourceDb, getVersion(),
+            Mapping pmap = new Mapping(dna, dnaToProteinMapping.getMap()
+                    .getInverse());
+            pref = new DBRefEntry(sourceDb, getSequenceVersion(),
                     this.getAccession());
             pref.setMap(pmap);
-            if (map.getTo() != null)
+            if (dnaToProteinMapping.getTo() != null)
             {
-              map.getTo().addDBRef(pref);
+              dnaToProteinMapping.getTo().addDBRef(pref);
             }
           }
         }
         dna.addDBRef(ref);
       }
-      if (noProteinDbref && product != null)
+    }
+
+    /*
+     * if we have a product (translation) but no explicit Uniprot dbref
+     * (example: EMBL AAFI02000057 protein_id EAL65544.1)
+     * then construct mappings to an assumed EMBLCDSPROTEIN accession
+     */
+    if (!hasUniprotDbref && product != null)
+    {
+      if (proteinToEmblProteinRef == null)
       {
-        // add protein coding reference to dna sequence so xref matches
-        if (protEMBLCDS == null)
-        {
-          protEMBLCDS = new DBRefEntry();
-          protEMBLCDS.setAccessionId(prid);
-          protEMBLCDS.setSource(DBRefSource.EMBLCDSProduct);
-          protEMBLCDS.setVersion(getVersion());
-          protEMBLCDS
-                  .setMap(new Mapping(product, map.getMap().getInverse()));
-        }
-        product.addDBRef(protEMBLCDS);
+        // assuming CDSPROTEIN sequence version = dna version (?!)
+        proteinToEmblProteinRef = new DBRefEntry(
+                DBRefSource.EMBLCDSProduct, getSequenceVersion(), proteinId);
+      }
+      product.addDBRef(proteinToEmblProteinRef);
 
-        // Add converse mapping reference
-        if (map != null)
-        {
-          Mapping pmap = new Mapping(product, protEMBLCDS.getMap().getMap()
-                  .getInverse());
-          DBRefEntry ncMap = new DBRefEntry(protEMBLCDS);
-          ncMap.setMap(pmap);
-          if (map.getTo() != null)
-          {
-            dna.addDBRef(ncMap);
-          }
-        }
+      if (dnaToProteinMapping != null
+              && dnaToProteinMapping.getTo() != null)
+      {
+        DBRefEntry dnaToEmblProteinRef = new DBRefEntry(
+                DBRefSource.EMBLCDSProduct, getSequenceVersion(), proteinId);
+        dnaToEmblProteinRef.setMap(dnaToProteinMapping);
+        dnaToProteinMapping.setMappedFromId(proteinId);
+        dna.addDBRef(dnaToEmblProteinRef);
       }
     }
   }
@@ -650,7 +610,7 @@ public class EmblEntry
   }
 
   /**
-   * Returns the CDS positions as a list of [start, end, start, end...]
+   * Returns the CDS positions as a single array of [start, end, start, end...]
    * positions. If on the reverse strand, these will be in descending order.
    * 
    * @param feature
@@ -658,51 +618,68 @@ public class EmblEntry
    */
   protected int[] getCdsRanges(EmblFeature feature)
   {
-    if (feature.locations == null)
+    if (feature.location == null)
     {
       return new int[] {};
     }
-    int cdsBoundaryCount = 0; // count of all start/stop locations
-    int[][] cdsLocations = new int[feature.locations.size()][];
-    int locationNumber = 0;
-    for (EmblFeatureLocations loc : feature.locations)
+
+    try
     {
-      int[] locationRanges = loc.getElementRanges(accession);
-      cdsLocations[locationNumber++] = locationRanges;
-      cdsBoundaryCount += locationRanges.length;
-    }
-    int[] cdsRanges = new int[cdsBoundaryCount];
-    int copyTo = 0;
-    for (int[] ranges : cdsLocations)
+      List<int[]> ranges = DnaUtils.parseLocation(feature.location);
+      return listToArray(ranges);
+    } catch (ParseException e)
     {
-      System.arraycopy(ranges, 0, cdsRanges, copyTo, ranges.length);
-      copyTo += ranges.length;
+      Cache.log.warn(String.format(
+              "Not parsing inexact CDS location %s in ENA %s",
+              feature.location, this.accession));
+      return new int[] {};
     }
-    return cdsRanges;
+  }
 
+  /**
+   * Converts a list of [start, end] ranges to a single array of [start, end,
+   * start, end ...]
+   * 
+   * @param ranges
+   * @return
+   */
+  int[] listToArray(List<int[]> ranges)
+  {
+    int[] result = new int[ranges.size() * 2];
+    int i = 0;
+    for (int[] range : ranges)
+    {
+      result[i++] = range[0];
+      result[i++] = range[1];
+    }
+    return result;
   }
 
   /**
-   * truncate the last exon interval to the prlength'th codon
+   * Truncates (if necessary) the exon intervals to match 3 times the length of
+   * the protein; also accepts 3 bases longer (for stop codon not included in
+   * protein)
    * 
-   * @param prlength
+   * @param proteinLength
    * @param exon
-   * @return new exon
+   *          an array of [start, end, start, end...] intervals
+   * @return the same array (if unchanged) or a truncated copy
    */
-  static int[] adjustForProteinLength(int prlength, int[] exon)
+  static int[] adjustForProteinLength(int proteinLength, int[] exon)
   {
-    if (prlength <= 0 || exon == null)
+    if (proteinLength <= 0 || exon == null)
     {
       return exon;
     }
-    int desiredCdsLength = prlength * 3;
+    int expectedCdsLength = proteinLength * 3;
     int exonLength = MappingUtils.getLength(Arrays.asList(exon));
 
     /*
-     * assuming here exon might include stop codon in addition to protein codons
+     * if exon length matches protein, or is shorter, or longer by the 
+     * length of a stop codon (3 bases), then leave it unchanged
      */
-    if (desiredCdsLength == exonLength
-            || desiredCdsLength == exonLength - 3)
+    if (expectedCdsLength >= exonLength
+            || expectedCdsLength == exonLength - 3)
     {
       return exon;
     }
@@ -716,11 +693,11 @@ public class EmblEntry
     for (int x = 0; x < exon.length; x += 2)
     {
       cdspos += Math.abs(exon[x + 1] - exon[x]) + 1;
-      if (desiredCdsLength <= cdspos)
+      if (expectedCdsLength <= cdspos)
       {
         // advanced beyond last codon.
         sxpos = x;
-        if (desiredCdsLength != cdspos)
+        if (expectedCdsLength != cdspos)
         {
           // System.err
           // .println("Truncating final exon interval on region by "
@@ -733,11 +710,11 @@ public class EmblEntry
          */
         if (exon[x + 1] >= exon[x])
         {
-          endxon = exon[x + 1] - cdspos + desiredCdsLength;
+          endxon = exon[x + 1] - cdspos + expectedCdsLength;
         }
         else
         {
-          endxon = exon[x + 1] + cdspos - desiredCdsLength;
+          endxon = exon[x + 1] + cdspos - expectedCdsLength;
         }
         break;
       }
@@ -754,4 +731,124 @@ public class EmblEntry
     }
     return exon;
   }
+
+  public String getSequenceVersion()
+  {
+    return sequenceVersion;
+  }
+
+  public void setSequenceVersion(String sequenceVersion)
+  {
+    this.sequenceVersion = sequenceVersion;
+  }
+
+  public String getSequenceLength()
+  {
+    return sequenceLength;
+  }
+
+  public void setSequenceLength(String sequenceLength)
+  {
+    this.sequenceLength = sequenceLength;
+  }
+
+  public String getEntryVersion()
+  {
+    return entryVersion;
+  }
+
+  public void setEntryVersion(String entryVersion)
+  {
+    this.entryVersion = entryVersion;
+  }
+
+  public String getMoleculeType()
+  {
+    return moleculeType;
+  }
+
+  public void setMoleculeType(String moleculeType)
+  {
+    this.moleculeType = moleculeType;
+  }
+
+  public String getTopology()
+  {
+    return topology;
+  }
+
+  public void setTopology(String topology)
+  {
+    this.topology = topology;
+  }
+
+  public String getTaxonomicDivision()
+  {
+    return taxonomicDivision;
+  }
+
+  public void setTaxonomicDivision(String taxonomicDivision)
+  {
+    this.taxonomicDivision = taxonomicDivision;
+  }
+
+  public String getDescription()
+  {
+    return description;
+  }
+
+  public void setDescription(String description)
+  {
+    this.description = description;
+  }
+
+  public String getFirstPublicDate()
+  {
+    return firstPublicDate;
+  }
+
+  public void setFirstPublicDate(String firstPublicDate)
+  {
+    this.firstPublicDate = firstPublicDate;
+  }
+
+  public String getFirstPublicRelease()
+  {
+    return firstPublicRelease;
+  }
+
+  public void setFirstPublicRelease(String firstPublicRelease)
+  {
+    this.firstPublicRelease = firstPublicRelease;
+  }
+
+  public String getLastUpdatedDate()
+  {
+    return lastUpdatedDate;
+  }
+
+  public void setLastUpdatedDate(String lastUpdatedDate)
+  {
+    this.lastUpdatedDate = lastUpdatedDate;
+  }
+
+  public String getLastUpdatedRelease()
+  {
+    return lastUpdatedRelease;
+  }
+
+  public void setLastUpdatedRelease(String lastUpdatedRelease)
+  {
+    this.lastUpdatedRelease = lastUpdatedRelease;
+  }
+
+  public String getDataClass()
+  {
+    return dataClass;
+  }
+
+  public void setDataClass(String dataClass)
+  {
+    this.dataClass = dataClass;
+  }
 }
index 7e503c9..51d740b 100644 (file)
@@ -37,7 +37,7 @@ public class EmblFeature
 
   Vector<Qualifier> qualifiers;
 
-  Vector<EmblFeatureLocations> locations;
+  String location;
 
   /**
    * @return the dbRefs
@@ -57,20 +57,19 @@ public class EmblFeature
   }
 
   /**
-   * @return the locations
+   * @return the location
    */
-  public Vector<EmblFeatureLocations> getLocations()
+  public String getLocation()
   {
-    return locations;
+    return location;
   }
 
   /**
-   * @param locations
-   *          the locations to set
+   * @param loc
    */
-  public void setLocations(Vector<EmblFeatureLocations> locations)
+  public void setLocation(String loc)
   {
-    this.locations = locations;
+    this.location = loc;
   }
 
   /**
diff --git a/src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java b/src/jalview/datamodel/xdb/embl/EmblFeatureLocElement.java
deleted file mode 100644 (file)
index 134ce9e..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.xdb.embl;
-
-/**
- * Data model for a feature/location/locationElement read from an EMBL query
- * reply
- * 
- * @see embl_mapping.xml
- */
-public class EmblFeatureLocElement
-{
-  String type;
-
-  String accession;
-
-  String version;
-
-  boolean complement;
-
-  BasePosition basePositions[];
-
-  /**
-   * @return the accession
-   */
-  public String getAccession()
-  {
-    return accession;
-  }
-
-  /**
-   * @param accession
-   *          the accession to set
-   */
-  public void setAccession(String accession)
-  {
-    this.accession = accession;
-  }
-
-  /**
-   * @return the basePositions
-   */
-  public BasePosition[] getBasePositions()
-  {
-    return basePositions;
-  }
-
-  /**
-   * @param basePositions
-   *          the basePositions to set
-   */
-  public void setBasePositions(BasePosition[] basePositions)
-  {
-    this.basePositions = basePositions;
-  }
-
-  /**
-   * @return the complement
-   */
-  public boolean isComplement()
-  {
-    return complement;
-  }
-
-  /**
-   * @param complement
-   *          the complement to set
-   */
-  public void setComplement(boolean complement)
-  {
-    this.complement = complement;
-  }
-
-  /**
-   * @return the type
-   */
-  public String getType()
-  {
-    return type;
-  }
-
-  /**
-   * @param type
-   *          the type to set
-   */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
-  }
-}
diff --git a/src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java b/src/jalview/datamodel/xdb/embl/EmblFeatureLocations.java
deleted file mode 100644 (file)
index 9774004..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.xdb.embl;
-
-import jalview.bin.Cache;
-import jalview.util.ArrayUtils;
-
-import java.util.Arrays;
-import java.util.Vector;
-
-/**
- * Data model for a &lt;location&gt; child element of a &lt;feature&gt; read
- * from an EMBL query reply
- * 
- * @see embl_mapping.xml
- * @see http://www.insdc.org/files/feature_table.html#3.4.2
- */
-public class EmblFeatureLocations
-{
-  Vector<EmblFeatureLocElement> locElements;
-
-  String locationType;
-
-  boolean locationComplement;
-
-  /**
-   * @return the locationComplement
-   */
-  public boolean isLocationComplement()
-  {
-    return locationComplement;
-  }
-
-  /**
-   * @param locationComplement
-   *          the locationComplement to set
-   */
-  public void setLocationComplement(boolean locationComplement)
-  {
-    this.locationComplement = locationComplement;
-  }
-
-  /**
-   * @return the locationType
-   */
-  public String getLocationType()
-  {
-    return locationType;
-  }
-
-  /**
-   * @param locationType
-   *          the locationType to set
-   */
-  public void setLocationType(String locationType)
-  {
-    this.locationType = locationType;
-  }
-
-  /**
-   * @return the locElements
-   */
-  public Vector<EmblFeatureLocElement> getLocElements()
-  {
-    return locElements;
-  }
-
-  /**
-   * @param locElements
-   *          the locElements to set
-   */
-  public void setLocElements(Vector<EmblFeatureLocElement> locElements)
-  {
-    this.locElements = locElements;
-  }
-
-  /**
-   * Return all location elements as start-end pairs (without accessions) TODO:
-   * pass back complement and 'less than or more than' range information Note:
-   * do not use this since it throws away any accessionIds associated with each
-   * location!
-   * 
-   * @return int[] { start1, end1, ... }
-   */
-  public int[] getElementRanges()
-  {
-    return getElementRanges(null);
-  }
-
-  /**
-   * Return all location elements concerning given accession as start-end pairs.
-   * If the CDS feature is on the forward strand, then start <= end, if on the
-   * reverse strand then start > end.
-   * 
-   * @param accession
-   *          the accession string for which locations are requested, or null
-   *          for all locations
-   * @return int[] { start1, end1, ... }
-   */
-  int[] getElementRanges(String accession)
-  {
-    int sepos = 0;
-    int[] se = new int[locElements.size() * 2];
-    if ("single".equalsIgnoreCase(locationType)
-            || "join".equalsIgnoreCase(locationType))
-    {
-      for (EmblFeatureLocElement loce : locElements)
-      {
-        if (accession == null || loce.accession != null
-                && accession.equals(loce.accession))
-        {
-          BasePosition bp[] = loce.getBasePositions();
-          if (bp.length == 2)
-          {
-            try
-            {
-              int start = Integer.parseInt(bp[0].getPos());
-              int end = Integer.parseInt(bp[1].getPos());
-              se[sepos++] = start;
-              se[sepos++] = end;
-            } catch (NumberFormatException e)
-            {
-              System.err
-                      .println("format error in EMBL CDS location basePosition: "
-                              + e.getMessage());
-            }
-          }
-          else
-          {
-            System.err
-                    .println("format error in EMBL CDS location, basePosition count = "
-                            + bp.length);
-          }
-        }
-      }
-    }
-    else if (locationType != null)
-    {
-      if (Cache.log != null)
-      {
-        Cache.log
-                .error("EmblFeatureLocations.getElementRanges cannot deal with locationType=='"
-                        + locationType + "'");
-      }
-      else
-      {
-        System.err
-                .println("EmblFeatureLocations.getElementRanges cannot deal with locationType=='"
-                        + locationType + "'");
-      }
-    }
-
-    if (sepos != se.length)
-    {
-      /*
-       * we failed to parse something - trim off null values
-       */
-      se = Arrays.copyOf(se, sepos);
-    }
-
-    /*
-     * If on the complement, reverse the ranges to [end, start, ...end1, start1].
-     * For an example of a joined complement, see (tRNA feature) CAGL0B00165r on
-     * http://www.ebi.ac.uk/ena/data/view/CR380948&display=xml
-     * http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/embl/CR380948/emblxml
-     */
-    if (locationComplement)
-    {
-      ArrayUtils.reverseIntArray(se);
-    }
-    return se;
-  }
-}
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;
+  }
 }
index 2a6fa84..92c424b 100644 (file)
@@ -27,12 +27,8 @@ package jalview.datamodel.xdb.embl;
  */
 public class EmblSequence
 {
-  String version;
-
   String sequence;
 
-  String type;
-
   /**
    * @return the sequence
    */
@@ -47,40 +43,7 @@ public class EmblSequence
    */
   public void setSequence(String sequence)
   {
-    this.sequence = sequence;
-  }
-
-  /**
-   * @return the type
-   */
-  public String getType()
-  {
-    return type;
-  }
-
-  /**
-   * @param type
-   *          the type to set
-   */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
-
-  /**
-   * @return the version
-   */
-  public String getVersion()
-  {
-    return version;
-  }
-
-  /**
-   * @param version
-   *          the version to set
-   */
-  public void setVersion(String version)
-  {
-    this.version = version;
+    // remove spaces introduced by unmarshalling of newline characters
+    this.sequence = sequence.replace(" ", "");
   }
 }
diff --git a/src/jalview/ext/android/ContainerHelpers.java b/src/jalview/ext/android/ContainerHelpers.java
new file mode 100644 (file)
index 0000000..f536819
--- /dev/null
@@ -0,0 +1,102 @@
+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.
+ */
+
+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 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
+  }
+}
diff --git a/src/jalview/ext/android/SparseIntArray.java b/src/jalview/ext/android/SparseIntArray.java
new file mode 100644 (file)
index 0000000..2b9c4af
--- /dev/null
@@ -0,0 +1,425 @@
+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>
+ */
+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..375d745
--- /dev/null
@@ -0,0 +1,439 @@
+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>
+ */
+/**
+ * A copy of SparseShortArray designed to store short values (to minimise space
+ * usage).
+ * <p>
+ * Note that operations append, put, add throw ArithmeticException if the
+ * resulting value overflows the range of a short.
+ */
+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 84b5dcf..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;
@@ -8,10 +28,9 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
-import jalview.schemes.FeatureColourAdapter;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.FeatureSettingsAdapter;
 import jalview.util.MapList;
-import jalview.util.StringUtils;
 
 import java.awt.Color;
 import java.io.UnsupportedEncodingException;
@@ -108,47 +127,88 @@ public class EnsemblGene extends EnsemblSeqProxy
   public AlignmentI getSequenceRecords(String query) throws Exception
   {
     /*
-     * if given a transcript id, look up its gene parent
+     * convert to a non-duplicated list of gene identifiers
      */
-    if (isTranscriptIdentifier(query))
+    List<String> geneIds = getGeneIds(query);
+
+    AlignmentI al = null;
+    for (String geneId : geneIds)
     {
-      query = new EnsemblLookup(getDomain()).getParent(query);
-      if (query == null)
+      /*
+       * fetch the gene sequence(s) with features and xrefs
+       */
+      AlignmentI geneAlignment = super.getSequenceRecords(geneId);
+      if (geneAlignment == null)
       {
-        return null;
+        continue;
+      }
+      if (geneAlignment.getHeight() == 1)
+      {
+        getTranscripts(geneAlignment, geneId);
+      }
+      if (al == null)
+      {
+        al = geneAlignment;
+      }
+      else
+      {
+        al.append(geneAlignment);
       }
     }
+    return al;
+  }
 
-    /*
-     * if given a gene or other external name, lookup and fetch 
-     * the corresponding gene for all model organisms 
-     */
-    if (!isGeneIdentifier(query))
+  /**
+   * Converts a query, which may contain one or more gene or transcript
+   * identifiers, into a non-redundant list of gene identifiers.
+   * 
+   * @param accessions
+   * @return
+   */
+  List<String> getGeneIds(String accessions)
+  {
+    List<String> geneIds = new ArrayList<String>();
+
+    for (String acc : accessions.split(getAccessionSeparator()))
     {
-      List<String> geneIds = new EnsemblSymbol(getDomain()).getIds(query);
-      if (geneIds.isEmpty())
+      if (isGeneIdentifier(acc))
       {
-        return null;
+        if (!geneIds.contains(acc))
+        {
+          geneIds.add(acc);
+        }
       }
-      String theIds = StringUtils.listToDelimitedString(geneIds,
-              getAccessionSeparator());
-      return getSequenceRecords(theIds);
-    }
 
-    /*
-     * fetch the gene sequence(s) with features and xrefs
-     */
-    AlignmentI al = super.getSequenceRecords(query);
+      /*
+       * if given a transcript id, look up its gene parent
+       */
+      else if (isTranscriptIdentifier(acc))
+      {
+        String geneId = new EnsemblLookup(getDomain()).getParent(acc);
+        if (geneId != null && !geneIds.contains(geneId))
+        {
+          geneIds.add(geneId);
+        }
+      }
 
-    /*
-     * if we retrieved a single gene, get its transcripts as well
-     */
-    if (al.getHeight() == 1)
-    {
-      getTranscripts(al, query);
+      /*
+       * if given a gene or other external name, lookup and fetch 
+       * the corresponding gene for all model organisms 
+       */
+      else
+      {
+        List<String> ids = new EnsemblSymbol(getDomain(), getDbSource(),
+                getDbVersion()).getIds(acc);
+        for (String geneId : ids)
+        {
+          if (!geneIds.contains(geneId))
+          {
+            geneIds.add(geneId);
+          }
+        }
+      }
     }
-
-    return al;
+    return geneIds;
   }
 
   /**
@@ -160,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)
@@ -221,8 +282,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
       }
       gene.setSequenceFeatures(filtered
-              .toArray(new SequenceFeature[filtered
-              .size()]));
+              .toArray(new SequenceFeature[filtered.size()]));
     }
   }
 
@@ -488,6 +548,7 @@ public class EnsemblGene extends EnsemblSeqProxy
     return new FeatureSettingsAdapter()
     {
       SequenceOntologyI so = SequenceOntologyFactory.getInstance();
+
       @Override
       public boolean isFeatureDisplayed(String type)
       {
@@ -500,7 +561,7 @@ public class EnsemblGene extends EnsemblSeqProxy
       {
         if (so.isA(type, SequenceOntologyI.EXON))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
             @Override
             public boolean isColourByLabel()
@@ -511,7 +572,7 @@ public class EnsemblGene extends EnsemblSeqProxy
         }
         if (so.isA(type, SequenceOntologyI.SEQUENCE_VARIANT))
         {
-          return new FeatureColourAdapter()
+          return new FeatureColour()
           {
 
             @Override
@@ -551,10 +612,4 @@ public class EnsemblGene extends EnsemblSeqProxy
     };
   }
 
-  @Override
-  public int getMaximumQueryCount()
-  {
-    return 1;
-  }
-
 }
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
diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java
new file mode 100644 (file)
index 0000000..3108194
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 data class to model the data and rest version of one Ensembl domain,
+ * currently for rest.ensembl.org and rest.ensemblgenomes.org
+ * 
+ * @author gmcarstairs
+ */
+class EnsemblInfo
+{
+  /*
+   * The http domain this object is holding data values for
+   */
+  String domain;
+
+  /*
+   * The latest version Jalview has tested for, e.g. "4.5"; a minor version change should be
+   * ok, a major version change may break stuff 
+   */
+  String expectedRestVersion;
+
+  /*
+   * Major / minor / point version e.g. "4.5.1"
+   * @see http://rest.ensembl.org/info/rest/?content-type=application/json
+   */
+  String restVersion;
+
+  /*
+   * data version
+   * @see http://rest.ensembl.org/info/data/?content-type=application/json
+   */
+  String dataVersion;
+
+  /*
+   * true when http://rest.ensembl.org/info/ping/?content-type=application/json
+   * returns response code 200 and not {"error":"Database is unavailable"}
+   */
+  boolean restAvailable;
+
+  /*
+   * absolute time when availability was last checked
+   */
+  long lastAvailableCheckTime;
+
+  /*
+   * absolute time when version numbers were last checked
+   */
+  long lastVersionCheckTime;
+
+  // flag set to true if REST major version is not the one expected
+  boolean restMajorVersionMismatch;
+
+  /*
+   * absolute time to wait till if we overloaded the REST service
+   */
+  long retryAfter;
+
+  /**
+   * Constructor given expected REST version number e.g 4.5 or 3.4.3
+   * 
+   * @param restExpected
+   */
+  EnsemblInfo(String theDomain, String restExpected)
+  {
+    domain = theDomain;
+    expectedRestVersion = restExpected;
+    lastAvailableCheckTime = -1;
+    lastVersionCheckTime = -1;
+  }
+
+}
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 441ec7c..5903f69 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 jalview.io.FileParse;
+import jalview.util.StringUtils;
 
 import java.io.BufferedReader;
 import java.io.DataOutputStream;
@@ -10,10 +31,16 @@ import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.ws.rs.HttpMethod;
 
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
 import com.stevesoft.pat.Regex;
 
 /**
@@ -23,31 +50,45 @@ import com.stevesoft.pat.Regex;
  */
 abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 {
-  private final static String ENSEMBL_REST = "http://rest.ensembl.org";
+  private static final int DEFAULT_READ_TIMEOUT = 5 * 60 * 1000; // 5 minutes
+
+  private static final int CONNECT_TIMEOUT_MS = 10 * 1000; // 10 seconds
 
-  protected final static String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org";
+  /*
+   * 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.7";
+
+  private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
+
+  private static Map<String, EnsemblInfo> domainData;
 
   // @see https://github.com/Ensembl/ensembl-rest/wiki/Output-formats
   private static final String PING_URL = "http://rest.ensembl.org/info/ping.json";
 
-  private final static long RETEST_INTERVAL = 10000L; // 10 seconds
+  private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds
+
+  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}$");
-
-  private String domain = ENSEMBL_REST;
-
-  private static boolean ensemblRestAvailable = false;
-
-  private static long lastCheck = -1;
+          "(ENS)([A-Z]{3}|)G[0-9]{11}$");
 
-  /*
-   * absolute time to wait till if we overloaded the REST service
-   */
-  private static long retryAfter;
+  static
+  {
+    domainData = new HashMap<String, EnsemblInfo>();
+    domainData.put(ENSEMBL_REST, new EnsemblInfo(ENSEMBL_REST,
+            LATEST_ENSEMBL_REST_VERSION));
+    domainData.put(ENSEMBL_GENOMES_REST, new EnsemblInfo(
+            ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION));
+  }
 
   protected volatile boolean inProgress = false;
 
@@ -66,30 +107,28 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
    */
   public EnsemblRestClient(String d)
   {
-    domain = d;
+    setDomain(d);
   }
 
   /**
-   * Returns the domain name to query e.g. http://rest.ensembl.org or
-   * http://rest.ensemblgenomes.org
+   * Answers true if the query matches the regular expression pattern for an
+   * Ensembl transcript stable identifier
    * 
+   * @param query
    * @return
    */
-  String getDomain()
-  {
-    return domain;
-  }
-
-  void setDomain(String d)
-  {
-    domain = d;
-  }
-
   public boolean isTranscriptIdentifier(String query)
   {
     return query == null ? false : TRANSCRIPT_REGEX.search(query);
   }
 
+  /**
+   * Answers true if the query matches the regular expression pattern for an
+   * Ensembl gene stable identifier
+   * 
+   * @param query
+   * @return
+   */
   public boolean isGeneIdentifier(String query)
   {
     return query == null ? false : GENE_REGEX.search(query);
@@ -143,30 +182,47 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   protected abstract String getResponseMimeType();
 
   /**
-   * Tries to connect to Ensembl's REST 'ping' endpoint, and returns true if
-   * successful, else false
+   * Checks Ensembl's REST 'ping' endpoint, and returns true if response
+   * indicates available, else false
    * 
+   * @see http://rest.ensembl.org/documentation/info/ping
    * @return
    */
   private boolean checkEnsembl()
   {
+    BufferedReader br = null;
     try
     {
       // note this format works for both ensembl and ensemblgenomes
       // info/ping.json works for ensembl only (March 2016)
       URL ping = new URL(getDomain()
               + "/info/ping?content-type=application/json");
-      HttpURLConnection conn = (HttpURLConnection) ping.openConnection();
-      int rc = conn.getResponseCode();
-      conn.disconnect();
-      if (rc >= 200 && rc < 300)
-      {
-        return true;
-      }
+
+      /*
+       * expect {"ping":1} if ok
+       * if ping takes more than 2 seconds to respond, treat as if unavailable
+       */
+      br = getHttpResponse(ping, null, 2 * 1000);
+      JSONParser jp = new JSONParser();
+      JSONObject val = (JSONObject) jp.parse(br);
+      String pingString = val.get("ping").toString();
+      return pingString != null;
     } catch (Throwable t)
     {
       System.err.println("Error connecting to " + PING_URL + ": "
               + t.getMessage());
+    } finally
+    {
+      if (br != null)
+      {
+        try
+        {
+          br.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
+      }
     }
     return false;
   }
@@ -182,33 +238,55 @@ 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(), "HTTP_POST");
     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
      */
-    boolean multipleIds = ids.size() > 1;// useGetRequest();
+    boolean multipleIds = ids != null && ids.size() > 1;
     connection.setRequestMethod(multipleIds ? HttpMethod.POST
             : HttpMethod.GET);
     connection.setRequestProperty("Content-Type",
@@ -219,29 +297,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;
@@ -270,13 +352,14 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     // to test:
     // retryDelay = "5";
 
+    EnsemblInfo info = domainData.get(getDomain());
     if (retryDelay != null)
     {
       System.err.println("Ensembl REST service rate limit exceeded, wait "
               + retryDelay + " seconds before retrying");
       try
       {
-        retryAfter = System.currentTimeMillis()
+        info.retryAfter = System.currentTimeMillis()
                 + (1000 * Integer.valueOf(retryDelay));
       } catch (NumberFormatException e)
       {
@@ -286,46 +369,64 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     }
     else
     {
-      retryAfter = 0;
+      info.retryAfter = 0;
       // debug:
       // System.out.println(String.format(
       // "%s Ensembl requests remaining of %s (reset in %ss)",
       // 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,
-   * else false.
+   * else false. Also retrieves and saves the current version of Ensembl data
+   * and REST services at intervals.
    * 
    * @return
    */
   protected boolean isEnsemblAvailable()
   {
+    EnsemblInfo info = domainData.get(getDomain());
+
     long now = System.currentTimeMillis();
 
     /*
      * check if we are waiting for 'Retry-After' to expire
      */
-    if (retryAfter > now)
+    if (info.retryAfter > now)
     {
-      System.err.println("Still " + (1 + (retryAfter - now) / 1000)
+      System.err.println("Still " + (1 + (info.retryAfter - now) / 1000)
               + " secs to wait before retrying Ensembl");
       return false;
     }
     else
     {
-      retryAfter = 0;
+      info.retryAfter = 0;
     }
 
-    boolean retest = now - lastCheck > RETEST_INTERVAL;
-    if (ensemblRestAvailable && !retest)
+    /*
+     * recheck if Ensembl is up if it was down, or the recheck period has elapsed
+     */
+    boolean retestAvailability = (now - info.lastAvailableCheckTime) > AVAILABILITY_RETEST_INTERVAL;
+    if (!info.restAvailable || retestAvailability)
     {
-      return true;
+      info.restAvailable = checkEnsembl();
+      info.lastAvailableCheckTime = now;
     }
-    ensemblRestAvailable = checkEnsembl();
-    lastCheck = now;
-    return ensemblRestAvailable;
+
+    /*
+     * refetch Ensembl versions if the recheck period has elapsed
+     */
+    boolean refetchVersion = (now - info.lastVersionCheckTime) > VERSION_RETEST_INTERVAL;
+    if (refetchVersion)
+    {
+      checkEnsemblRestVersion();
+      checkEnsemblDataVersion();
+      info.lastVersionCheckTime = now;
+    }
+
+    return info.restAvailable;
   }
 
   /**
@@ -364,4 +465,103 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
     wr.close();
   }
 
+  /**
+   * Fetches and checks Ensembl's REST version number
+   * 
+   * @return
+   */
+  private void checkEnsemblRestVersion()
+  {
+    EnsemblInfo info = domainData.get(getDomain());
+
+    JSONParser jp = new JSONParser();
+    URL url = null;
+    try
+    {
+      url = new URL(getDomain()
+              + "/info/rest?content-type=application/json");
+      BufferedReader br = getHttpResponse(url, null);
+      JSONObject val = (JSONObject) jp.parse(br);
+      String version = val.get("release").toString();
+      String majorVersion = version.substring(0, version.indexOf("."));
+      String expected = info.expectedRestVersion;
+      String expectedMajorVersion = expected.substring(0,
+              expected.indexOf("."));
+      info.restMajorVersionMismatch = false;
+      try
+      {
+        /*
+         * if actual REST major version is ahead of what we expect,
+         * record this in case we want to warn the user
+         */
+        if (Float.valueOf(majorVersion) > Float
+                .valueOf(expectedMajorVersion))
+        {
+          info.restMajorVersionMismatch = true;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.err.println("Error in REST version: " + e.toString());
+      }
+
+      /*
+       * check if REST version is later than what Jalview has tested against,
+       * if so warn; we don't worry if it is earlier (this indicates Jalview has
+       * been tested in advance against the next pending REST version)
+       */
+      boolean laterVersion = StringUtils.compareVersions(version, expected) == 1;
+      if (laterVersion)
+      {
+        System.err.println(String.format(
+                "Expected %s REST version %s but found %s, see %s",
+                getDbSource(), expected, version, REST_CHANGE_LOG));
+      }
+      info.restVersion = version;
+    } catch (Throwable t)
+    {
+      System.err.println("Error checking Ensembl REST version: "
+              + t.getMessage());
+    }
+  }
+
+  public boolean isRestMajorVersionMismatch()
+  {
+    return domainData.get(getDomain()).restMajorVersionMismatch;
+  }
+
+  /**
+   * Fetches and checks Ensembl's data version number
+   * 
+   * @return
+   */
+  private void checkEnsemblDataVersion()
+  {
+    JSONParser jp = new JSONParser();
+    URL url = null;
+    try
+    {
+      url = new URL(getDomain()
+              + "/info/data?content-type=application/json");
+      BufferedReader br = getHttpResponse(url, null);
+      JSONObject val = (JSONObject) jp.parse(br);
+      JSONArray versions = (JSONArray) val.get("releases");
+      domainData.get(getDomain()).dataVersion = versions.get(0).toString();
+    } catch (Throwable t)
+    {
+      System.err.println("Error checking Ensembl data version: "
+              + t.getMessage());
+    }
+  }
+
+  public String getEnsemblDataVersion()
+  {
+    return domainData.get(getDomain()).dataVersion;
+  }
+
+  @Override
+  public String getDbVersion()
+  {
+    return getEnsemblDataVersion();
+  }
+
 }
index 8fb668a..7aa7178 100644 (file)
@@ -1,7 +1,28 @@
+/*
+ * 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;
@@ -14,6 +35,7 @@ import jalview.io.FastaFile;
 import jalview.io.FileParse;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
+import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 
@@ -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(), getDbVersion(),
-                proteinSeq.getName(), map);
+        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,24 +372,19 @@ 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)
     {
       seq.addDBRef(xref);
-      /*
-       * Save any Uniprot xref to be the reference for SIFTS mapping
-       */
-      if (DBRefSource.UNIPROT.equals(xref.getSource()))
-      {
-        seq.setSourceDBRef(xref);
-      }
     }
 
     /*
      * and add a reference to itself
      */
-    DBRefEntry self = new DBRefEntry(getDbSource(), "0", seq.getName());
+    DBRefEntry self = new DBRefEntry(getDbSource(),
+            getEnsemblDataVersion(), seq.getName());
     seq.addDBRef(self);
   }
 
@@ -349,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())
     {
@@ -373,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)
         {
@@ -385,7 +447,9 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         if (ids.contains(name)
                 || ids.contains(name.replace("ENSP", "ENST")))
         {
-          DBRefUtils.parseToDbRef(sq, DBRefSource.ENSEMBL, "0", name);
+          DBRefEntry dbref = DBRefUtils.parseToDbRef(sq, getDbSource(),
+                  getEnsemblDataVersion(), name);
+          sq.addDBRef(dbref);
         }
       }
       if (alignment == null)
@@ -505,7 +569,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     int mappedLength = 0;
     int direction = 1; // forward
     boolean directionSet = false;
-  
+
     for (SequenceFeature sf : sfs)
     {
       /*
@@ -522,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);
@@ -550,7 +614,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
         }
       }
     }
-  
+
     if (regions.isEmpty())
     {
       System.out.println("Failed to identify target sequence for " + accId
@@ -563,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);
   }
 
@@ -610,12 +674,16 @@ 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);
       copy.setBegin(Math.min(mappedRange[0], mappedRange[1]));
       copy.setEnd(Math.max(mappedRange[0], mappedRange[1]));
+      if (".".equals(copy.getFeatureGroup()))
+      {
+        copy.setFeatureGroup(getDbSource());
+      }
       targetSequence.addSequenceFeature(copy);
 
       /*
@@ -679,16 +747,21 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient
     {
       complement.append(",");
     }
-    if ("HGMD_MUTATION".equalsIgnoreCase(allele))
+
+    /*
+     * some 'alleles' are actually descriptive terms 
+     * e.g. HGMD_MUTATION, PhenCode_variation
+     * - we don't want to 'reverse complement' these
+     */
+    if (!Comparison.isNucleotideSequence(allele, true))
     {
       complement.append(allele);
     }
     else
     {
-      char[] alleles = allele.toCharArray();
-      for (int i = alleles.length - 1; i >= 0; i--)
+      for (int i = allele.length() - 1; i >= 0; i--)
       {
-        complement.append(Dna.getComplement(alleles[i]));
+        complement.append(Dna.getComplement(allele.charAt(i)));
       }
     }
   }
@@ -711,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;
@@ -843,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 9a4952e..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;
@@ -20,6 +40,10 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
   private static final Regex ACCESSION_REGEX = new Regex(
           "(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)");
 
+  protected static final String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org";
+
+  protected static final String ENSEMBL_REST = "http://rest.ensembl.org";
+
   /*
    * possible values for the 'feature' parameter of the /overlap REST service
    * @see http://rest.ensembl.org/documentation/info/overlap_id
@@ -31,17 +55,17 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
     constrained, regulatory
   }
 
+  private String domain = ENSEMBL_REST;
+
   @Override
   public String getDbSource()
   {
     // NB ensure Uniprot xrefs are canonicalised from "Ensembl" to "ENSEMBL"
-    return DBRefSource.ENSEMBL; // "ENSEMBL"
-  }
-
-  @Override
-  public String getDbVersion()
-  {
-    return "0";
+    if (ENSEMBL_GENOMES_REST.equals(getDomain()))
+    {
+      return DBRefSource.ENSEMBLGENOMES;
+    }
+    return DBRefSource.ENSEMBL;
   }
 
   @Override
@@ -90,4 +114,20 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl
   {
     return true;
   }
+
+  /**
+   * Returns the domain name to query e.g. http://rest.ensembl.org or
+   * http://rest.ensemblgenomes.org
+   * 
+   * @return
+   */
+  protected String getDomain()
+  {
+    return domain;
+  }
+
+  protected void setDomain(String d)
+  {
+    domain = d;
+  }
 }
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 3f0847b..fbac400 100644 (file)
@@ -43,6 +43,7 @@ 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;
@@ -57,7 +58,6 @@ import org.jmol.api.JmolStatusListener;
 import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
 import org.jmol.script.T;
-import org.jmol.viewer.JC;
 import org.jmol.viewer.Viewer;
 
 public abstract class JalviewJmolBinding extends AAStructureBindingModel
@@ -94,11 +94,6 @@ 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;
@@ -170,12 +165,9 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   public void closeViewer()
   {
-    viewer.acm.setModeMouse(JC.MOUSE_NONE);
     // remove listeners for all structures in viewer
     getSsm().removeStructureViewerListener(this, this.getPdbFile());
-    // and shut down jmol
-    viewer.evalStringQuiet("zap");
-    viewer.setJmolStatusListener(null);
+    viewer.dispose();
     lastCommand = null;
     viewer = null;
     releaseUIResources();
@@ -262,8 +254,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))
     {
@@ -311,6 +307,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++)
       {
@@ -356,6 +353,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;
@@ -423,6 +421,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
@@ -453,12 +453,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);
       }
@@ -469,7 +470,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());
@@ -651,15 +652,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
@@ -667,39 +668,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;
   }
index 0cbd620..b2ba256 100644 (file)
@@ -22,16 +22,18 @@ package jalview.ext.jmol;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.DBRefSource;
+import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
 import jalview.io.FileParse;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
-import jalview.structure.StructureViewSettings;
+import jalview.structure.StructureImportSettings;
+import jalview.util.Format;
 import jalview.util.MessageManager;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
@@ -59,15 +61,12 @@ public class JmolParser extends StructureFile implements JmolStatusListener
 {
   Viewer viewer = null;
 
-  public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr, String inFile, String type)
-          throws IOException
+  public JmolParser(String inFile, String type) throws IOException
   {
     super(inFile, type);
   }
 
-  public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
-          boolean externalSecStr, FileParse fp) throws IOException
+  public JmolParser(FileParse fp) throws IOException
   {
     super(fp);
   }
@@ -87,15 +86,6 @@ public class JmolParser extends StructureFile implements JmolStatusListener
   @Override
   public void parse() throws IOException
   {
-    String dataName = getDataName();
-    if (dataName.endsWith(".cif"))
-    {
-      setDbRefType(DBRefSource.MMCIF);
-    }
-    else
-    {
-      setDbRefType(DBRefSource.PDB);
-    }
     setChains(new Vector<PDBChain>());
     Viewer jmolModel = getJmolData();
     jmolModel.openReader(getDataName(), getDataName(), getReader());
@@ -106,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);
     }
   }
@@ -121,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
@@ -144,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)
       {
@@ -159,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);
         }
@@ -170,10 +186,6 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       makeResidueList();
       makeCaBondList();
 
-      if (getId() == null)
-      {
-        setId(inFile.getName());
-      }
       for (PDBChain chain : getChains())
       {
         SequenceI chainseq = postProcessChain(chain);
@@ -186,7 +198,7 @@ public class JmolParser extends StructureFile implements JmolStatusListener
           prot.add(chainseq);
         }
 
-        if (StructureViewSettings.isPredictSecondaryStructure())
+        if (StructureImportSettings.isProcessSecondaryStructure())
         {
           createAnnotation(chainseq, chain, ms.at);
         }
@@ -204,30 +216,99 @@ public class JmolParser extends StructureFile implements JmolStatusListener
   private List<Atom> convertSignificantAtoms(ModelSet ms)
   {
     List<Atom> significantAtoms = new ArrayList<Atom>();
+    HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
+    org.jmol.modelset.Atom prevAtom = null;
     for (org.jmol.modelset.Atom atom : ms.at)
     {
       if (atom.getAtomName().equalsIgnoreCase("CA")
               || atom.getAtomName().equalsIgnoreCase("P"))
       {
+        if (!atomValidated(atom, prevAtom, chainTerMap))
+        {
+          continue;
+        }
         Atom curAtom = new Atom(atom.x, atom.y, atom.z);
         curAtom.atomIndex = atom.getIndex();
         curAtom.chain = atom.getChainIDStr();
-        curAtom.insCode = atom.group.getInsertionCode();
+        curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
+                : atom.group.getInsertionCode();
         curAtom.name = atom.getAtomName();
         curAtom.number = atom.getAtomNumber();
         curAtom.resName = atom.getGroup3(true);
         curAtom.resNumber = atom.getResno();
         curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
                 .getIndex()] : Float.valueOf(atom.getOccupancy100());
-        curAtom.resNumIns = "" + curAtom.resNumber + curAtom.insCode;
+        String fmt = new Format("%4i").form(curAtom.resNumber);
+        curAtom.resNumIns = (fmt + curAtom.insCode);
         curAtom.tfactor = atom.getBfactor100() / 100f;
         curAtom.type = 0;
-        significantAtoms.add(curAtom);
+        // significantAtoms.add(curAtom);
+        // ignore atoms from subsequent models
+        if (!significantAtoms.contains(curAtom))
+        {
+          significantAtoms.add(curAtom);
+        }
+        prevAtom = atom;
       }
     }
     return significantAtoms;
   }
 
+  private boolean atomValidated(org.jmol.modelset.Atom curAtom,
+          org.jmol.modelset.Atom prevAtom,
+          HashMap<String, org.jmol.modelset.Atom> chainTerMap)
+  {
+    // System.out.println("Atom: " + curAtom.getAtomNumber()
+    // + "   Last atom index " + curAtom.group.lastAtomIndex);
+    if (chainTerMap == null || prevAtom == null)
+    {
+      return true;
+    }
+    String curAtomChId = curAtom.getChainIDStr();
+    String prevAtomChId = prevAtom.getChainIDStr();
+    // new chain encoutered
+    if (!prevAtomChId.equals(curAtomChId))
+    {
+      // On chain switch add previous chain termination to xTerMap if not exists
+      if (!chainTerMap.containsKey(prevAtomChId))
+      {
+        chainTerMap.put(prevAtomChId, prevAtom);
+      }
+      // if current atom belongs to an already terminated chain and the resNum
+      // 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);
+          return true;
+        }
+        return false;
+      }
+    }
+    // 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);
+        return true;
+      }
+      return false;
+    }
+    // HETATM with resNum jump > 2
+    return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
+            .getResno()) > 2));
+  }
+
   private void createAnnotation(SequenceI sequence, PDBChain chain,
           org.jmol.modelset.Atom[] jmolAtoms)
   {
@@ -279,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();
index 85c84ab..5b75206 100644 (file)
@@ -45,13 +45,20 @@ import org.json.simple.parser.ParseException;
  * 
  * @author jimp
  * 
- *         History: v1.0 revised from original due to refactoring of
- *         paradise-ubmc.u-strasbg.fr/webservices/annotate3d to
- *         http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview
+ * @version v1.0 revised from original due to refactoring of
+ *          paradise-ubmc.u-strasbg.fr/webservices/annotate3d to
+ *          http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview <br/>
+ *          See also testing URL from fjossinet:<br/>
+ *          http://charn2-ibmc.u-strasbg.fr:8080/api/compute/2d <br/>
+ *          If in doubt, check against the REST client at:
+ *          https://github.com/fjossinet/RNA-Science
+ *          -Toolbox/blob/master/pyrna/restclient.py
  */
 public class Annotate3D
 {
-  private static String twoDtoolsURL = "http://arn-ibmc.in2p3.fr/api/compute/2d";
+  // also test with
+  // "http://charn2-ibmc.u-strasbg.fr:8080/api/compute/2d";
+  private static String twoDtoolsURL = "http://arn-ibmc.in2p3.fr/api/compute/2d?tool=rnaview";
 
   private static ContentHandler createContentHandler()
   {
index 1ce0d2b..7ba9186 100644 (file)
@@ -101,17 +101,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private String lastCommand;
 
-  private boolean loadedInline;
-
-  /**
-   * current set of model filenames loaded
-   */
-  String[] modelFileNames = null;
-
   String lastHighlightCommand;
 
-  private List<String> lastReply;
-
   /*
    * incremented every time a load notification is successfully handled -
    * lightweight mechanism for other threads to detect when they can start
@@ -617,7 +608,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     if (lastCommand == null || !lastCommand.equals(command))
     {
       // trim command or it may never find a match in the replyLog!!
-      lastReply = viewer.sendChimeraCommand(command.trim(), logResponse);
+      List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
+              logResponse);
       if (logResponse && debug)
       {
         log("Response from command ('" + command + "') was:\n" + lastReply);
@@ -715,17 +707,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   // End StructureListener
   // //////////////////////////
 
-  public Color getColour(int atomIndex, int pdbResNum, String chain,
-          String pdbfile)
-  {
-    if (getModelNum(pdbfile) < 0)
-    {
-      return null;
-    }
-    log("get model / residue colour attribute unimplemented");
-    return null;
-  }
-
   /**
    * returns the current featureRenderer that should be used to colour the
    * structures
@@ -795,15 +776,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * map from string to applet
-   */
-  public Map getRegistryInfo()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  /**
    * returns the current sequenceRenderer that should be used to colour the
    * structures
    * 
@@ -815,20 +787,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           AlignmentViewPanel alignment);
 
   /**
-   * Construct and send a command to highlight zero, one or more atoms.
-   * 
-   * <pre>
-   * Done by generating a command like (to 'highlight' positions 44 and 46)
-   *   show #0:44,46.C
-   * </pre>
+   * Construct and send a command to highlight zero, one or more atoms. We do
+   * this by sending an "rlabel" command to show the residue label at that
+   * position.
    */
   @Override
   public void highlightAtoms(List<AtomSpec> atoms)
   {
-    if (atoms == null)
+    if (atoms == null || atoms.size() == 0)
     {
       return;
     }
+
     StringBuilder cmd = new StringBuilder(128);
     boolean first = true;
     boolean found = false;
@@ -843,7 +813,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       {
         if (first)
         {
-          cmd.append("show #").append(cms.get(0).getModelNumber())
+          cmd.append("rlabel #").append(cms.get(0).getModelNumber())
                   .append(":");
         }
         else
@@ -851,7 +821,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           cmd.append(",");
         }
         first = false;
-        cmd.append(cms.get(0).getModelNumber()).append(":");
         cmd.append(pdbResNum);
         if (!chain.equals(" "))
         {
@@ -863,19 +832,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     String command = cmd.toString();
 
     /*
-     * Avoid repeated commands for the same residue
+     * avoid repeated commands for the same residue
      */
     if (command.equals(lastHighlightCommand))
     {
       return;
     }
 
-    viewerCommandHistory(false);
+    /*
+     * unshow the label for the previous residue
+     */
+    if (lastHighlightCommand != null)
+    {
+      viewer.sendChimeraCommand("~" + lastHighlightCommand, false);
+    }
     if (found)
     {
-      viewer.sendChimeraCommand(command.toString(), false);
+      viewer.sendChimeraCommand(command, false);
     }
-    viewerCommandHistory(true);
     this.lastHighlightCommand = command;
   }
 
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)
similarity index 60%
rename from src/jalview/datamodel/xdb/embl/BasePosition.java
rename to src/jalview/fts/api/FTSData.java
index 3737adc..9e9d62c 100644 (file)
  * 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;
+
+package jalview.fts.api;
 
 /**
- * Data model for a feature/location/locationElement/basePosition read from an
- * EMBL query reply
+ * This interface provides a model for the summary data;
  * 
- * @see embl_mapping.xml
+ * @author tcnofoegbu
+ *
  */
-public class BasePosition
+public interface FTSData
 {
-  String type;
-
-  String pos;
-
-  /**
-   * @return the pos
-   */
-  public String getPos()
-  {
-    return pos;
-  }
-
-  /**
-   * @param pos
-   *          the pos to set
-   */
-  public void setPos(String pos)
-  {
-    this.pos = pos;
-  }
 
   /**
-   * @return the type
+   * Return an array of Objects representing the retrieved FTS data
+   * 
+   * @return
    */
-  public String getType()
-  {
-    return type;
-  }
+  public Object[] getSummaryData();
 
   /**
-   * @param type
-   *          the type to set
+   * The primary key object for the retrieved FTS data
+   * 
+   * @return
    */
-  public void setType(String type)
-  {
-    this.type = type;
-  }
+  public Object getPrimaryKey();
 }
diff --git a/src/jalview/fts/api/FTSDataColumnI.java b/src/jalview/fts/api/FTSDataColumnI.java
new file mode 100644 (file)
index 0000000..80990b4
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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.api;
+
+/**
+ * This interface provides a model for the dynamic data column configuration
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public interface FTSDataColumnI
+{
+  /**
+   * Returns the name of the data column
+   * 
+   * @return the data column's name
+   */
+  public String getName();
+
+  /**
+   * Returns the code of the data column
+   * 
+   * @return the data column's code
+   */
+  public String getCode();
+
+  /**
+   * Returns the alternative code value for the data column
+   * 
+   * @return the data column's code
+   */
+  public String getAltCode();
+
+  /**
+   * Returns the minimum width of the data column
+   * 
+   * @return the data column's minimum width
+   */
+  public int getMinWidth();
+
+  /**
+   * Returns the maximum width of the data column
+   * 
+   * @return the data column's maximum width
+   */
+  public int getMaxWidth();
+
+  /**
+   * Returns the preferred width of the data column
+   * 
+   * @return the data column's preferred width
+   */
+  public int getPreferredWidth();
+
+  /**
+   * Determines if the data column is the primary key column
+   * 
+   * @return true if data column is the primary key column, otherwise false
+   */
+  public boolean isPrimaryKeyColumn();
+
+  /**
+   * Checks if the data column field can be used to perform a search query
+   * 
+   * @return true means the data column is searchable
+   */
+  public boolean isSearchable();
+
+  /**
+   * Checks if the data column is displayed by default
+   * 
+   * @return true means the data column is shown by default
+   */
+  public boolean isVisibleByDefault();
+
+  /**
+   * Returns the data column's FTS data column group
+   * 
+   * @return the FTSDataColumnGroupI for the column
+   */
+  public FTSDataColumnGroupI getGroup();
+
+  /**
+   * Returns the data columns data type POJO
+   * 
+   * @return the DataTypeI for the column
+   */
+  public DataTypeI getDataType();
+
+  /**
+   * This interface provides a model for the dynamic data column group
+   * 
+   */
+  public interface FTSDataColumnGroupI
+  {
+    /**
+     * Returns the Id of the data column's group
+     * 
+     * @return the data column's group Id
+     */
+    public String getID();
+
+    /**
+     * Returns the name of the group
+     * 
+     * @return the group's name
+     */
+    public String getName();
+
+    /**
+     * Returns the sort order of the group
+     * 
+     * @return the group's sort order
+     */
+    public int getSortOrder();
+  }
+
+  public interface DataTypeI
+  {
+    /**
+     * Returns the data column's data type class
+     * 
+     * @return the Class for the data column's data type
+     */
+    public Class getDataTypeClass();
+
+    /**
+     * Checks if the numeric data column's data will be formated
+     * 
+     * @return true means the numeric data column shall be formatted
+     */
+    public boolean isFormtted();
+
+    /**
+     * Returns the number of significant figure to be used for the numeric value
+     * formatting
+     * 
+     * @return the number of significant figures
+     */
+    public int getSignificantFigures();
+  }
+}
diff --git a/src/jalview/fts/api/FTSRestClientI.java b/src/jalview/fts/api/FTSRestClientI.java
new file mode 100644 (file)
index 0000000..33b0ed6
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.api;
+
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+
+import java.util.Collection;
+
+/**
+ * Methods for FTS Rest client.
+ * 
+ * @author tcnofoegbu
+ */
+public interface FTSRestClientI
+{
+
+  /**
+   * Execute a given FTS request, process the response and return it as an
+   * FTSRestResponse object
+   * 
+   * @param ftsRestRequest
+   *          the FTS request to execute
+   * @return FTSRestResponse - the response after executing an FTS request
+   * @throws Exception
+   */
+  public FTSRestResponse executeRequest(FTSRestRequest ftsRequest)
+          throws Exception;
+
+  /**
+   * Return the resource file path for the data columns configuration file
+   * 
+   * @return
+   */
+  public String getColumnDataConfigFileName();
+
+  /**
+   * Fetch FTSDataColumnGroupI by the group's Id
+   * 
+   * @param groupId
+   * @return FTSDataColumnGroupI
+   * @throws Exception
+   */
+  public FTSDataColumnGroupI getDataColumnGroupById(String groupId)
+          throws Exception;
+
+  /**
+   * Fetch FTSDataColumnI by name or code
+   * 
+   * @param nameOrCode
+   * @return FTSDataColumnI
+   * @throws Exception
+   */
+  public FTSDataColumnI getDataColumnByNameOrCode(String nameOrCode)
+          throws Exception;
+
+  /**
+   * Convert collection of FTSDataColumnI objects to a comma delimited string of
+   * the 'code' values
+   * 
+   * @param wantedFields
+   *          the collection of FTSDataColumnI to process
+   * @return the generated comma delimited string from the supplied
+   *         FTSDataColumnI collection
+   */
+  public String getDataColumnsFieldsAsCommaDelimitedString(
+          Collection<FTSDataColumnI> wantedFields);
+
+  /**
+   * Fetch index of the primary key column for the dynamic table
+   * 
+   * @param wantedFields
+   *          the available table columns
+   * @param hasRefSeq
+   *          true if the data columns has an additional column for reference
+   *          sequence
+   * @return index of the primary key column
+   * @throws Exception
+   */
+  public int getPrimaryKeyColumIndex(
+          Collection<FTSDataColumnI> wantedFields, boolean hasRefSeq)
+          throws Exception;
+
+  /**
+   * Fetch the primary key data column object
+   * 
+   * @return the FTSDataColumnI object for the primary key column
+   */
+  public FTSDataColumnI getPrimaryKeyColumn();
+
+  /**
+   * Returns list of FTSDataColumnI objects to be displayed by default
+   * 
+   * @return list of columns to display by default
+   */
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns();
+
+  /**
+   * Return list of FTSDataColumnI objects that can be used to perform a search
+   * query
+   * 
+   * @return list of searchable FTSDataColumnI object
+   */
+  public Collection<FTSDataColumnI> getSearchableDataColumns();
+
+  /**
+   * Return list of all available FTSDataColumnI object
+   * 
+   * @return list of all FTSColumnI objcet
+   */
+  public Collection<FTSDataColumnI> getAllFTSDataColumns();
+
+  /**
+   * Return the default response page limit
+   * 
+   * @return the default response page size
+   */
+  public int getDefaultResponsePageSize();
+}
diff --git a/src/jalview/fts/api/GFTSPanelI.java b/src/jalview/fts/api/GFTSPanelI.java
new file mode 100644 (file)
index 0000000..f86c3bc
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.api;
+
+import java.util.Map;
+
+import javax.swing.JTable;
+
+/**
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public interface GFTSPanelI
+{
+
+  /**
+   * Action performed when a text is entered in the search field.
+   * 
+   * @param isFreshSearch
+   *          if true a fresh search is executed else a pagination search is
+   *          executed
+   */
+  public void searchAction(boolean isFreshSearch);
+
+  /**
+   * Action performed when search results are selected and the 'ok' button is
+   * pressed.
+   */
+  public void okAction();
+
+  /**
+   * Return the entered text
+   * 
+   * @return the entered text
+   */
+  public String getTypedText();
+
+  /**
+   * The JTable for presenting the query result
+   * 
+   * @return JTable
+   */
+  public JTable getResultTable();
+
+  /**
+   * Return the title to display on the search interface main panel
+   * 
+   * @return String - the title
+   */
+  public String getFTSFrameTitle();
+
+  /**
+   * Return a singleton instance of FTSRestClientI
+   * 
+   * @return FTSRestClientI
+   */
+  public FTSRestClientI getFTSRestClient();
+
+  /**
+   * Set error message when one occurs
+   * 
+   * @param message
+   *          the error message to set
+   */
+  public void setErrorMessage(String message);
+
+  /**
+   * Updates the title displayed on the search interface's main panel
+   * 
+   * @param newTitle
+   */
+  public void updateSearchFrameTitle(String newTitle);
+
+  /**
+   * Controls the progress spinner, set to 'true' while search operation is in
+   * progress and 'false' after it completes
+   * 
+   * @param isSearchInProgress
+   */
+  public void setSearchInProgress(Boolean isSearchInProgress);
+
+  /**
+   * Action performed when previous page (<<) button is pressed pressed.
+   */
+  public void prevPageAction();
+
+  /**
+   * Action performed when next page (>>) button is pressed pressed.
+   */
+  public void nextPageAction();
+
+  /**
+   * Checks if the current service's search result is paginate-able
+   * 
+   * @return true means the service provides paginated results
+   */
+  public boolean isPaginationEnabled();
+
+  /**
+   * Updates the 'enabled' state for the previous page button
+   * 
+   * @param isEnabled
+   */
+  public void setPrevPageButtonEnabled(boolean isEnabled);
+
+  /**
+   * Updates the 'enabled' state for the next page button
+   * 
+   * @param isEnabled
+   */
+  public void setNextPageButtonEnabled(boolean isEnabled);
+
+  /**
+   * The HashMap used to store user preferences for summary table columns,
+   * window size and position
+   * 
+   * @return
+   */
+  public Map<String, Integer> getTempUserPrefs();
+}
diff --git a/src/jalview/fts/core/DecimalFormatTableCellRenderer.java b/src/jalview/fts/core/DecimalFormatTableCellRenderer.java
new file mode 100644 (file)
index 0000000..a9e303c
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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;
+import java.text.DecimalFormat;
+
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/**
+ * The class to handle the formatting of the double values for JTable cells.
+ */
+public class DecimalFormatTableCellRenderer extends
+        DefaultTableCellRenderer
+{
+  private DecimalFormat formatter;
+
+  public DecimalFormatTableCellRenderer(boolean isFormated,
+          int significantFigures)
+  {
+    String integerFormater = isFormated ? "###,##0" : "0";
+    String fractionFormater = isFormated ? "###,##0." : "0.";
+    if (significantFigures > 0)
+    {
+      StringBuilder significantFigureBuilder = new StringBuilder();
+      for (int x = 1; x <= significantFigures; ++x)
+      {
+        significantFigureBuilder.append("0");
+      }
+      formatter = new DecimalFormat(fractionFormater
+              + significantFigureBuilder.toString());
+    }
+    else
+    {
+      formatter = new DecimalFormat(integerFormater);
+    }
+    super.setHorizontalAlignment(JLabel.RIGHT);
+  }
+
+  public DecimalFormatTableCellRenderer()
+  {
+    super.setHorizontalAlignment(JLabel.RIGHT);
+  }
+
+  @Override
+  public Component getTableCellRendererComponent(JTable table,
+          Object value, boolean isSelected, boolean hasFocus, int row,
+          int column)
+  {
+    if (value == null)
+    {
+      return null;
+    }
+
+    value = formatter.format(value);
+
+    return super.getTableCellRendererComponent(table, value, isSelected,
+            hasFocus, row, column);
+  }
+}
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.jbgui;
+package jalview.fts.core;
 
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField.Group;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.service.pdb.PDBFTSRestClient;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -38,20 +40,19 @@ import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
 
-
 @SuppressWarnings("serial")
-public class PDBDocFieldPreferences extends JScrollPane
+public class FTSDataColumnPreferences extends JScrollPane
 {
-  protected JTable tbl_pdbDocFieldConfig = new JTable();
+  protected JTable tbl_FTSDataColumnPrefs = new JTable();
 
   protected JScrollPane scrl_pdbDocFieldConfig = new JScrollPane(
-          tbl_pdbDocFieldConfig);
+          tbl_FTSDataColumnPrefs);
 
-  private HashMap<String, PDBDocField> map = new HashMap<String, PDBDocField>();
+  private HashMap<String, FTSDataColumnI> map = new HashMap<String, FTSDataColumnI>();
 
-  private static Collection<PDBDocField> searchSummaryFields = new LinkedHashSet<PDBDocField>();
+  private Collection<FTSDataColumnI> structSummaryColumns = new LinkedHashSet<FTSDataColumnI>();
 
-  private static Collection<PDBDocField> structureSummaryFields = new LinkedHashSet<PDBDocField>();
+  private Collection<FTSDataColumnI> allFTSDataColumns = new LinkedHashSet<FTSDataColumnI>();
 
   public enum PreferenceSource
   {
@@ -60,24 +61,22 @@ public class PDBDocFieldPreferences extends JScrollPane
 
   private PreferenceSource currentSource;
 
-  static
-  {
-    searchSummaryFields.add(PDBDocField.PDB_ID);
-    searchSummaryFields.add(PDBDocField.TITLE);
-    searchSummaryFields.add(PDBDocField.RESOLUTION);
-
-    structureSummaryFields.add(PDBDocField.PDB_ID);
-    structureSummaryFields.add(PDBDocField.TITLE);
-    structureSummaryFields.add(PDBDocField.RESOLUTION);
-  }
+  private FTSRestClientI ftsRestClient;
 
-  public PDBDocFieldPreferences(PreferenceSource source)
+  public FTSDataColumnPreferences(PreferenceSource source,
+          FTSRestClientI ftsRestClient)
   {
-    tbl_pdbDocFieldConfig.setAutoCreateRowSorter(true);
-
-
+    this.ftsRestClient = ftsRestClient;
+    if (source.equals(PreferenceSource.STRUCTURE_CHOOSER)
+            || source.equals(PreferenceSource.PREFERENCES))
+    {
+      structSummaryColumns = ((PDBFTSRestClient) ftsRestClient)
+              .getAllDefaultDisplayedStructureDataColumns();
+    }
+    allFTSDataColumns.addAll(ftsRestClient.getAllFTSDataColumns());
 
-    this.getViewport().add(tbl_pdbDocFieldConfig);
+    tbl_FTSDataColumnPrefs.setAutoCreateRowSorter(true);
+    this.getViewport().add(tbl_FTSDataColumnPrefs);
     this.currentSource = source;
 
     String[] columnNames = null;
@@ -97,9 +96,10 @@ public class PDBDocFieldPreferences extends JScrollPane
       break;
     }
 
-    Object[][] data = new Object[PDBDocField.values().length - 1][3];
+    Object[][] data = new Object[allFTSDataColumns.size() - 1][3];
+
     int x = 0;
-    for (PDBDocField field : PDBDocField.values())
+    for (FTSDataColumnI field : allFTSDataColumns)
     {
       if (field.getName().equalsIgnoreCase("all"))
       {
@@ -109,17 +109,19 @@ public class PDBDocFieldPreferences extends JScrollPane
       switch (source)
       {
       case SEARCH_SUMMARY:
-        data[x++] = new Object[] { searchSummaryFields.contains(field),
-            field.getName(), field.getGroup() };
+        data[x++] = new Object[] {
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns().contains(
+                    field), field.getName(), field.getGroup() };
         break;
       case STRUCTURE_CHOOSER:
-        data[x++] = new Object[] { structureSummaryFields.contains(field),
+        data[x++] = new Object[] { structSummaryColumns.contains(field),
             field.getName(), field.getGroup() };
         break;
       case PREFERENCES:
-        data[x++] = new Object[] { field.getName(),
-            searchSummaryFields.contains(field),
-            structureSummaryFields.contains(field) };
+        data[x++] = new Object[] {
+            field.getName(),
+            ftsRestClient.getAllDefaultDisplayedFTSDataColumns().contains(
+                    field), structSummaryColumns.contains(field) };
         break;
       default:
         break;
@@ -127,46 +129,46 @@ public class PDBDocFieldPreferences extends JScrollPane
       map.put(field.getName(), field);
     }
 
-    PDBFieldTableModel model = new PDBFieldTableModel(columnNames, data);
-    tbl_pdbDocFieldConfig.setModel(model);
+    FTSDataColumnPrefsTableModel model = new FTSDataColumnPrefsTableModel(
+            columnNames, data);
+    tbl_FTSDataColumnPrefs.setModel(model);
 
     switch (source)
     {
     case SEARCH_SUMMARY:
     case STRUCTURE_CHOOSER:
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(0)
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0)
               .setPreferredWidth(30);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(0).setMinWidth(20);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(0).setMaxWidth(40);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(1)
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0).setMinWidth(20);
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(0).setMaxWidth(40);
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(1)
               .setPreferredWidth(150);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(1).setMinWidth(150);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(2)
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(1).setMinWidth(150);
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2)
               .setPreferredWidth(150);
-      tbl_pdbDocFieldConfig.getColumnModel().getColumn(2)
-.setMinWidth(150);
+      tbl_FTSDataColumnPrefs.getColumnModel().getColumn(2).setMinWidth(150);
 
       TableRowSorter<TableModel> sorter = new TableRowSorter<>(
-              tbl_pdbDocFieldConfig.getModel());
-      tbl_pdbDocFieldConfig.setRowSorter(sorter);
+              tbl_FTSDataColumnPrefs.getModel());
+      tbl_FTSDataColumnPrefs.setRowSorter(sorter);
       List<RowSorter.SortKey> sortKeys = new ArrayList<>();
       int columnIndexToSort = 2;
       sortKeys.add(new RowSorter.SortKey(columnIndexToSort,
               SortOrder.ASCENDING));
       sorter.setSortKeys(sortKeys);
-      sorter.setComparator(
-              columnIndexToSort,
-              new Comparator<jalview.ws.dbsources.PDBRestClient.PDBDocField.Group>()
+      sorter.setComparator(columnIndexToSort,
+              new Comparator<FTSDataColumnGroupI>()
               {
                 @Override
-                public int compare(Group o1, Group o2)
+                public int compare(FTSDataColumnGroupI o1,
+                        FTSDataColumnGroupI o2)
                 {
                   return o1.getSortOrder() - o2.getSortOrder();
                 }
               });
       sorter.sort();
 
-      tbl_pdbDocFieldConfig
+      tbl_FTSDataColumnPrefs
               .setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
       break;
     case PREFERENCES:
@@ -176,32 +178,16 @@ public class PDBDocFieldPreferences extends JScrollPane
 
   }
 
-  public static Collection<PDBDocField> getSearchSummaryFields()
+  public Collection<FTSDataColumnI> getStructureSummaryFields()
   {
-    return searchSummaryFields;
+    return structSummaryColumns;
   }
 
-  public static void setSearchSummaryFields(
-          Collection<PDBDocField> searchSummaryFields)
+  class FTSDataColumnPrefsTableModel extends AbstractTableModel
   {
-    PDBDocFieldPreferences.searchSummaryFields = searchSummaryFields;
-  }
 
-  public static Collection<PDBDocField> getStructureSummaryFields()
-  {
-    return structureSummaryFields;
-  }
-
-  public static void setStructureSummaryFields(
-          Collection<PDBDocField> structureSummaryFields)
-  {
-    PDBDocFieldPreferences.structureSummaryFields = structureSummaryFields;
-  }
-
-  class PDBFieldTableModel extends AbstractTableModel
-  {
-
-    public PDBFieldTableModel(String[] columnNames, Object[][] data)
+    public FTSDataColumnPrefsTableModel(String[] columnNames,
+            Object[][] data)
     {
       this.data = data;
       this.columnNames = columnNames;
@@ -261,9 +247,9 @@ public class PDBDocFieldPreferences extends JScrollPane
       {
       case SEARCH_SUMMARY:
       case STRUCTURE_CHOOSER:
-        return (col == 0) && !isPDBID(row, 1);
+        return (col == 0) && !isPrimaryKeyCell(row, 1);
       case PREFERENCES:
-        return (col == 1 || col == 2) && !isPDBID(row, 0);
+        return (col == 1 || col == 2) && !isPrimaryKeyCell(row, 0);
       default:
         return false;
       }
@@ -278,16 +264,11 @@ public class PDBDocFieldPreferences extends JScrollPane
      * @return
      */
 
-    public boolean isPDBID(int row, int col)
+    public boolean isPrimaryKeyCell(int row, int col)
     {
-      boolean matched = false;
       String name = getValueAt(row, col).toString();
-      PDBDocField pdbField = map.get(name);
-      if (pdbField == PDBDocField.PDB_ID)
-      {
-        matched = true;
-      }
-      return matched;
+      FTSDataColumnI pdbField = map.get(name);
+      return pdbField.isPrimaryKeyColumn();
     }
 
     /*
@@ -314,40 +295,42 @@ public class PDBDocFieldPreferences extends JScrollPane
       }
       boolean selected = ((Boolean) value).booleanValue();
 
-      PDBDocField pdbField = map.get(name);
+      FTSDataColumnI ftsDataColumn = map.get(name);
 
       if (currentSource == PreferenceSource.SEARCH_SUMMARY)
       {
-        updatePrefs(searchSummaryFields, pdbField, selected);
+        updatePrefs(ftsRestClient.getAllDefaultDisplayedFTSDataColumns(),
+                ftsDataColumn, selected);
       }
       else if (currentSource == PreferenceSource.STRUCTURE_CHOOSER)
       {
-        updatePrefs(structureSummaryFields, pdbField, selected);
+        updatePrefs(structSummaryColumns, ftsDataColumn, selected);
       }
       else if (currentSource == PreferenceSource.PREFERENCES)
       {
         if (col == 1)
         {
-          updatePrefs(searchSummaryFields, pdbField, selected);
+          updatePrefs(ftsRestClient.getAllDefaultDisplayedFTSDataColumns(),
+                  ftsDataColumn, selected);
         }
         else if (col == 2)
         {
-          updatePrefs(structureSummaryFields, pdbField, selected);
+          updatePrefs(structSummaryColumns, ftsDataColumn, selected);
         }
       }
     }
 
-    private void updatePrefs(Collection<PDBDocField> prefConfig,
-            PDBDocField pdbField, boolean selected)
+    private void updatePrefs(Collection<FTSDataColumnI> prefConfig,
+            FTSDataColumnI dataColumn, boolean selected)
     {
-      if (prefConfig.contains(pdbField) && !selected)
+      if (prefConfig.contains(dataColumn) && !selected)
       {
-        prefConfig.remove(pdbField);
+        prefConfig.remove(dataColumn);
       }
 
-      if (!prefConfig.contains(pdbField) && selected)
+      if (!prefConfig.contains(dataColumn) && selected)
       {
-        prefConfig.add(pdbField);
+        prefConfig.add(dataColumn);
       }
     }
 
diff --git a/src/jalview/fts/core/FTSRestClient.java b/src/jalview/fts/core/FTSRestClient.java
new file mode 100644 (file)
index 0000000..4899e38
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * 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;
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.util.MessageManager;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * Base class providing implementation for common methods defined in
+ * FTSRestClientI
+ * 
+ * @author tcnofoegbu
+ * 
+ * @note implementations MUST be accessed as a singleton.
+ */
+public abstract class FTSRestClient implements FTSRestClientI
+{
+  protected Collection<FTSDataColumnI> dataColumns = new ArrayList<FTSDataColumnI>();
+
+  protected Collection<FTSDataColumnGroupI> dataColumnGroups = new ArrayList<FTSDataColumnGroupI>();
+
+  protected Collection<FTSDataColumnI> searchableDataColumns = new ArrayList<FTSDataColumnI>();
+
+  protected Collection<FTSDataColumnI> defaulDisplayedDataColumns = new ArrayList<FTSDataColumnI>();
+
+  protected FTSDataColumnI primaryKeyColumn;
+
+  private String primaryKeyColumnCode = null;
+
+  private int defaultResponsePageSize = 100;
+
+  protected FTSRestClient()
+  {
+
+  }
+
+  public void parseDataColumnsConfigFile()
+  {
+    String fileName = getColumnDataConfigFileName();
+
+    InputStream in = getClass().getResourceAsStream(fileName);
+
+    try (BufferedReader br = new BufferedReader(new InputStreamReader(in)))
+    {
+      String line;
+      while ((line = br.readLine()) != null)
+      {
+        final String[] lineData = line.split(";");
+        try
+        {
+          if (lineData.length == 2)
+          {
+            if (lineData[0].equalsIgnoreCase("_data_column.primary_key"))
+            {
+              primaryKeyColumnCode = lineData[1];
+            }
+            if (lineData[0]
+                    .equalsIgnoreCase("_data_column.default_response_page_size"))
+            {
+              defaultResponsePageSize = Integer.valueOf(lineData[1]);
+            }
+          }
+          else if (lineData.length == 3)
+          {
+            dataColumnGroups.add(new FTSDataColumnGroupI()
+            {
+              @Override
+              public String getID()
+              {
+                return lineData[0];
+              }
+
+              @Override
+              public String getName()
+              {
+                return lineData[1];
+              }
+
+              @Override
+              public int getSortOrder()
+              {
+                return Integer.valueOf(lineData[2]);
+              }
+
+              @Override
+              public String toString()
+              {
+                return lineData[1];
+              }
+
+              @Override
+              public int hashCode()
+              {
+                return Objects.hash(this.getID(), this.getName(),
+                        this.getSortOrder());
+              }
+
+              @Override
+              public boolean equals(Object otherObject)
+              {
+                FTSDataColumnGroupI that = (FTSDataColumnGroupI) otherObject;
+                return this.getID().equals(that.getID())
+                        && this.getName().equals(that.getName())
+                        && this.getSortOrder() == that.getSortOrder();
+              }
+            });
+          }
+          else if (lineData.length > 6)
+          {
+            FTSDataColumnI dataCol = new FTSDataColumnI()
+            {
+              @Override
+              public String toString()
+              {
+                return lineData[0];
+              }
+
+              @Override
+              public String getName()
+              {
+                return lineData[0];
+              }
+
+              @Override
+              public String getCode()
+              {
+                return lineData[1].split("\\|")[0];
+              }
+
+              @Override
+              public String getAltCode()
+              {
+                return lineData[1].split("\\|").length > 1 ? lineData[1]
+                        .split("\\|")[1] : getCode();
+              }
+
+              @Override
+              public DataTypeI getDataType()
+              {
+                final String[] dataTypeString = lineData[2].split("\\|");
+                final String classString = dataTypeString[0].toUpperCase();
+
+                return new DataTypeI()
+                {
+
+                  @Override
+                  public boolean isFormtted()
+                  {
+                    if (dataTypeString.length > 1
+                            && dataTypeString[1] != null)
+                    {
+                      switch (dataTypeString[1].toUpperCase())
+                      {
+                      case "T":
+                      case "TRUE":
+                        return true;
+                      case "F":
+                      case "False":
+                      default:
+                        return false;
+                      }
+                    }
+                    return false;
+                  }
+
+                  @Override
+                  public int getSignificantFigures()
+                  {
+                    if (dataTypeString.length > 2
+                            && dataTypeString[2] != null)
+                    {
+                      return Integer.valueOf(dataTypeString[2]);
+                    }
+                    return 0;
+                  }
+
+                  @Override
+                  public Class getDataTypeClass()
+                  {
+                    switch (classString)
+                    {
+                    case "INT":
+                    case "INTEGER":
+                      return Integer.class;
+                    case "DOUBLE":
+                      return Double.class;
+                    case "STRING":
+                    default:
+                      return String.class;
+                    }
+                  }
+                };
+
+              }
+
+              @Override
+              public FTSDataColumnGroupI getGroup()
+              {
+                FTSDataColumnGroupI group = null;
+                try
+                {
+                  group = getDataColumnGroupById(lineData[3]);
+                } catch (Exception e)
+                {
+                  e.printStackTrace();
+                }
+                return group;
+              }
+
+              @Override
+              public int getMinWidth()
+              {
+                return Integer.valueOf(lineData[4]);
+              }
+
+              @Override
+              public int getMaxWidth()
+              {
+                return Integer.valueOf(lineData[5]);
+              }
+
+              @Override
+              public int getPreferredWidth()
+              {
+                return Integer.valueOf(lineData[6]);
+              }
+
+              @Override
+              public boolean isPrimaryKeyColumn()
+              {
+                return getName().equalsIgnoreCase(primaryKeyColumnCode)
+                        || getCode().equalsIgnoreCase(primaryKeyColumnCode);
+              }
+
+              @Override
+              public boolean isVisibleByDefault()
+              {
+                return Boolean.valueOf(lineData[7]);
+              }
+
+              @Override
+              public boolean isSearchable()
+              {
+                return Boolean.valueOf(lineData[8]);
+              }
+
+              @Override
+              public int hashCode()
+              {
+                return Objects.hash(this.getName(), this.getCode(),
+                        this.getGroup());
+              }
+
+              @Override
+              public boolean equals(Object otherObject)
+              {
+                FTSDataColumnI that = (FTSDataColumnI) otherObject;
+                return this.getCode().equals(that.getCode())
+                        && this.getName().equals(that.getName())
+                        && this.getGroup().equals(that.getGroup());
+              }
+
+            };
+            dataColumns.add(dataCol);
+
+            if (dataCol.isSearchable())
+            {
+              searchableDataColumns.add(dataCol);
+            }
+
+            if (dataCol.isVisibleByDefault())
+            {
+              defaulDisplayedDataColumns.add(dataCol);
+            }
+
+          }
+          else
+          {
+            continue;
+          }
+        } catch (Exception e)
+        {
+          e.printStackTrace();
+        }
+      }
+      try
+      {
+        this.primaryKeyColumn = getDataColumnByNameOrCode(primaryKeyColumnCode);
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  @Override
+  public int getPrimaryKeyColumIndex(
+          Collection<FTSDataColumnI> wantedFields, boolean hasRefSeq)
+          throws Exception
+  {
+
+    // If a reference sequence is attached then start counting from 1 else
+    // start from zero
+    int pdbFieldIndexCounter = hasRefSeq ? 1 : 0;
+
+    for (FTSDataColumnI field : wantedFields)
+    {
+      if (field.isPrimaryKeyColumn())
+      {
+        break; // Once PDB Id index is determined exit iteration
+      }
+      ++pdbFieldIndexCounter;
+    }
+    return pdbFieldIndexCounter;
+  }
+
+  @Override
+  public String getDataColumnsFieldsAsCommaDelimitedString(
+          Collection<FTSDataColumnI> dataColumnFields)
+  {
+    String result = "";
+    if (dataColumnFields != null && !dataColumnFields.isEmpty())
+    {
+      StringBuilder returnedFields = new StringBuilder();
+      for (FTSDataColumnI field : dataColumnFields)
+      {
+        returnedFields.append(",").append(field.getCode());
+      }
+      returnedFields.deleteCharAt(0);
+      result = returnedFields.toString();
+    }
+    return result;
+  }
+
+  @Override
+  public Collection<FTSDataColumnI> getAllFTSDataColumns()
+  {
+    if (dataColumns == null || dataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    return dataColumns;
+  }
+
+  @Override
+  public Collection<FTSDataColumnI> getSearchableDataColumns()
+  {
+    if (searchableDataColumns == null || searchableDataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    return searchableDataColumns;
+  }
+
+  @Override
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedFTSDataColumns()
+  {
+    if (defaulDisplayedDataColumns == null
+            || defaulDisplayedDataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    return defaulDisplayedDataColumns;
+  }
+
+  @Override
+  public FTSDataColumnI getPrimaryKeyColumn()
+  {
+    if (defaulDisplayedDataColumns == null
+            || defaulDisplayedDataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    return primaryKeyColumn;
+  }
+
+  @Override
+  public FTSDataColumnI getDataColumnByNameOrCode(String nameOrCode)
+          throws Exception
+  {
+    if (dataColumns == null || dataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    for (FTSDataColumnI column : dataColumns)
+    {
+      if (column.getName().equalsIgnoreCase(nameOrCode)
+              || column.getCode().equalsIgnoreCase(nameOrCode))
+      {
+        return column;
+      }
+    }
+    throw new Exception("Couldn't find data column with name : "
+            + nameOrCode);
+  }
+
+  @Override
+  public FTSDataColumnGroupI getDataColumnGroupById(String id)
+          throws Exception
+  {
+    if (dataColumns == null || dataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    for (FTSDataColumnGroupI columnGroup : dataColumnGroups)
+    {
+      if (columnGroup.getID().equalsIgnoreCase(id))
+      {
+        return columnGroup;
+      }
+    }
+    throw new Exception("Couldn't find data column group with id : " + id);
+  }
+
+  public String getMessageByHTTPStatusCode(int code, String service)
+  {
+    String message = "";
+    switch (code)
+    {
+    case 400:
+      message = MessageManager.getString("exception.bad_request");
+      break;
+
+    case 410:
+      message = MessageManager.formatMessage(
+              "exception.fts_rest_service_no_longer_available", service);
+      break;
+    case 403:
+    case 404:
+      message = MessageManager.getString("exception.resource_not_be_found");
+      break;
+    case 408:
+    case 409:
+    case 500:
+    case 501:
+    case 502:
+    case 504:
+    case 505:
+      message = MessageManager.formatMessage("exception.fts_server_error",
+              service);
+      break;
+    case 503:
+      message = MessageManager.getString("exception.service_not_available");
+      break;
+    default:
+      break;
+    }
+    return message;
+  }
+
+  protected String getResourceFile(String fileName)
+  {
+    String result = "";
+    try
+    {
+      result = getClass().getResource(fileName).getFile();
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    return result;
+
+  }
+
+  @Override
+  public int getDefaultResponsePageSize()
+  {
+    if (dataColumns == null || dataColumns.isEmpty())
+    {
+      parseDataColumnsConfigFile();
+    }
+    return defaultResponsePageSize;
+  }
+
+}
similarity index 79%
rename from src/jalview/ws/uimodel/PDBRestRequest.java
rename to src/jalview/fts/core/FTSRestRequest.java
index 7bfc226..2e1c632 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 
-package jalview.ws.uimodel;
+package jalview.fts.core;
 
 import jalview.bin.Cache;
 import jalview.datamodel.SequenceI;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
+import jalview.fts.api.FTSDataColumnI;
 
 import java.util.Collection;
 
 /**
- * Represents the PDB request to be consumed by the PDBRestClient
+ * Represents the FTS request to be consumed by the FTSRestClient
  * 
  * @author tcnofoegbu
  *
  */
-public class PDBRestRequest
+public class FTSRestRequest
 {
   private String fieldToSearchBy;
 
@@ -56,9 +56,11 @@ public class PDBRestRequest
 
   private int responseSize;
 
+  private int offSet;
+
   private boolean isSortAscending;
 
-  private Collection<PDBDocField> wantedFields;
+  private Collection<FTSDataColumnI> wantedFields;
 
   public String getFieldToSearchBy()
   {
@@ -100,12 +102,12 @@ public class PDBRestRequest
     this.responseSize = responseSize;
   }
 
-  public Collection<PDBDocField> getWantedFields()
+  public Collection<FTSDataColumnI> getWantedFields()
   {
     return wantedFields;
   }
 
-  public void setWantedFields(Collection<PDBDocField> wantedFields)
+  public void setWantedFields(Collection<FTSDataColumnI> wantedFields)
   {
     this.wantedFields = wantedFields;
   }
@@ -136,21 +138,6 @@ public class PDBRestRequest
     this.associatedSequence = associatedSequence;
   }
 
-  public String getQuery()
-  {
-    return fieldToSearchBy + searchTerm
-            + (isAllowEmptySeq() ? "" : " AND molecule_sequence:['' TO *]")
-            + (isAllowUnpublishedEntries() ? "" : " AND status:REL");
-  }
-
-  @Override
-  public String toString()
-  {
-    return "Query : " + getQuery() + " sort field: " + fieldToSortBy
-            + " isAsc: " + isAscending() + " Associated Seq : "
-            + associatedSequence;
-  }
-
   public boolean isAllowUnpublishedEntries()
   {
     return allowUnpublishedEntries;
@@ -190,4 +177,14 @@ public class PDBRestRequest
   {
     this.facetPivotMinCount = facetPivotMinCount;
   }
+
+  public int getOffSet()
+  {
+    return offSet;
+  }
+
+  public void setOffSet(int offSet)
+  {
+    this.offSet = offSet;
+  }
 }
diff --git a/src/jalview/fts/core/FTSRestResponse.java b/src/jalview/fts/core/FTSRestResponse.java
new file mode 100644 (file)
index 0000000..5d8fb96
--- /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.fts.core;
+
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+
+/**
+ * Represents the response model generated by the FTSRestClient upon successful
+ * execution of a given FTS request
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public class FTSRestResponse
+{
+  private int numberOfItemsFound;
+
+  private String responseTime;
+
+  private Collection<FTSData> searchSummary;
+
+  public int getNumberOfItemsFound()
+  {
+    return numberOfItemsFound;
+  }
+
+  public void setNumberOfItemsFound(int itemFound)
+  {
+    this.numberOfItemsFound = itemFound;
+  }
+
+  public String getResponseTime()
+  {
+    return responseTime;
+  }
+
+  public void setResponseTime(String responseTime)
+  {
+    this.responseTime = responseTime;
+  }
+
+  public Collection<FTSData> getSearchSummary()
+  {
+    return searchSummary;
+  }
+
+  public void setSearchSummary(Collection<FTSData> searchSummary)
+  {
+    this.searchSummary = searchSummary;
+  }
+
+  /**
+   * Convenience method to obtain a Table model for a given summary List based
+   * on the request parameters
+   * 
+   * @param request
+   *          the FTSRestRequest object which holds useful information for
+   *          creating a table model
+   * @param summariesList
+   *          the summary list which contains the data for populating the
+   *          table's rows
+   * @return the table model which was dynamically generated
+   */
+  public static DefaultTableModel getTableModel(FTSRestRequest request,
+          Collection<FTSData> summariesList)
+  {
+    final FTSDataColumnI[] cols = request.getWantedFields().toArray(
+            new FTSDataColumnI[0]);
+    final int colOffset = request.getAssociatedSequence() == null ? 0 : 1;
+    DefaultTableModel tableModel = new DefaultTableModel()
+    {
+      @Override
+      public boolean isCellEditable(int row, int column)
+      {
+        return false;
+      }
+
+      @Override
+      public Class<?> getColumnClass(int columnIndex)
+      {
+        if (colOffset == 1 && columnIndex == 0)
+        {
+          return String.class;
+        }
+        return cols[columnIndex - colOffset].getDataType()
+                .getDataTypeClass();
+      }
+
+    };
+    if (request.getAssociatedSequence() != null)
+    {
+      tableModel.addColumn("Ref Sequence"); // Create sequence column header if
+      // exists in the request
+    }
+    for (FTSDataColumnI field : request.getWantedFields())
+    {
+      tableModel.addColumn(field.getName()); // Create sequence column header if
+                                             // exists in the request
+    }
+
+    for (FTSData res : summariesList)
+    {
+      tableModel.addRow(res.getSummaryData()); // Populate table rows with
+                                               // summary list
+    }
+
+    return tableModel;
+  }
+
+  public static void configureTableColumn(JTable tbl_summary,
+          Collection<FTSDataColumnI> wantedFields,
+          Map<String, Integer> columnPrefs)
+  {
+    for (FTSDataColumnI wantedField : wantedFields)
+    {
+      try
+      {
+        tbl_summary.getColumn(wantedField.getName()).setMinWidth(
+                wantedField.getMinWidth());
+        tbl_summary.getColumn(wantedField.getName()).setMaxWidth(
+                wantedField.getMaxWidth());
+        int prefedWidth = columnPrefs.get(wantedField.getName()) == null ? wantedField
+                .getPreferredWidth() : columnPrefs.get(wantedField
+                .getName());
+        tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(
+                prefedWidth);
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
+      if (wantedField.getDataType().getDataTypeClass() == Double.class)
+      {
+        DecimalFormatTableCellRenderer dfr = new DecimalFormatTableCellRenderer(
+                wantedField.getDataType().isFormtted(), wantedField
+                        .getDataType().getSignificantFigures());
+        tbl_summary.getColumn(wantedField.getName()).setCellRenderer(dfr);
+      }
+      else if (wantedField.getDataType().getDataTypeClass() == Integer.class)
+      {
+        DecimalFormatTableCellRenderer dfr = new DecimalFormatTableCellRenderer(
+                wantedField.getDataType().isFormtted(), wantedField
+                        .getDataType().getSignificantFigures());
+        tbl_summary.getColumn(wantedField.getName()).setCellRenderer(dfr);
+      }
+    }
+  }
+
+}
diff --git a/src/jalview/fts/core/GFTSPanel.java b/src/jalview/fts/core/GFTSPanel.java
new file mode 100644 (file)
index 0000000..a69d9f8
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+ * 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;
+import jalview.fts.api.GFTSPanelI;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.gui.Desktop;
+import jalview.gui.IProgressIndicator;
+import jalview.gui.JvSwingUtils;
+import jalview.gui.SequenceFetcher;
+import jalview.util.MessageManager;
+
+import java.awt.BorderLayout;
+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;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.Timer;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.InternalFrameEvent;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumn;
+
+/**
+ * This class provides the swing GUI layout for FTS Panel and implements most of
+ * the contracts defined in GFSPanelI
+ * 
+ * @author tcnofoegbu
+ *
+ */
+
+@SuppressWarnings("serial")
+public abstract class GFTSPanel extends JPanel implements GFTSPanelI
+{
+  protected JInternalFrame mainFrame = new JInternalFrame(
+          getFTSFrameTitle());
+
+  protected IProgressIndicator progressIndicator;
+
+  protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
+
+  protected JButton btn_ok = new JButton();
+
+  protected JButton btn_back = new JButton();
+
+  protected JButton btn_cancel = new JButton();
+
+  protected JTextField txt_search = new JTextField(30);
+
+  protected SequenceFetcher seqFetcher;
+
+  protected Collection<FTSDataColumnI> wantedFields;
+
+  private String lastSearchTerm = "";
+
+  protected JButton btn_next_page = new JButton();
+
+  protected JButton btn_prev_page = new JButton();
+
+  protected StringBuilder errorWarning = new StringBuilder();
+
+  protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
+          "/images/warning.gif"));
+
+  protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
+          "/images/loading.gif"));
+
+  protected ImageIcon balnkPlaceholderImage = new ImageIcon(getClass()
+          .getResource("/images/blank_16x16_placeholder.png"));
+
+  protected JLabel lbl_warning = new JLabel(warningImage);
+
+  protected JLabel lbl_loading = new JLabel(loadingImage);
+
+  protected JLabel lbl_blank = new JLabel(balnkPlaceholderImage);
+
+  private JTabbedPane tabbedPane = new JTabbedPane();
+
+  private JPanel pnl_actions = new JPanel();
+
+  private JPanel pnl_results = new JPanel(new CardLayout());
+
+  private JPanel pnl_inputs = new JPanel();
+
+  private BorderLayout mainLayout = new BorderLayout();
+
+  protected Object[] previousWantedFields;
+
+  protected int resultSetCount;
+
+  protected int totalResultSetCount;
+
+  protected int offSet;
+
+  protected int pageLimit;
+
+  protected HashSet<String> paginatorCart = new HashSet<String>();
+
+  protected static final DecimalFormat totalNumberformatter = new DecimalFormat(
+          "###,###");
+
+  private JTable tbl_summary = new JTable()
+  {
+    private boolean inLayout;
+
+    @Override
+    public boolean getScrollableTracksViewportWidth()
+    {
+      return hasExcessWidth();
+
+    }
+
+    @Override
+    public void doLayout()
+    {
+      if (hasExcessWidth())
+      {
+        autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
+      }
+      inLayout = true;
+      super.doLayout();
+      inLayout = false;
+      autoResizeMode = AUTO_RESIZE_OFF;
+    }
+
+    protected boolean hasExcessWidth()
+    {
+      return getPreferredSize().width < getParent().getWidth();
+    }
+
+    @Override
+    public void columnMarginChanged(ChangeEvent e)
+    {
+      if (isEditing())
+      {
+        removeEditor();
+      }
+      TableColumn resizingColumn = getTableHeader().getResizingColumn();
+      // Need to do this here, before the parent's
+      // layout manager calls getPreferredSize().
+      if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
+              && !inLayout)
+      {
+        resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+        String colHeader = resizingColumn.getHeaderValue().toString();
+        getTempUserPrefs().put(colHeader, resizingColumn.getWidth());
+      }
+      resizeAndRepaint();
+    }
+
+    @Override
+    public String getToolTipText(MouseEvent evt)
+    {
+      String toolTipText = null;
+      java.awt.Point pnt = evt.getPoint();
+      int rowIndex = rowAtPoint(pnt);
+      int colIndex = columnAtPoint(pnt);
+
+      try
+      {
+        if (getValueAt(rowIndex, colIndex) == null)
+        {
+          return null;
+        }
+        toolTipText = getValueAt(rowIndex, colIndex).toString();
+
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
+      toolTipText = (toolTipText == null ? null
+              : (toolTipText.length() > 500 ? JvSwingUtils.wrapTooltip(
+                      true, toolTipText.subSequence(0, 500) + "...")
+                      : JvSwingUtils.wrapTooltip(true, toolTipText)));
+
+      return toolTipText;
+    }
+  };
+
+  protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
+
+  public GFTSPanel()
+  {
+    try
+    {
+      jbInit();
+      mainFrame.addFocusListener(new FocusAdapter()
+      {
+        @Override
+        public void focusGained(FocusEvent e)
+        {
+          txt_search.requestFocusInWindow();
+        }
+      });
+      mainFrame.invalidate();
+      mainFrame.pack();
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Initializes the GUI default properties
+   * 
+   * @throws Exception
+   */
+  private void jbInit() throws Exception
+  {
+    Integer width = getTempUserPrefs().get("FTSPanel.width") == null ? 800
+            : getTempUserPrefs().get("FTSPanel.width");
+    Integer height = getTempUserPrefs().get("FTSPanel.height") == null ? 400
+            : getTempUserPrefs().get("FTSPanel.height");
+    lbl_warning.setVisible(false);
+    lbl_warning.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_loading.setVisible(false);
+    lbl_loading.setFont(new java.awt.Font("Verdana", 0, 12));
+    lbl_blank.setVisible(true);
+    lbl_blank.setFont(new java.awt.Font("Verdana", 0, 12));
+
+    tbl_summary.setAutoCreateRowSorter(true);
+    tbl_summary.getTableHeader().setReorderingAllowed(false);
+    tbl_summary.addMouseListener(new MouseAdapter()
+    {
+      @Override
+      public void mouseClicked(MouseEvent e)
+      {
+        validateSelection();
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent e)
+      {
+        validateSelection();
+      }
+    });
+    tbl_summary.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        validateSelection();
+        switch (evt.getKeyCode())
+        {
+        case KeyEvent.VK_ESCAPE: // escape key
+          btn_back_ActionPerformed();
+          break;
+        case KeyEvent.VK_ENTER: // enter key
+          if (btn_ok.isEnabled())
+          {
+            okAction();
+          }
+          evt.consume();
+          break;
+        case KeyEvent.VK_TAB: // tab key
+          if (evt.isShiftDown())
+          {
+            tabbedPane.requestFocus();
+          }
+          else
+          {
+            btn_back.requestFocus();
+          }
+          evt.consume();
+          break;
+        default:
+          return;
+        }
+      }
+    });
+
+    btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_back.setText(MessageManager.getString("action.back"));
+    btn_back.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        btn_back_ActionPerformed();
+      }
+    });
+    btn_back.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          btn_back_ActionPerformed();
+        }
+      }
+    });
+
+    btn_ok.setEnabled(false);
+    btn_ok.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_ok.setText(MessageManager.getString("action.ok"));
+    btn_ok.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        okAction();
+      }
+    });
+    btn_ok.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          okAction();
+        }
+      }
+    });
+    btn_next_page.setEnabled(false);
+    btn_next_page.setToolTipText(MessageManager
+            .getString("label.next_page_tooltip"));
+    btn_next_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_next_page.setText(MessageManager.getString("action.next_page"));
+    btn_next_page.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        nextPageAction();
+      }
+    });
+    btn_next_page.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          nextPageAction();
+        }
+      }
+    });
+
+    btn_prev_page.setEnabled(false);
+    btn_prev_page.setToolTipText(MessageManager
+            .getString("label.prev_page_tooltip"));
+    btn_prev_page.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_prev_page.setText(MessageManager.getString("action.prev_page"));
+    btn_prev_page.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        prevPageAction();
+      }
+    });
+    btn_prev_page.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          prevPageAction();
+        }
+      }
+    });
+
+    if (isPaginationEnabled())
+    {
+      btn_prev_page.setVisible(true);
+      btn_next_page.setVisible(true);
+    }
+    else
+    {
+      btn_prev_page.setVisible(false);
+      btn_next_page.setVisible(false);
+    }
+
+    btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
+    btn_cancel.setText(MessageManager.getString("action.cancel"));
+    btn_cancel.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        btn_cancel_ActionPerformed();
+      }
+    });
+    btn_cancel.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          btn_cancel_ActionPerformed();
+        }
+      }
+    });
+    scrl_searchResult.setPreferredSize(new Dimension(width, height));
+
+    cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
+    cmb_searchTarget.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        String tooltipText;
+        if ("all".equalsIgnoreCase(getCmbSearchTarget().getSelectedItem()
+                .toString()))
+        {
+          tooltipText = MessageManager.getString("label.search_all");
+        }
+        else if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
+                .getSelectedItem().toString()))
+        {
+          tooltipText = MessageManager
+                  .getString("label.separate_multiple_accession_ids");
+        }
+        else
+        {
+          tooltipText = MessageManager.formatMessage(
+                  "label.separate_multiple_query_values",
+                  new Object[] { getCmbSearchTarget().getSelectedItem()
+                          .toString() });
+        }
+        txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
+                tooltipText));
+        searchAction(true);
+      }
+    });
+
+    populateCmbSearchTargetOptions();
+
+    txt_search.setFont(new java.awt.Font("Verdana", 0, 12));
+
+    txt_search.addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent e)
+      {
+        if (e.getKeyCode() == KeyEvent.VK_ENTER)
+        {
+          if (txt_search.getText() == null
+                  || txt_search.getText().isEmpty())
+          {
+            return;
+          }
+          String primaryKeyName = getFTSRestClient().getPrimaryKeyColumn()
+                  .getName();
+          if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
+                  .getSelectedItem().toString()))
+          {
+            transferToSequenceFetcher(txt_search.getText());
+          }
+        }
+      }
+    });
+
+    final DeferredTextInputListener listener = new DeferredTextInputListener(
+            1500, new ActionListener()
+            {
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                if (!getTypedText().equalsIgnoreCase(lastSearchTerm))
+                {
+                  searchAction(true);
+                  paginatorCart.clear();
+                  lastSearchTerm = getTypedText();
+                }
+              }
+            }, false);
+    txt_search.getDocument().addDocumentListener(listener);
+    txt_search.addFocusListener(new FocusListener()
+    {
+      @Override
+      public void focusGained(FocusEvent e)
+      {
+        listener.start();
+      }
+
+      @Override
+      public void focusLost(FocusEvent e)
+      {
+        // listener.stop();
+      }
+    });
+
+    final String searchTabTitle = MessageManager
+            .getString("label.search_result");
+    final String configureCols = MessageManager
+            .getString("label.configure_displayed_columns");
+    ChangeListener changeListener = new ChangeListener()
+    {
+      @Override
+      public void stateChanged(ChangeEvent changeEvent)
+      {
+        JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
+                .getSource();
+        int index = sourceTabbedPane.getSelectedIndex();
+
+        btn_back.setVisible(true);
+        btn_cancel.setVisible(true);
+        btn_ok.setVisible(true);
+        if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
+        {
+          btn_back.setVisible(false);
+          btn_cancel.setVisible(false);
+          btn_ok.setVisible(false);
+          btn_back.setEnabled(false);
+          btn_cancel.setEnabled(false);
+          btn_ok.setEnabled(false);
+          btn_next_page.setEnabled(false);
+          btn_prev_page.setEnabled(false);
+          txt_search.setEnabled(false);
+          cmb_searchTarget.setEnabled(false);
+          previousWantedFields = getFTSRestClient()
+                  .getAllDefaultDisplayedFTSDataColumns().toArray(
+                          new Object[0]);
+        }
+        if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
+        {
+          btn_back.setEnabled(true);
+          btn_cancel.setEnabled(true);
+          refreshPaginatorState();
+          txt_search.setEnabled(true);
+          cmb_searchTarget.setEnabled(true);
+          if (wantedFieldsUpdated())
+          {
+            searchAction(true);
+            paginatorCart.clear();
+          }
+          else
+          {
+            validateSelection();
+          }
+        }
+      }
+    };
+    tabbedPane.addChangeListener(changeListener);
+    tabbedPane.setPreferredSize(new Dimension(width, height));
+    tabbedPane.add(searchTabTitle, scrl_searchResult);
+    tabbedPane.add(configureCols, new FTSDataColumnPreferences(
+            PreferenceSource.SEARCH_SUMMARY, getFTSRestClient()));
+
+    pnl_actions.add(btn_back);
+    pnl_actions.add(btn_ok);
+    pnl_actions.add(btn_cancel);
+
+    pnl_results.add(tabbedPane);
+    pnl_inputs.add(cmb_searchTarget);
+    pnl_inputs.add(txt_search);
+    pnl_inputs.add(lbl_loading);
+    pnl_inputs.add(lbl_warning);
+    pnl_inputs.add(lbl_blank);
+    pnl_inputs.add(btn_prev_page);
+    pnl_inputs.add(btn_next_page);
+
+    this.setLayout(mainLayout);
+    this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
+    this.add(pnl_results, java.awt.BorderLayout.CENTER);
+    this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
+    mainFrame.setVisible(true);
+    mainFrame.setContentPane(this);
+    mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+    mainFrame
+            .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+            {
+              @Override
+              public void internalFrameClosing(InternalFrameEvent e)
+              {
+                closeAction();
+              }
+            });
+    mainFrame.setVisible(true);
+    mainFrame.setContentPane(this);
+    mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+    Integer x = getTempUserPrefs().get("FTSPanel.x");
+    Integer y = getTempUserPrefs().get("FTSPanel.y");
+    if (x != null && y != null)
+    {
+      mainFrame.setLocation(x, y);
+    }
+    Desktop.addInternalFrame(mainFrame, getFTSFrameTitle(), width, height);
+  }
+
+  protected void closeAction()
+  {
+    // System.out.println(">>>>>>>>>> closing internal frame!!!");
+    // System.out.println("width : " + this.getWidth());
+    // System.out.println("heigh : " + this.getHeight());
+    // System.out.println("x : " + mainFrame.getX());
+    // System.out.println("y : " + mainFrame.getY());
+    getTempUserPrefs().put("FTSPanel.width", this.getWidth());
+    getTempUserPrefs().put("FTSPanel.height", pnl_results.getHeight());
+    getTempUserPrefs().put("FTSPanel.x", mainFrame.getX());
+    getTempUserPrefs().put("FTSPanel.y", mainFrame.getY());
+    mainFrame.dispose();
+  }
+
+  public class DeferredTextInputListener implements DocumentListener
+  {
+    private final Timer swingTimer;
+
+    public DeferredTextInputListener(int timeOut, ActionListener listener,
+            boolean repeats)
+    {
+      swingTimer = new Timer(timeOut, listener);
+      swingTimer.setRepeats(repeats);
+    }
+
+    public void start()
+    {
+      swingTimer.start();
+    }
+
+    public void stop()
+    {
+      swingTimer.stop();
+    }
+
+    @Override
+    public void insertUpdate(DocumentEvent e)
+    {
+      swingTimer.restart();
+    }
+
+    @Override
+    public void removeUpdate(DocumentEvent e)
+    {
+      swingTimer.restart();
+    }
+
+    @Override
+    public void changedUpdate(DocumentEvent e)
+    {
+      swingTimer.restart();
+    }
+
+  }
+
+  public boolean wantedFieldsUpdated()
+  {
+    if (previousWantedFields == null)
+    {
+      return true;
+    }
+
+    return Arrays.equals(getFTSRestClient()
+            .getAllDefaultDisplayedFTSDataColumns().toArray(new Object[0]),
+            previousWantedFields) ? false : true;
+
+  }
+
+  public void validateSelection()
+  {
+    if (tbl_summary.getSelectedRows().length > 0
+            || !paginatorCart.isEmpty())
+    {
+      btn_ok.setEnabled(true);
+    }
+    else
+    {
+      btn_ok.setEnabled(false);
+    }
+  }
+
+  public JComboBox<FTSDataColumnI> getCmbSearchTarget()
+  {
+    return cmb_searchTarget;
+  }
+
+  public JTextField getTxtSearch()
+  {
+    return txt_search;
+  }
+
+  public JInternalFrame getMainFrame()
+  {
+    return mainFrame;
+  }
+
+  protected void delayAndEnableActionButtons()
+  {
+    new Thread()
+    {
+      @Override
+      public void run()
+      {
+        try
+        {
+          Thread.sleep(1500);
+        } catch (InterruptedException e)
+        {
+          e.printStackTrace();
+        }
+        btn_ok.setEnabled(true);
+        btn_back.setEnabled(true);
+        btn_cancel.setEnabled(true);
+      }
+    }.start();
+  }
+
+  protected void checkForErrors()
+  {
+    lbl_warning.setVisible(false);
+    lbl_blank.setVisible(true);
+    if (errorWarning.length() > 0)
+    {
+      lbl_loading.setVisible(false);
+      lbl_blank.setVisible(false);
+      lbl_warning.setToolTipText(JvSwingUtils.wrapTooltip(true,
+              errorWarning.toString()));
+      lbl_warning.setVisible(true);
+    }
+  }
+
+  protected void btn_back_ActionPerformed()
+  {
+    closeAction();
+    new SequenceFetcher(progressIndicator);
+  }
+
+  protected void disableActionButtons()
+  {
+    btn_ok.setEnabled(false);
+    btn_back.setEnabled(false);
+    btn_cancel.setEnabled(false);
+  }
+
+  protected void btn_cancel_ActionPerformed()
+  {
+    closeAction();
+  }
+
+  /**
+   * Populates search target combo-box options
+   */
+  public void populateCmbSearchTargetOptions()
+  {
+    List<FTSDataColumnI> searchableTargets = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      Collection<FTSDataColumnI> foundFTSTargets = getFTSRestClient()
+              .getSearchableDataColumns();
+      searchableTargets.addAll(foundFTSTargets);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    Collections.sort(searchableTargets, new Comparator<FTSDataColumnI>()
+    {
+      @Override
+      public int compare(FTSDataColumnI o1, FTSDataColumnI o2)
+      {
+        return o1.getName().compareTo(o2.getName());
+      }
+    });
+
+    for (FTSDataColumnI searchTarget : searchableTargets)
+    {
+      cmb_searchTarget.addItem(searchTarget);
+    }
+  }
+
+  public void transferToSequenceFetcher(String ids)
+  {
+    // mainFrame.dispose();
+    seqFetcher.getTextArea().setText(ids);
+    Thread worker = new Thread(seqFetcher);
+    worker.start();
+  }
+
+  @Override
+  public String getTypedText()
+  {
+    return txt_search.getText().trim();
+  }
+
+  @Override
+  public JTable getResultTable()
+  {
+    return tbl_summary;
+  }
+
+  public void reset()
+  {
+    lbl_loading.setVisible(false);
+    errorWarning.setLength(0);
+    lbl_warning.setVisible(false);
+    lbl_blank.setVisible(true);
+    btn_ok.setEnabled(false);
+    mainFrame.setTitle(getFTSFrameTitle());
+    referesh();
+    tbl_summary.setModel(new DefaultTableModel());
+    tbl_summary.setVisible(false);
+  }
+
+  @Override
+  public void setPrevPageButtonEnabled(boolean isEnabled)
+  {
+    btn_prev_page.setEnabled(isEnabled);
+  }
+
+  @Override
+  public void setNextPageButtonEnabled(boolean isEnabled)
+  {
+    btn_next_page.setEnabled(isEnabled);
+  }
+
+  @Override
+  public void setErrorMessage(String message)
+  {
+    errorWarning.append(message);
+  }
+
+  @Override
+  public void updateSearchFrameTitle(String title)
+  {
+    mainFrame.setTitle(title);
+  }
+
+  @Override
+  public void setSearchInProgress(Boolean isSearchInProgress)
+  {
+    lbl_blank.setVisible(!isSearchInProgress);
+    lbl_loading.setVisible(isSearchInProgress);
+  }
+
+  @Override
+  public void prevPageAction()
+  {
+    updatePaginatorCart();
+    if (offSet >= pageLimit)
+    {
+      offSet = offSet - pageLimit;
+      searchAction(false);
+    }
+    else
+    {
+      refreshPaginatorState();
+    }
+  }
+
+  @Override
+  public void nextPageAction()
+  {
+    updatePaginatorCart();
+    offSet = offSet + pageLimit;
+    searchAction(false);
+  }
+
+  public void updatePaginatorCart()
+  {
+    int primaryKeyColIndex = 0;
+    JTable resultTable = getResultTable();
+    int totalRows = resultTable.getRowCount();
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    for (int row = 0; row < totalRows; row++)
+    {
+      String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
+      if (paginatorCart.contains(id))
+      {
+        paginatorCart.remove(id);
+      }
+    }
+    int[] selectedRows = resultTable.getSelectedRows();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = resultTable.getValueAt(summaryRow, primaryKeyColIndex)
+              .toString();
+      paginatorCart.add(idStr);
+    }
+    // System.out.println("Paginator shopping cart size : "
+    // + paginatorCart.size());
+  }
+
+  public void updateSummaryTableSelections()
+  {
+    JTable resultTable = getResultTable();
+    if (paginatorCart.isEmpty())
+    {
+      return;
+    }
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    // System.out.println(">>>>>> got here : 1");
+    int totalRows = resultTable.getRowCount();
+    // resultTable.clearSelection();
+    for (int row = 0; row < totalRows; row++)
+    {
+      String id = (String) resultTable.getValueAt(row, primaryKeyColIndex);
+      if (paginatorCart.contains(id))
+      {
+        resultTable.addRowSelectionInterval(row, row);
+      }
+    }
+    validateSelection();
+  }
+
+  public void refreshPaginatorState()
+  {
+    // System.out.println("resultSet count : " + resultSetCount);
+    // System.out.println("offSet : " + offSet);
+    // System.out.println("page limit : " + pageLimit);
+    setPrevPageButtonEnabled(false);
+    setNextPageButtonEnabled(false);
+    if (resultSetCount == 0 && pageLimit == 0)
+    {
+      return;
+    }
+    if (resultSetCount >= pageLimit)
+    {
+      setNextPageButtonEnabled(true);
+    }
+    if (offSet >= pageLimit)
+    {
+      setPrevPageButtonEnabled(true);
+    }
+  }
+
+  public void referesh()
+  {
+    mainFrame.setTitle(getFTSFrameTitle());
+  }
+
+}
diff --git a/src/jalview/fts/service/pdb/PDBFTSPanel.java b/src/jalview/fts/service/pdb/PDBFTSPanel.java
new file mode 100644 (file)
index 0000000..1dfabce
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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.service.pdb;
+
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.GFTSPanel;
+import jalview.gui.SequenceFetcher;
+import jalview.util.MessageManager;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+@SuppressWarnings("serial")
+public class PDBFTSPanel extends GFTSPanel
+{
+  private static String defaultFTSFrameTitle = MessageManager
+          .getString("label.pdb_sequence_fetcher");
+
+  private String ftsFrameTitle = defaultFTSFrameTitle;
+
+  private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+
+  public PDBFTSPanel(SequenceFetcher seqFetcher)
+  {
+    super();
+    pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
+    this.seqFetcher = seqFetcher;
+    this.progressIndicator = (seqFetcher == null) ? null : seqFetcher
+            .getProgressIndicator();
+  }
+
+  @Override
+  public void searchAction(boolean isFreshSearch)
+  {
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
+    new Thread()
+    {
+      @Override
+      public void run()
+      {
+        ftsFrameTitle = defaultFTSFrameTitle;
+        reset();
+        boolean allowEmptySequence = false;
+        if (getTypedText().length() > 0)
+        {
+          setSearchInProgress(true);
+          long startTime = System.currentTimeMillis();
+
+          String searchTarget = ((FTSDataColumnI) cmb_searchTarget
+                  .getSelectedItem()).getCode();
+          wantedFields = PDBFTSRestClient.getInstance()
+                  .getAllDefaultDisplayedFTSDataColumns();
+          String searchTerm = decodeSearchTerm(txt_search.getText(),
+                  searchTarget);
+
+          FTSRestRequest request = new FTSRestRequest();
+          request.setAllowEmptySeq(allowEmptySequence);
+          request.setResponseSize(100);
+          request.setFieldToSearchBy("(" + searchTarget + ":");
+          request.setSearchTerm(searchTerm + ")");
+          request.setOffSet(offSet);
+          request.setWantedFields(wantedFields);
+          FTSRestClientI pdbRestCleint = PDBFTSRestClient.getInstance();
+          FTSRestResponse resultList;
+          try
+          {
+            resultList = pdbRestCleint.executeRequest(request);
+          } catch (Exception e)
+          {
+            setErrorMessage(e.getMessage());
+            checkForErrors();
+            return;
+          }
+
+          if (resultList.getSearchSummary() != null
+                  && resultList.getSearchSummary().size() > 0)
+          {
+            getResultTable().setModel(
+                    FTSRestResponse.getTableModel(request,
+                            resultList.getSearchSummary()));
+            FTSRestResponse.configureTableColumn(getResultTable(),
+                    wantedFields, tempUserPrefs);
+            getResultTable().setVisible(true);
+          }
+
+          long endTime = System.currentTimeMillis();
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0) ? MessageManager
+                  .getString("label.results") : MessageManager
+                  .getString("label.result");
+
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle
+                    + " - "
+                    + result
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount) + " "
+                    + " (" + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+
+          setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
+        }
+      }
+    }.start();
+  }
+
+  public static String decodeSearchTerm(String enteredText,
+          String targetField)
+  {
+    String foundSearchTerms = enteredText;
+    StringBuilder foundSearchTermsBuilder = new StringBuilder();
+    if (enteredText.contains(";"))
+    {
+      String[] searchTerms = enteredText.split(";");
+      for (String searchTerm : searchTerms)
+      {
+        if (searchTerm.contains(":"))
+        {
+          foundSearchTermsBuilder.append(targetField).append(":")
+                  .append(searchTerm.split(":")[0]).append(" OR ");
+        }
+        else
+        {
+          foundSearchTermsBuilder.append(targetField).append(":")
+                  .append(searchTerm).append(" OR ");
+        }
+      }
+      int endIndex = foundSearchTermsBuilder.lastIndexOf(" OR ");
+      foundSearchTerms = foundSearchTermsBuilder.toString();
+      if (foundSearchTerms.contains(" OR "))
+      {
+        foundSearchTerms = foundSearchTerms.substring(
+                targetField.length() + 1, endIndex);
+      }
+    }
+    else if (enteredText.contains(":"))
+    {
+      foundSearchTerms = foundSearchTerms.split(":")[0];
+    }
+    return foundSearchTerms;
+  }
+
+  @Override
+  public void okAction()
+  {
+    // mainFrame.dispose();
+    disableActionButtons();
+    StringBuilder selectedIds = new StringBuilder();
+    HashSet<String> selectedIdsSet = new HashSet<String>();
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    int[] selectedRows = getResultTable().getSelectedRows();
+    String searchTerm = txt_search.getText();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = getResultTable().getValueAt(summaryRow,
+              primaryKeyColIndex).toString();
+      selectedIdsSet.add(getPDBIdwithSpecifiedChain(idStr, searchTerm));
+    }
+
+    for (String idStr : paginatorCart)
+    {
+      selectedIdsSet.add(getPDBIdwithSpecifiedChain(idStr, searchTerm));
+    }
+
+    for (String selectedId : selectedIdsSet)
+    {
+      selectedIds.append(selectedId).append(";");
+    }
+
+    String ids = selectedIds.toString();
+    // System.out.println(">>>>>>>>>>>>>>>> selected Ids: " + ids);
+    seqFetcher.getTextArea().setText(ids);
+    Thread worker = new Thread(seqFetcher);
+    worker.start();
+    delayAndEnableActionButtons();
+  }
+
+  public static String getPDBIdwithSpecifiedChain(String pdbId,
+          String searchTerm)
+  {
+    String pdbIdWithChainCode = "";
+    if (searchTerm.contains(";"))
+    {
+      String[] foundTerms = searchTerm.split(";");
+      for (String foundTerm : foundTerms)
+      {
+        if (foundTerm.contains(pdbId))
+        {
+          pdbIdWithChainCode = foundTerm;
+        }
+      }
+    }
+    else if (searchTerm.contains(pdbId))
+    {
+      pdbIdWithChainCode = searchTerm;
+    }
+    else
+    {
+      pdbIdWithChainCode = pdbId;
+    }
+    return pdbIdWithChainCode;
+  }
+
+  @Override
+  public FTSRestClientI getFTSRestClient()
+  {
+    return PDBFTSRestClient.getInstance();
+  }
+
+  @Override
+  public String getFTSFrameTitle()
+  {
+    return ftsFrameTitle;
+  }
+
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
+
+  @Override
+  public Map<String, Integer> getTempUserPrefs()
+  {
+    return tempUserPrefs;
+  }
+
+}
diff --git a/src/jalview/fts/service/pdb/PDBFTSRestClient.java b/src/jalview/fts/service/pdb/PDBFTSRestClient.java
new file mode 100644 (file)
index 0000000..06bf55b
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * 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.service.pdb;
+
+import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+import javax.ws.rs.core.MediaType;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+/**
+ * A rest client for querying the Search endpoint of the PDB API
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public class PDBFTSRestClient extends FTSRestClient
+{
+
+  private static FTSRestClientI instance = null;
+
+  public static final String PDB_SEARCH_ENDPOINT = "http://www.ebi.ac.uk/pdbe/search/pdb/select?";
+
+  protected PDBFTSRestClient()
+  {
+  }
+
+  /**
+   * Takes a PDBRestRequest object and returns a response upon execution
+   * 
+   * @param pdbRestRequest
+   *          the PDBRestRequest instance to be processed
+   * @return the pdbResponse object for the given request
+   * @throws Exception
+   */
+  @Override
+  public FTSRestResponse executeRequest(FTSRestRequest pdbRestRequest)
+          throws Exception
+  {
+    try
+    {
+      ClientConfig clientConfig = new DefaultClientConfig();
+      Client client = Client.create(clientConfig);
+
+      String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(pdbRestRequest
+              .getWantedFields());
+      int responseSize = (pdbRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
+              : pdbRestRequest.getResponseSize();
+      int offSet = pdbRestRequest.getOffSet();
+      String sortParam = null;
+      if (pdbRestRequest.getFieldToSortBy() == null
+              || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
+      {
+        sortParam = "";
+      }
+      else
+      {
+        if (pdbRestRequest.getFieldToSortBy()
+                .equalsIgnoreCase("Resolution"))
+        {
+          sortParam = pdbRestRequest.getFieldToSortBy()
+                  + (pdbRestRequest.isAscending() ? " asc" : " desc");
+        }
+        else
+        {
+          sortParam = pdbRestRequest.getFieldToSortBy()
+                  + (pdbRestRequest.isAscending() ? " desc" : " asc");
+        }
+      }
+
+      String facetPivot = (pdbRestRequest.getFacetPivot() == null || pdbRestRequest
+              .getFacetPivot().isEmpty()) ? "" : pdbRestRequest
+              .getFacetPivot();
+      String facetPivotMinCount = String.valueOf(pdbRestRequest
+              .getFacetPivotMinCount());
+
+      String query = pdbRestRequest.getFieldToSearchBy()
+              + pdbRestRequest.getSearchTerm()
+              + (pdbRestRequest.isAllowEmptySeq() ? ""
+                      : " AND molecule_sequence:['' TO *]")
+              + (pdbRestRequest.isAllowUnpublishedEntries() ? ""
+                      : " AND status:REL");
+
+      // Build request parameters for the REST Request
+      WebResource webResource = null;
+      if (pdbRestRequest.isFacet())
+      {
+        webResource = client.resource(PDB_SEARCH_ENDPOINT)
+                .queryParam("wt", "json").queryParam("fl", wantedFields)
+                .queryParam("rows", String.valueOf(responseSize))
+                .queryParam("q", query)
+                .queryParam("start", String.valueOf(offSet))
+                .queryParam("sort", sortParam).queryParam("facet", "true")
+                .queryParam("facet.pivot", facetPivot)
+                .queryParam("facet.pivot.mincount", facetPivotMinCount);
+      }
+      else
+      {
+        webResource = client.resource(PDB_SEARCH_ENDPOINT)
+                .queryParam("wt", "json").queryParam("fl", wantedFields)
+                .queryParam("rows", String.valueOf(responseSize))
+                .queryParam("start", String.valueOf(offSet))
+                .queryParam("q", query).queryParam("sort", sortParam);
+      }
+      // Execute the REST request
+      ClientResponse clientResponse = webResource.accept(
+              MediaType.APPLICATION_JSON).get(ClientResponse.class);
+
+      // Get the JSON string from the response object
+      String responseString = clientResponse.getEntity(String.class);
+      // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
+
+      // Check the response status and report exception if one occurs
+      if (clientResponse.getStatus() != 200)
+      {
+        String errorMessage = "";
+        if (clientResponse.getStatus() == 400)
+        {
+          errorMessage = parseJsonExceptionString(responseString);
+          throw new Exception(errorMessage);
+        }
+        else
+        {
+          errorMessage = getMessageByHTTPStatusCode(
+                  clientResponse.getStatus(), "PDB");
+          throw new Exception(errorMessage);
+        }
+      }
+
+      // Make redundant objects eligible for garbage collection to conserve
+      // memory
+      clientResponse = null;
+      client = null;
+
+      // Process the response and return the result to the caller.
+      return parsePDBJsonResponse(responseString, pdbRestRequest);
+    } catch (Exception e)
+    {
+      String exceptionMsg = e.getMessage();
+      if (exceptionMsg.contains("SocketException"))
+      {
+        // No internet connection
+        throw new Exception(
+                MessageManager
+                        .getString("exception.unable_to_detect_internet_connection"));
+      }
+      else if (exceptionMsg.contains("UnknownHostException"))
+      {
+        // The server 'www.ebi.ac.uk' is unreachable
+        throw new Exception(MessageManager.formatMessage(
+                "exception.fts_server_unreachable", "PDB Solr"));
+      }
+      else
+      {
+        throw e;
+      }
+    }
+  }
+
+  /**
+   * Process error response from PDB server if/when one occurs.
+   * 
+   * @param jsonResponse
+   *          the JSON string containing error message from the server
+   * @return the processed error message from the JSON string
+   */
+  public static String parseJsonExceptionString(String jsonErrorResponse)
+  {
+    StringBuilder errorMessage = new StringBuilder(
+            "\n============= PDB Rest Client RunTime error =============\n");
+
+    try
+    {
+      JSONParser jsonParser = new JSONParser();
+      JSONObject jsonObj = (JSONObject) jsonParser.parse(jsonErrorResponse);
+      JSONObject errorResponse = (JSONObject) jsonObj.get("error");
+
+      JSONObject responseHeader = (JSONObject) jsonObj
+              .get("responseHeader");
+      JSONObject paramsObj = (JSONObject) responseHeader.get("params");
+      String status = responseHeader.get("status").toString();
+      String message = errorResponse.get("msg").toString();
+      String query = paramsObj.get("q").toString();
+      String fl = paramsObj.get("fl").toString();
+
+      errorMessage.append("Status: ").append(status).append("\n");
+      errorMessage.append("Message: ").append(message).append("\n");
+      errorMessage.append("query: ").append(query).append("\n");
+      errorMessage.append("fl: ").append(fl).append("\n");
+
+    } catch (ParseException e)
+    {
+      e.printStackTrace();
+    }
+    return errorMessage.toString();
+  }
+
+  /**
+   * Parses the JSON response string from PDB REST API. The response is dynamic
+   * hence, only fields specifically requested for in the 'wantedFields'
+   * parameter is fetched/processed
+   * 
+   * @param pdbJsonResponseString
+   *          the JSON string to be parsed
+   * @param pdbRestRequest
+   *          the request object which contains parameters used to process the
+   *          JSON string
+   * @return
+   */
+  @SuppressWarnings("unchecked")
+  public static FTSRestResponse parsePDBJsonResponse(
+          String pdbJsonResponseString, FTSRestRequest pdbRestRequest)
+  {
+    FTSRestResponse searchResult = new FTSRestResponse();
+    List<FTSData> result = null;
+    try
+    {
+      JSONParser jsonParser = new JSONParser();
+      JSONObject jsonObj = (JSONObject) jsonParser
+              .parse(pdbJsonResponseString);
+
+      JSONObject pdbResponse = (JSONObject) jsonObj.get("response");
+      String queryTime = ((JSONObject) jsonObj.get("responseHeader")).get(
+              "QTime").toString();
+      int numFound = Integer
+              .valueOf(pdbResponse.get("numFound").toString());
+      if (numFound > 0)
+      {
+        result = new ArrayList<FTSData>();
+        JSONArray docs = (JSONArray) pdbResponse.get("docs");
+        for (Iterator<JSONObject> docIter = docs.iterator(); docIter
+                .hasNext();)
+        {
+          JSONObject doc = docIter.next();
+          result.add(getFTSData(doc, pdbRestRequest));
+        }
+        searchResult.setNumberOfItemsFound(numFound);
+        searchResult.setResponseTime(queryTime);
+        searchResult.setSearchSummary(result);
+      }
+    } catch (ParseException e)
+    {
+      e.printStackTrace();
+    }
+    return searchResult;
+  }
+
+  public static FTSData getFTSData(JSONObject pdbJsonDoc,
+          FTSRestRequest request)
+  {
+
+    String primaryKey = null;
+
+    Object[] summaryRowData;
+
+    SequenceI associatedSequence;
+
+    Collection<FTSDataColumnI> diplayFields = request.getWantedFields();
+    SequenceI associatedSeq = request.getAssociatedSequence();
+    int colCounter = 0;
+    summaryRowData = new Object[(associatedSeq != null) ? diplayFields
+            .size() + 1 : diplayFields.size()];
+    if (associatedSeq != null)
+    {
+      associatedSequence = associatedSeq;
+      summaryRowData[0] = associatedSequence;
+      colCounter = 1;
+    }
+
+    for (FTSDataColumnI field : diplayFields)
+    {
+      String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
+              : pdbJsonDoc.get(field.getCode()).toString();
+      if (field.isPrimaryKeyColumn())
+      {
+        primaryKey = fieldData;
+        summaryRowData[colCounter++] = primaryKey;
+      }
+      else if (fieldData == null || fieldData.isEmpty())
+      {
+        summaryRowData[colCounter++] = null;
+      }
+      else
+      {
+        try
+        {
+          summaryRowData[colCounter++] = (field.getDataType()
+                  .getDataTypeClass() == Integer.class) ? Integer
+                  .valueOf(fieldData) : (field.getDataType()
+                  .getDataTypeClass() == Double.class) ? Double
+                  .valueOf(fieldData) : sanitiseData(fieldData);
+        } catch (Exception e)
+        {
+          e.printStackTrace();
+          System.out.println("offending value:" + fieldData);
+        }
+      }
+    }
+
+    final String primaryKey1 = primaryKey;
+
+    final Object[] summaryRowData1 = summaryRowData;
+    return new FTSData()
+    {
+      @Override
+      public Object[] getSummaryData()
+      {
+        return summaryRowData1;
+      }
+
+      @Override
+      public Object getPrimaryKey()
+      {
+        return primaryKey1;
+      }
+
+      /**
+       * Returns a string representation of this object;
+       */
+      @Override
+      public String toString()
+      {
+        StringBuilder summaryFieldValues = new StringBuilder();
+        for (Object summaryField : summaryRowData1)
+        {
+          summaryFieldValues.append(
+                  summaryField == null ? " " : summaryField.toString())
+                  .append("\t");
+        }
+        return summaryFieldValues.toString();
+      }
+
+      /**
+       * Returns hash code value for this object
+       */
+      @Override
+      public int hashCode()
+      {
+        return Objects.hash(primaryKey1, this.toString());
+      }
+
+      @Override
+      public boolean equals(Object that)
+      {
+        return this.toString().equals(that.toString());
+      }
+    };
+  }
+
+  private static String sanitiseData(String data)
+  {
+    String cleanData = data.replaceAll("\\[\"", "").replaceAll("\\]\"", "")
+            .replaceAll("\\[", "").replaceAll("\\]", "")
+            .replaceAll("\",\"", ", ").replaceAll("\"", "");
+    return cleanData;
+  }
+
+  @Override
+  public String getColumnDataConfigFileName()
+  {
+    return "/fts/pdb_data_columns.txt";
+  }
+
+  public static FTSRestClientI getInstance()
+  {
+    if (instance == null)
+    {
+      instance = new PDBFTSRestClient();
+    }
+    return instance;
+  }
+
+  private Collection<FTSDataColumnI> allDefaultDisplayedStructureDataColumns;
+
+  public Collection<FTSDataColumnI> getAllDefaultDisplayedStructureDataColumns()
+  {
+    if (allDefaultDisplayedStructureDataColumns == null
+            || allDefaultDisplayedStructureDataColumns.isEmpty())
+    {
+      allDefaultDisplayedStructureDataColumns = new ArrayList<FTSDataColumnI>();
+      allDefaultDisplayedStructureDataColumns.addAll(super
+              .getAllDefaultDisplayedFTSDataColumns());
+    }
+    return allDefaultDisplayedStructureDataColumns;
+  }
+}
diff --git a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
new file mode 100644 (file)
index 0000000..27bfca8
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * 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.service.uniprot;
+
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestClient;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+import javax.ws.rs.core.MediaType;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+
+public class UniProtFTSRestClient extends FTSRestClient
+{
+  private static FTSRestClientI instance = null;
+
+  public static final String UNIPROT_SEARCH_ENDPOINT = "http://www.uniprot.org/uniprot/?";
+
+  @Override
+  public FTSRestResponse executeRequest(FTSRestRequest uniportRestRequest)
+          throws Exception
+  {
+    try
+    {
+      ClientConfig clientConfig = new DefaultClientConfig();
+      Client client = Client.create(clientConfig);
+
+      String wantedFields = getDataColumnsFieldsAsCommaDelimitedString(uniportRestRequest
+              .getWantedFields());
+      int responseSize = (uniportRestRequest.getResponseSize() == 0) ? getDefaultResponsePageSize()
+              : uniportRestRequest.getResponseSize();
+
+      int offSet = uniportRestRequest.getOffSet();
+      String query;
+      if (isAdvancedQuery(uniportRestRequest.getSearchTerm()))
+      {
+        query = uniportRestRequest.getSearchTerm();
+      }
+      else
+      {
+        query = uniportRestRequest.getFieldToSearchBy().equalsIgnoreCase(
+                "Search All") ? uniportRestRequest.getSearchTerm()
+                + " or mnemonic:" + uniportRestRequest.getSearchTerm()
+                : uniportRestRequest.getFieldToSearchBy() + ":"
+                        + uniportRestRequest.getSearchTerm();
+      }
+
+      WebResource webResource = null;
+      webResource = client.resource(UNIPROT_SEARCH_ENDPOINT)
+              .queryParam("format", "tab")
+              .queryParam("columns", wantedFields)
+              .queryParam("limit", String.valueOf(responseSize))
+              .queryParam("offset", String.valueOf(offSet))
+              .queryParam("sort", "score").queryParam("query", query);
+      // Execute the REST request
+      ClientResponse clientResponse = webResource.accept(
+              MediaType.TEXT_PLAIN).get(ClientResponse.class);
+      String uniProtTabDelimittedResponseString = clientResponse
+              .getEntity(String.class);
+      // Make redundant objects eligible for garbage collection to conserve
+      // memory
+      // System.out.println(">>>>> response : "
+      // + uniProtTabDelimittedResponseString);
+      if (clientResponse.getStatus() != 200)
+      {
+        String errorMessage = getMessageByHTTPStatusCode(
+                clientResponse.getStatus(), "Uniprot");
+        throw new Exception(errorMessage);
+
+      }
+      int xTotalResults = Integer.valueOf(clientResponse.getHeaders()
+              .get("X-Total-Results").get(0));
+      clientResponse = null;
+      client = null;
+      return parseUniprotResponse(uniProtTabDelimittedResponseString,
+              uniportRestRequest, xTotalResults);
+    } catch (Exception e)
+    {
+      String exceptionMsg = e.getMessage();
+      if (exceptionMsg.contains("SocketException"))
+      {
+        // No internet connection
+        throw new Exception(
+                MessageManager
+                        .getString("exception.unable_to_detect_internet_connection"));
+      }
+      else if (exceptionMsg.contains("UnknownHostException"))
+      {
+        // The server 'http://www.uniprot.org' is unreachable
+        throw new Exception(MessageManager.formatMessage(
+                "exception.fts_server_unreachable", "Uniprot"));
+      }
+      else
+      {
+        throw e;
+      }
+    }
+  }
+
+  public boolean isAdvancedQuery(String query)
+  {
+    if (query.contains(" AND ") || query.contains(" OR ")
+            || query.contains(" NOT ") || query.contains(" ! ")
+            || query.contains(" || ") || query.contains(" && ")
+            || query.contains(":") || query.contains("-"))
+    {
+      return true;
+    }
+    return false;
+  }
+
+  public FTSRestResponse parseUniprotResponse(
+          String uniProtTabDelimittedResponseString,
+          FTSRestRequest uniprotRestRequest, int xTotalResults)
+  {
+    FTSRestResponse searchResult = new FTSRestResponse();
+    List<FTSData> result = null;
+    if (uniProtTabDelimittedResponseString == null
+            || uniProtTabDelimittedResponseString.trim().isEmpty())
+    {
+      searchResult.setNumberOfItemsFound(0);
+      return searchResult;
+    }
+    String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n");
+    if (foundDataRow != null && foundDataRow.length > 0)
+    {
+      result = new ArrayList<FTSData>();
+      String titleRow = getDataColumnsFieldsAsTabDelimitedString(uniprotRestRequest
+              .getWantedFields());
+      // System.out.println(">>>>Title row : " + titleRow);
+      for (String dataRow : foundDataRow)
+      {
+        if (dataRow.equalsIgnoreCase(titleRow))
+        {
+          // System.out.println(">>>>>>>>>> matched!!!");
+          continue;
+        }
+        // System.out.println(dataRow);
+        result.add(getFTSData(dataRow, uniprotRestRequest));
+      }
+      searchResult.setNumberOfItemsFound(xTotalResults);
+      searchResult.setSearchSummary(result);
+    }
+    return searchResult;
+  }
+
+  /**
+   * Takes a collection of FTSDataColumnI and converts its 'code' values into a
+   * tab delimited string.
+   * 
+   * @param dataColumnFields
+   *          the collection of FTSDataColumnI to process
+   * @return the generated comma delimited string from the supplied
+   *         FTSDataColumnI collection
+   */
+  private String getDataColumnsFieldsAsTabDelimitedString(
+          Collection<FTSDataColumnI> dataColumnFields)
+  {
+    String result = "";
+    if (dataColumnFields != null && !dataColumnFields.isEmpty())
+    {
+      StringBuilder returnedFields = new StringBuilder();
+      for (FTSDataColumnI field : dataColumnFields)
+      {
+        if (field.getName().equalsIgnoreCase("Uniprot Id"))
+        {
+          returnedFields.append("\t").append("Entry");
+        }
+        else
+        {
+          returnedFields.append("\t").append(field.getName());
+        }
+      }
+      returnedFields.deleteCharAt(0);
+      result = returnedFields.toString();
+    }
+    return result;
+  }
+
+  public static FTSData getFTSData(String tabDelimittedDataStr,
+          FTSRestRequest request)
+  {
+    String primaryKey = null;
+
+    Object[] summaryRowData;
+
+    Collection<FTSDataColumnI> diplayFields = request.getWantedFields();
+    int colCounter = 0;
+    summaryRowData = new Object[diplayFields.size()];
+    String[] columns = tabDelimittedDataStr.split("\t");
+    for (FTSDataColumnI field : diplayFields)
+    {
+      try
+      {
+        String fieldData = columns[colCounter];
+        if (field.isPrimaryKeyColumn())
+        {
+          primaryKey = fieldData;
+          summaryRowData[colCounter++] = primaryKey;
+        }
+        else if (fieldData == null || fieldData.isEmpty())
+        {
+          summaryRowData[colCounter++] = null;
+        }
+        else
+        {
+          try
+          {
+            summaryRowData[colCounter++] = (field.getDataType()
+                    .getDataTypeClass() == Integer.class) ? Integer
+                    .valueOf(fieldData.replace(",", ""))
+                    : (field.getDataType().getDataTypeClass() == Double.class) ? Double
+                            .valueOf(fieldData) : fieldData;
+          } catch (Exception e)
+          {
+            e.printStackTrace();
+            System.out.println("offending value:" + fieldData);
+          }
+        }
+      } catch (Exception e)
+      {
+        // e.printStackTrace();
+      }
+    }
+
+    final String primaryKey1 = primaryKey;
+
+    final Object[] summaryRowData1 = summaryRowData;
+    return new FTSData()
+    {
+      @Override
+      public Object[] getSummaryData()
+      {
+        return summaryRowData1;
+      }
+
+      @Override
+      public Object getPrimaryKey()
+      {
+        return primaryKey1;
+      }
+
+      /**
+       * Returns a string representation of this object;
+       */
+      @Override
+      public String toString()
+      {
+        StringBuilder summaryFieldValues = new StringBuilder();
+        for (Object summaryField : summaryRowData1)
+        {
+          summaryFieldValues.append(
+                  summaryField == null ? " " : summaryField.toString())
+                  .append("\t");
+        }
+        return summaryFieldValues.toString();
+      }
+
+      /**
+       * Returns hash code value for this object
+       */
+      @Override
+      public int hashCode()
+      {
+        return Objects.hash(primaryKey1, this.toString());
+      }
+
+      @Override
+      public boolean equals(Object that)
+      {
+        return this.toString().equals(that.toString());
+      }
+    };
+  }
+
+  public static FTSRestClientI getInstance()
+  {
+    if (instance == null)
+    {
+      instance = new UniProtFTSRestClient();
+    }
+    return instance;
+  }
+
+  @Override
+  public String getColumnDataConfigFileName()
+  {
+    return "/fts/uniprot_data_columns.txt";
+  }
+
+}
diff --git a/src/jalview/fts/service/uniprot/UniprotFTSPanel.java b/src/jalview/fts/service/uniprot/UniprotFTSPanel.java
new file mode 100644 (file)
index 0000000..f04e4fa
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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.service.uniprot;
+
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.core.GFTSPanel;
+import jalview.gui.SequenceFetcher;
+import jalview.util.MessageManager;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+@SuppressWarnings("serial")
+public class UniprotFTSPanel extends GFTSPanel
+{
+
+  private static String defaultFTSFrameTitle = MessageManager
+          .getString("label.uniprot_sequence_fetcher");
+
+  private String ftsFrameTitle = defaultFTSFrameTitle;
+
+  private static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+
+  public UniprotFTSPanel(SequenceFetcher seqFetcher)
+  {
+    super();
+    pageLimit = UniProtFTSRestClient.getInstance()
+            .getDefaultResponsePageSize();
+    this.seqFetcher = seqFetcher;
+    this.progressIndicator = (seqFetcher == null) ? null : seqFetcher
+            .getProgressIndicator();
+  }
+
+  @Override
+  public void searchAction(boolean isFreshSearch)
+  {
+    if (isFreshSearch)
+    {
+      offSet = 0;
+    }
+    new Thread()
+    {
+      @Override
+      public void run()
+      {
+        ftsFrameTitle = defaultFTSFrameTitle;
+        reset();
+        if (getTypedText().length() > 0)
+        {
+          setSearchInProgress(true);
+          long startTime = System.currentTimeMillis();
+
+          String searchTarget = ((FTSDataColumnI) cmb_searchTarget
+                  .getSelectedItem()).getAltCode();
+
+          wantedFields = UniProtFTSRestClient.getInstance()
+                  .getAllDefaultDisplayedFTSDataColumns();
+          String searchTerm = decodeSearchTerm(txt_search.getText(),
+                  searchTarget);
+
+          FTSRestRequest request = new FTSRestRequest();
+          request.setFieldToSearchBy(searchTarget);
+          request.setSearchTerm(searchTerm);
+          request.setOffSet(offSet);
+          request.setWantedFields(wantedFields);
+          FTSRestClientI uniProtRestCleint = UniProtFTSRestClient
+                  .getInstance();
+          FTSRestResponse resultList;
+          try
+          {
+            resultList = uniProtRestCleint.executeRequest(request);
+          } catch (Exception e)
+          {
+            e.printStackTrace();
+            setErrorMessage(e.getMessage());
+            checkForErrors();
+            return;
+          }
+
+          if (resultList.getSearchSummary() != null
+                  && resultList.getSearchSummary().size() > 0)
+          {
+            getResultTable().setModel(
+                    FTSRestResponse.getTableModel(request,
+                            resultList.getSearchSummary()));
+            FTSRestResponse.configureTableColumn(getResultTable(),
+                    wantedFields, tempUserPrefs);
+            getResultTable().setVisible(true);
+          }
+
+          long endTime = System.currentTimeMillis();
+          totalResultSetCount = resultList.getNumberOfItemsFound();
+          resultSetCount = resultList.getSearchSummary() == null ? 0
+                  : resultList.getSearchSummary().size();
+          String result = (resultSetCount > 0) ? MessageManager
+                  .getString("label.results") : MessageManager
+                  .getString("label.result");
+          if (isPaginationEnabled() && resultSetCount > 0)
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle
+                    + " - "
+                    + result
+                    + " "
+                    + totalNumberformatter.format((Number) (offSet + 1))
+                    + " to "
+                    + totalNumberformatter
+                            .format((Number) (offSet + resultSetCount))
+                    + " of "
+                    + totalNumberformatter
+                            .format((Number) totalResultSetCount) + " "
+                    + " (" + (endTime - startTime) + " milli secs)");
+          }
+          else
+          {
+            updateSearchFrameTitle(defaultFTSFrameTitle + " - "
+                    + resultSetCount + " " + result + " ("
+                    + (endTime - startTime) + " milli secs)");
+          }
+          setSearchInProgress(false);
+          refreshPaginatorState();
+          updateSummaryTableSelections();
+        }
+      }
+    }.start();
+
+  }
+
+  public String decodeSearchTerm(String enteredText, String targetField)
+  {
+    int searchTargetLength = targetField.equalsIgnoreCase("Search All") ? 0
+            : targetField.length() + 1;
+    String searchTarget = targetField.equalsIgnoreCase("Search All") ? ""
+            : targetField + ":";
+    String foundSearchTerms = enteredText;
+    StringBuilder foundSearchTermsBuilder = new StringBuilder();
+    if (enteredText.contains(";"))
+    {
+      String[] searchTerms = enteredText.split(";");
+      for (String searchTerm : searchTerms)
+      {
+        foundSearchTermsBuilder.append(searchTarget).append(searchTerm)
+                .append(" OR ");
+      }
+      int endIndex = foundSearchTermsBuilder.lastIndexOf(" OR ");
+      foundSearchTerms = foundSearchTermsBuilder.toString();
+      if (foundSearchTerms.contains(" OR "))
+      {
+        foundSearchTerms = foundSearchTerms.substring(searchTargetLength,
+                endIndex);
+      }
+    }
+    return foundSearchTerms;
+  }
+
+  @Override
+  public boolean isPaginationEnabled()
+  {
+    return true;
+  }
+
+  @Override
+  public void okAction()
+  {
+    disableActionButtons();
+    StringBuilder selectedIds = new StringBuilder();
+    HashSet<String> selectedIdsSet = new HashSet<String>();
+    int primaryKeyColIndex = 0;
+    try
+    {
+      primaryKeyColIndex = getFTSRestClient().getPrimaryKeyColumIndex(
+              wantedFields, false);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    int[] selectedRows = getResultTable().getSelectedRows();
+    for (int summaryRow : selectedRows)
+    {
+      String idStr = getResultTable().getValueAt(summaryRow,
+              primaryKeyColIndex).toString();
+      selectedIdsSet.add(idStr);
+    }
+    selectedIdsSet.addAll(paginatorCart);
+    for (String selectedId : selectedIdsSet)
+    {
+      selectedIds.append(selectedId).append(";");
+    }
+
+    String ids = selectedIds.toString();
+    // System.out.println(">>>>>>>>>>>>>>>> selected Ids: " + ids);
+    seqFetcher.getTextArea().setText(ids);
+    Thread worker = new Thread(seqFetcher);
+    worker.start();
+    delayAndEnableActionButtons();
+  }
+
+  @Override
+  public FTSRestClientI getFTSRestClient()
+  {
+    return UniProtFTSRestClient.getInstance();
+  }
+
+  @Override
+  public String getFTSFrameTitle()
+  {
+    return ftsFrameTitle;
+  }
+
+  @Override
+  public Map<String, Integer> getTempUserPrefs()
+  {
+    return tempUserPrefs;
+  }
+
+}
index cb769bb..e8b865b 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;
@@ -93,12 +91,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;
@@ -119,6 +115,8 @@ import java.awt.dnd.DropTargetEvent;
 import java.awt.dnd.DropTargetListener;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.KeyAdapter;
@@ -466,6 +464,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       formatMenu.add(vsel);
     }
+    addFocusListener(new FocusAdapter()
+    {
+      @Override
+      public void focusGained(FocusEvent e)
+      {
+        Jalview.setCurrentAlignFrame(AlignFrame.this);
+      }
+    });
 
   }
 
@@ -839,8 +845,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     showGroupConservation.setEnabled(!nucleotide);
     rnahelicesColour.setEnabled(nucleotide);
     purinePyrimidineColour.setEnabled(nucleotide);
-    showComplementMenuItem.setText(MessageManager
-            .getString(nucleotide ? "label.protein" : "label.nucleotide"));
+    showComplementMenuItem.setText(nucleotide ? MessageManager
+            .getString("label.protein") : MessageManager
+            .getString("label.nucleotide"));
     setColourSelected(jalview.bin.Cache.getDefault(
             nucleotide ? Preferences.DEFAULT_COLOUR_NUC
                     : Preferences.DEFAULT_COLOUR_PROT, "None"));
@@ -911,10 +918,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
 
     showProducts.setEnabled(canShowProducts());
+    setGroovyEnabled(Desktop.getGroovyConsole() != null);
 
     updateEditMenuBar();
   }
 
+  /**
+   * Set the enabled state of the 'Run Groovy' option in the Calculate menu
+   * 
+   * @param b
+   */
+  public void setGroovyEnabled(boolean b)
+  {
+    runGroovy.setEnabled(b);
+  }
+
   private IProgressIndicator progressBar;
 
   /*
@@ -1292,7 +1310,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
     {
-      omitHidden = viewport.getViewAsString(false);
+      omitHidden = viewport.getViewAsString(false,
+              settings.isExportHiddenSequences());
     }
 
     int[] alignmentStartEnd = new int[2];
@@ -1303,17 +1322,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else
     {
       alignmentToExport = viewport.getAlignment();
-      alignmentStartEnd = viewport.getAlignment()
-              .getVisibleStartAndEndIndex(
-                      viewport
-              .getColumnSelection().getHiddenColumns());
     }
+    alignmentStartEnd = alignmentToExport
+            .getVisibleStartAndEndIndex(viewport.getColumnSelection()
+                    .getHiddenColumns());
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
             omitHidden, alignmentStartEnd, settings);
     return ed;
   }
 
-
   /**
    * DOCUMENT ME!
    * 
@@ -1330,7 +1347,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
     BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this);
-    bjs.exportJalviewAlignmentAsBioJsHtmlFile();
+    bjs.exportJalviewAlignmentAsBioJsHtmlFile(null);
   }
 
   public void createImageMap(File file, String image)
@@ -2414,7 +2431,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
     viewport.setSelectionGroup(sg);
     viewport.sendSelection();
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
   }
 
@@ -2437,7 +2457,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setSelectionGroup(null);
     alignPanel.getSeqPanel().seqCanvas.highlightSearchResults(null);
     alignPanel.getIdPanel().getIdCanvas().searchResults = null;
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2464,6 +2487,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
     }
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
 
     alignPanel.paintAlignment(true);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
@@ -2811,7 +2837,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void expandViews_actionPerformed(ActionEvent e)
   {
-    Desktop.instance.explodeViews(this);
+    Desktop.explodeViews(this);
   }
 
   /**
@@ -2952,9 +2978,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()))
       {
@@ -2982,8 +3006,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);
       }
@@ -2991,7 +3014,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         hideSelColumns_actionPerformed(null);
         if (!toggleSeqs)
@@ -3190,30 +3213,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * Set or clear 'Show Sequence Features'
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
-  {
-    viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
-            .isSelected());
-    if (viewport.isShowSequenceFeaturesHeight())
-    {
-      // ensure we're actually displaying features
-      viewport.setShowSequenceFeatures(true);
-      showSeqFeatures.setSelected(true);
-    }
-    alignPanel.paintAlignment(true);
-    if (alignPanel.getOverviewPanel() != null)
-    {
-      alignPanel.getOverviewPanel().updateOverviewImage();
-    }
-  }
-
-  /**
    * Action on toggle of the 'Show annotations' menu item. This shows or hides
    * the annotations panel as a whole.
    * 
@@ -3619,35 +3618,50 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isControlDown()
-                    || SwingUtilities.isRightMouseButton(evt))
+            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);
+                }
+              });
             }
           }
         });
@@ -4124,7 +4138,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         JMenuItem tm = new JMenuItem();
         ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype);
-        if (sm.isProtein() == !viewport.getAlignment().isNucleotide())
+        if (sm.isDNA() == viewport.getAlignment().isNucleotide()
+                || sm.isProtein() == !viewport.getAlignment()
+                        .isNucleotide())
         {
           String smn = MessageManager.getStringOrReturn(
                   "label.score_model_", sm.getName());
@@ -4437,22 +4453,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           // object broker mechanism.
           final Vector<JMenu> wsmenu = new Vector<JMenu>();
           final IProgressIndicator af = me;
+
+          /*
+           * do not i18n these strings - they are hard-coded in class
+           * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and
+           * SequenceAnnotationWSClient.initSequenceAnnotationWSClient()
+           */
           final JMenu msawsmenu = new JMenu("Alignment");
           final JMenu secstrmenu = new JMenu(
                   "Secondary Structure Prediction");
           final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
           final JMenu analymenu = new JMenu("Analysis");
           final JMenu dismenu = new JMenu("Protein Disorder");
-          // final JMenu msawsmenu = new
-          // JMenu(MessageManager.getString("label.alignment"));
-          // final JMenu secstrmenu = new
-          // JMenu(MessageManager.getString("label.secondary_structure_prediction"));
-          // final JMenu seqsrchmenu = new
-          // JMenu(MessageManager.getString("label.sequence_database_search"));
-          // final JMenu analymenu = new
-          // JMenu(MessageManager.getString("label.analysis"));
-          // final JMenu dismenu = new
-          // JMenu(MessageManager.getString("label.protein_disorder"));
           // JAL-940 - only show secondary structure prediction services from
           // the legacy server
           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
@@ -4612,38 +4624,45 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * Searches selected sequences for xRef products and builds the Show
-   * Cross-References menu (formerly called Show Products)
+   * Searches the alignment sequences for xRefs and builds the Show
+   * Cross-References menu (formerly called Show Products), with database
+   * sources for which cross-references are found (protein sources for a
+   * nucleotide alignment and vice versa)
    * 
-   * @return true if Show Cross-references menu should be enabled.
+   * @return true if Show Cross-references menu should be enabled
    */
   public boolean canShowProducts()
   {
-    SequenceI[] selection = viewport.getSequenceSelection();
+    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();
-      String[] ptypes = (selection == null || selection.length == 0) ? null
-              : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
+      List<String> ptypes = new CrossRef(seqs, dataset)
+              .findXrefSourcesForSequences(dna);
 
-      for (int t = 0; ptypes != null && t < ptypes.length; t++)
+      for (final String source : ptypes)
       {
         showp = true;
         final AlignFrame af = this;
-        final String source = ptypes[t];
-        JMenuItem xtype = new JMenuItem(ptypes[t]);
+        JMenuItem xtype = new JMenuItem(source);
         xtype.addActionListener(new ActionListener()
         {
-
           @Override
           public void actionPerformed(ActionEvent e)
           {
             showProductsFor(af.viewport.getSequenceSelection(), dna, source);
           }
-
         });
         showProducts.add(xtype);
       }
@@ -4651,7 +4670,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showProducts.setEnabled(showp);
     } catch (Exception e)
     {
-      jalview.bin.Cache.log
+      Cache.log
               .warn("canShowProducts threw an exception - please report to help@jalview.org",
                       e);
       return false;
@@ -4659,228 +4678,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return showp;
   }
 
-  protected void showProductsFor(final SequenceI[] sel, final boolean dna,
-          final String source)
+  /**
+   * Finds and displays cross-references for the selected sequences (protein
+   * products for nucleotide sequences, dna coding sequences for peptides).
+   * 
+   * @param sel
+   *          the sequences to show cross-references for
+   * @param dna
+   *          true if from a nucleotide alignment (so showing proteins)
+   * @param source
+   *          the database to show cross-references for
+   */
+  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 xrefs = CrossRef.findXrefSequences(sel, dna, source,
-                  alignment);
-          if (xrefs != null)
-          {
-            /*
-             * get display scheme (if any) to apply to features
-             */
-            FeatureSettingsModelI featureColourScheme = new SequenceFetcher()
-                    .getFeatureColourScheme(source);
-
-            AlignmentI al = makeCrossReferencesAlignment(
-                    alignment.getDataset(), xrefs);
-
-            AlignFrame newFrame = new AlignFrame(al, DEFAULT_WIDTH,
-                    DEFAULT_HEIGHT);
-            String newtitle = String.format("%s %s %s",
-                    MessageManager.getString(dna ? "label.proteins"
-                            : "label.nucleotides"), MessageManager
-                            .getString("label.for"), getTitle());
-            newFrame.setTitle(newtitle);
-
-            if (!Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
-            {
-              /*
-               * split frame display is turned off in preferences file
-               */
-              Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH,
-                      DEFAULT_HEIGHT);
-              return; // via finally clause
-            }
-
-            /*
-             * Make a copy of this alignment (sharing the same dataset
-             * sequences). If we are DNA, drop introns and update mappings
-             */
-            AlignmentI copyAlignment = null;
-            final SequenceI[] sequenceSelection = AlignFrame.this.viewport
-                    .getSequenceSelection();
-            List<AlignedCodonFrame> cf = xrefs.getCodonFrames();
-            boolean copyAlignmentIsAligned = false;
-            if (dna)
-            {
-              copyAlignment = AlignmentUtils.makeCdsAlignment(
-                      sequenceSelection, cf, alignment);
-              if (copyAlignment.getHeight() == 0)
-              {
-                System.err.println("Failed to make CDS alignment");
-              }
-              al.getCodonFrames().clear();
-              al.getCodonFrames().addAll(copyAlignment.getCodonFrames());
-
-              /*
-               * 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(
-                      sequenceSelection, xrefs.getSequencesArray());
-              copyAlignment.getCodonFrames().addAll(cf);
-            }
-            copyAlignment.setGapCharacter(AlignFrame.this.viewport
-                    .getGapCharacter());
-
-            StructureSelectionManager ssm = StructureSelectionManager
-                    .getStructureSelectionManager(Desktop.instance);
-            ssm.registerMappings(cf);
-
-            if (copyAlignment.getHeight() <= 0)
-            {
-              System.err.println("No Sequences generated for xRef type "
-                      + source);
-              return;
-            }
-            /*
-             * align protein to dna
-             */
-            if (dna && copyAlignmentIsAligned)
-            {
-              al.alignAs(copyAlignment);
-            }
-            else
-            {
-              /*
-               * align cdna to protein - currently only if 
-               * fetching and aligning Ensembl transcripts!
-               */
-              if (DBRefSource.ENSEMBL.equalsIgnoreCase(source))
-              {
-                copyAlignment.alignAs(al);
-              }
-            }
-
-            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 (Exception e)
-        {
-          Cache.log.error(
-                  "Exception when finding crossreferences", e);
-        } 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. If this is of the
-       * same type as the given dataset (nucleotide/protein), then the new
-       * alignment shares the same dataset, and its dataset sequences are added
-       * to it. Otherwise a new dataset sequence is created for the
-       * cross-references.
-       * 
-       * @param dataset
-       * @param seqs
-       * @return
-       */
-      protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
-              AlignmentI seqs)
-      {
-        boolean sameType = dataset.isNucleotide() == seqs.isNucleotide();
-
-        SequenceI[] sprods = new SequenceI[seqs.getHeight()];
-        for (int s = 0; s < sprods.length; s++)
-        {
-          sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
-          if (sameType)
-          {
-            if (dataset.getSequences() == null
-                    || !dataset.getSequences().contains(
-                            sprods[s].getDatasetSequence()))
-            {
-              dataset.addSequence(sprods[s].getDatasetSequence());
-            }
-          }
-          sprods[s].updatePDBIds();
-        }
-        Alignment al = new Alignment(sprods);
-        if (sameType)
-        {
-          al.setDataset((Alignment) dataset);
-        }
-        else
-        {
-          al.createDatasetAlignment();
-        }
-        return al;
-      }
-
-    };
-    Thread frunner = new Thread(foo);
-    frunner.start();
+    new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+            .start();
   }
 
   /**
@@ -4904,7 +4717,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getString("label.error_when_translating_sequences_submit_bug_report");
       final String errorTitle = MessageManager
               .getString("label.implementation_error")
-              + MessageManager.getString("translation_failed");
+              + MessageManager.getString("label.translation_failed");
       JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
               JOptionPane.ERROR_MESSAGE);
       return;
@@ -5002,50 +4815,15 @@ 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();
-    java.util.List files = null;
+    java.util.List<String> files = new ArrayList<String>(), protocols = new ArrayList<String>();
 
     try
     {
-      DataFlavor uriListFlavor = new DataFlavor(
-              "text/uri-list;class=java.lang.String");
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-      {
-        // Works on Windows and MacOSX
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        files = (java.util.List) t
-                .getTransferData(DataFlavor.javaFileListFlavor);
-      }
-      else if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        String data = (String) t.getTransferData(uriListFlavor);
-        files = new java.util.ArrayList(1);
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
-          String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
-            // the line is a comment (as per the RFC 2483)
-            continue;
-          }
-
-          java.net.URI uri = new java.net.URI(s);
-          // check to see if we can handle this kind of URI
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
-            files.add(uri.toString());
-          }
-          else
-          {
-            // otherwise preserve old behaviour: catch all for file objects
-            java.io.File file = new java.io.File(uri);
-            files.add(file.toString());
-          }
-        }
-      }
+      Desktop.transferFromDropTarget(files, protocols, evt, t);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -5107,7 +4885,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               }
               if (type != null)
               {
-                if (type.equalsIgnoreCase("PDB"))
+                if (type.equalsIgnoreCase("PDB")
+                        || type.equalsIgnoreCase("mmCIF"))
                 {
                   filesmatched.add(new Object[] { file, protocol, mtch });
                   continue;
@@ -5127,14 +4906,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)
 
           {
@@ -5371,7 +5150,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void tabbedPane_mousePressed(MouseEvent e)
   {
-    if (SwingUtilities.isRightMouseButton(e))
+    if (e.isPopupTrigger())
     {
       String msg = MessageManager.getString("label.enter_view_name");
       String reply = JOptionPane.showInternalInputDialog(this, msg, msg,
@@ -5520,8 +5299,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 AlignFrame.this.setMenusForViewport();
               }
             });
-            dbRefFetcher
-                    .fetchDBRefs(false);
+            dbRefFetcher.fetchDBRefs(false);
           }
         }).start();
 
@@ -5962,8 +5740,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
-    for (AlignmentAnnotation aa : alignPanel.getAlignment()
-            .getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = alignPanel.getAlignment()
+            .getAlignmentAnnotation();
+    if (anns == null)
+    {
+      return;
+    }
+    for (AlignmentAnnotation aa : anns)
     {
       /*
        * don't display non-positional annotations on an alignment
@@ -6079,15 +5862,75 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     try
     {
       Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
-
       al = dna.reverseCdna(complement);
       viewport.addAlignment(al, "");
+      addHistoryItem(new EditCommand(
+              MessageManager.getString("label.add_sequences"),
+              Action.PASTE, al.getSequencesArray(), 0, al.getWidth(),
+              viewport.getAlignment()));
     } catch (Exception ex)
     {
       System.err.println(ex.getMessage());
       return;
     }
   }
+
+  /**
+   * Try to run a script in the Groovy console, having first ensured that this
+   * AlignFrame is set as currentAlignFrame in Desktop, to allow the script to
+   * be targeted at this alignment.
+   */
+  @Override
+  protected void runGroovy_actionPerformed()
+  {
+    Jalview.setCurrentAlignFrame(this);
+    groovy.ui.Console console = Desktop.getGroovyConsole();
+    if (console != null)
+    {
+      try
+      {
+        console.runScript();
+      } catch (Exception ex)
+      {
+        System.err.println((ex.toString()));
+        JOptionPane
+                .showInternalMessageDialog(Desktop.desktop, MessageManager
+                        .getString("label.couldnt_run_groovy_script"),
+                        MessageManager
+                                .getString("label.groovy_support_failed"),
+                        JOptionPane.ERROR_MESSAGE);
+      }
+    }
+    else
+    {
+      System.err.println("Can't run Groovy script as console not found");
+    }
+  }
+
+  /**
+   * Hides columns containing (or not containing) a specified feature, provided
+   * that would not leave all columns hidden
+   * 
+   * @param featureType
+   * @param columnsContaining
+   * @return
+   */
+  public boolean hideFeatureColumns(String featureType,
+          boolean columnsContaining)
+  {
+    boolean notForHiding = avc.markColumnsContainingFeatures(
+            columnsContaining, false, false, featureType);
+    if (notForHiding)
+    {
+      if (avc.markColumnsContainingFeatures(!columnsContaining, false,
+              false, featureType))
+      {
+        getViewport().hideSelectedColumns();
+        return true;
+      }
+    }
+    return false;
+  }
 }
 
 class PrintThread extends Thread
index 692cd18..d0a0f11 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;
@@ -419,10 +401,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);
   }
 
   /**
@@ -507,17 +490,6 @@ public class AlignViewport extends AlignmentViewport implements
   /**
    * DOCUMENT ME!
    * 
-   * @return DOCUMENT ME!
-   */
-  @Override
-  public ColumnSelection getColumnSelection()
-  {
-    return colSel;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
    * @param tree
    *          DOCUMENT ME!
    */
@@ -683,27 +655,44 @@ public class AlignViewport extends AlignmentViewport implements
     List<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
     for (PDBEntry pdb : pdbEntries)
     {
-      List<SequenceI> seqs = new ArrayList<SequenceI>();
+      List<SequenceI> choosenSeqs = new ArrayList<SequenceI>();
       for (SequenceI sq : alignment.getSequences())
       {
-        Vector<PDBEntry> pdbs = sq.getDatasetSequence().getAllPDBEntries();
-        if (pdbs == null)
+        Vector<PDBEntry> pdbRefEntries = sq.getDatasetSequence()
+                .getAllPDBEntries();
+        if (pdbRefEntries == null)
         {
           continue;
         }
-        for (PDBEntry p1 : pdbs)
+        for (PDBEntry pdbRefEntry : pdbRefEntries)
         {
-          if (p1.getId().equals(pdb.getId()))
+          if (pdbRefEntry.getId().equals(pdb.getId()))
           {
-            if (!seqs.contains(sq))
+            if (pdbRefEntry.getChainCode() != null
+                    && pdb.getChainCode() != null)
             {
-              seqs.add(sq);
-              continue;
+              if (pdbRefEntry.getChainCode().equalsIgnoreCase(
+                      pdb.getChainCode())
+                      && !choosenSeqs.contains(sq))
+              {
+                choosenSeqs.add(sq);
+                continue;
+              }
             }
+            else
+            {
+              if (!choosenSeqs.contains(sq))
+              {
+                choosenSeqs.add(sq);
+                continue;
+              }
+            }
+
           }
         }
       }
-      seqvectors.add(seqs.toArray(new SequenceI[seqs.size()]));
+      seqvectors
+              .add(choosenSeqs.toArray(new SequenceI[choosenSeqs.size()]));
     }
     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
   }
@@ -1103,6 +1092,7 @@ public class AlignViewport extends AlignmentViewport implements
    * 
    * @param featureSettings
    */
+  @Override
   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings)
   {
     if (featureSettings == null)
index f06ca94..4db029c 100644 (file)
@@ -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();
@@ -1269,6 +1272,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
   void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
   {
+    int boarderBottomOffset = 5;
     long pSessionId = System.currentTimeMillis();
     headless = (System.getProperty("java.awt.headless") != null && System
             .getProperty("java.awt.headless").equals("true"));
@@ -1277,7 +1281,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);
       }
     }
@@ -1305,14 +1309,15 @@ public class AlignmentPanel extends GAlignmentPanel implements
         }
 
         im = new jalview.util.ImageMaker(this, type, imageAction,
-                aDimension.getWidth(), aDimension.getHeight(), file,
-                imageTitle, alignFrame, pSessionId, headless);
+                aDimension.getWidth(), aDimension.getHeight()
+                        + boarderBottomOffset, file, imageTitle,
+                alignFrame, pSessionId, headless);
         if (av.getWrapAlignment())
         {
           if (im.getGraphics() != null)
           {
             printWrappedAlignment(im.getGraphics(), aDimension.getWidth(),
-                    aDimension.getHeight(), 0);
+                    aDimension.getHeight() + boarderBottomOffset, 0);
             im.writeImage();
           }
         }
@@ -1593,8 +1598,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);
@@ -1602,7 +1617,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
index 19eed27..39cde03 100644 (file)
@@ -141,7 +141,7 @@ public class AnnotationColourChooser extends AnnotationRowFilter
       default:
         throw new Error(
                 MessageManager
-                        .getString("error.implementation_error_dont_know_about_thereshold_setting"));
+                        .getString("error.implementation_error_dont_know_about_threshold_setting"));
       }
       thresholdIsMin.setSelected(acg.thresholdIsMinMax);
       thresholdValue.setText("" + acg.getAnnotationThreshold());
@@ -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 d688ddd..0d47e36 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceI;
 import jalview.io.AnnotationFile;
@@ -155,18 +156,26 @@ public class AnnotationExporter extends JPanel
             .getString("label.no_features_on_alignment");
     if (features)
     {
+      Map<String, FeatureColourI> displayedFeatureColours = ap
+              .getFeatureRenderer().getDisplayedFeatureCols();
       FeaturesFile formatter = new FeaturesFile();
       SequenceI[] sequences = ap.av.getAlignment().getSequencesArray();
-      Map<String, Object> featureColours = ap.getFeatureRenderer()
+      Map<String, FeatureColourI> featureColours = ap.getFeatureRenderer()
               .getDisplayedFeatureCols();
       boolean includeNonPositional = ap.av.isShowNPFeats();
       if (GFFFormat.isSelected())
       {
+        text = new FeaturesFile().printGffFormat(ap.av.getAlignment()
+                .getDataset().getSequencesArray(), displayedFeatureColours,
+                true, ap.av.isShowNPFeats());
         text = formatter.printGffFormat(sequences, featureColours, true,
                 includeNonPositional);
       }
       else
       {
+        text = new FeaturesFile().printJalviewFormat(ap.av.getAlignment()
+                .getDataset().getSequencesArray(), displayedFeatureColours,
+                true, ap.av.isShowNPFeats()); // ap.av.featuresDisplayed);
         text = formatter.printJalviewFormat(sequences, featureColours,
                 true, includeNonPositional);
       }
index 3105ab9..1a9541c 100755 (executable)
@@ -219,6 +219,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,
@@ -231,11 +232,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))
     {
@@ -244,6 +250,8 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     else if (evt.getActionCommand().equals(DELETE))
     {
       ap.av.getAlignment().deleteAnnotation(aa[selectedRow]);
+      ap.av.getCalcManager().removeWorkerForAnnotation(aa[selectedRow]);
+      fullRepaint = true;
     }
     else if (evt.getActionCommand().equals(SHOWALL))
     {
@@ -254,6 +262,7 @@ public class AnnotationLabels extends JPanel implements MouseListener,
           aa[i].visible = true;
         }
       }
+      fullRepaint = true;
     }
     else if (evt.getActionCommand().equals(OUTPUT_TEXT))
     {
@@ -282,18 +291,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();
+    }
   }
 
   /**
@@ -304,6 +325,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",
@@ -326,418 +348,145 @@ public class AnnotationLabels extends JPanel implements MouseListener,
     return true;
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
   @Override
   public void mousePressed(MouseEvent evt)
   {
     getSelectedRow(evt.getY() - getScrollOffset());
     oldY = evt.getY();
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void mouseReleased(MouseEvent evt)
-  {
-    int start = selectedRow;
-    getSelectedRow(evt.getY() - getScrollOffset());
-    int end = selectedRow;
-
-    if (start != end)
+    if (evt.isPopupTrigger())
     {
-      // Swap these annotations
-      AlignmentAnnotation startAA = ap.av.getAlignment()
-              .getAlignmentAnnotation()[start];
-      if (end == -1)
-      {
-        end = ap.av.getAlignment().getAlignmentAnnotation().length - 1;
-      }
-      AlignmentAnnotation endAA = ap.av.getAlignment()
-              .getAlignmentAnnotation()[end];
-
-      ap.av.getAlignment().getAlignmentAnnotation()[end] = startAA;
-      ap.av.getAlignment().getAlignmentAnnotation()[start] = endAA;
+      showPopupMenu(evt);
     }
-
-    resizePanel = false;
-    dragEvent = null;
-    repaint();
-    ap.getAnnotationPanel().repaint();
   }
 
   /**
-   * DOCUMENT ME!
+   * Build and show the Pop-up menu at the right-click mouse position
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
-  @Override
-  public void mouseEntered(MouseEvent evt)
+  void showPopupMenu(MouseEvent evt)
   {
-    if (evt.getY() < 10)
-    {
-      resizePanel = true;
-      repaint();
-    }
-  }
+    evt.consume();
+    final AlignmentAnnotation[] aa = ap.av.getAlignment()
+            .getAlignmentAnnotation();
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void mouseExited(MouseEvent evt)
-  {
-    if (dragEvent == null)
+    JPopupMenu pop = new JPopupMenu(
+            MessageManager.getString("label.annotations"));
+    JMenuItem item = new JMenuItem(ADDNEW);
+    item.addActionListener(this);
+    pop.add(item);
+    if (selectedRow < 0)
     {
-      resizePanel = false;
-      repaint();
+      if (hasHiddenRows)
+      { // let the user make everything visible again
+        item = new JMenuItem(SHOWALL);
+        item.addActionListener(this);
+        pop.add(item);
+      }
+      pop.show(this, evt.getX(), evt.getY());
+      return;
     }
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void mouseDragged(MouseEvent evt)
-  {
-    dragEvent = evt;
-
-    if (resizePanel)
+    item = new JMenuItem(EDITNAME);
+    item.addActionListener(this);
+    pop.add(item);
+    item = new JMenuItem(HIDE);
+    item.addActionListener(this);
+    pop.add(item);
+    // JAL-1264 hide all sequence-specific annotations of this type
+    if (selectedRow < aa.length)
     {
-      Dimension d = ap.annotationScroller.getPreferredSize();
-      int dif = evt.getY() - oldY;
-
-      dif /= ap.av.getCharHeight();
-      dif *= ap.av.getCharHeight();
-
-      if ((d.height - dif) > 20)
+      if (aa[selectedRow].sequenceRef != null)
       {
-        ap.annotationScroller.setPreferredSize(new Dimension(d.width,
-                d.height - dif));
-        d = ap.annotationSpaceFillerHolder.getPreferredSize();
-        ap.annotationSpaceFillerHolder.setPreferredSize(new Dimension(
-                d.width, d.height - dif));
-        ap.paintAlignment(true);
+        final String label = aa[selectedRow].label;
+        JMenuItem hideType = new JMenuItem();
+        String text = MessageManager.getString("label.hide_all") + " "
+                + label;
+        hideType.setText(text);
+        hideType.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            AlignmentUtils.showOrHideSequenceAnnotations(
+                    ap.av.getAlignment(), Collections.singleton(label),
+                    null, false, false);
+            // for (AlignmentAnnotation ann : ap.av.getAlignment()
+            // .getAlignmentAnnotation())
+            // {
+            // if (ann.sequenceRef != null && ann.label != null
+            // && ann.label.equals(label))
+            // {
+            // ann.visible = false;
+            // }
+            // }
+            refresh(true);
+          }
+        });
+        pop.add(hideType);
       }
-
-      ap.addNotify();
     }
-    else
+    item = new JMenuItem(DELETE);
+    item.addActionListener(this);
+    pop.add(item);
+    if (hasHiddenRows)
     {
-      repaint();
+      item = new JMenuItem(SHOWALL);
+      item.addActionListener(this);
+      pop.add(item);
     }
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void mouseMoved(MouseEvent evt)
-  {
-    resizePanel = evt.getY() < 10;
-
-    getSelectedRow(evt.getY() - getScrollOffset());
-
-    if (selectedRow > -1
-            && ap.av.getAlignment().getAlignmentAnnotation().length > selectedRow)
+    item = new JMenuItem(OUTPUT_TEXT);
+    item.addActionListener(this);
+    pop.add(item);
+    // TODO: annotation object should be typed for autocalculated/derived
+    // property methods
+    if (selectedRow < aa.length)
     {
-      AlignmentAnnotation aa = ap.av.getAlignment()
-              .getAlignmentAnnotation()[selectedRow];
-
-      StringBuffer desc = new StringBuffer();
-      if (aa.description != null
-              && !aa.description.equals("New description"))
+      final String label = aa[selectedRow].label;
+      if (!aa[selectedRow].autoCalculated)
       {
-        // TODO: we could refactor and merge this code with the code in
-        // jalview.gui.SeqPanel.mouseMoved(..) that formats sequence feature
-        // tooltips
-        desc.append(aa.getDescription(true).trim());
-        // check to see if the description is an html fragment.
-        if (desc.length() < 6
-                || (desc.substring(0, 6).toLowerCase().indexOf("<html>") < 0))
+        if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
         {
-          // clean the description ready for embedding in html
-          desc = new StringBuffer(LEFT_ANGLE_BRACKET_PATTERN.matcher(desc)
-                  .replaceAll("&lt;"));
-          desc.insert(0, "<html>");
+          // display formatting settings for this row.
+          pop.addSeparator();
+          // av and sequencegroup need to implement same interface for
+          item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
+                  aa[selectedRow].scaleColLabel);
+          item.addActionListener(this);
+          pop.add(item);
         }
-        else
+      }
+      else if (label.indexOf("Consensus") > -1)
+      {
+        pop.addSeparator();
+        // av and sequencegroup need to implement same interface for
+        final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
+                MessageManager.getString("label.ignore_gaps_consensus"),
+                (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef
+                        .getIgnoreGapsConsensus() : ap.av
+                        .isIgnoreGapsConsensus());
+        final AlignmentAnnotation aaa = aa[selectedRow];
+        cbmi.addActionListener(new ActionListener()
         {
-          // remove terminating html if any
-          int i = desc.substring(desc.length() - 7).toLowerCase()
-                  .lastIndexOf("</html>");
-          if (i > -1)
+          @Override
+          public void actionPerformed(ActionEvent e)
           {
-            desc.setLength(desc.length() - 7 + i);
+            if (aaa.groupRef != null)
+            {
+              // TODO: pass on reference to ap so the view can be updated.
+              aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
+              ap.getAnnotationPanel().paint(
+                      ap.getAnnotationPanel().getGraphics());
+            }
+            else
+            {
+              ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
+            }
+            ap.alignmentChanged();
           }
-        }
-        if (aa.hasScore())
-        {
-          desc.append("<br/>");
-        }
-        // if (aa.hasProperties())
-        // {
-        // desc.append("<table>");
-        // for (String prop : aa.getProperties())
-        // {
-        // desc.append("<tr><td>" + prop + "</td><td>"
-        // + aa.getProperty(prop) + "</td><tr>");
-        // }
-        // desc.append("</table>");
-        // }
-      }
-      else
-      {
-        // begin the tooltip's html fragment
-        desc.append("<html>");
-        if (aa.hasScore())
-        {
-          // TODO: limit precision of score to avoid noise from imprecise
-          // doubles
-          // (64.7 becomes 64.7+/some tiny value).
-          desc.append(" Score: " + aa.score);
-        }
-      }
-      if (desc.length() > 6)
-      {
-        desc.append("</html>");
-        this.setToolTipText(desc.toString());
-      }
-      else
-      {
-        this.setToolTipText(null);
-      }
-    }
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void mouseClicked(MouseEvent evt)
-  {
-    final AlignmentAnnotation[] aa = ap.av.getAlignment()
-            .getAlignmentAnnotation();
-    if (SwingUtilities.isLeftMouseButton(evt))
-    {
-      if (selectedRow > -1 && selectedRow < aa.length)
-      {
-        if (aa[selectedRow].groupRef != null)
-        {
-          if (evt.getClickCount() >= 2)
-          {
-            // todo: make the ap scroll to the selection - not necessary, first
-            // click highlights/scrolls, second selects
-            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(null);
-            ap.av.setSelectionGroup(// new SequenceGroup(
-            aa[selectedRow].groupRef); // );
-            ap.paintAlignment(false);
-            PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
-            ap.av.sendSelection();
-          }
-          else
-          {
-            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(
-                    aa[selectedRow].groupRef.getSequences(null));
-          }
-          return;
-        }
-        else if (aa[selectedRow].sequenceRef != null)
-        {
-          if (evt.getClickCount() == 1)
-          {
-            ap.getSeqPanel().ap
-                    .getIdPanel()
-                    .highlightSearchResults(
-                            Arrays.asList(new SequenceI[] { aa[selectedRow].sequenceRef }));
-          }
-          else if (evt.getClickCount() >= 2)
-          {
-            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(null);
-            SequenceGroup sg = ap.av.getSelectionGroup();
-            if (sg != null)
-            {
-              // we make a copy rather than edit the current selection if no
-              // modifiers pressed
-              // see Enhancement JAL-1557
-              if (!(evt.isControlDown() || evt.isShiftDown()))
-              {
-                sg = new SequenceGroup(sg);
-                sg.clear();
-                sg.addSequence(aa[selectedRow].sequenceRef, false);
-              }
-              else
-              {
-                if (evt.isControlDown())
-                {
-                  sg.addOrRemove(aa[selectedRow].sequenceRef, true);
-                }
-                else
-                {
-                  // notionally, we should also add intermediate sequences from
-                  // last added sequence ?
-                  sg.addSequence(aa[selectedRow].sequenceRef, true);
-                }
-              }
-            }
-            else
-            {
-              sg = new SequenceGroup();
-              sg.setStartRes(0);
-              sg.setEndRes(ap.av.getAlignment().getWidth() - 1);
-              sg.addSequence(aa[selectedRow].sequenceRef, false);
-            }
-            ap.av.setSelectionGroup(sg);
-            ap.av.sendSelection();
-            ap.paintAlignment(false);
-            PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
-          }
-
-        }
-      }
-    }
-    if (!SwingUtilities.isRightMouseButton(evt))
-    {
-      return;
-    }
-
-    JPopupMenu pop = new JPopupMenu(
-            MessageManager.getString("label.annotations"));
-    JMenuItem item = new JMenuItem(ADDNEW);
-    item.addActionListener(this);
-    pop.add(item);
-    if (selectedRow < 0)
-    {
-      if (hasHiddenRows)
-      { // let the user make everything visible again
-        item = new JMenuItem(SHOWALL);
-        item.addActionListener(this);
-        pop.add(item);
-      }
-      pop.show(this, evt.getX(), evt.getY());
-      return;
-    }
-    item = new JMenuItem(EDITNAME);
-    item.addActionListener(this);
-    pop.add(item);
-    item = new JMenuItem(HIDE);
-    item.addActionListener(this);
-    pop.add(item);
-    // JAL-1264 hide all sequence-specific annotations of this type
-    if (selectedRow < aa.length)
-    {
-      if (aa[selectedRow].sequenceRef != null)
-      {
-        final String label = aa[selectedRow].label;
-        JMenuItem hideType = new JMenuItem();
-        String text = MessageManager.getString("label.hide_all") + " "
-                + label;
-        hideType.setText(text);
-        hideType.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            AlignmentUtils.showOrHideSequenceAnnotations(
-                    ap.av.getAlignment(), Collections.singleton(label),
-                    null, false, false);
-            // for (AlignmentAnnotation ann : ap.av.getAlignment()
-            // .getAlignmentAnnotation())
-            // {
-            // if (ann.sequenceRef != null && ann.label != null
-            // && ann.label.equals(label))
-            // {
-            // ann.visible = false;
-            // }
-            // }
-            refresh();
-          }
-        });
-        pop.add(hideType);
-      }
-    }
-    item = new JMenuItem(DELETE);
-    item.addActionListener(this);
-    pop.add(item);
-    if (hasHiddenRows)
-    {
-      item = new JMenuItem(SHOWALL);
-      item.addActionListener(this);
-      pop.add(item);
-    }
-    item = new JMenuItem(OUTPUT_TEXT);
-    item.addActionListener(this);
-    pop.add(item);
-    // TODO: annotation object should be typed for autocalculated/derived
-    // property methods
-    if (selectedRow < aa.length)
-    {
-      final String label = aa[selectedRow].label;
-      if (!aa[selectedRow].autoCalculated)
-      {
-        if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
-        {
-          // display formatting settings for this row.
-          pop.addSeparator();
-          // av and sequencegroup need to implement same interface for
-          item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
-                  aa[selectedRow].scaleColLabel);
-          item.addActionListener(this);
-          pop.add(item);
-        }
-      }
-      else if (label.indexOf("Consensus") > -1)
-      {
-        pop.addSeparator();
-        // av and sequencegroup need to implement same interface for
-        final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
-                MessageManager.getString("label.ignore_gaps_consensus"),
-                (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef
-                        .getIgnoreGapsConsensus() : ap.av
-                        .isIgnoreGapsConsensus());
-        final AlignmentAnnotation aaa = aa[selectedRow];
-        cbmi.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            if (aaa.groupRef != null)
-            {
-              // TODO: pass on reference to ap so the view can be updated.
-              aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState());
-              ap.getAnnotationPanel().paint(
-                      ap.getAnnotationPanel().getGraphics());
-            }
-            else
-            {
-              ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap);
-            }
-          }
-        });
-        pop.add(cbmi);
-        // av and sequencegroup need to implement same interface for
-        if (aaa.groupRef != null)
+        });
+        pop.add(cbmi);
+        // av and sequencegroup need to implement same interface for
+        if (aaa.groupRef != null)
         {
           final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
                   MessageManager.getString("label.show_group_histogram"),
@@ -879,6 +628,325 @@ public class AnnotationLabels extends JPanel implements MouseListener,
   }
 
   /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void mouseReleased(MouseEvent evt)
+  {
+    if (evt.isPopupTrigger())
+    {
+      showPopupMenu(evt);
+      return;
+    }
+
+    int start = selectedRow;
+    getSelectedRow(evt.getY() - getScrollOffset());
+    int end = selectedRow;
+
+    if (start != end)
+    {
+      // Swap these annotations
+      AlignmentAnnotation startAA = ap.av.getAlignment()
+              .getAlignmentAnnotation()[start];
+      if (end == -1)
+      {
+        end = ap.av.getAlignment().getAlignmentAnnotation().length - 1;
+      }
+      AlignmentAnnotation endAA = ap.av.getAlignment()
+              .getAlignmentAnnotation()[end];
+
+      ap.av.getAlignment().getAlignmentAnnotation()[end] = startAA;
+      ap.av.getAlignment().getAlignmentAnnotation()[start] = endAA;
+    }
+
+    resizePanel = false;
+    dragEvent = null;
+    repaint();
+    ap.getAnnotationPanel().repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void mouseEntered(MouseEvent evt)
+  {
+    if (evt.getY() < 10)
+    {
+      resizePanel = true;
+      repaint();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void mouseExited(MouseEvent evt)
+  {
+    if (dragEvent == null)
+    {
+      resizePanel = false;
+      repaint();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void mouseDragged(MouseEvent evt)
+  {
+    dragEvent = evt;
+
+    if (resizePanel)
+    {
+      Dimension d = ap.annotationScroller.getPreferredSize();
+      int dif = evt.getY() - oldY;
+
+      dif /= ap.av.getCharHeight();
+      dif *= ap.av.getCharHeight();
+
+      if ((d.height - dif) > 20)
+      {
+        ap.annotationScroller.setPreferredSize(new Dimension(d.width,
+                d.height - dif));
+        d = ap.annotationSpaceFillerHolder.getPreferredSize();
+        ap.annotationSpaceFillerHolder.setPreferredSize(new Dimension(
+                d.width, d.height - dif));
+        ap.paintAlignment(true);
+      }
+
+      ap.addNotify();
+    }
+    else
+    {
+      repaint();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void mouseMoved(MouseEvent evt)
+  {
+    resizePanel = evt.getY() < 10;
+
+    getSelectedRow(evt.getY() - getScrollOffset());
+
+    if (selectedRow > -1
+            && ap.av.getAlignment().getAlignmentAnnotation().length > selectedRow)
+    {
+      AlignmentAnnotation aa = ap.av.getAlignment()
+              .getAlignmentAnnotation()[selectedRow];
+
+      StringBuffer desc = new StringBuffer();
+      if (aa.description != null
+              && !aa.description.equals("New description"))
+      {
+        // TODO: we could refactor and merge this code with the code in
+        // jalview.gui.SeqPanel.mouseMoved(..) that formats sequence feature
+        // tooltips
+        desc.append(aa.getDescription(true).trim());
+        // check to see if the description is an html fragment.
+        if (desc.length() < 6
+                || (desc.substring(0, 6).toLowerCase().indexOf("<html>") < 0))
+        {
+          // clean the description ready for embedding in html
+          desc = new StringBuffer(LEFT_ANGLE_BRACKET_PATTERN.matcher(desc)
+                  .replaceAll("&lt;"));
+          desc.insert(0, "<html>");
+        }
+        else
+        {
+          // remove terminating html if any
+          int i = desc.substring(desc.length() - 7).toLowerCase()
+                  .lastIndexOf("</html>");
+          if (i > -1)
+          {
+            desc.setLength(desc.length() - 7 + i);
+          }
+        }
+        if (aa.hasScore())
+        {
+          desc.append("<br/>");
+        }
+        // if (aa.hasProperties())
+        // {
+        // desc.append("<table>");
+        // for (String prop : aa.getProperties())
+        // {
+        // desc.append("<tr><td>" + prop + "</td><td>"
+        // + aa.getProperty(prop) + "</td><tr>");
+        // }
+        // desc.append("</table>");
+        // }
+      }
+      else
+      {
+        // begin the tooltip's html fragment
+        desc.append("<html>");
+        if (aa.hasScore())
+        {
+          // TODO: limit precision of score to avoid noise from imprecise
+          // doubles
+          // (64.7 becomes 64.7+/some tiny value).
+          desc.append(" Score: " + aa.score);
+        }
+      }
+      if (desc.length() > 6)
+      {
+        desc.append("</html>");
+        this.setToolTipText(desc.toString());
+      }
+      else
+      {
+        this.setToolTipText(null);
+      }
+    }
+  }
+
+  @Override
+  public void mouseClicked(MouseEvent evt)
+  {
+    final AlignmentAnnotation[] aa = ap.av.getAlignment()
+            .getAlignmentAnnotation();
+    if (!evt.isPopupTrigger() && SwingUtilities.isLeftMouseButton(evt))
+    {
+      if (selectedRow > -1 && selectedRow < aa.length)
+      {
+        if (aa[selectedRow].groupRef != null)
+        {
+          if (evt.getClickCount() >= 2)
+          {
+            // todo: make the ap scroll to the selection - not necessary, first
+            // click highlights/scrolls, second selects
+            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(null);
+            // process modifiers
+            SequenceGroup sg = ap.av.getSelectionGroup();
+            if (sg == null
+                    || sg == aa[selectedRow].groupRef
+                    || !(jalview.util.Platform.isControlDown(evt) || evt
+                            .isShiftDown()))
+            {
+              if (jalview.util.Platform.isControlDown(evt)
+                      || evt.isShiftDown())
+              {
+                // clone a new selection group from the associated group
+                ap.av.setSelectionGroup(new SequenceGroup(
+                        aa[selectedRow].groupRef));
+              }
+              else
+              {
+                // set selection to the associated group so it can be edited
+                ap.av.setSelectionGroup(aa[selectedRow].groupRef);
+              }
+            }
+            else
+            {
+              // modify current selection with associated group
+              int remainToAdd = aa[selectedRow].groupRef.getSize();
+              for (SequenceI sgs : aa[selectedRow].groupRef.getSequences())
+              {
+                if (jalview.util.Platform.isControlDown(evt))
+                {
+                  sg.addOrRemove(sgs, --remainToAdd == 0);
+                }
+                else
+                {
+                  // notionally, we should also add intermediate sequences from
+                  // last added sequence ?
+                  sg.addSequence(sgs, --remainToAdd == 0);
+                }
+              }
+            }
+
+            ap.paintAlignment(false);
+            PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
+            ap.av.sendSelection();
+          }
+          else
+          {
+            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(
+                    aa[selectedRow].groupRef.getSequences(null));
+          }
+          return;
+        }
+        else if (aa[selectedRow].sequenceRef != null)
+        {
+          if (evt.getClickCount() == 1)
+          {
+            ap.getSeqPanel().ap
+                    .getIdPanel()
+                    .highlightSearchResults(
+                            Arrays.asList(new SequenceI[] { aa[selectedRow].sequenceRef }));
+          }
+          else if (evt.getClickCount() >= 2)
+          {
+            ap.getSeqPanel().ap.getIdPanel().highlightSearchResults(null);
+            SequenceGroup sg = ap.av.getSelectionGroup();
+            if (sg != null)
+            {
+              // we make a copy rather than edit the current selection if no
+              // modifiers pressed
+              // see Enhancement JAL-1557
+              if (!(jalview.util.Platform.isControlDown(evt) || evt
+                      .isShiftDown()))
+              {
+                sg = new SequenceGroup(sg);
+                sg.clear();
+                sg.addSequence(aa[selectedRow].sequenceRef, false);
+              }
+              else
+              {
+                if (jalview.util.Platform.isControlDown(evt))
+                {
+                  sg.addOrRemove(aa[selectedRow].sequenceRef, true);
+                }
+                else
+                {
+                  // notionally, we should also add intermediate sequences from
+                  // last added sequence ?
+                  sg.addSequence(aa[selectedRow].sequenceRef, true);
+                }
+              }
+            }
+            else
+            {
+              sg = new SequenceGroup();
+              sg.setStartRes(0);
+              sg.setEndRes(ap.av.getAlignment().getWidth() - 1);
+              sg.addSequence(aa[selectedRow].sequenceRef, false);
+            }
+            ap.av.setSelectionGroup(sg);
+            ap.paintAlignment(false);
+            PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
+            ap.av.sendSelection();
+          }
+
+        }
+      }
+      return;
+    }
+  }
+
+  /**
    * do a single sequence copy to jalview and the system clipboard
    * 
    * @param sq
index a70d4b9..199c4e5 100755 (executable)
@@ -26,6 +26,8 @@ import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 import jalview.renderer.AwtRenderPanelI;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.AlphaComposite;
@@ -47,6 +49,9 @@ 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;
 
 import javax.swing.JColorChooser;
 import javax.swing.JMenuItem;
@@ -54,7 +59,6 @@ import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.Scrollable;
-import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
 /**
@@ -119,8 +123,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
   boolean mouseDragging = false;
 
-  boolean MAC = false;
-
   // for editing cursor
   int cursorX = 0;
 
@@ -138,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);
@@ -287,14 +286,18 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       aa[activeRow].annotations = anot;
     }
 
-    if (evt.getActionCommand().equals(REMOVE))
+    String action = evt.getActionCommand();
+    if (action.equals(REMOVE))
     {
-      for (int sel : av.getColumnSelection().getSelected())
+      for (int index : av.getColumnSelection().getSelected())
       {
-        anot[sel] = null;
+        if (av.getColumnSelection().isVisible(index))
+        {
+          anot[index] = null;
+        }
       }
     }
-    else if (evt.getActionCommand().equals(LABEL))
+    else if (action.equals(LABEL))
     {
       String exMesg = collectAnnotVals(anot, LABEL);
       String label = JOptionPane.showInputDialog(this,
@@ -319,10 +322,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
         if (anot[index] == null)
         {
-          anot[index] = new Annotation(label, "", ' ', 0); // TODO: verify that
-          // null exceptions
-          // aren't raised
-          // elsewhere.
+          anot[index] = new Annotation(label, "", ' ', 0);
         }
         else
         {
@@ -330,7 +330,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         }
       }
     }
-    else if (evt.getActionCommand().equals(COLOUR))
+    else if (action.equals(COLOUR))
     {
       Color col = JColorChooser.showDialog(this,
               MessageManager.getString("label.select_foreground_colour"),
@@ -352,26 +352,27 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       }
     }
     else
-    // HELIX OR SHEET
+    // HELIX, SHEET or STEM
     {
       char type = 0;
-      String symbol = "\u03B1";
+      String symbol = "\u03B1"; // alpha
 
-      if (evt.getActionCommand().equals(HELIX))
+      if (action.equals(HELIX))
       {
         type = 'H';
       }
-      else if (evt.getActionCommand().equals(SHEET))
+      else if (action.equals(SHEET))
       {
         type = 'E';
-        symbol = "\u03B2";
+        symbol = "\u03B2"; // beta
       }
 
       // Added by LML to color stems
-      else if (evt.getActionCommand().equals(STEM))
+      else if (action.equals(STEM))
       {
         type = 'S';
-        symbol = "\u03C3";
+        int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
+        symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
       }
 
       if (!aa[activeRow].hasIcons)
@@ -390,7 +391,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       if ((label.length() > 0) && !aa[activeRow].hasText)
       {
         aa[activeRow].hasText = true;
-        if (evt.getActionCommand().equals(STEM))
+        if (action.equals(STEM))
         {
           aa[activeRow].showAllColLabels = true;
         }
@@ -413,22 +414,41 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
 
       }
     }
+
     av.getAlignment().validateAnnotation(aa[activeRow]);
     ap.alignmentChanged();
-
+    ap.alignFrame.setMenusForViewport();
     adjustPanelHeight();
     repaint();
 
     return;
   }
 
-  private String collectAnnotVals(Annotation[] anot, String label2)
+  /**
+   * Returns any existing annotation concatenated as a string. For each
+   * annotation, takes the description, if any, else the secondary structure
+   * character (if type is HELIX, SHEET or STEM), else the display character (if
+   * type is LABEL).
+   * 
+   * @param anots
+   * @param type
+   * @return
+   */
+  private String collectAnnotVals(Annotation[] anots, String type)
   {
-    String collatedInput = "";
+    // TODO is this method wanted? why? 'last' is not used
+
+    StringBuilder collatedInput = new StringBuilder(64);
     String last = "";
     ColumnSelection viscols = av.getColumnSelection();
-    // TODO: refactor and save av.getColumnSelection for efficiency
-    for (int index : 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)
     {
       // always check for current display state - just in case
       if (!viscols.isVisible(index))
@@ -436,22 +456,22 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         continue;
       }
       String tlabel = null;
-      if (anot[index] != null)
+      if (anots[index] != null)
       { // LML added stem code
-        if (label2.equals(HELIX) || label2.equals(SHEET)
-                || label2.equals(STEM) || label2.equals(LABEL))
+        if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
+                || type.equals(LABEL))
         {
-          tlabel = anot[index].description;
+          tlabel = anots[index].description;
           if (tlabel == null || tlabel.length() < 1)
           {
-            if (label2.equals(HELIX) || label2.equals(SHEET)
-                    || label2.equals(STEM))
+            if (type.equals(HELIX) || type.equals(SHEET)
+                    || type.equals(STEM))
             {
-              tlabel = "" + anot[index].secondaryStructure;
+              tlabel = "" + anots[index].secondaryStructure;
             }
             else
             {
-              tlabel = "" + anot[index].displayCharacter;
+              tlabel = "" + anots[index].displayCharacter;
             }
           }
         }
@@ -459,13 +479,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         {
           if (last.length() > 0)
           {
-            collatedInput += " ";
+            collatedInput.append(" ");
           }
-          collatedInput += tlabel;
+          collatedInput.append(tlabel);
         }
       }
     }
-    return collatedInput;
+    return collatedInput.toString();
   }
 
   /**
@@ -487,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)
@@ -494,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)
         {
@@ -504,62 +525,71 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
         {
           // Stretch Graph
           graphStretch = i;
-          graphStretchY = evt.getY();
+          graphStretchY = y;
         }
 
         break;
       }
     }
 
-    if (SwingUtilities.isRightMouseButton(evt) && activeRow != -1)
+    /*
+     * isPopupTrigger fires in mousePressed on Mac,
+     * not until mouseRelease on Windows
+     */
+    if (evt.isPopupTrigger() && activeRow != -1)
     {
-      if (av.getColumnSelection() == null)
-      {
-        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() == true)
-      {
-        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;
     }
-
-    if (aa == null)
-    {
-      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);
   }
 
   /**
@@ -575,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());
+    }
+
   }
 
   /**
@@ -629,10 +669,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
   }
 
   /**
-   * DOCUMENT ME!
+   * Constructs the tooltip, and constructs and displays a status message, for
+   * the current mouse position
    * 
    * @param evt
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseMoved(MouseEvent evt)
@@ -658,7 +698,6 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       if (evt.getY() < height)
       {
         row = i;
-
         break;
       }
     }
@@ -669,64 +708,139 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
       return;
     }
 
-    int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+    int column = (evt.getX() / av.getCharWidth()) + av.getStartRes();
 
     if (av.hasHiddenColumns())
     {
-      res = av.getColumnSelection().adjustForHiddenColumns(res);
+      column = av.getColumnSelection().adjustForHiddenColumns(column);
     }
 
-    if (row > -1 && aa[row].annotations != null
-            && res < aa[row].annotations.length)
+    AlignmentAnnotation ann = aa[row];
+    if (row > -1 && ann.annotations != null
+            && column < ann.annotations.length)
+    {
+      buildToolTip(ann, column, aa);
+      setStatusMessage(column, ann);
+    }
+    else
+    {
+      this.setToolTipText(null);
+      ap.alignFrame.statusBar.setText(" ");
+    }
+  }
+
+  /**
+   * Builds a tooltip for the annotation at the current mouse position.
+   * 
+   * @param ann
+   * @param column
+   * @param anns
+   */
+  void buildToolTip(AlignmentAnnotation ann, int column,
+          AlignmentAnnotation[] anns)
+  {
+    if (ann.graphGroup > -1)
     {
-      if (aa[row].graphGroup > -1)
+      StringBuilder tip = new StringBuilder(32);
+      tip.append("<html>");
+      for (int i = 0; i < anns.length; i++)
       {
-        StringBuffer tip = new StringBuffer("<html>");
-        for (int gg = 0; gg < aa.length; gg++)
+        if (anns[i].graphGroup == ann.graphGroup
+                && anns[i].annotations[column] != null)
         {
-          if (aa[gg].graphGroup == aa[row].graphGroup
-                  && aa[gg].annotations[res] != null)
+          tip.append(anns[i].label);
+          String description = anns[i].annotations[column].description;
+          if (description != null && description.length() > 0)
           {
-            tip.append(aa[gg].label + " "
-                    + aa[gg].annotations[res].description + "<br>");
+            tip.append(" ").append(description);
           }
-        }
-        if (tip.length() != 6)
-        {
-          tip.setLength(tip.length() - 4);
-          this.setToolTipText(tip.toString() + "</html>");
+          tip.append("<br>");
         }
       }
-      else if (aa[row].annotations[res] != null
-              && aa[row].annotations[res].description != null
-              && aa[row].annotations[res].description.length() > 0)
+      if (tip.length() != 6)
       {
-        this.setToolTipText(JvSwingUtils.wrapTooltip(true,
-                aa[row].annotations[res].description));
+        tip.setLength(tip.length() - 4);
+        this.setToolTipText(tip.toString() + "</html>");
       }
-      else
+    }
+    else if (ann.annotations[column] != null)
+    {
+      String description = ann.annotations[column].description;
+      if (description != null && description.length() > 0)
       {
-        // clear the tooltip.
-        this.setToolTipText(null);
+        this.setToolTipText(JvSwingUtils.wrapTooltip(true, description));
       }
+    }
+    else
+    {
+      // clear the tooltip.
+      this.setToolTipText(null);
+    }
+  }
 
-      if (aa[row].annotations[res] != null)
+  /**
+   * Constructs and displays the status bar message
+   * 
+   * @param column
+   * @param ann
+   */
+  void setStatusMessage(int column, AlignmentAnnotation ann)
+  {
+    /*
+     * show alignment column and annotation description if any
+     */
+    StringBuilder text = new StringBuilder(32);
+    text.append(MessageManager.getString("label.column")).append(" ")
+            .append(column + 1);
+
+    if (ann.annotations[column] != null)
+    {
+      String description = ann.annotations[column].description;
+      if (description != null && description.trim().length() > 0)
       {
-        StringBuffer text = new StringBuffer("Sequence position "
-                + (res + 1));
+        text.append("  ").append(description);
+      }
+    }
 
-        if (aa[row].annotations[res].description != null)
+    /*
+     * if the annotation is sequence-specific, show the sequence number
+     * in the alignment, and (if not a gap) the residue and position
+     */
+    SequenceI seqref = ann.sequenceRef;
+    if (seqref != null)
+    {
+      int seqIndex = av.getAlignment().findIndex(seqref);
+      if (seqIndex != -1)
+      {
+        text.append(", ")
+                .append(MessageManager.getString("label.sequence"))
+                .append(" ").append(seqIndex + 1);
+        char residue = seqref.getCharAt(column);
+        if (!Comparison.isGap(residue))
         {
-          text.append("  " + aa[row].annotations[res].description);
+          text.append(" ");
+          String name;
+          if (av.getAlignment().isNucleotide())
+          {
+            name = ResidueProperties.nucleotideName.get(String
+                    .valueOf(residue));
+            text.append(" Nucleotide: ").append(
+                    name != null ? name : residue);
+          }
+          else
+          {
+            name = 'X' == residue ? "X" : ('*' == residue ? "STOP"
+                    : ResidueProperties.aa2Triplet.get(String
+                            .valueOf(residue)));
+            text.append(" Residue: ").append(name != null ? name : residue);
+          }
+          int residuePos = seqref.findPosition(column);
+          text.append(" (").append(residuePos).append(")");
         }
-
-        ap.alignFrame.statusBar.setText(text.toString());
       }
     }
-    else
-    {
-      this.setToolTipText(null);
-    }
+
+    ap.alignFrame.statusBar.setText(text.toString());
   }
 
   /**
@@ -1019,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 17298ba..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();
   }
@@ -257,15 +265,14 @@ public abstract class AnnotationRowFilter extends JPanel
   protected void populateThresholdComboBox(JComboBox<String> threshold)
   {
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_no_thereshold"));
+            .getString("label.threshold_feature_no_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_above_thereshold"));
+            .getString("label.threshold_feature_above_threshold"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_below_thereshold"));
+            .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..1c0dfe6 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;
@@ -70,6 +71,7 @@ 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 +79,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;
@@ -303,12 +312,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 +382,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)
     {
@@ -475,15 +482,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 +667,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 +684,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 +707,7 @@ public class AppJmol extends StructureViewerBase
           }
           if (file != null)
           {
-            files.append(" \"" + Platform.escapeString(file) + "\"");
+            files.add(file);
           }
         }
       }
@@ -555,114 +717,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
index 2e72e17..ab9aad7 100644 (file)
@@ -41,6 +41,7 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -285,6 +286,7 @@ public class BlogReader extends JPanel
   /**
    * check if the news panel's container is visible
    */
+  @Override
   public boolean isVisible()
   {
     if (parent == null)
@@ -312,6 +314,7 @@ public class BlogReader extends JPanel
           xf.setContentPane(me);
           xf.addWindowListener(new WindowAdapter()
           {
+            @Override
             public void windowClosing(WindowEvent e)
             {
               ActionEvent actionEvent = new ActionEvent(this,
@@ -320,6 +323,7 @@ public class BlogReader extends JPanel
               exitAction.actionPerformed(actionEvent);
             }
 
+            @Override
             public void windowOpened(WindowEvent e)
             {
             }
@@ -367,9 +371,9 @@ public class BlogReader extends JPanel
               + " and lastDate is " + lastDate);
       for (Item i : (List<Item>) chan.getItems())
       {
+        Date published = i.getPublishDate();
         boolean isread = lastDate == null ? false
-                : (i.getPublishDate() != null && !lastDate.before(i
-                        .getPublishDate()));
+                : (published != null && !lastDate.before(published));
 
         if (!updating || updateItems)
         {
@@ -379,11 +383,11 @@ public class BlogReader extends JPanel
         {
           i.setRead(isread);
         }
-        if (i.getPublishDate() != null && !i.isRead())
+        if (published != null && !i.isRead())
         {
-          if (earliest == null || earliest.after(i.getPublishDate()))
+          if (earliest == null || earliest.after(published))
           {
-            earliest = i.getPublishDate();
+            earliest = published;
           }
         }
       }
@@ -420,11 +424,9 @@ public class BlogReader extends JPanel
       }
       if (lastDate != null)
       {
-        jalview.bin.Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
-                lastDate);
-        jalview.bin.Cache.log.debug("Saved last read date as "
-                + jalview.bin.Cache.date_format.format(lastDate));
-
+        String formatted = Cache.setDateProperty(
+                "JALVIEW_NEWS_RSS_LASTMODIFIED", lastDate);
+        Cache.log.debug("Saved last read date as " + formatted);
       }
     }
   }
@@ -472,6 +474,7 @@ public class BlogReader extends JPanel
 
     listItems.addMouseListener(new java.awt.event.MouseAdapter()
     {
+      @Override
       public void mouseClicked(MouseEvent e)
       {
         listItems_mouseClicked(e);
@@ -497,6 +500,7 @@ public class BlogReader extends JPanel
     }
     textDescription.addHyperlinkListener(new HyperlinkListener()
     {
+      @Override
       public void hyperlinkUpdate(HyperlinkEvent e)
       {
         if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
@@ -508,6 +512,7 @@ public class BlogReader extends JPanel
 
     listItems.addListSelectionListener(new ListSelectionListener()
     {
+      @Override
       public void valueChanged(ListSelectionEvent e)
       {
         if (e.getValueIsAdjusting() == false)
@@ -537,6 +542,7 @@ public class BlogReader extends JPanel
       _listItems = listItems;
     }
 
+    @Override
     public void actionPerformed(ActionEvent e)
     {
       Object o = _listItems.getSelectedValue();
@@ -550,6 +556,7 @@ public class BlogReader extends JPanel
       }
     }
 
+    @Override
     public void update(Object o)
     {
       setEnabled(true);
@@ -754,11 +761,10 @@ public class BlogReader extends JPanel
     lastread.set(1983, 01, 01);
     while (lastread.before(today))
     {
-      Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED",
-              lastread.getTime());
+      String formattedDate = Cache.setDateProperty(
+              "JALVIEW_NEWS_RSS_LASTMODIFIED", lastread.getTime());
       BlogReader me = new BlogReader();
-      System.out.println("Set last date to "
-              + jalview.bin.Cache.date_format.format(lastread.getTime()));
+      System.out.println("Set last date to " + formattedDate);
       if (me.isNewsNew())
       {
         Cache.log.debug("There is news to read.");
@@ -810,6 +816,7 @@ class ChannelsRenderer extends DefaultListCellRenderer
   private final static Icon _icon = new ImageIcon(
           Main.class.getResource("image/ComposeMail16.gif"));
 
+  @Override
   public Component getListCellRendererComponent(JList list, Object value,
           int index, boolean isSelected, boolean cellHasFocus)
   {
@@ -837,6 +844,7 @@ class ItemsRenderer extends DefaultListCellRenderer
   private final static Icon _icon = new ImageIcon(
           Main.class.getResource("image/ComposeMail16.gif"));
 
+  @Override
   public Component getListCellRendererComponent(JList list, Object value,
           int index, boolean isSelected, boolean cellHasFocus)
   {
index f2244d5..ce719d0 100644 (file)
@@ -59,9 +59,7 @@ 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;
@@ -196,7 +194,7 @@ public class ChimeraViewFrame extends StructureViewerBase
   public ChimeraViewFrame(PDBEntry pdbentry, SequenceI[] seq,
           String[] chains, final AlignmentPanel ap)
   {
-    super();
+    this();
     String pdbId = pdbentry.getId();
 
     /*
@@ -249,6 +247,7 @@ public class ChimeraViewFrame extends StructureViewerBase
           SequenceI[][] seqs)
   {
     createProgressBar();
+    // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs
     String[][] chains = extractChains(seqs);
     jmb = new JalviewChimeraBindingModel(this,
             ap.getStructureSelectionManager(), pdbentrys, seqs, chains,
@@ -303,6 +302,9 @@ public class ChimeraViewFrame extends StructureViewerBase
                   .getAllPDBEntries();
           if (pdbrefs != null && pdbrefs.size() > 0)
           {
+            // FIXME: SequenceI.PDBEntry[0] chain mapping used for
+            // ChimeraViewFrame. Is this even used ???
+
             chain = pdbrefs.get(0).getChainCode();
           }
         }
@@ -329,7 +331,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 +360,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);
   }
 
   /**
@@ -539,7 +532,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 +552,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();
   }
 
   /**
@@ -656,7 +658,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());
@@ -728,6 +731,7 @@ public class ChimeraViewFrame extends StructureViewerBase
    */
   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 7d5d8d7..dae83d1 100644 (file)
@@ -100,6 +100,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
     });
     SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         textarea.requestFocus();
@@ -143,6 +144,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
     textarea.setText(text);
   }
 
+  @Override
   public void save_actionPerformed(ActionEvent e)
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
@@ -173,6 +175,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
     }
   }
 
+  @Override
   public void toggleHtml_actionPerformed(ActionEvent e)
   {
     String txt = textarea.getText();
@@ -187,6 +190,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void copyItem_actionPerformed(ActionEvent e)
   {
     Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
@@ -210,6 +214,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void cancel_actionPerformed(ActionEvent e)
   {
     try
@@ -220,9 +225,11 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
     }
   }
 
+  @Override
   public void textarea_mousePressed(MouseEvent e)
   {
-    if (SwingUtilities.isRightMouseButton(e))
+    // isPopupTrigger is on mousePressed (Mac) or mouseReleased (Windows)
+    if (e.isPopupTrigger())
     {
       JPopupMenu popup = new JPopupMenu(
               MessageManager.getString("action.edit"));
@@ -230,6 +237,7 @@ public class CutAndPasteHtmlTransfer extends GCutAndPasteHtmlTransfer
               MessageManager.getString("action.copy"));
       item.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
           copyItem_actionPerformed(e);
index 76f1041..ed2b9bf 100644 (file)
@@ -358,7 +358,11 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
   @Override
   public void textarea_mousePressed(MouseEvent e)
   {
-    if (SwingUtilities.isRightMouseButton(e))
+    /*
+     * isPopupTrigger is checked in mousePressed on Mac,
+     * in mouseReleased on Windows
+     */
+    if (e.isPopupTrigger())
     {
       JPopupMenu popup = new JPopupMenu(
               MessageManager.getString("action.edit"));
index 53e3c8d..e677084 100644 (file)
@@ -81,6 +81,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     ListSelectionModel rowSM = table.getSelectionModel();
     rowSM.addListSelectionListener(new ListSelectionListener()
     {
+      @Override
       public void valueChanged(ListSelectionEvent e)
       {
         ListSelectionModel lsm = (ListSelectionModel) e.getSource();
@@ -94,10 +95,10 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     table.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mouseClicked(MouseEvent evt)
       {
-        if (evt.getClickCount() == 2
-                || SwingUtilities.isRightMouseButton(evt))
+        if (evt.getClickCount() == 2 || evt.isPopupTrigger())
         {
           editRemoveLocalSource(evt);
         }
@@ -119,6 +120,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     this(null);
   }
 
+  @Override
   public void paintComponent(java.awt.Graphics g)
   {
     if (sourceRegistry == null)
@@ -145,6 +147,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     javax.swing.SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         TableSorter sorter = (TableSorter) table.getModel();
@@ -282,6 +285,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     fullDetails.setText(text.toString());
     javax.swing.SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         fullDetailsScrollpane.getVerticalScrollBar().setValue(0);
@@ -289,6 +293,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     });
   }
 
+  @Override
   public void run()
   {
     loadingDasSources = true;
@@ -358,6 +363,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     return selected;
   }
 
+  @Override
   public void refresh_actionPerformed(ActionEvent e)
   {
     saveProperties(jalview.bin.Cache.applicationProperties);
@@ -411,6 +417,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     javax.swing.SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         filter1.setSelectedIndex(0);
@@ -420,6 +427,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     });
   }
 
+  @Override
   public void amendLocal(boolean newSource)
   {
     String url = "http://localhost:8080/", nickname = "";
@@ -440,7 +448,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     seqs.setSelected(seqsrc);
     JPanel panel = new JPanel(new BorderLayout());
     JPanel pane12 = new JPanel(new BorderLayout());
-    pane12.add(new JLabel(MessageManager.getString("label.name")),
+    pane12.add(new JLabel(MessageManager.getString("label.name:")),
             BorderLayout.CENTER);
     pane12.add(nametf, BorderLayout.EAST);
     panel.add(pane12, BorderLayout.NORTH);
@@ -503,6 +511,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         scrollPane.getVerticalScrollBar().setValue(
@@ -571,6 +580,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
       refreshTableData(data);
       SwingUtilities.invokeLater(new Runnable()
       {
+        @Override
         public void run()
         {
           scrollPane.getVerticalScrollBar().setValue(
@@ -582,6 +592,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     }
   }
 
+  @Override
   public void valueChanged(ListSelectionEvent evt)
   {
     // Called when the MainTable selection changes
@@ -691,6 +702,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     }
   }
 
+  @Override
   public void reset_actionPerformed(ActionEvent e)
   {
     registryURL.setText(sourceRegistry.getDasRegistryURL());
@@ -743,21 +755,25 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     private Object[][] data;
 
+    @Override
     public int getColumnCount()
     {
       return columnNames.length;
     }
 
+    @Override
     public int getRowCount()
     {
       return data.length;
     }
 
+    @Override
     public String getColumnName(int col)
     {
       return columnNames[col];
     }
 
+    @Override
     public Object getValueAt(int row, int col)
     {
       return data[row][col];
@@ -768,6 +784,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
      * each cell. If we didn't implement this method, then the last column would
      * contain text ("true"/"false"), rather than a check box.
      */
+    @Override
     public Class getColumnClass(int c)
     {
       return getValueAt(0, c).getClass();
@@ -776,6 +793,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     /*
      * Don't need to implement this method unless your table's editable.
      */
+    @Override
     public boolean isCellEditable(int row, int col)
     {
       // Note that the data/cell address is constant,
@@ -787,6 +805,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
     /*
      * Don't need to implement this method unless your table's data can change.
      */
+    @Override
     public void setValueAt(Object value, int row, int col)
     {
       data[row][col] = value;
@@ -812,6 +831,7 @@ public class DasSourceBrowser extends GDasSourceBrowser implements
 
     Thread thr = new Thread(new Runnable()
     {
+      @Override
       public void run()
       {
         // this actually initialises the das source list
index 27f60ea..3f457ea 100644 (file)
@@ -47,6 +47,7 @@ import java.awt.GridLayout;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.Toolkit;
+import java.awt.Window;
 import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.ClipboardOwner;
 import java.awt.datatransfer.DataFlavor;
@@ -60,18 +61,16 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 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;
-import java.lang.reflect.Constructor;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Hashtable;
@@ -82,6 +81,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Semaphore;
 
+import javax.swing.AbstractAction;
 import javax.swing.DefaultDesktopManager;
 import javax.swing.DesktopManager;
 import javax.swing.JButton;
@@ -96,9 +96,12 @@ import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JProgressBar;
+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;
 
@@ -169,8 +172,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   static final int yOffset = 30;
 
-  private static AlignFrame currentAlignFrame;
-
   public static jalview.ws.jws1.Discoverer discoverer;
 
   public static Object[] jalviewClipboard;
@@ -312,7 +313,20 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      */
     instance = this;
     doVamsasClientCheck();
-    doGroovyCheck();
+
+    groovyShell = new JMenuItem();
+    groovyShell.setText(MessageManager.getString("label.groovy_console"));
+    groovyShell.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        groovyShell_actionPerformed();
+      }
+    });
+    toolsMenu.add(groovyShell);
+    groovyShell.setVisible(true);
+
     doConfigureStructurePrefs();
     setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@@ -383,7 +397,16 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        if (SwingUtilities.isRightMouseButton(evt))
+        if (evt.isPopupTrigger()) // Mac
+        {
+          showPasteMenu(evt.getX(), evt.getY());
+        }
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent evt)
+      {
+        if (evt.isPopupTrigger()) // Windows
         {
           showPasteMenu(evt.getX(), evt.getY());
         }
@@ -791,32 +814,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();
       };
@@ -837,47 +881,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);
 
@@ -938,54 +941,19 @@ 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();
-    java.util.List files = null;
-    java.util.List protocols = null;
+    java.util.List<String> files = new ArrayList<String>();
+    java.util.List<String> protocols = new ArrayList<String>();
 
     try
     {
-      DataFlavor uriListFlavor = new DataFlavor(
-              "text/uri-list;class=java.lang.String");
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-      {
-        // Works on Windows and MacOSX
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        files = (java.util.List) t
-                .getTransferData(DataFlavor.javaFileListFlavor);
-      }
-      else if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        String data = (String) t.getTransferData(uriListFlavor);
-        files = new java.util.ArrayList(1);
-        protocols = new java.util.ArrayList(1);
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
-          String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
-            // the line is a comment (as per the RFC 2483)
-            continue;
-          }
-          java.net.URI uri = new java.net.URI(s);
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
-            protocols.add(FormatAdapter.URL);
-            files.add(uri.toString());
-          }
-          else
-          {
-            // otherwise preserve old behaviour: catch all for file objects
-            java.io.File file = new java.io.File(uri);
-            protocols.add(FormatAdapter.FILE);
-            files.add(file.toString());
-          }
-        }
-      }
+      Desktop.transferFromDropTarget(files, protocols, evt, t);
     } catch (Exception e)
     {
+      e.printStackTrace();
       success = false;
     }
 
@@ -1205,6 +1173,13 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       dialogExecutor.shutdownNow();
     }
     closeAll_actionPerformed(null);
+
+    if (groovyConsole != null)
+    {
+      // suppress a possible repeat prompt to save script
+      groovyConsole.setDirty(false);
+      groovyConsole.exit();
+    }
     System.exit(0);
   }
 
@@ -1328,6 +1303,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++)
     {
@@ -1338,6 +1314,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
       {
       }
     }
+    Jalview.setCurrentAlignFrame(null);
     System.out.println("ALL CLOSED");
     if (v_client != null)
     {
@@ -1354,6 +1331,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     {
       ssm.resetAll();
     }
+    System.gc();
   }
 
   @Override
@@ -1823,7 +1801,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    * 
    * @param af
    */
-  public void explodeViews(AlignFrame af)
+  public static void explodeViews(AlignFrame af)
   {
     int size = af.alignPanels.size();
     if (size < 2)
@@ -2386,25 +2364,6 @@ public class Desktop extends jalview.jbgui.GDesktop implements
 
   protected JMenuItem groovyShell;
 
-  public void doGroovyCheck()
-  {
-    if (jalview.bin.Cache.groovyJarsPresent())
-    {
-      groovyShell = new JMenuItem();
-      groovyShell.setText(MessageManager.getString("label.groovy_console"));
-      groovyShell.addActionListener(new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          groovyShell_actionPerformed();
-        }
-      });
-      toolsMenu.add(groovyShell);
-      groovyShell.setVisible(true);
-    }
-  }
-
   /**
    * Accessor method to quickly get all the AlignmentFrames loaded.
    * 
@@ -2415,7 +2374,7 @@ public class Desktop extends jalview.jbgui.GDesktop implements
     if (Jalview.isHeadlessMode())
     {
       // Desktop.desktop is null in headless mode
-      return new AlignFrame[] { currentAlignFrame };
+      return new AlignFrame[] { Jalview.currentAlignFrame };
     }
 
     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
@@ -2492,24 +2451,9 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   public void groovyShell_actionPerformed()
   {
-    // use reflection to avoid creating compilation dependency.
-    if (!jalview.bin.Cache.groovyJarsPresent())
-    {
-      throw new Error(
-              MessageManager
-                      .getString("error.implementation_error_cannot_create_groovyshell"));
-    }
     try
     {
-      Class<?> gcClass = Desktop.class.getClassLoader().loadClass(
-              "groovy.ui.Console");
-      Constructor<?> gccons = gcClass.getConstructor();
-      java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
-              new Class[] { String.class, Object.class });
-      java.lang.reflect.Method run = gcClass.getMethod("run");
-      Object gc = gccons.newInstance();
-      setvar.invoke(gc, new Object[] { "Jalview", this });
-      run.invoke(gc);
+      openGroovyConsole();
     } catch (Exception ex)
     {
       jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
@@ -2522,6 +2466,93 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   }
 
   /**
+   * Open the Groovy console
+   */
+  void openGroovyConsole()
+  {
+    if (groovyConsole == null)
+    {
+      groovyConsole = new groovy.ui.Console();
+      groovyConsole.setVariable("Jalview", this);
+      groovyConsole.run();
+
+      /*
+       * We allow only one console at a time, so that AlignFrame menu option
+       * 'Calculate | Run Groovy script' is unambiguous.
+       * Disable 'Groovy Console', and enable 'Run script', when the console is 
+       * opened, and the reverse when it is closed
+       */
+      Window window = (Window) groovyConsole.getFrame();
+      window.addWindowListener(new WindowAdapter()
+      {
+        @Override
+        public void windowClosed(WindowEvent e)
+        {
+          /*
+           * rebind CMD-Q from Groovy Console to Jalview Quit
+           */
+          addQuitHandler();
+          enableExecuteGroovy(false);
+        }
+      });
+    }
+
+    /*
+     * show Groovy console window (after close and reopen)
+     */
+    ((Window) groovyConsole.getFrame()).setVisible(true);
+
+    /*
+     * if we got this far, enable 'Run Groovy' in AlignFrame menus
+     * and disable opening a second console
+     */
+    enableExecuteGroovy(true);
+  }
+
+  /**
+   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
+   * binding when opened
+   */
+  protected void addQuitHandler()
+  {
+    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+            KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit
+                    .getDefaultToolkit().getMenuShortcutKeyMask()), "Quit");
+    getRootPane().getActionMap().put("Quit", new AbstractAction()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        quit();
+      }
+    });
+  }
+
+  /**
+   * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
+   * 
+   * @param enabled
+   *          true if Groovy console is open
+   */
+  public void enableExecuteGroovy(boolean enabled)
+  {
+    /*
+     * disable opening a second Groovy console
+     * (or re-enable when the console is closed)
+     */
+    groovyShell.setEnabled(!enabled);
+
+    AlignFrame[] alignFrames = getAlignFrames();
+    if (alignFrames != null)
+    {
+      for (AlignFrame af : alignFrames)
+      {
+        af.setGroovyEnabled(enabled);
+      }
+    }
+  }
+
+  /**
    * Progress bars managed by the IProgressIndicator method.
    */
   private Hashtable<Long, JPanel> progressBars;
@@ -2917,6 +2948,8 @@ public class Desktop extends jalview.jbgui.GDesktop implements
    */
   private java.util.concurrent.Semaphore block = new Semaphore(0);
 
+  private static groovy.ui.Console groovyConsole;
+
   /**
    * add another dialog thread to the queue
    * 
@@ -3132,17 +3165,106 @@ public class Desktop extends jalview.jbgui.GDesktop implements
      * The dust settles...give focus to the tab we did this from.
      */
     myTopFrame.setDisplayedView(myTopFrame.alignPanel);
-
   }
 
-  public static AlignFrame getCurrentAlignFrame()
+  public static groovy.ui.Console getGroovyConsole()
   {
-    return currentAlignFrame;
+    return groovyConsole;
   }
 
-  public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
+  public static void transferFromDropTarget(List<String> files,
+          List<String> protocols, DropTargetDropEvent evt, Transferable t)
+          throws Exception
   {
-    Desktop.currentAlignFrame = currentAlignFrame;
-  }
 
+    DataFlavor uriListFlavor = new DataFlavor(
+            "text/uri-list;class=java.lang.String");
+    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+    {
+      // Works on Windows and MacOSX
+      Cache.log.debug("Drop handled as javaFileListFlavor");
+      for (Object file : (List) t
+              .getTransferData(DataFlavor.javaFileListFlavor))
+      {
+        files.add(((File) file).toString());
+        protocols.add(FormatAdapter.FILE);
+      }
+    }
+    else
+    {
+      // Unix like behaviour
+      boolean added = false;
+      String data = null;
+      if (t.isDataFlavorSupported(uriListFlavor))
+      {
+        Cache.log.debug("Drop handled as uriListFlavor");
+        // This is used by Unix drag system
+        data = (String) t.getTransferData(uriListFlavor);
+      }
+      if (data == null)
+      {
+        // fallback to text: workaround - on OSX where there's a JVM bug
+        Cache.log.debug("standard URIListFlavor failed. Trying text");
+        // try text fallback
+        data = (String) t.getTransferData(new DataFlavor(
+                "text/plain;class=java.lang.String"));
+        if (Cache.log.isDebugEnabled())
+        {
+          Cache.log.debug("fallback returned " + data);
+        }
+      }
+      while (protocols.size() < files.size())
+      {
+        Cache.log.debug("Adding missing FILE protocol for "
+                + files.get(protocols.size()));
+        protocols.add(FormatAdapter.FILE);
+      }
+      for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+              data, "\r\n"); st.hasMoreTokens();)
+      {
+        added = true;
+        String s = st.nextToken();
+        if (s.startsWith("#"))
+        {
+          // the line is a comment (as per the RFC 2483)
+          continue;
+        }
+        java.net.URI uri = new java.net.URI(s);
+        if (uri.getScheme().toLowerCase().startsWith("http"))
+        {
+          protocols.add(FormatAdapter.URL);
+          files.add(uri.toString());
+        }
+        else
+        {
+          // otherwise preserve old behaviour: catch all for file objects
+          java.io.File file = new java.io.File(uri);
+          protocols.add(FormatAdapter.FILE);
+          files.add(file.toString());
+        }
+      }
+      if (Cache.log.isDebugEnabled())
+      {
+        if (data == null || !added)
+        {
+          Cache.log
+                  .debug("Couldn't resolve drop data. Here are the supported flavors:");
+          for (DataFlavor fl : t.getTransferDataFlavors())
+          {
+            Cache.log.debug("Supported transfer dataflavor: "
+                    + fl.toString());
+            Object df = t.getTransferData(fl);
+            if (df != null)
+            {
+              Cache.log.debug("Retrieves: " + df);
+            }
+            else
+            {
+              Cache.log.debug("Retrieved nothing");
+            }
+          }
+        }
+      }
+    }
+  }
 }
index 064d58b..5594e1a 100644 (file)
@@ -20,9 +20,9 @@
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.GraphLine;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -33,7 +33,6 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.util.Hashtable;
 
 import javax.swing.BorderFactory;
 import javax.swing.JCheckBox;
@@ -52,16 +51,16 @@ public class FeatureColourChooser extends JalviewDialog
   // FeatureSettings fs;
   FeatureRenderer fr;
 
-  private GraduatedColor cs;
+  private FeatureColourI cs;
 
-  private Object oldcs;
+  private FeatureColourI oldcs;
 
   /**
    * 
    * @return the last colour setting selected by user - either oldcs (which may
    *         be a java.awt.Color) or the new GraduatedColor
    */
-  public Object getLastColour()
+  public FeatureColourI getLastColour()
   {
     if (cs == null)
     {
@@ -70,8 +69,6 @@ public class FeatureColourChooser extends JalviewDialog
     return cs;
   }
 
-  Hashtable oldgroupColours;
-
   AlignmentPanel ap;
 
   boolean adjusting = false;
@@ -127,7 +124,7 @@ public class FeatureColourChooser extends JalviewDialog
       }
     });
 
-    float mm[] = ((float[][]) fr.getMinMax().get(type))[0];
+    float mm[] = fr.getMinMax().get(type)[0];
     min = mm[0];
     max = mm[1];
 
@@ -139,32 +136,32 @@ public class FeatureColourChooser extends JalviewDialog
     scaleFactor = (max == min) ? 1f : 100f / (max - min);
 
     oldcs = fr.getFeatureColours().get(type);
-    if (oldcs instanceof GraduatedColor)
+    if (!oldcs.isSimpleColour())
     {
-      if (((GraduatedColor) oldcs).isAutoScale())
+      if (oldcs.isAutoScaled())
       {
         // update the scale
-        cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
+        cs = new FeatureColour((FeatureColour) oldcs, min, max);
       }
       else
       {
-        cs = new GraduatedColor((GraduatedColor) oldcs);
+        cs = new FeatureColour((FeatureColour) oldcs);
       }
     }
     else
     {
       // promote original color to a graduated color
-      Color bl = Color.black;
-      if (oldcs instanceof Color)
+      Color bl = oldcs.getColour();
+      if (bl == null)
       {
-        bl = (Color) oldcs;
+        bl = Color.BLACK;
       }
       // original colour becomes the maximum colour
-      cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
+      cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
       cs.setColourByLabel(false);
     }
-    minColour.setBackground(oldminColour = cs.getMinColor());
-    maxColour.setBackground(oldmaxColour = cs.getMaxColor());
+    minColour.setBackground(oldminColour = cs.getMinColour());
+    maxColour.setBackground(oldmaxColour = cs.getMaxColour());
     adjusting = true;
 
     try
@@ -174,18 +171,15 @@ public class FeatureColourChooser extends JalviewDialog
     {
     }
     // update the gui from threshold state
-    thresholdIsMin.setSelected(!cs.isAutoScale());
+    thresholdIsMin.setSelected(!cs.isAutoScaled());
     colourByLabel.setSelected(cs.isColourByLabel());
-    if (cs.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
+    if (cs.hasThreshold())
     {
       // initialise threshold slider and selector
-      threshold
-              .setSelectedIndex(cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
-                      : 2);
+      threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2);
       slider.setEnabled(true);
       thresholdValue.setEnabled(true);
-      threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
-              "Threshold", Color.black);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
 
     }
 
@@ -248,11 +242,11 @@ public class FeatureColourChooser extends JalviewDialog
     threshold.setToolTipText(MessageManager
             .getString("label.threshold_feature_display_by_score"));
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_no_thereshold")); // index 0
+            .getString("label.threshold_feature_no_threshold")); // index 0
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_above_thereshold")); // index 1
+            .getString("label.threshold_feature_above_threshold")); // index 1
     threshold.addItem(MessageManager
-            .getString("label.threshold_feature_below_thereshold")); // index 2
+            .getString("label.threshold_feature_below_threshold")); // index 2
     jPanel3.setLayout(flowLayout2);
     thresholdValue.addActionListener(new ActionListener()
     {
@@ -269,7 +263,7 @@ public class FeatureColourChooser extends JalviewDialog
     slider.setOpaque(false);
     slider.setPreferredSize(new Dimension(100, 32));
     slider.setToolTipText(MessageManager
-            .getString("label.adjust_thereshold"));
+            .getString("label.adjust_threshold"));
     thresholdValue.setEnabled(false);
     thresholdValue.setColumns(7);
     jPanel3.setBackground(Color.white);
@@ -395,50 +389,50 @@ public class FeatureColourChooser extends JalviewDialog
       return;
     }
 
-    int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
+    boolean aboveThreshold = false;
+    boolean belowThreshold = false;
     if (threshold.getSelectedIndex() == 1)
     {
-      aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
+      aboveThreshold = true;
     }
     else if (threshold.getSelectedIndex() == 2)
     {
-      aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
+      belowThreshold = true;
     }
+    boolean hasThreshold = aboveThreshold || belowThreshold;
 
     slider.setEnabled(true);
     thresholdValue.setEnabled(true);
 
-    GraduatedColor acg;
+    FeatureColourI acg;
     if (cs.isColourByLabel())
     {
-      acg = new GraduatedColor(oldminColour, oldmaxColour, min, max);
+      acg = new FeatureColour(oldminColour, oldmaxColour, min, max);
     }
     else
     {
-      acg = new GraduatedColor(oldminColour = minColour.getBackground(),
+      acg = new FeatureColour(oldminColour = minColour.getBackground(),
               oldmaxColour = maxColour.getBackground(), min, max);
 
     }
 
-    if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
+    if (!hasThreshold)
     {
       slider.setEnabled(false);
       thresholdValue.setEnabled(false);
       thresholdValue.setText("");
       thresholdIsMin.setEnabled(false);
     }
-    else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
-            && threshline == null)
+    else if (threshline == null)
     {
       // todo visual indication of feature threshold
-      threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
-              "Threshold", Color.black);
+      threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
     }
 
-    if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    if (hasThreshold)
     {
       adjusting = true;
-      acg.setThresh(threshline.value);
+      acg.setThreshold(threshline.value);
 
       float range = (max - min) * scaleFactor;
 
@@ -453,18 +447,18 @@ public class FeatureColourChooser extends JalviewDialog
       adjusting = false;
     }
 
-    acg.setThreshType(aboveThreshold);
-    if (thresholdIsMin.isSelected()
-            && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    acg.setAboveThreshold(aboveThreshold);
+    acg.setBelowThreshold(belowThreshold);
+    if (thresholdIsMin.isSelected() && hasThreshold)
     {
       acg.setAutoScaled(false);
-      if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
+      if (aboveThreshold)
       {
-        acg = new GraduatedColor(acg, threshline.value, max);
+        acg = new FeatureColour((FeatureColour) acg, threshline.value, max);
       }
       else
       {
-        acg = new GraduatedColor(acg, min, threshline.value);
+        acg = new FeatureColour((FeatureColour) acg, min, threshline.value);
       }
     }
     else
@@ -554,7 +548,7 @@ public class FeatureColourChooser extends JalviewDialog
   public void valueChanged()
   {
     threshline.value = slider.getValue() / scaleFactor;
-    cs.setThresh(threshline.value);
+    cs.setThreshold(threshline.value);
     changeColour();
     ap.paintAlignment(false);
   }
index 1cf15ac..426ea32 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -73,9 +75,8 @@ public class FeatureRenderer extends
    */
   public FeatureRenderer(AlignmentPanel ap)
   {
-    super();
+    super(ap.av);
     this.ap = ap;
-    this.av = ap.av;
     if (ap != null && ap.getSeqPanel() != null
             && ap.getSeqPanel().seqCanvas != null
             && ap.getSeqPanel().seqCanvas.fr != null)
@@ -94,7 +95,7 @@ public class FeatureRenderer extends
 
   static String lastDescriptionAdded;
 
-  Object oldcol, fcol;
+  FeatureColourI oldcol, fcol;
 
   int featureIndex = 0;
 
@@ -126,20 +127,19 @@ public class FeatureRenderer extends
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        if (fcol instanceof Color)
+        if (fcol.isSimpleColour())
         {
           Color col = JColorChooser.showDialog(Desktop.desktop,
                   MessageManager.getString("label.select_feature_colour"),
-                  ((Color) fcol));
+                  fcol.getColour());
           if (col != null)
           {
-            fcol = col;
-            updateColourButton(bigPanel, colour, col);
+            fcol = new FeatureColour(col);
+            updateColourButton(bigPanel, colour, new FeatureColour(col));
           }
         }
         else
         {
-
           if (fcc == null)
           {
             final String type = features[featureIndex].getType();
@@ -173,7 +173,8 @@ public class FeatureRenderer extends
     {
       panel = new JPanel(new GridLayout(4, 1));
       tmp = new JPanel();
-      tmp.add(new JLabel(MessageManager.getString("label.select_feature")));
+      tmp.add(new JLabel(MessageManager.getString("label.select_feature")
+              + ":"));
       overlaps = new JComboBox();
       for (int i = 0; i < features.length; i++)
       {
@@ -206,11 +207,11 @@ public class FeatureRenderer extends
             ap.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
 
           }
-          Object col = getFeatureStyle(name.getText());
+          FeatureColourI col = getFeatureStyle(name.getText());
           if (col == null)
           {
-            col = new jalview.schemes.UserColourScheme()
-                    .createColourFromName(name.getText());
+            col = new FeatureColour(UserColourScheme
+                    .createColourFromName(name.getText()));
           }
           oldcol = fcol = col;
           updateColourButton(bigPanel, colour, col);
@@ -224,12 +225,13 @@ public class FeatureRenderer extends
 
     tmp = new JPanel();
     panel.add(tmp);
-    tmp.add(new JLabel(MessageManager.getString("label.name"), JLabel.RIGHT));
+    tmp.add(new JLabel(MessageManager.getString("label.name:"),
+            JLabel.RIGHT));
     tmp.add(name);
 
     tmp = new JPanel();
     panel.add(tmp);
-    tmp.add(new JLabel(MessageManager.getString("label.group") + ":",
+    tmp.add(new JLabel(MessageManager.getString("label.group:"),
             JLabel.RIGHT));
     tmp.add(source);
 
@@ -248,7 +250,7 @@ public class FeatureRenderer extends
     bigPanel.add(panel, BorderLayout.NORTH);
 
     panel = new JPanel();
-    panel.add(new JLabel(MessageManager.getString("label.description"),
+    panel.add(new JLabel(MessageManager.getString("label.description:"),
             JLabel.RIGHT));
     description.setFont(JvSwingUtils.getTextAreaFont());
     description.setLineWrap(true);
@@ -421,26 +423,25 @@ public class FeatureRenderer extends
    * 
    * @param bigPanel
    * @param col
-   * @param col2
+   * @param col
    */
   protected void updateColourButton(JPanel bigPanel, JLabel colour,
-          Object col2)
+          FeatureColourI col)
   {
     colour.removeAll();
     colour.setIcon(null);
     colour.setToolTipText(null);
     colour.setText("");
 
-    if (col2 instanceof Color)
+    if (col.isSimpleColour())
     {
-      colour.setBackground((Color) col2);
+      colour.setBackground(col.getColour());
     }
     else
     {
       colour.setBackground(bigPanel.getBackground());
       colour.setForeground(Color.black);
-      FeatureSettings.renderGraduatedColor(colour, (GraduatedColor) col2);
-      // colour.setForeground(colour.getBackground());
+      FeatureSettings.renderGraduatedColor(colour, col);
     }
   }
 
index 6ca0769..15f3e5b 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemabinding.version2.JalviewUserColours;
+import jalview.schemes.FeatureColour;
+import jalview.util.Format;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.util.QuickSort;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.dbsources.das.api.jalviewSourceI;
 
@@ -58,6 +62,7 @@ import java.util.Arrays;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
 
@@ -159,8 +164,8 @@ public class FeatureSettings extends JPanel implements
 
     table.setDefaultEditor(Color.class, new ColorEditor(this));
 
-    table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
-    table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
+    table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
+    table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
     table.addMouseListener(new MouseAdapter()
@@ -169,7 +174,7 @@ public class FeatureSettings extends JPanel implements
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
-        if (SwingUtilities.isRightMouseButton(evt))
+        if (evt.isPopupTrigger())
         {
           popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
                   table.getValueAt(selectedRow, 1), fr.getMinMax(),
@@ -177,14 +182,16 @@ public class FeatureSettings extends JPanel implements
         }
         else if (evt.getClickCount() == 2)
         {
+          boolean invertSelection = evt.isAltDown();
+          boolean toggleSelection = Platform.isControlDown(evt);
+          boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
-                  evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
-                  evt.isMetaDown(),
+                  invertSelection, extendSelection, toggleSelection,
                   (String) table.getValueAt(selectedRow, 0));
         }
       }
 
-      // isPopupTrigger fires on mouseReleased on Mac
+      // isPopupTrigger fires on mouseReleased on Windows
       @Override
       public void mouseReleased(MouseEvent evt)
       {
@@ -206,11 +213,20 @@ public class FeatureSettings extends JPanel implements
         int newRow = table.rowAtPoint(evt.getPoint());
         if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
         {
+          /*
+           * reposition 'selectedRow' to 'newRow' (the dragged to location)
+           * this could be more than one row away for a very fast drag action
+           * so just swap it with adjacent rows until we get it there
+           */
           Object[][] data = ((FeatureTableModel) table.getModel())
                   .getData();
-          Object[] temp = data[selectedRow];
-          data[selectedRow] = data[newRow];
-          data[newRow] = temp;
+          int direction = newRow < selectedRow ? -1 : 1;
+          for (int i = selectedRow; i != newRow; i += direction)
+          {
+            Object[] temp = data[i];
+            data[i] = data[i + direction];
+            data[i + direction] = temp;
+          }
           updateFeatureRenderer(data);
           table.repaint();
           selectedRow = newRow;
@@ -250,7 +266,7 @@ public class FeatureSettings extends JPanel implements
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    if (new jalview.util.Platform().isAMac())
+    if (Platform.isAMac())
     {
       Desktop.addInternalFrame(frame,
               MessageManager.getString("label.sequence_feature_settings"),
@@ -277,8 +293,11 @@ public class FeatureSettings extends JPanel implements
   }
 
   protected void popupSort(final int selectedRow, final String type,
-          final Object typeCol, final Hashtable minmax, int x, int y)
+          final Object typeCol, final Map<String, float[][]> minmax, int x,
+          int y)
   {
+    final FeatureColourI featureColour = (FeatureColourI) typeCol;
+
     JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
             "label.settings_for_param", new String[] { type }));
     JMenuItem scr = new JMenuItem(
@@ -312,7 +331,7 @@ public class FeatureSettings extends JPanel implements
     men.add(dens);
     if (minmax != null)
     {
-      final Object typeMinMax = minmax.get(type);
+      final float[][] typeMinMax = minmax.get(type);
       /*
        * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
        * this is broken at the moment and isn't that useful anyway!
@@ -327,14 +346,14 @@ public class FeatureSettings extends JPanel implements
        * 
        * men.add(chb);
        */
-      if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
+      if (typeMinMax != null && typeMinMax[0] != null)
       {
         // if (table.getValueAt(row, column));
         // graduated colourschemes for those where minmax exists for the
         // positional features
         final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
                 "Graduated Colour");
-        mxcol.setSelected(!(typeCol instanceof Color));
+        mxcol.setSelected(!featureColour.isSimpleColour());
         men.add(mxcol);
         mxcol.addActionListener(new ActionListener()
         {
@@ -345,7 +364,7 @@ public class FeatureSettings extends JPanel implements
           {
             if (e.getSource() == mxcol)
             {
-              if (typeCol instanceof Color)
+              if (featureColour.isSimpleColour())
               {
                 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
                         type);
@@ -359,8 +378,7 @@ public class FeatureSettings extends JPanel implements
                         "Select new Colour", true, // modal
                         colorChooser, this, // OK button handler
                         null); // no CANCEL button handler
-                colorChooser.setColor(((GraduatedColor) typeCol)
-                        .getMaxColor());
+                colorChooser.setColor(featureColour.getMaxColour());
                 dialog.setVisible(true);
               }
             }
@@ -376,7 +394,9 @@ public class FeatureSettings extends JPanel implements
               else
               {
                 // probably the color chooser!
-                table.setValueAt(colorChooser.getColor(), selectedRow, 1);
+                table.setValueAt(
+                        new FeatureColour(colorChooser.getColor()),
+                        selectedRow, 1);
                 table.validate();
                 me.updateFeatureRenderer(
                         ((FeatureTableModel) table.getModel()).getData(),
@@ -392,7 +412,6 @@ public class FeatureSettings extends JPanel implements
             MessageManager.getString("label.select_columns_containing"));
     selCols.addActionListener(new ActionListener()
     {
-
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
@@ -404,7 +423,6 @@ public class FeatureSettings extends JPanel implements
             MessageManager.getString("label.select_columns_not_containing"));
     clearCols.addActionListener(new ActionListener()
     {
-
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
@@ -412,8 +430,30 @@ public class FeatureSettings extends JPanel implements
                 false, type);
       }
     });
+    JMenuItem hideCols = new JMenuItem(
+            MessageManager.getString("label.hide_columns_containing"));
+    hideCols.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        fr.ap.alignFrame.hideFeatureColumns(type, true);
+      }
+    });
+    JMenuItem hideOtherCols = new JMenuItem(
+            MessageManager.getString("label.hide_columns_not_containing"));
+    hideOtherCols.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        fr.ap.alignFrame.hideFeatureColumns(type, false);
+      }
+    });
     men.add(selCols);
     men.add(clearCols);
+    men.add(hideCols);
+    men.add(hideOtherCols);
     men.show(table, x, y);
   }
 
@@ -425,13 +465,13 @@ public class FeatureSettings extends JPanel implements
   /**
    * contains a float[3] for each feature type string. created by setTableData
    */
-  Hashtable typeWidth = null;
+  Map<String, float[]> typeWidth = null;
 
   @Override
   synchronized public void discoverAllFeatureData()
   {
-    Vector allFeatures = new Vector();
-    Vector allGroups = new Vector();
+    Vector<String> allFeatures = new Vector<String>();
+    Vector<String> allGroups = new Vector<String>();
     SequenceFeature[] tmpfeatures;
     String group;
     for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
@@ -537,13 +577,13 @@ public class FeatureSettings extends JPanel implements
       return;
     }
     resettingTable = true;
-    typeWidth = new Hashtable();
+    typeWidth = new Hashtable<String, float[]>();
     // TODO: change avWidth calculation to 'per-sequence' average and use long
     // rather than float
     float[] avWidth = null;
     SequenceFeature[] tmpfeatures;
     String group = null, type;
-    Vector visibleChecks = new Vector();
+    Vector<String> visibleChecks = new Vector<String>();
 
     // Find out which features should be visible depending on which groups
     // are selected / deselected
@@ -584,7 +624,7 @@ public class FeatureSettings extends JPanel implements
         }
         else
         {
-          avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
+          avWidth = typeWidth.get(tmpfeatures[index].getType());
         }
         avWidth[0]++;
         if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
@@ -729,8 +769,7 @@ public class FeatureSettings extends JPanel implements
         InputStreamReader in = new InputStreamReader(new FileInputStream(
                 file), "UTF-8");
 
-        jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
-        jucs = jucs.unmarshal(in);
+        JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
 
         for (int i = jucs.getColourCount() - 1; i >= 0; i--)
         {
@@ -749,7 +788,7 @@ public class FeatureSettings extends JPanel implements
               Cache.log.warn("Couldn't parse out graduated feature color.",
                       e);
             }
-            GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
+            FeatureColourI gcol = new FeatureColour(mincol, maxcol,
                     newcol.getMin(), newcol.getMax());
             if (newcol.hasAutoScale())
             {
@@ -761,31 +800,28 @@ public class FeatureSettings extends JPanel implements
             }
             if (newcol.hasThreshold())
             {
-              gcol.setThresh(newcol.getThreshold());
-              gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
+              gcol.setThreshold(newcol.getThreshold());
             }
             if (newcol.getThreshType().length() > 0)
             {
               String ttyp = newcol.getThreshType();
-              if (ttyp.equalsIgnoreCase("NONE"))
-              {
-                gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
-              }
               if (ttyp.equalsIgnoreCase("ABOVE"))
               {
-                gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
+                gcol.setAboveThreshold(true);
               }
               if (ttyp.equalsIgnoreCase("BELOW"))
               {
-                gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
+                gcol.setBelowThreshold(true);
               }
             }
             fr.setColour(name = newcol.getName(), gcol);
           }
           else
           {
-            fr.setColour(name = jucs.getColour(i).getName(), new Color(
-                    Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
+            Color color = new Color(Integer.parseInt(jucs.getColour(i)
+                    .getRGB(), 16));
+            fr.setColour(name = jucs.getColour(i).getName(),
+                    new FeatureColour(color));
           }
           fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
         }
@@ -808,8 +844,7 @@ public class FeatureSettings extends JPanel implements
   void save()
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
-            new String[] { "fc" },
+            Cache.getProperty("LAST_DIRECTORY"), new String[] { "fc" },
             new String[] { "Sequence Feature Colours" },
             "Sequence Feature Colours");
     chooser.setFileView(new jalview.io.JalviewFileView());
@@ -829,50 +864,40 @@ public class FeatureSettings extends JPanel implements
         PrintWriter out = new PrintWriter(new OutputStreamWriter(
                 new FileOutputStream(choice), "UTF-8"));
 
-        Set fr_colours = fr.getAllFeatureColours();
-        Iterator e = fr_colours.iterator();
+        Set<String> fr_colours = fr.getAllFeatureColours();
+        Iterator<String> e = fr_colours.iterator();
         float[] sortOrder = new float[fr_colours.size()];
         String[] sortTypes = new String[fr_colours.size()];
         int i = 0;
         while (e.hasNext())
         {
-          sortTypes[i] = e.next().toString();
+          sortTypes[i] = e.next();
           sortOrder[i] = fr.getOrder(sortTypes[i]);
           i++;
         }
-        jalview.util.QuickSort.sort(sortOrder, sortTypes);
+        QuickSort.sort(sortOrder, sortTypes);
         sortOrder = null;
-        Object fcol;
-        GraduatedColor gcol;
         for (i = 0; i < sortTypes.length; i++)
         {
           jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
           col.setName(sortTypes[i]);
-          col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
-                  .getName())));
-          fcol = fr.getFeatureStyle(sortTypes[i]);
-          if (fcol instanceof GraduatedColor)
+          FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
+          if (fcol.isSimpleColour())
           {
-            gcol = (GraduatedColor) fcol;
-            col.setMin(gcol.getMin());
-            col.setMax(gcol.getMax());
-            col.setMinRGB(jalview.util.Format.getHexString(gcol
-                    .getMinColor()));
-            col.setAutoScale(gcol.isAutoScale());
-            col.setThreshold(gcol.getThresh());
-            col.setColourByLabel(gcol.isColourByLabel());
-            switch (gcol.getThreshType())
-            {
-            case AnnotationColourGradient.NO_THRESHOLD:
-              col.setThreshType("NONE");
-              break;
-            case AnnotationColourGradient.ABOVE_THRESHOLD:
-              col.setThreshType("ABOVE");
-              break;
-            case AnnotationColourGradient.BELOW_THRESHOLD:
-              col.setThreshType("BELOW");
-              break;
-            }
+            col.setRGB(Format.getHexString(fcol.getColour()));
+          }
+          else
+          {
+            col.setRGB(Format.getHexString(fcol.getMaxColour()));
+            col.setMin(fcol.getMin());
+            col.setMax(fcol.getMax());
+            col.setMinRGB(jalview.util.Format.getHexString(fcol
+                    .getMinColour()));
+            col.setAutoScale(fcol.isAutoScaled());
+            col.setThreshold(fcol.getThreshold());
+            col.setColourByLabel(fcol.isColourByLabel());
+            col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
+                    .isBelowThreshold() ? "BELOW" : "NONE"));
           }
           ucs.addColour(col);
         }
@@ -908,7 +933,7 @@ public class FeatureSettings extends JPanel implements
     int num = 0;
     for (int i = 0; i < data.length; i++)
     {
-      awidth = (float[]) typeWidth.get(data[i][0]);
+      awidth = typeWidth.get(data[i][0]);
       if (awidth[0] > 0)
       {
         width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
@@ -1231,7 +1256,8 @@ public class FeatureSettings extends JPanel implements
     fetchDAS.setEnabled(false);
     cancelDAS.setEnabled(true);
     dassourceBrowser.setGuiEnabled(false);
-    Vector selectedSources = dassourceBrowser.getSelectedSources();
+    Vector<jalviewSourceI> selectedSources = dassourceBrowser
+            .getSelectedSources();
     doDasFeatureFetch(selectedSources, true, true);
   }
 
@@ -1290,7 +1316,7 @@ public class FeatureSettings extends JPanel implements
    *          Vector of Strings to resolve to DAS source nicknames.
    * @return sources that are present in source list.
    */
-  public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
+  public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
   {
     return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
   }
@@ -1301,7 +1327,7 @@ public class FeatureSettings extends JPanel implements
    * 
    * @return vector of selected das source nicknames
    */
-  public Vector getSelectedSources()
+  public Vector<jalviewSourceI> getSelectedSources()
   {
     return dassourceBrowser.getSelectedSources();
   }
@@ -1315,7 +1341,7 @@ public class FeatureSettings extends JPanel implements
    *          if true then runs in same thread, otherwise passes to the Swing
    *          executor
    */
-  public void fetchDasFeatures(Vector sources, boolean block)
+  public void fetchDasFeatures(Vector<String> sources, boolean block)
   {
     initDasSources();
     List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
@@ -1481,10 +1507,11 @@ public class FeatureSettings extends JPanel implements
     }
 
     @Override
-    public Component getTableCellRendererComponent(JTable table,
+    public Component getTableCellRendererComponent(JTable tbl,
             Object color, boolean isSelected, boolean hasFocus, int row,
             int column)
     {
+      FeatureColourI cellColour = (FeatureColourI) color;
       // JLabel comp = new JLabel();
       // comp.
       setOpaque(true);
@@ -1492,11 +1519,11 @@ public class FeatureSettings extends JPanel implements
       // setBounds(getBounds());
       Color newColor;
       setToolTipText(baseTT);
-      setBackground(table.getBackground());
-      if (color instanceof GraduatedColor)
+      setBackground(tbl.getBackground());
+      if (!cellColour.isSimpleColour())
       {
-        Rectangle cr = table.getCellRect(row, column, false);
-        FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
+        Rectangle cr = tbl.getCellRect(row, column, false);
+        FeatureSettings.renderGraduatedColor(this, cellColour,
                 (int) cr.getWidth(), (int) cr.getHeight());
 
       }
@@ -1504,20 +1531,16 @@ public class FeatureSettings extends JPanel implements
       {
         this.setText("");
         this.setIcon(null);
-        newColor = (Color) color;
-        // comp.
+        newColor = cellColour.getColour();
         setBackground(newColor);
-        // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
-        // + newColor.getGreen() + ", " + newColor.getBlue());
       }
       if (isSelected)
       {
         if (selectedBorder == null)
         {
           selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
-                  table.getSelectionBackground());
+                  tbl.getSelectionBackground());
         }
-        // comp.
         setBorder(selectedBorder);
       }
       else
@@ -1525,9 +1548,8 @@ public class FeatureSettings extends JPanel implements
         if (unselectedBorder == null)
         {
           unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
-                  table.getBackground());
+                  tbl.getBackground());
         }
-        // comp.
         setBorder(unselectedBorder);
       }
 
@@ -1541,7 +1563,7 @@ public class FeatureSettings extends JPanel implements
    * @param comp
    * @param gcol
    */
-  public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
   {
     int w = comp.getWidth(), h = comp.getHeight();
     if (w < 20)
@@ -1557,23 +1579,23 @@ public class FeatureSettings extends JPanel implements
     renderGraduatedColor(comp, gcol, w, h);
   }
 
-  public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
           int w, int h)
   {
     boolean thr = false;
     String tt = "";
     String tx = "";
-    if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
+    if (gcol.isAboveThreshold())
     {
       thr = true;
       tx += ">";
-      tt += "Thresholded (Above " + gcol.getThresh() + ") ";
+      tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
     }
-    if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
+    if (gcol.isBelowThreshold())
     {
       thr = true;
       tx += "<";
-      tt += "Thresholded (Below " + gcol.getThresh() + ") ";
+      tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
     }
     if (gcol.isColourByLabel())
     {
@@ -1587,7 +1609,7 @@ public class FeatureSettings extends JPanel implements
     }
     else
     {
-      Color newColor = gcol.getMaxColor();
+      Color newColor = gcol.getMaxColour();
       comp.setBackground(newColor);
       // System.err.println("Width is " + w / 2);
       Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
@@ -1615,7 +1637,7 @@ public class FeatureSettings extends JPanel implements
 
 class FeatureIcon implements Icon
 {
-  GraduatedColor gcol;
+  FeatureColourI gcol;
 
   Color backg;
 
@@ -1627,7 +1649,7 @@ class FeatureIcon implements Icon
 
   Color mpcolour = Color.white;
 
-  FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
+  FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
   {
     gcol = gfc;
     backg = bg;
@@ -1667,7 +1689,7 @@ class FeatureIcon implements Icon
       g.setColor(backg);
       g.fillRect(0, 0, width, height);
       // need an icon here.
-      g.setColor(gcol.getMaxColor());
+      g.setColor(gcol.getMaxColour());
 
       g.setFont(new Font("Verdana", Font.PLAIN, 9));
 
@@ -1681,7 +1703,7 @@ class FeatureIcon implements Icon
     }
     else
     {
-      Color minCol = gcol.getMinColor();
+      Color minCol = gcol.getMinColour();
       g.setColor(minCol);
       g.fillRect(0, 0, s1, height);
       if (midspace)
@@ -1689,7 +1711,7 @@ class FeatureIcon implements Icon
         g.setColor(Color.white);
         g.fillRect(s1, 0, e1 - s1, height);
       }
-      g.setColor(gcol.getMaxColor());
+      g.setColor(gcol.getMaxColour());
       g.fillRect(0, e1, width - e1, height);
     }
   }
@@ -1700,14 +1722,12 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
 {
   FeatureSettings me;
 
-  GraduatedColor currentGColor;
+  FeatureColourI currentColor;
 
   FeatureColourChooser chooser;
 
   String type;
 
-  Color currentColor;
-
   JButton button;
 
   JColorChooser colorChooser;
@@ -1747,11 +1767,11 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     {
       // The user has clicked the cell, so
       // bring up the dialog.
-      if (currentColor != null)
+      if (currentColor.isSimpleColour())
       {
         // bring up simple color chooser
-        button.setBackground(currentColor);
-        colorChooser.setColor(currentColor);
+        button.setBackground(currentColor.getColour());
+        colorChooser.setColor(currentColor.getColour());
         dialog.setVisible(true);
       }
       else
@@ -1768,15 +1788,13 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     }
     else
     { // User pressed dialog's "OK" button.
-      if (currentColor != null)
+      if (currentColor.isSimpleColour())
       {
-        currentColor = colorChooser.getColor();
+        currentColor = new FeatureColour(colorChooser.getColor());
       }
       else
       {
-        // class cast exceptions may be raised if the chooser created on a
-        // non-graduated color
-        currentGColor = (GraduatedColor) chooser.getLastColour();
+        currentColor = chooser.getLastColour();
       }
       me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
       fireEditingStopped();
@@ -1788,10 +1806,6 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
   @Override
   public Object getCellEditorValue()
   {
-    if (currentColor == null)
-    {
-      return currentGColor;
-    }
     return currentColor;
   }
 
@@ -1800,18 +1814,16 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
   public Component getTableCellEditorComponent(JTable table, Object value,
           boolean isSelected, int row, int column)
   {
-    currentGColor = null;
-    currentColor = null;
+    currentColor = (FeatureColourI) value;
     this.selectedRow = row;
     type = me.table.getValueAt(row, 0).toString();
     button.setOpaque(true);
     button.setBackground(me.getBackground());
-    if (value instanceof GraduatedColor)
+    if (!currentColor.isSimpleColour())
     {
-      currentGColor = (GraduatedColor) value;
       JLabel btn = new JLabel();
       btn.setSize(button.getSize());
-      FeatureSettings.renderGraduatedColor(btn, currentGColor);
+      FeatureSettings.renderGraduatedColor(btn, currentColor);
       button.setBackground(btn.getBackground());
       button.setIcon(btn.getIcon());
       button.setText(btn.getText());
@@ -1820,8 +1832,7 @@ class ColorEditor extends AbstractCellEditor implements TableCellEditor,
     {
       button.setText("");
       button.setIcon(null);
-      currentColor = (Color) value;
-      button.setBackground(currentColor);
+      button.setBackground(currentColor.getColour());
     }
     return button;
   }
index 535196e..1f6c068 100755 (executable)
@@ -157,6 +157,7 @@ public class FontChooser extends GFontChooser
     init = false;
   }
 
+  @Override
   public void smoothFont_actionPerformed(ActionEvent e)
   {
     ap.av.antiAlias = smoothFont.isSelected();
@@ -170,6 +171,7 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void ok_actionPerformed(ActionEvent e)
   {
     try
@@ -194,6 +196,7 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void cancel_actionPerformed(ActionEvent e)
   {
     if (ap != null)
@@ -247,10 +250,10 @@ public class FontChooser extends GFontChooser
     double iw = iBounds.getWidth();
     if (mw < 1 || iw < 1)
     {
-      final String messageKey = iBounds.getHeight() < 1 ? "label.font_doesnt_have_letters_defined"
-              : "label.font_too_small";
-      JOptionPane.showInternalMessageDialog(this,
-              MessageManager.getString(messageKey),
+      String message = iBounds.getHeight() < 1 ? MessageManager
+              .getString("label.font_doesnt_have_letters_defined")
+              : MessageManager.getString("label.font_too_small");
+      JOptionPane.showInternalMessageDialog(this, message,
               MessageManager.getString("label.invalid_font"),
               JOptionPane.WARNING_MESSAGE);
       /*
@@ -301,6 +304,7 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void fontName_actionPerformed(ActionEvent e)
   {
     if (init)
@@ -317,6 +321,7 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void fontSize_actionPerformed(ActionEvent e)
   {
     if (init)
@@ -333,6 +338,7 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   protected void fontStyle_actionPerformed(ActionEvent e)
   {
     if (init)
@@ -349,6 +355,7 @@ public class FontChooser extends GFontChooser
    * 
    * @param e
    */
+  @Override
   public void defaultButton_actionPerformed(ActionEvent e)
   {
     Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString());
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 c89a9d5..37be8bc 100755 (executable)
@@ -204,6 +204,7 @@ public class IdCanvas extends JPanel
    * @param g
    *          DOCUMENT ME!
    */
+  @Override
   public void paintComponent(Graphics g)
   {
     g.setColor(Color.white);
@@ -479,7 +480,7 @@ public class IdCanvas extends JPanel
     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
             .getSize());
 
-    if (av.isHiddenRepSequence(seq))
+    if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq))
     {
       gg.setFont(bold);
     }
index c3ede0b..161c787 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;
 
@@ -193,6 +194,8 @@ public class IdPanel extends JPanel implements MouseListener,
      */
     if (e.getClickCount() < 2 || SwingUtilities.isRightMouseButton(e))
     {
+      // reinstate isRightMouseButton check to ignore mouse-related popup events
+      // note - this does nothing on default MacBookPro force-trackpad config!
       return;
     }
 
@@ -314,38 +317,24 @@ public class IdPanel extends JPanel implements MouseListener,
       return;
     }
 
-    int seq = alignPanel.getSeqPanel().findSeq(e);
-
-    if (SwingUtilities.isRightMouseButton(e))
+    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 nlinks = new Vector(Preferences.sequenceURLLinks);
-      SequenceFeature sf[] = sq == null ? null : sq.getSequenceFeatures();
-      for (int sl = 0; sf != null && sl < sf.length; sl++)
-      {
-        if (sf[sl].begin == sf[sl].end && sf[sl].begin == 0)
-        {
-          if (sf[sl].links != null && sf[sl].links.size() > 0)
-          {
-            for (int l = 0, lSize = sf[sl].links.size(); l < lSize; l++)
-            {
-              nlinks.addElement(sf[sl].links.elementAt(l));
-            }
-          }
-        }
-      }
-
-      jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu(alignPanel, sq,
-              nlinks, new Vector(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)
-            || ((!e.isControlDown() && !e.isShiftDown()) && av
+            || (!jalview.util.Platform.isControlDown(e) && !e.isShiftDown() && av
                     .getSelectionGroup() != null))
     {
       av.setSelectionGroup(new SequenceGroup());
@@ -353,6 +342,7 @@ public class IdPanel extends JPanel implements MouseListener,
       av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
     }
 
+    int seq = alignPanel.getSeqPanel().findSeq(e);
     if (e.isShiftDown() && (lastid != -1))
     {
       selectSeqs(lastid, seq);
@@ -361,13 +351,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
@@ -434,6 +459,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 6f602ad..2a3d788 100644 (file)
@@ -26,7 +26,6 @@ import jalview.ws.seqfetcher.DbSourceProxy;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridLayout;
@@ -34,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;
@@ -73,7 +74,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
       @Override
       public void actionPerformed(ActionEvent arg0)
       {
-        showDialog(null);
+        showDialog();
       }
     });
     return viewdbs;
@@ -169,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);
@@ -188,6 +202,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     jc.validate();
     // j.setPreferredSize(new Dimension(300,50));
     add(jc, BorderLayout.CENTER);
+    ok.setEnabled(false);
     j.add(ok);
     j.add(cancel);
     add(j, BorderLayout.SOUTH);
@@ -308,7 +323,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
   protected void okPressed()
   {
     _setSelectionState();
-    closeDialog();
   }
 
   @Override
@@ -320,7 +334,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     closeDialog();
   }
 
-  private void showDialog(Container parent)
+  void showDialog()
   {
     oldselection = selection;
     oldtsel = tsel;
@@ -349,10 +363,12 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     {
       return;
     }
+    ok.setEnabled(false);
     if (dbviews.getSelectionCount() == 0)
     {
       selection = null;
     }
+
     tsel = dbviews.getSelectionPaths();
     boolean forcedFirstChild = false;
     List<DbSourceProxy> srcs = new ArrayList<DbSourceProxy>();
@@ -364,6 +380,10 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
                 .getLastPathComponent();
         if (dmt.getUserObject() != null)
         {
+          /*
+           * enable OK button once a selection has been made
+           */
+          ok.setEnabled(true);
           if (dmt.getUserObject() instanceof DbSourceProxy)
           {
             srcs.add((DbSourceProxy) dmt.getUserObject());
@@ -419,6 +439,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
       }
     }
 
+    dbstatex.setText(" ");
     if (allowMultiSelections)
     {
       dbstatus.setText(MessageManager.formatMessage(
@@ -427,7 +448,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
                   (srcs.size() == 1 ? "" : "s"),
                   (srcs.size() > 0 ? " with " + x + " test quer"
                           + (x == 1 ? "y" : "ies") : ".") }));
-      dbstatex.setText(" ");
     }
     else
     {
@@ -440,10 +460,6 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
           dbstatex.setText(MessageManager.formatMessage(
                   "label.example_param", new String[] { qr }));
         }
-        else
-        {
-          dbstatex.setText(" ");
-        }
       }
       else
       {
@@ -555,6 +571,7 @@ public class JDatabaseTree extends JalviewDialog implements KeyListener
     {
       action = arg0.getKeyCode();
       okPressed();
+      closeDialog();
     }
     if (!arg0.isConsumed() && arg0.getKeyChar() == KeyEvent.VK_ESCAPE)
     {
index 2799a7e..1c90889 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.gui;
 
+import jalview.analysis.Conservation;
+import jalview.api.FeatureColourI;
 import jalview.api.ViewStyleI;
 import jalview.api.structures.JalviewStructureDisplayI;
 import jalview.bin.Cache;
@@ -71,7 +73,7 @@ import jalview.schemabinding.version2.Viewport;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
@@ -79,6 +81,7 @@ import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.StringUtils;
 import jalview.util.jarInputStreamProvider;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
@@ -90,6 +93,7 @@ import jalview.ws.params.ArgumentI;
 import jalview.ws.params.AutoCalcSetting;
 import jalview.ws.params.WsParamSetI;
 
+import java.awt.Color;
 import java.awt.Rectangle;
 import java.io.BufferedReader;
 import java.io.DataInputStream;
@@ -105,6 +109,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -116,7 +121,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
@@ -163,7 +167,9 @@ public class Jalview2XML
    */
   Map<String, SequenceI> seqRefIds = null;
 
-  Vector<Object[]> frefedSequence = null;
+  Map<String, SequenceI> incompleteSeqs = null;
+
+  List<SeqFref> frefedSequence = null;
 
   boolean raiseGUI = true; // whether errors are raised in dialog boxes or not
 
@@ -218,6 +224,10 @@ public class Jalview2XML
       {
         seqsToIds.clear();
       }
+      if (incompleteSeqs != null)
+      {
+        incompleteSeqs.clear();
+      }
       // seqRefIds = null;
       // seqsToIds = null;
     }
@@ -240,6 +250,14 @@ public class Jalview2XML
     {
       seqRefIds = new HashMap<String, SequenceI>();
     }
+    if (incompleteSeqs == null)
+    {
+      incompleteSeqs = new HashMap<String, SequenceI>();
+    }
+    if (frefedSequence == null)
+    {
+      frefedSequence = new ArrayList<SeqFref>();
+    }
   }
 
   public Jalview2XML()
@@ -251,78 +269,185 @@ public class Jalview2XML
     this.raiseGUI = raiseGUI;
   }
 
+  /**
+   * base class for resolving forward references to sequences by their ID
+   * 
+   * @author jprocter
+   *
+   */
+  abstract class SeqFref
+  {
+    String sref;
+
+    String type;
+
+    public SeqFref(String _sref, String type)
+    {
+      sref = _sref;
+      this.type = type;
+    }
+
+    public String getSref()
+    {
+      return sref;
+    }
+
+    public SequenceI getSrefSeq()
+    {
+      return seqRefIds.get(sref);
+    }
+
+    public boolean isResolvable()
+    {
+      return seqRefIds.get(sref) != null;
+    }
+
+    public SequenceI getSrefDatasetSeq()
+    {
+      SequenceI sq = seqRefIds.get(sref);
+      if (sq != null)
+      {
+        while (sq.getDatasetSequence() != null)
+        {
+          sq = sq.getDatasetSequence();
+        }
+      }
+      return sq;
+    }
+
+    /**
+     * @return true if the forward reference was fully resolved
+     */
+    abstract boolean resolve();
+
+    @Override
+    public String toString()
+    {
+      return type + " reference to " + sref;
+    }
+  }
+
+  /**
+   * create forward reference for a mapping
+   * 
+   * @param sref
+   * @param _jmap
+   * @return
+   */
+  public SeqFref newMappingRef(final String sref,
+          final jalview.datamodel.Mapping _jmap)
+  {
+    SeqFref fref = new SeqFref(sref, "Mapping")
+    {
+      public jalview.datamodel.Mapping jmap = _jmap;
+
+      @Override
+      boolean resolve()
+      {
+        SequenceI seq = getSrefDatasetSeq();
+        if (seq == null)
+        {
+          return false;
+        }
+        jmap.setTo(seq);
+        return true;
+      }
+    };
+    return fref;
+  }
+
+  public SeqFref newAlcodMapRef(final String sref,
+          final AlignedCodonFrame _cf, final jalview.datamodel.Mapping _jmap)
+  {
+
+    SeqFref fref = new SeqFref(sref, "Codon Frame")
+    {
+      AlignedCodonFrame cf = _cf;
+
+      public jalview.datamodel.Mapping mp = _jmap;
+
+      @Override
+      public boolean isResolvable()
+      {
+        return super.isResolvable() && mp.getTo() != null;
+      };
+
+      @Override
+      boolean resolve()
+      {
+        SequenceI seq = getSrefDatasetSeq();
+        if (seq == null)
+        {
+          return false;
+        }
+        cf.addMap(seq, mp.getTo(), mp.getMap());
+        return true;
+      }
+    };
+    return fref;
+  }
+
   public void resolveFrefedSequences()
   {
-    if (frefedSequence.size() > 0)
+    Iterator<SeqFref> nextFref = frefedSequence.iterator();
+    int toresolve = frefedSequence.size();
+    int unresolved = 0, failedtoresolve = 0;
+    while (nextFref.hasNext())
     {
-      int r = 0, rSize = frefedSequence.size();
-      while (r < rSize)
+      SeqFref ref = nextFref.next();
+      if (ref.isResolvable())
       {
-        Object[] ref = frefedSequence.elementAt(r);
-        if (ref != null)
+        try
         {
-          String sref = (String) ref[0];
-          if (seqRefIds.containsKey(sref))
+          if (ref.resolve())
           {
-            if (ref[1] instanceof jalview.datamodel.Mapping)
-            {
-              SequenceI seq = seqRefIds.get(sref);
-              while (seq.getDatasetSequence() != null)
-              {
-                seq = seq.getDatasetSequence();
-              }
-              ((jalview.datamodel.Mapping) ref[1]).setTo(seq);
-            }
-            else
-            {
-              if (ref[1] instanceof jalview.datamodel.AlignedCodonFrame)
-              {
-                SequenceI seq = seqRefIds.get(sref);
-                while (seq.getDatasetSequence() != null)
-                {
-                  seq = seq.getDatasetSequence();
-                }
-                if (ref[2] != null
-                        && ref[2] instanceof jalview.datamodel.Mapping)
-                {
-                  jalview.datamodel.Mapping mp = (jalview.datamodel.Mapping) ref[2];
-                  ((jalview.datamodel.AlignedCodonFrame) ref[1]).addMap(
-                          seq, mp.getTo(), mp.getMap());
-                }
-                else
-                {
-                  System.err
-                          .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for AlcodonFrames involving "
-                                  + ref[2].getClass() + " type objects.");
-                }
-              }
-              else
-              {
-                System.err
-                        .println("IMPLEMENTATION ERROR: Unimplemented forward sequence references for "
-                                + ref[1].getClass() + " type objects.");
-              }
-            }
-            frefedSequence.remove(r);
-            rSize--;
+            nextFref.remove();
           }
           else
           {
-            System.err
-                    .println("IMPLEMENTATION WARNING: Unresolved forward reference for hash string "
-                            + ref[0]
-                            + " with objecttype "
-                            + ref[1].getClass());
-            r++;
+            failedtoresolve++;
           }
+        } 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)
+    {
+      System.err.println("Jalview Project Import: There were " + unresolved
+              + " forward references left unresolved on the stack.");
+    }
+    if (failedtoresolve > 0)
+    {
+      System.err.println("SERIOUS! " + failedtoresolve
+              + " resolvable forward references failed to resolve.");
+    }
+    if (incompleteSeqs != null && incompleteSeqs.size() > 0)
+    {
+      System.err.println("Jalview Project Import: There are "
+              + incompleteSeqs.size()
+              + " sequences which may have incomplete metadata.");
+      if (incompleteSeqs.size() < 10)
+      {
+        for (SequenceI s : incompleteSeqs.values())
         {
-          // empty reference
-          frefedSequence.remove(r);
-          rSize--;
+          System.err.println(s.toString());
         }
       }
+      else
+      {
+        System.err
+                .println("Too many to report. Skipping output of incomplete sequences.");
+      }
     }
   }
 
@@ -394,7 +519,20 @@ public class Jalview2XML
     {
       return;
     }
+    saveAllFrames(Arrays.asList(frames), jout);
+  }
 
+  /**
+   * core method for storing state for a set of AlignFrames.
+   * 
+   * @param frames
+   *          - frames involving all data to be exported (including containing
+   *          splitframes)
+   * @param jout
+   *          - project output stream
+   */
+  private void saveAllFrames(List<AlignFrame> frames, JarOutputStream jout)
+  {
     Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
 
     /*
@@ -414,9 +552,9 @@ public class Jalview2XML
       List<String> viewIds = new ArrayList<String>();
 
       // REVERSE ORDER
-      for (int i = frames.length - 1; i > -1; i--)
+      for (int i = frames.size() - 1; i > -1; i--)
       {
-        AlignFrame af = frames[i];
+        AlignFrame af = frames.get(i);
         // skip ?
         if (skipList != null
                 && skipList
@@ -519,30 +657,20 @@ public class Jalview2XML
   {
     try
     {
-      int ap = 0;
-      int apSize = af.alignPanels.size();
       FileOutputStream fos = new FileOutputStream(jarFile);
       JarOutputStream jout = new JarOutputStream(fos);
-      Hashtable<String, AlignFrame> dsses = new Hashtable<String, AlignFrame>();
-      List<String> viewIds = new ArrayList<String>();
+      List<AlignFrame> frames = new ArrayList<AlignFrame>();
 
-      for (AlignmentPanel apanel : af.alignPanels)
+      // resolve splitframes
+      if (af.getViewport().getCodingComplement() != null)
       {
-        String jfileName = apSize == 1 ? fileName : fileName + ap;
-        ap++;
-        if (!jfileName.endsWith(".xml"))
-        {
-          jfileName = jfileName + ".xml";
-        }
-        saveState(apanel, jfileName, jout, viewIds);
-        String dssid = getDatasetIdRef(af.getViewport().getAlignment()
-                .getDataset());
-        if (!dsses.containsKey(dssid))
-        {
-          dsses.put(dssid, af);
-        }
+        frames = ((SplitFrame) af.getSplitViewContainer()).getAlignFrames();
+      }
+      else
+      {
+        frames.add(af);
       }
-      writeDatasetFor(dsses, fileName, jout);
+      saveAllFrames(frames, jout);
       try
       {
         jout.flush();
@@ -633,11 +761,15 @@ public class Jalview2XML
     object.setVersion(jalview.bin.Cache.getDefault("VERSION",
             "Development Build"));
 
-    jalview.datamodel.AlignmentI jal = av.getAlignment();
+    /**
+     * rjal is full height alignment, jal is actual alignment with full metadata
+     * but excludes hidden sequences.
+     */
+    jalview.datamodel.AlignmentI rjal = av.getAlignment(), jal = rjal;
 
     if (av.hasHiddenRows())
     {
-      jal = jal.getHiddenSequences().getFullAlignment();
+      rjal = jal.getHiddenSequences().getFullAlignment();
     }
 
     SequenceSet vamsasSet = new SequenceSet();
@@ -654,6 +786,7 @@ public class Jalview2XML
       {
         // switch jal and the dataset
         jal = jal.getDataset();
+        rjal = jal;
       }
     }
     if (jal.getProperties() != null)
@@ -671,38 +804,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 (int i = 0; i < jal.getHeight(); i++)
+    for (final SequenceI jds : rjal.getSequences())
     {
-      final SequenceI jds = jal.getSequenceAt(i);
       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());
@@ -714,26 +851,33 @@ public class Jalview2XML
         // Store any sequences this sequence represents
         if (av.hasHiddenRows())
         {
+          // use rjal, contains the full height alignment
           jseq.setHidden(av.getAlignment().getHiddenSequences()
                   .isHidden(jds));
 
-          if (av.isHiddenRepSequence(jal.getSequenceAt(i)))
+          if (av.isHiddenRepSequence(jds))
           {
             jalview.datamodel.SequenceI[] reps = av
-                    .getRepresentedSequences(jal.getSequenceAt(i))
-                    .getSequencesInOrder(jal);
+                    .getRepresentedSequences(jds).getSequencesInOrder(rjal);
 
             for (int h = 0; h < reps.length; h++)
             {
-              if (reps[h] != jal.getSequenceAt(i))
+              if (reps[h] != jds)
               {
-                jseq.addHiddenSequences(jal.findIndex(reps[h]));
+                jseq.addHiddenSequences(rjal.findIndex(reps[h]));
               }
             }
           }
         }
+        // mark sequence as reference - if it is the reference for this view
+        if (jal.hasSeqrep())
+        {
+          jseq.setViewreference(jds == jal.getSeqrep());
+        }
       }
 
+      // TODO: omit sequence features from each alignment view's XML dump if we
+      // are storing dataset
       if (jds.getSequenceFeatures() != null)
       {
         jalview.datamodel.SequenceFeature[] sf = jds.getSequenceFeatures();
@@ -848,17 +992,16 @@ public class Jalview2XML
             }
           }
 
-          if (entry.getProperty() != null && !entry.getProperty().isEmpty())
+          Enumeration<String> props = entry.getProperties();
+          if (props.hasMoreElements())
           {
             PdbentryItem item = new PdbentryItem();
-            Hashtable properties = entry.getProperty();
-            Enumeration en2 = properties.keys();
-            while (en2.hasMoreElements())
+            while (props.hasMoreElements())
             {
               Property prop = new Property();
-              String key = en2.nextElement().toString();
+              String key = props.nextElement();
               prop.setName(key);
-              prop.setValue(properties.get(key).toString());
+              prop.setValue(entry.getProperty(key).toString());
               item.addProperty(prop);
             }
             pdb.addPdbentryItem(item);
@@ -878,16 +1021,17 @@ public class Jalview2XML
       jal = av.getAlignment();
     }
     // SAVE MAPPINGS
-    if (jal.getCodonFrames() != null)
+    // FOR DATASET
+    if (storeDS && jal.getCodonFrames() != null)
     {
       List<AlignedCodonFrame> jac = jal.getCodonFrames();
       for (AlignedCodonFrame acf : jac)
       {
         AlcodonFrame alc = new AlcodonFrame();
-        vamsasSet.addAlcodonFrame(alc);
         if (acf.getProtMappings() != null
                 && acf.getProtMappings().length > 0)
         {
+          boolean hasMap = false;
           SequenceI[] dnas = acf.getdnaSeqs();
           jalview.datamodel.Mapping[] pmaps = acf.getProtMappings();
           for (int m = 0; m < pmaps.length; m++)
@@ -897,9 +1041,14 @@ public class Jalview2XML
             alcmap.setMapping(createVamsasMapping(pmaps[m], dnas[m], null,
                     false));
             alc.addAlcodMap(alcmap);
+            hasMap = true;
+          }
+          if (hasMap)
+          {
+            vamsasSet.addAlcodonFrame(alc);
           }
         }
-
+        // TODO: delete this ? dead code from 2.8.3->2.9 ?
         // {
         // AlcodonFrame alc = new AlcodonFrame();
         // vamsasSet.addAlcodonFrame(alc);
@@ -1194,82 +1343,53 @@ public class Jalview2XML
                 .getFeatureRenderer().getRenderOrder()
                 .toArray(new String[0]);
 
-        Vector settingsAdded = new Vector();
-        Object gstyle = null;
-        GraduatedColor gcol = null;
+        Vector<String> settingsAdded = new Vector<String>();
         if (renderOrder != null)
         {
-          for (int ro = 0; ro < renderOrder.length; ro++)
+          for (String featureType : renderOrder)
           {
-            gstyle = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                    .getFeatureStyle(renderOrder[ro]);
+            FeatureColourI fcol = ap.getSeqPanel().seqCanvas
+                    .getFeatureRenderer().getFeatureStyle(featureType);
             Setting setting = new Setting();
-            setting.setType(renderOrder[ro]);
-            if (gstyle instanceof GraduatedColor)
+            setting.setType(featureType);
+            if (!fcol.isSimpleColour())
             {
-              gcol = (GraduatedColor) gstyle;
-              setting.setColour(gcol.getMaxColor().getRGB());
-              setting.setMincolour(gcol.getMinColor().getRGB());
-              setting.setMin(gcol.getMin());
-              setting.setMax(gcol.getMax());
-              setting.setColourByLabel(gcol.isColourByLabel());
-              setting.setAutoScale(gcol.isAutoScale());
-              setting.setThreshold(gcol.getThresh());
-              setting.setThreshstate(gcol.getThreshType());
+              setting.setColour(fcol.getMaxColour().getRGB());
+              setting.setMincolour(fcol.getMinColour().getRGB());
+              setting.setMin(fcol.getMin());
+              setting.setMax(fcol.getMax());
+              setting.setColourByLabel(fcol.isColourByLabel());
+              setting.setAutoScale(fcol.isAutoScaled());
+              setting.setThreshold(fcol.getThreshold());
+              // -1 = No threshold, 0 = Below, 1 = Above
+              setting.setThreshstate(fcol.isAboveThreshold() ? 1 : (fcol
+                      .isBelowThreshold() ? 0 : -1));
             }
             else
             {
-              setting.setColour(ap.getSeqPanel().seqCanvas
-                      .getFeatureRenderer().getColour(renderOrder[ro])
-                      .getRGB());
+              setting.setColour(fcol.getColour().getRGB());
             }
 
             setting.setDisplay(av.getFeaturesDisplayed().isVisible(
-                    renderOrder[ro]));
+                    featureType));
             float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                    .getOrder(renderOrder[ro]);
+                    .getOrder(featureType);
             if (rorder > -1)
             {
               setting.setOrder(rorder);
             }
             fs.addSetting(setting);
-            settingsAdded.addElement(renderOrder[ro]);
+            settingsAdded.addElement(featureType);
           }
         }
 
-        // Make sure we save none displayed feature settings
-        Iterator en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                .getFeatureColours().keySet().iterator();
-        while (en.hasNext())
-        {
-          String key = en.next().toString();
-          if (settingsAdded.contains(key))
-          {
-            continue;
-          }
-
-          Setting setting = new Setting();
-          setting.setType(key);
-          setting.setColour(ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .getColour(key).getRGB());
-
-          setting.setDisplay(false);
-          float rorder = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                  .getOrder(key);
-          if (rorder > -1)
-          {
-            setting.setOrder(rorder);
-          }
-          fs.addSetting(setting);
-          settingsAdded.addElement(key);
-        }
         // is groups actually supposed to be a map here ?
-        en = ap.getSeqPanel().seqCanvas.getFeatureRenderer()
-                .getFeatureGroups().iterator();
-        Vector groupsAdded = new Vector();
+        Iterator<String> en = ap.getSeqPanel().seqCanvas
+                .getFeatureRenderer().getFeatureGroups().iterator();
+        Vector<String> groupsAdded = new Vector<String>();
         while (en.hasNext())
         {
-          String grp = en.next().toString();
+          String grp = en.next();
           if (groupsAdded.contains(grp))
           {
             continue;
@@ -1283,7 +1403,6 @@ public class Jalview2XML
           groupsAdded.addElement(grp);
         }
         jms.setFeatureSettings(fs);
-
       }
 
       if (av.hasHiddenColumns())
@@ -1949,16 +2068,17 @@ public class Jalview2XML
     if (jds.getDatasetSequence() != null)
     {
       vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence()));
-      if (jds.getDatasetSequence().getDBRefs() != null)
-      {
-        dbrefs = jds.getDatasetSequence().getDBRefs();
-      }
     }
     else
     {
-      vamsasSeq.setDsseqid(id); // so we can tell which sequences really are
+      // seqId==dsseqid so we can tell which sequences really are
       // dataset sequences only
+      vamsasSeq.setDsseqid(id);
       dbrefs = jds.getDBRefs();
+      if (parentseq == null)
+      {
+        parentseq = jds;
+      }
     }
     if (dbrefs != null)
     {
@@ -2010,38 +2130,32 @@ public class Jalview2XML
       if (jmp.getTo() != null)
       {
         MappingChoice mpc = new MappingChoice();
-        if (recurse
-                && (parentseq != jmp.getTo() || parentseq
-                        .getDatasetSequence() != jmp.getTo()))
+
+        // check/create ID for the sequence referenced by getTo()
+
+        String jmpid = "";
+        SequenceI ps = null;
+        if (parentseq != jmp.getTo()
+                && parentseq.getDatasetSequence() != jmp.getTo())
         {
-          mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()),
-                  jmp.getTo(), jds));
+          // chaining dbref rather than a handshaking one
+          jmpid = seqHash(ps = jmp.getTo());
         }
         else
         {
-          String jmpid = "";
-          SequenceI ps = null;
-          if (parentseq != jmp.getTo()
-                  && parentseq.getDatasetSequence() != jmp.getTo())
-          {
-            // chaining dbref rather than a handshaking one
-            jmpid = seqHash(ps = jmp.getTo());
-          }
-          else
-          {
-            jmpid = seqHash(ps = parentseq);
-          }
-          mpc.setDseqFor(jmpid);
-          if (!seqRefIds.containsKey(mpc.getDseqFor()))
-          {
-            jalview.bin.Cache.log.debug("creatign new DseqFor ID");
-            seqRefIds.put(mpc.getDseqFor(), ps);
-          }
-          else
-          {
-            jalview.bin.Cache.log.debug("reusing DseqFor ID");
-          }
+          jmpid = seqHash(ps = parentseq);
+        }
+        mpc.setDseqFor(jmpid);
+        if (!seqRefIds.containsKey(mpc.getDseqFor()))
+        {
+          jalview.bin.Cache.log.debug("creatign new DseqFor ID");
+          seqRefIds.put(mpc.getDseqFor(), ps);
         }
+        else
+        {
+          jalview.bin.Cache.log.debug("reusing DseqFor ID");
+        }
+
         mp.setMappingChoice(mpc);
       }
     }
@@ -2250,14 +2364,10 @@ public class Jalview2XML
     }
     if (seqRefIds == null)
     {
-      seqRefIds = new HashMap<String, SequenceI>();
-    }
-    if (frefedSequence == null)
-    {
-      frefedSequence = new Vector<Object[]>();
+      initSeqRefs();
     }
-
     AlignFrame af = null, _af = null;
+    IdentityHashMap<AlignmentI, AlignmentI> importedDatasets = new IdentityHashMap<AlignmentI, AlignmentI>();
     Map<String, AlignFrame> gatherToThisFrame = new HashMap<String, AlignFrame>();
     final String file = jprovider.getFilename();
     try
@@ -2285,13 +2395,24 @@ public class Jalview2XML
           if (true) // !skipViewport(object))
           {
             _af = loadFromObject(object, file, true, jprovider);
-            if (object.getJalviewModelSequence().getViewportCount() > 0)
+            if (_af != null
+                    && object.getJalviewModelSequence().getViewportCount() > 0)
             {
-              af = _af;
-              if (af.viewport.isGatherViewsHere())
+              if (af == null)
               {
-                gatherToThisFrame.put(af.viewport.getSequenceSetId(), af);
+                // store a reference to the first view
+                af = _af;
               }
+              if (_af.viewport.isGatherViewsHere())
+              {
+                // if this is a gathered view, keep its reference since
+                // after gathering views, only this frame will remain
+                af = _af;
+                gatherToThisFrame.put(_af.viewport.getSequenceSetId(), _af);
+              }
+              // Save dataset to register mappings once all resolved
+              importedDatasets.put(af.viewport.getAlignment().getDataset(),
+                      af.viewport.getAlignment().getDataset());
             }
           }
           entryCount++;
@@ -2347,11 +2468,6 @@ public class Jalview2XML
       e.printStackTrace();
     }
 
-    if (Desktop.instance != null)
-    {
-      Desktop.instance.stopLoading();
-    }
-
     /*
      * Regather multiple views (with the same sequence set id) to the frame (if
      * any) that is flagged as the one to gather to, i.e. convert them to tabbed
@@ -2365,11 +2481,24 @@ public class Jalview2XML
     }
 
     restoreSplitFrames();
-
+    for (AlignmentI ds : importedDatasets.keySet())
+    {
+      if (ds.getCodonFrames() != null)
+      {
+        StructureSelectionManager.getStructureSelectionManager(
+                Desktop.instance).registerMappings(ds.getCodonFrames());
+      }
+    }
     if (errorMessage != null)
     {
       reportErrors();
     }
+
+    if (Desktop.instance != null)
+    {
+      Desktop.instance.stopLoading();
+    }
+
     return af;
   }
 
@@ -2414,6 +2543,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);
@@ -2435,6 +2566,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");
       }
@@ -2538,14 +2670,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);
@@ -2562,14 +2696,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();
@@ -2587,7 +2733,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;
@@ -2675,36 +2821,71 @@ public class Jalview2XML
     // LOAD SEQUENCES
 
     List<SequenceI> hiddenSeqs = null;
-    jalview.datamodel.Sequence jseq;
 
     List<SequenceI> tmpseqs = new ArrayList<SequenceI>();
 
     boolean multipleView = false;
-
+    SequenceI referenceseqForView = null;
     JSeq[] jseqs = object.getJalviewModelSequence().getJSeq();
     int vi = 0; // counter in vamsasSeq array
     for (int i = 0; i < jseqs.length; i++)
     {
       String seqId = jseqs[i].getId();
 
-      if (seqRefIds.get(seqId) != null)
+      SequenceI tmpSeq = seqRefIds.get(seqId);
+      if (tmpSeq != null)
       {
-        tmpseqs.add(seqRefIds.get(seqId));
-        multipleView = true;
+        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())
+          {
+            System.err
+                    .println("Warning JAL-2154 regression: updating start/end for sequence "
+                            + tmpSeq.toString() + " to " + jseqs[i]);
+          }
+        }
+        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);
       }
       else
       {
-        jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
+        tmpSeq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(),
                 vamsasSeq[vi].getSequence());
-        jseq.setDescription(vamsasSeq[vi].getDescription());
-        jseq.setStart(jseqs[i].getStart());
-        jseq.setEnd(jseqs[i].getEnd());
-        jseq.setVamsasId(uniqueSetSuffix + seqId);
-        seqRefIds.put(vamsasSeq[vi].getId(), jseq);
-        tmpseqs.add(jseq);
+        tmpSeq.setDescription(vamsasSeq[vi].getDescription());
+        tmpSeq.setStart(jseqs[i].getStart());
+        tmpSeq.setEnd(jseqs[i].getEnd());
+        tmpSeq.setVamsasId(uniqueSetSuffix + seqId);
+        seqRefIds.put(vamsasSeq[vi].getId(), tmpSeq);
+        tmpseqs.add(tmpSeq);
         vi++;
       }
 
+      if (jseqs[i].hasViewreference() && jseqs[i].getViewreference())
+      {
+        referenceseqForView = tmpseqs.get(tmpseqs.size() - 1);
+      }
+
       if (jseqs[i].getHidden())
       {
         if (hiddenSeqs == null)
@@ -2712,9 +2893,8 @@ public class Jalview2XML
           hiddenSeqs = new ArrayList<SequenceI>();
         }
 
-        hiddenSeqs.add(seqRefIds.get(seqId));
+        hiddenSeqs.add(tmpSeq);
       }
-
     }
 
     // /
@@ -2723,31 +2903,51 @@ public class Jalview2XML
     SequenceI[] orderedSeqs = tmpseqs
             .toArray(new SequenceI[tmpseqs.size()]);
 
-    Alignment al = new Alignment(orderedSeqs);
-
-    // / Add the alignment properties
-    for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
-    {
-      SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
-      al.setProperty(ssp.getKey(), ssp.getValue());
-    }
-
-    // /
-    // SequenceFeatures are added to the DatasetSequence,
-    // so we must create or recover the dataset before loading features
+    AlignmentI al = null;
+    // so we must create or recover the dataset alignment before going further
     // ///////////////////////////////
     if (vamsasSet.getDatasetId() == null || vamsasSet.getDatasetId() == "")
     {
-      // older jalview projects do not have a dataset id.
+      // older jalview projects do not have a dataset - so creat alignment and
+      // dataset
+      al = new Alignment(orderedSeqs);
       al.setDataset(null);
     }
     else
     {
-      // recover dataset - passing on flag indicating if this a 'viewless'
-      // sequence set (a.k.a. a stored dataset for the project)
-      recoverDatasetFor(vamsasSet, al, object.getJalviewModelSequence()
-              .getViewportCount() == 0);
+      boolean isdsal = object.getJalviewModelSequence().getViewportCount() == 0;
+      if (isdsal)
+      {
+        // we are importing a dataset record, so
+        // recover reference to an alignment already materialsed as dataset
+        al = getDatasetFor(vamsasSet.getDatasetId());
+      }
+      if (al == null)
+      {
+        // materialse the alignment
+        al = new Alignment(orderedSeqs);
+      }
+      if (isdsal)
+      {
+        addDatasetRef(vamsasSet.getDatasetId(), al);
+      }
+
+      // finally, verify all data in vamsasSet is actually present in al
+      // passing on flag indicating if it is actually a stored dataset
+      recoverDatasetFor(vamsasSet, al, isdsal);
+    }
+
+    if (referenceseqForView != null)
+    {
+      al.setSeqrep(referenceseqForView);
     }
+    // / Add the alignment properties
+    for (int i = 0; i < vamsasSet.getSequenceSetPropertiesCount(); i++)
+    {
+      SequenceSetProperties ssp = vamsasSet.getSequenceSetProperties(i);
+      al.setProperty(ssp.getKey(), ssp.getValue());
+    }
+
     // ///////////////////////////////
 
     Hashtable pdbloaded = new Hashtable(); // TODO nothing writes to this??
@@ -2755,6 +2955,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)
@@ -2781,13 +2987,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)
         {
@@ -2798,29 +3008,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);
+            }
           }
         }
       }
@@ -2849,20 +3079,20 @@ 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(new Object[] { 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);
         }
-        al.addCodonFrame(cf);
       }
     }
 
@@ -3171,8 +3401,7 @@ public class Jalview2XML
         }
         if (jGroup.getConsThreshold() != 0)
         {
-          jalview.analysis.Conservation c = new jalview.analysis.Conservation(
-                  "All", ResidueProperties.propHash, 3,
+          Conservation c = new Conservation("All", 3,
                   sg.getSequences(null), 0, sg.getWidth() - 1);
           c.calculate();
           c.verdict(false, 25);
@@ -3362,7 +3591,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);
         }
@@ -3537,7 +3766,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();
@@ -3548,7 +3778,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)
@@ -3708,7 +3939,7 @@ public class Jalview2XML
      */
     String viewerJarEntryName = getViewerJarEntryName(data.getViewId());
     chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName,
-            "chimera");
+            "chimera", null);
 
     Set<Entry<File, StructureData>> fileData = data.getFileData()
             .entrySet();
@@ -3789,6 +4020,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());
@@ -4047,18 +4283,22 @@ public class Jalview2XML
   }
 
   /**
+   * Answers true if 'version' is equal to or later than 'supported', where each
+   * is formatted as major/minor versions like "2.8.3" or "2.3.4b1" for bugfix
+   * changes. Development and test values for 'version' are leniently treated
+   * i.e. answer true.
    * 
    * @param supported
    *          - minimum version we are comparing against
    * @param version
-   *          - version of data being processsed.
-   * @return true if version is development/null or evaluates to the same or
-   *         later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*)
+   *          - version of data being processsed
+   * @return
    */
   public static boolean isVersionStringLaterThan(String supported,
           String version)
   {
-    if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD")
+    if (supported == null || version == null
+            || version.equalsIgnoreCase("DEVELOPMENT BUILD")
             || version.equalsIgnoreCase("Test")
             || version.equalsIgnoreCase("AUTOMATED BUILD"))
     {
@@ -4069,45 +4309,8 @@ public class Jalview2XML
     }
     else
     {
-      StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer(
-              version, ".");
-      while (currentV.hasMoreTokens() && fileV.hasMoreTokens())
-      {
-        // convert b to decimal to catch bugfix releases within a series
-        String curT = currentV.nextToken().toLowerCase().replace('b', '.');
-        String fileT = fileV.nextToken().toLowerCase().replace('b', '.');
-        try
-        {
-          float supportedVersionToken = Float.parseFloat(curT);
-          float myVersiontoken = Float.parseFloat(fileT);
-          if (supportedVersionToken > myVersiontoken)
-          {
-            // current version is newer than the version that wrote the file
-            return false;
-          }
-          if (supportedVersionToken < myVersiontoken)
-          {
-            // current version is older than the version that wrote the file
-            return true;
-          }
-        } catch (NumberFormatException nfe)
-        {
-          System.err
-                  .println("** WARNING: Version comparison failed for tokens ("
-                          + curT
-                          + ") and ("
-                          + fileT
-                          + ")\n** Current: '"
-                          + supported + "' and Version: '" + version + "'");
-        }
-      }
-      if (currentV.hasMoreElements())
-      {
-        // fileV has no minor version but identical series to current
-        return false;
-      }
+      return StringUtils.compareVersions(version, supported, "b") >= 0;
     }
-    return true;
   }
 
   Vector<JalviewStructureDisplayI> newStructureViewers = null;
@@ -4135,7 +4338,7 @@ public class Jalview2XML
   }
 
   AlignFrame loadViewport(String file, JSeq[] JSEQ,
-          List<SequenceI> hiddenSeqs, Alignment al,
+          List<SequenceI> hiddenSeqs, AlignmentI al,
           JalviewModelSequence jms, Viewport view, String uniqueSeqSetId,
           String viewId, List<JvAnnotRow> autoAlan)
   {
@@ -4151,6 +4354,12 @@ public class Jalview2XML
               .getSequenceAt(i), new java.awt.Color(JSEQ[i].getColour()));
     }
 
+    if (al.hasSeqrep())
+    {
+      af.getViewport().setColourByReferenceSeq(true);
+      af.getViewport().setDisplayReferenceSeq(true);
+    }
+
     af.viewport.setGatherViewsHere(view.getGatheredViews());
 
     if (view.getSequenceSetId() != null)
@@ -4177,25 +4386,25 @@ public class Jalview2XML
     {
       for (int s = 0; s < JSEQ.length; s++)
       {
-        jalview.datamodel.SequenceGroup hidden = new jalview.datamodel.SequenceGroup();
-
+        SequenceGroup hidden = new SequenceGroup();
+        boolean isRepresentative = false;
         for (int r = 0; r < JSEQ[s].getHiddenSequencesCount(); r++)
         {
-          hidden.addSequence(
-                  al.getSequenceAt(JSEQ[s].getHiddenSequences(r)), false);
+          isRepresentative = true;
+          SequenceI sequenceToHide = al.getSequenceAt(JSEQ[s]
+                  .getHiddenSequences(r));
+          hidden.addSequence(sequenceToHide, false);
+          // remove from hiddenSeqs list so we don't try to hide it twice
+          hiddenSeqs.remove(sequenceToHide);
+        }
+        if (isRepresentative)
+        {
+          SequenceI representativeSequence = al.getSequenceAt(s);
+          hidden.addSequence(representativeSequence, false);
+          af.viewport.hideRepSequences(representativeSequence, hidden);
         }
-        af.viewport.hideRepSequences(al.getSequenceAt(s), hidden);
       }
 
-      // jalview.datamodel.SequenceI[] hseqs = new
-      // jalview.datamodel.SequenceI[hiddenSeqs
-      // .size()];
-      //
-      // for (int s = 0; s < hiddenSeqs.size(); s++)
-      // {
-      // hseqs[s] = (jalview.datamodel.SequenceI) hiddenSeqs.elementAt(s);
-      // }
-
       SequenceI[] hseqs = hiddenSeqs.toArray(new SequenceI[hiddenSeqs
               .size()]);
       af.viewport.hideSequence(hseqs);
@@ -4354,25 +4563,33 @@ public class Jalview2XML
       af.viewport.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
       String[] renderOrder = new String[jms.getFeatureSettings()
               .getSettingCount()];
-      Hashtable featureGroups = new Hashtable();
-      Hashtable featureColours = new Hashtable();
-      Hashtable featureOrder = new Hashtable();
+      Map<String, FeatureColourI> featureColours = new Hashtable<String, FeatureColourI>();
+      Map<String, Float> featureOrder = new Hashtable<String, Float>();
 
       for (int fs = 0; fs < jms.getFeatureSettings().getSettingCount(); fs++)
       {
         Setting setting = jms.getFeatureSettings().getSetting(fs);
         if (setting.hasMincolour())
         {
-          GraduatedColor gc = setting.hasMin() ? new GraduatedColor(
-                  new java.awt.Color(setting.getMincolour()),
-                  new java.awt.Color(setting.getColour()),
-                  setting.getMin(), setting.getMax()) : new GraduatedColor(
-                  new java.awt.Color(setting.getMincolour()),
-                  new java.awt.Color(setting.getColour()), 0, 1);
+          FeatureColourI gc = setting.hasMin() ? new FeatureColour(
+                  new Color(setting.getMincolour()), new Color(
+                          setting.getColour()), setting.getMin(),
+                  setting.getMax()) : new FeatureColour(new Color(
+                  setting.getMincolour()), new Color(setting.getColour()),
+                  0, 1);
           if (setting.hasThreshold())
           {
-            gc.setThresh(setting.getThreshold());
-            gc.setThreshType(setting.getThreshstate());
+            gc.setThreshold(setting.getThreshold());
+            int threshstate = setting.getThreshstate();
+            // -1 = None, 0 = Below, 1 = Above threshold
+            if (threshstate == 0)
+            {
+              gc.setBelowThreshold(true);
+            }
+            else if (threshstate == 1)
+            {
+              gc.setAboveThreshold(true);
+            }
           }
           gc.setAutoScaled(true); // default
           if (setting.hasAutoScale())
@@ -4388,8 +4605,8 @@ public class Jalview2XML
         }
         else
         {
-          featureColours.put(setting.getType(),
-                  new java.awt.Color(setting.getColour()));
+          featureColours.put(setting.getType(), new FeatureColour(
+                  new Color(setting.getColour())));
         }
         renderOrder[fs] = setting.getType();
         if (setting.hasOrder())
@@ -4406,7 +4623,7 @@ public class Jalview2XML
           fdi.setVisible(setting.getType());
         }
       }
-      Hashtable fgtable = new Hashtable();
+      Map<String, Boolean> fgtable = new Hashtable<String, Boolean>();
       for (int gs = 0; gs < jms.getFeatureSettings().getGroupCount(); gs++)
       {
         Group grp = jms.getFeatureSettings().getGroup(gs);
@@ -4449,7 +4666,7 @@ public class Jalview2XML
       }
     }
     af.setMenusFromViewport(af.viewport);
-
+    af.setTitle(view.getTitle());
     // TODO: we don't need to do this if the viewport is aready visible.
     /*
      * Add the AlignFrame to the desktop (it may be 'gathered' later), unless it
@@ -4474,7 +4691,7 @@ public class Jalview2XML
   }
 
   private ColourSchemeI constructAnnotationColour(
-          AnnotationColours viewAnnColour, AlignFrame af, Alignment al,
+          AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
           JalviewModelSequence jms, boolean checkGroupAnnColour)
   {
     boolean propagateAnnColour = false;
@@ -4598,7 +4815,7 @@ public class Jalview2XML
     return cs;
   }
 
-  private void reorderAutoannotation(AlignFrame af, Alignment al,
+  private void reorderAutoannotation(AlignFrame af, AlignmentI al,
           List<JvAnnotRow> autoAlan)
   {
     // copy over visualization settings for autocalculated annotation in the
@@ -4753,10 +4970,11 @@ public class Jalview2XML
     }
   }
 
-  private void recoverDatasetFor(SequenceSet vamsasSet, Alignment al,
+  private void recoverDatasetFor(SequenceSet vamsasSet, AlignmentI al,
           boolean ignoreUnrefed)
   {
-    jalview.datamodel.Alignment ds = getDatasetFor(vamsasSet.getDatasetId());
+    jalview.datamodel.AlignmentI ds = getDatasetFor(vamsasSet
+            .getDatasetId());
     Vector dseqs = null;
     if (ds == null)
     {
@@ -4766,7 +4984,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)
@@ -4793,18 +5011,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;
@@ -4900,21 +5129,50 @@ 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);
+        }
+      }
+    }
   }
 
   /*
    * TODO use AlignmentI here and in related methods - needs
    * AlignmentI.getDataset() changed to return AlignmentI instead of Alignment
    */
-  Hashtable<String, Alignment> datasetIds = null;
+  Hashtable<String, AlignmentI> datasetIds = null;
 
-  IdentityHashMap<Alignment, String> dataset2Ids = null;
+  IdentityHashMap<AlignmentI, String> dataset2Ids = null;
 
-  private Alignment getDatasetFor(String datasetId)
+  private AlignmentI getDatasetFor(String datasetId)
   {
     if (datasetIds == null)
     {
-      datasetIds = new Hashtable<String, Alignment>();
+      datasetIds = new Hashtable<String, AlignmentI>();
       return null;
     }
     if (datasetIds.containsKey(datasetId))
@@ -4924,11 +5182,11 @@ public class Jalview2XML
     return null;
   }
 
-  private void addDatasetRef(String datasetId, Alignment dataset)
+  private void addDatasetRef(String datasetId, AlignmentI dataset)
   {
     if (datasetIds == null)
     {
-      datasetIds = new Hashtable<String, Alignment>();
+      datasetIds = new Hashtable<String, AlignmentI>();
     }
     datasetIds.put(datasetId, dataset);
   }
@@ -4939,7 +5197,7 @@ public class Jalview2XML
    * @param dataset
    * @return
    */
-  private String getDatasetIdRef(Alignment dataset)
+  private String getDatasetIdRef(AlignmentI dataset)
   {
     if (dataset.getDataset() != null)
     {
@@ -4951,7 +5209,7 @@ public class Jalview2XML
       // make a new datasetId and record it
       if (dataset2Ids == null)
       {
-        dataset2Ids = new IdentityHashMap<Alignment, String>();
+        dataset2Ids = new IdentityHashMap<AlignmentI, String>();
       }
       else
       {
@@ -5019,7 +5277,7 @@ public class Jalview2XML
         }
         else
         {
-          frefedSequence.add(new Object[] { dsfor, jmap });
+          frefedSequence.add(newMappingRef(dsfor, jmap));
         }
       }
       else
@@ -5057,6 +5315,7 @@ public class Jalview2XML
           djs.setEnd(jmap.getMap().getToHighest());
           djs.setVamsasId(uniqueSetSuffix + sqid);
           jmap.setTo(djs);
+          incompleteSeqs.put(sqid, djs);
           seqRefIds.put(sqid, djs);
 
         }
index 61e20fa..f8a296f 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;
@@ -37,7 +38,6 @@ import jalview.binding.Viewport;
 import jalview.datamodel.PDBEntry;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.util.jarInputStreamProvider;
@@ -359,8 +359,7 @@ public class Jalview2XML_V1
 
         if (groups[i].getConsThreshold() != 0)
         {
-          jalview.analysis.Conservation c = new jalview.analysis.Conservation(
-                  "All", ResidueProperties.propHash, 3,
+          Conservation c = new Conservation("All", 3,
                   sg.getSequences(null), 0, sg.getWidth() - 1);
           c.calculate();
           c.verdict(false, 25);
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 8a0fe77..e584eb7 100644 (file)
@@ -114,7 +114,7 @@ public class OptsAndParamsPage
                 .wrapTooltip(
                         true,
                         ((desc == null || desc.trim().length() == 0) ? MessageManager
-                                .getString("label.opt_and_params_further_details ")
+                                .getString("label.opt_and_params_further_details")
                                 : desc)
                                 + "<br><img src=\"" + linkImageURL + "\"/>"));
         enabled.addMouseListener(this);
@@ -130,9 +130,9 @@ public class OptsAndParamsPage
       add(enabled, BorderLayout.NORTH);
       for (Object str : opt.getPossibleValues())
       {
-        val.addItem((String) str);
+        val.addItem(str);
       }
-      val.setSelectedItem((String) opt.getValue());
+      val.setSelectedItem(opt.getValue());
       if (opt.getPossibleValues().size() > 1)
       {
         setLayout(new GridLayout(1, 2));
@@ -145,6 +145,7 @@ public class OptsAndParamsPage
       setInitialValue();
     }
 
+    @Override
     public void actionPerformed(ActionEvent e)
     {
       if (e.getSource() != enabled)
@@ -206,36 +207,41 @@ public class OptsAndParamsPage
       return opt;
     }
 
+    @Override
     public void mouseClicked(MouseEvent e)
     {
-      if (javax.swing.SwingUtilities.isRightMouseButton(e))
+      if (e.isPopupTrigger()) // for Windows
       {
         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
       }
     }
 
+    @Override
     public void mouseEntered(MouseEvent e)
     {
       // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void mouseExited(MouseEvent e)
     {
       // TODO Auto-generated method stub
 
     }
 
+    @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)
@@ -351,7 +357,7 @@ public class OptsAndParamsPage
                                         + linkImageURL
                                         + "\"/>"
                                         + MessageManager
-                                                .getString("label.opt_and_params_further_detail")
+                                                .getString("label.opt_and_params_further_details")
                                         : "")));
       }
 
@@ -412,6 +418,7 @@ public class OptsAndParamsPage
         showDesc.addActionListener(new ActionListener()
         {
 
+          @Override
           public void actionPerformed(ActionEvent e)
           {
             descisvisible = !descisvisible;
@@ -451,6 +458,7 @@ public class OptsAndParamsPage
       validate();
     }
 
+    @Override
     public void actionPerformed(ActionEvent e)
     {
       if (adjusting)
@@ -526,45 +534,53 @@ public class OptsAndParamsPage
       lastVal = null;
     }
 
+    @Override
     public void mouseClicked(MouseEvent e)
     {
-      if (javax.swing.SwingUtilities.isRightMouseButton(e))
+      if (e.isPopupTrigger()) // for Windows
       {
         showUrlPopUp(this, finfo.toString(), e.getX(), e.getY());
       }
     }
 
+    @Override
     public void mouseEntered(MouseEvent e)
     {
       // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void mouseExited(MouseEvent e)
     {
       // TODO Auto-generated method stub
 
     }
 
+    @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
     public void mouseReleased(MouseEvent e)
     {
       // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void stateChanged(ChangeEvent e)
     {
       if (!adjusting)
       {
         valueField.setText(""
-                + ((integ) ? ("" + (int) slider.getValue())
-                        : ("" + (float) (slider.getValue() / 1000f))));
+                + ((integ) ? ("" + slider.getValue()) : ("" + slider
+                        .getValue() / 1000f)));
         checkIfModified();
       }
 
index de0dbe5..1c48690 100755 (executable)
@@ -295,14 +295,25 @@ public class OverviewPanel extends JPanel implements Runnable
     final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av
             .hasHiddenColumns();
     boolean hiddenRow = false;
+    // get hidden row and hidden column map once at beginning.
+    // clone featureRenderer settings to avoid race conditions... if state is
+    // updated just need to refresh again
     for (row = 0; row < sequencesHeight; row++)
     {
+      if (resizeAgain)
+      {
+        break;
+      }
       if ((int) (row * sampleRow) == lastrow)
       {
         // No need to recalculate the colours,
         // Just copy from the row above
         for (col = 0; col < width; col++)
         {
+          if (resizeAgain)
+          {
+            break;
+          }
           miniMe.setRGB(col, row, miniMe.getRGB(col, row - 1));
         }
         continue;
@@ -340,6 +351,10 @@ public class OverviewPanel extends JPanel implements Runnable
 
       for (col = 0; col < width; col++)
       {
+        if (resizeAgain)
+        {
+          break;
+        }
         if ((int) (col * sampleCol) == lastcol
                 && (int) (row * sampleRow) == lastrow)
         {
@@ -380,6 +395,10 @@ public class OverviewPanel extends JPanel implements Runnable
       renderer.updateFromAlignViewport(av);
       for (col = 0; col < width; col++)
       {
+        if (resizeAgain)
+        {
+          break;
+        }
         lastcol = (int) (col * sampleCol);
         {
           mg.translate(col, sequencesHeight);
@@ -395,13 +414,17 @@ public class OverviewPanel extends JPanel implements Runnable
 
     resizing = false;
 
-    setBoxPosition();
-
     if (resizeAgain)
     {
       resizeAgain = false;
       updateOverviewImage();
     }
+    else
+    {
+      lastMiniMe = miniMe;
+    }
+
+    setBoxPosition();
   }
 
   /**
@@ -456,6 +479,8 @@ public class OverviewPanel extends JPanel implements Runnable
     repaint();
   }
 
+  private BufferedImage lastMiniMe = null;
+
   /**
    * DOCUMENT ME!
    * 
@@ -465,19 +490,32 @@ public class OverviewPanel extends JPanel implements Runnable
   @Override
   public void paintComponent(Graphics g)
   {
-    if (resizing)
+    if (resizing || resizeAgain)
     {
-      g.setColor(Color.white);
+      if (lastMiniMe == null)
+      {
+        g.setColor(Color.white);
+        g.fillRect(0, 0, getWidth(), getHeight());
+      }
+      else
+      {
+        g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+      }
+      g.setColor(new Color(100, 100, 100, 25));
       g.fillRect(0, 0, getWidth(), getHeight());
     }
-    else if (miniMe != null)
+    else if (lastMiniMe != null)
     {
-      g.drawImage(miniMe, 0, 0, this);
+      g.drawImage(lastMiniMe, 0, 0, this);
+      if (lastMiniMe != miniMe)
+      {
+        g.setColor(new Color(100, 100, 100, 25));
+        g.fillRect(0, 0, getWidth(), getHeight());
+      }
     }
-
+    // TODO: render selected regions
     g.setColor(Color.red);
     g.drawRect(boxX, boxY, boxWidth, boxHeight);
     g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);
-
   }
 }
index 47add28..51d247d 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SeqCigar;
@@ -139,8 +140,8 @@ public class PCAPanel extends GPCAPanel implements Runnable,
       {
         // create an entry for this score matrix for use in PCA
         JCheckBoxMenuItem jm = new JCheckBoxMenuItem();
-        jm.setText(MessageManager
-                .getStringOrReturn("label.score_model", sm));
+        jm.setText(MessageManager.getStringOrReturn("label.score_model_",
+                sm));
         jm.setSelected(pcaModel.getScore_matrix().equals(sm));
         if ((ResidueProperties.scoreMatrices.get(sm).isDNA() && ResidueProperties.scoreMatrices
                 .get(sm).isProtein())
@@ -383,8 +384,8 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     {
       // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
 
-      Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
-      Alignment dataset = (av != null && av.getAlignment() != null) ? av
+      AlignmentI al = new Alignment((SequenceI[]) alAndColsel[0]);
+      AlignmentI dataset = (av != null && av.getAlignment() != null) ? av
               .getAlignment().getDataset() : null;
       if (dataset != null)
       {
diff --git a/src/jalview/gui/PDBSearchPanel.java b/src/jalview/gui/PDBSearchPanel.java
deleted file mode 100644 (file)
index 9b94c27..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-
-package jalview.gui;
-
-import jalview.jbgui.GPDBSearchPanel;
-import jalview.jbgui.PDBDocFieldPreferences;
-import jalview.util.MessageManager;
-import jalview.ws.dbsources.PDBRestClient;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
-import jalview.ws.uimodel.PDBRestRequest;
-import jalview.ws.uimodel.PDBRestResponse;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-
-import javax.swing.table.DefaultTableModel;
-
-@SuppressWarnings("serial")
-public class PDBSearchPanel extends GPDBSearchPanel
-{
-  private SequenceFetcher seqFetcher;
-
-  private IProgressIndicator progressIdicator;
-
-  private Collection<PDBDocField> wantedFields;
-
-  public PDBSearchPanel(SequenceFetcher seqFetcher)
-  {
-    this.seqFetcher = seqFetcher;
-    this.progressIdicator = (seqFetcher == null) ? null : seqFetcher
-            .getProgressIndicator();
-  }
-
-  /**
-   * Action performed when an input is detected on txt_search field.
-   */
-  @Override
-  public void txt_search_ActionPerformed()
-  {
-    new Thread()
-    {
-      @Override
-      public void run()
-      {
-        lbl_loading.setVisible(false);
-        errorWarning.setLength(0);
-        lbl_warning.setVisible(false);
-        btn_ok.setEnabled(false);
-        boolean allowEmptySequence = false;
-        mainFrame.setTitle(MessageManager
-                .getString("label.pdb_sequence_getcher"));
-        tbl_summary.setModel(new DefaultTableModel());
-        if (txt_search.getText().trim().length() > 0)
-        {
-          lbl_loading.setVisible(true);
-          long startTime = System.currentTimeMillis();
-
-          String searchTarget = ((PDBDocField) cmb_searchTarget
-                  .getSelectedItem()).getCode();
-
-          wantedFields = PDBDocFieldPreferences.getSearchSummaryFields();
-
-          String searchTerm = decodeSearchTerm(txt_search.getText(),
-                  searchTarget);
-
-          PDBRestRequest request = new PDBRestRequest();
-          request.setAllowEmptySeq(allowEmptySequence);
-          request.setResponseSize(100);
-          request.setFieldToSearchBy("(" + searchTarget + ":");
-          request.setSearchTerm(searchTerm + ")");
-          request.setWantedFields(wantedFields);
-          // System.out.println(">>>>>>>>>>>>>> " + request.getQuery());
-          PDBRestClient pdbRestCleint = new PDBRestClient();
-          PDBRestResponse resultList;
-          try
-          {
-            resultList = pdbRestCleint.executeRequest(request);
-          } catch (Exception e)
-          {
-            // e.printStackTrace();
-            errorWarning.append(e.getMessage());
-            checkForErrors();
-            return;
-          }
-
-          if (resultList.getSearchSummary() != null)
-          {
-            tbl_summary.setModel(PDBRestResponse.getTableModel(request,
-                    resultList.getSearchSummary()));
-          }
-
-          PDBRestResponse.configureTableColumn(tbl_summary, wantedFields);
-
-          long endTime = System.currentTimeMillis();
-          int resultSetCount = resultList.getNumberOfItemsFound();
-          String result = (resultSetCount > 1) ? MessageManager
-                  .getString("label.results") : MessageManager
-                  .getString("label.result");
-          mainFrame.setTitle(frameTitle + " - " + resultSetCount + " "
-                  + result + " (" + (endTime - startTime) + " milli secs)");
-          lbl_loading.setVisible(false);
-        }
-      }
-    }.start();
-  }
-
-  public static String decodeSearchTerm(String enteredText,
-          String targetField)
-  {
-    String foundSearchTerms = enteredText;
-    StringBuilder foundSearchTermsBuilder = new StringBuilder();
-    if (enteredText.contains(";"))
-    {
-      String[] searchTerms = enteredText.split(";");
-      for (String searchTerm : searchTerms)
-      {
-        if (searchTerm.contains(":"))
-        {
-          foundSearchTermsBuilder.append(targetField).append(":")
-                  .append(searchTerm.split(":")[0]).append(" OR ");
-        }
-        else
-        {
-          foundSearchTermsBuilder.append(targetField).append(":")
-                  .append(searchTerm).append(" OR ");
-        }
-      }
-      int endIndex = foundSearchTermsBuilder.lastIndexOf(" OR ");
-      foundSearchTerms = foundSearchTermsBuilder.toString();
-      if (foundSearchTerms.contains(" OR "))
-      {
-        foundSearchTerms = foundSearchTerms.substring(
-                targetField.length() + 1, endIndex);
-      }
-    }
-    else if (enteredText.contains(":"))
-    {
-      foundSearchTerms = foundSearchTerms.split(":")[0];
-    }
-    return foundSearchTerms;
-  }
-
-  @Override
-  public void btn_ok_ActionPerformed()
-  {
-    loadSelectedPDBSequencesToAlignment();
-  }
-
-  @Override
-  public void btn_back_ActionPerformed()
-  {
-    mainFrame.dispose();
-    new SequenceFetcher(progressIdicator);
-  }
-
-  @Override
-  public void btn_cancel_ActionPerformed()
-  {
-    mainFrame.dispose();
-  }
-
-  @Override
-  public void transferToSequenceFetcher(String ids)
-  {
-    // mainFrame.dispose();
-    seqFetcher.textArea.setText(ids);
-    Thread worker = new Thread(seqFetcher);
-    worker.start();
-  }
-
-  /**
-   * Add the discovered/selected sequences to a target alignment window
-   */
-  public void loadSelectedPDBSequencesToAlignment()
-  {
-    // mainFrame.dispose();
-    disableActionButtons();
-    StringBuilder selectedIds = new StringBuilder();
-    HashSet<String> selectedIdsSet = new HashSet<String>();
-    int pdbIdCol = PDBRestClient.getPDBIdColumIndex(wantedFields, false);
-    int[] selectedRows = tbl_summary.getSelectedRows();
-    for (int summaryRow : selectedRows)
-    {
-      String pdbIdStr = tbl_summary.getValueAt(summaryRow, pdbIdCol)
-              .toString();
-      String searchTerm = txt_search.getText();
-      selectedIdsSet.add(getPDBIdwithSpecifiedChain(pdbIdStr, searchTerm));
-    }
-
-    for (String selectedId : selectedIdsSet)
-    {
-      selectedIds.append(selectedId).append(";");
-    }
-
-    String ids = selectedIds.toString();
-    // System.out.println(">>>>>>>>>>>>>>>> selected Ids: " + ids);
-    seqFetcher.textArea.setText(ids);
-    Thread worker = new Thread(seqFetcher);
-    worker.start();
-    delayAndEnableActionButtons();
-
-  }
-
-  private void disableActionButtons()
-  {
-    btn_ok.setEnabled(false);
-    btn_back.setEnabled(false);
-    btn_cancel.setEnabled(false);
-  }
-
-  private void delayAndEnableActionButtons()
-  {
-    new Thread()
-    {
-      @Override
-      public void run()
-      {
-        try
-        {
-          Thread.sleep(1500);
-        } catch (InterruptedException e)
-        {
-          e.printStackTrace();
-        }
-        btn_ok.setEnabled(true);
-        btn_back.setEnabled(true);
-        btn_cancel.setEnabled(true);
-      }
-    }.start();
-  }
-
-  public static String getPDBIdwithSpecifiedChain(String pdbId,
-          String searchTerm)
-  {
-    String pdbIdWithChainCode = "";
-    if (searchTerm.contains(";"))
-    {
-      String[] foundTerms = searchTerm.split(";");
-      for (String foundTerm : foundTerms)
-      {
-        if (foundTerm.contains(pdbId))
-        {
-          pdbIdWithChainCode = foundTerm;
-        }
-      }
-    }
-    else if (searchTerm.contains(pdbId))
-    {
-      pdbIdWithChainCode = searchTerm;
-    }
-    else
-    {
-      pdbIdWithChainCode = pdbId;
-    }
-    return pdbIdWithChainCode;
-  }
-
-  /**
-   * Populates search target combo-box options
-   */
-  @Override
-  public void populateCmbSearchTargetOptions()
-  {
-    List<PDBDocField> searchableTargets = new ArrayList<PDBDocField>();
-    searchableTargets.add(PDBDocField.PDB_ID);
-    searchableTargets.add(PDBDocField.PFAM_ACCESSION);
-    searchableTargets.add(PDBDocField.MOLECULE_TYPE);
-    searchableTargets.add(PDBDocField.MOLECULE_NAME);
-    searchableTargets.add(PDBDocField.UNIPROT_ACCESSION);
-    searchableTargets.add(PDBDocField.GENE_NAME);
-    searchableTargets.add(PDBDocField.GENUS);
-    searchableTargets.add(PDBDocField.ALL);
-
-    Collections.sort(searchableTargets, new Comparator<PDBDocField>()
-    {
-      @Override
-      public int compare(PDBDocField o1, PDBDocField o2)
-      {
-        return o1.getName().compareTo(o2.getName());
-      }
-    });
-
-    for (PDBDocField searchTarget : searchableTargets)
-    {
-      cmb_searchTarget.addItem(searchTarget);
-    }
-  }
-
-  public void checkForErrors()
-  {
-    lbl_warning.setVisible(false);
-    if (errorWarning.length() > 0)
-    {
-      lbl_loading.setVisible(false);
-      lbl_warning.setToolTipText(JvSwingUtils.wrapTooltip(true,
-              errorWarning.toString()));
-      lbl_warning.setVisible(true);
-    }
-  }
-}
index 008de18..3b79fdc 100644 (file)
@@ -24,6 +24,7 @@ import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentAnnotationUtils;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.Conservation;
+import jalview.bin.Cache;
 import jalview.commands.ChangeCaseCommand;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
@@ -48,12 +49,12 @@ 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;
@@ -62,6 +63,7 @@ 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.Collections;
 import java.util.Hashtable;
@@ -88,10 +90,6 @@ import javax.swing.JRadioButtonMenuItem;
  */
 public class PopupMenu extends JPopupMenu
 {
-  private static final String ALL_ANNOTATIONS = "All";
-
-  private static final String COMMA = ",";
-
   JMenu groupMenu = new JMenu();
 
   JMenuItem groupName = new JMenuItem();
@@ -216,7 +214,7 @@ public class PopupMenu extends JPopupMenu
    * @param seq
    *          DOCUMENT ME!
    */
-  public PopupMenu(final AlignmentPanel ap, Sequence seq, Vector links)
+  public PopupMenu(final AlignmentPanel ap, Sequence seq, List<String> links)
   {
     this(ap, seq, links, null);
   }
@@ -229,7 +227,7 @@ public class PopupMenu extends JPopupMenu
    * @param groupLinks
    */
   public PopupMenu(final AlignmentPanel ap, final SequenceI seq,
-          Vector links, Vector groupLinks)
+          List<String> links, List<String> groupLinks)
   {
     // /////////////////////////////////////////////////////////
     // If this is activated from the sequence panel, the user may want to
@@ -477,8 +475,6 @@ public class PopupMenu extends JPopupMenu
 
     if (sg != null && sg.getSize() > 0)
     {
-      groupName.setText(MessageManager.formatMessage("label.name_param",
-              new Object[] { sg.getName() }));
       groupName.setText(MessageManager
               .getString("label.edit_name_and_description_current_group"));
 
@@ -608,122 +604,139 @@ public class PopupMenu extends JPopupMenu
 
     if (links != null && links.size() > 0)
     {
+      addFeatureLinks(seq, links);
+    }
+  }
 
-      JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
-      Vector linkset = new Vector();
-      for (int i = 0; i < links.size(); i++)
+  /**
+   * 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)
+  {
+    JMenu linkMenu = new JMenu(MessageManager.getString("action.link"));
+    List<String> linkset = new ArrayList<String>();
+    for (String link : links)
+    {
+      UrlLink urlLink = null;
+      try
       {
-        String link = links.elementAt(i).toString();
-        UrlLink urlLink = null;
-        try
-        {
-          urlLink = new UrlLink(link);
-        } catch (Exception foo)
-        {
-          jalview.bin.Cache.log.error("Exception for URLLink '" + link
-                  + "'", foo);
-          continue;
-        }
-        ;
-        if (!urlLink.isValid())
-        {
-          jalview.bin.Cache.log.error(urlLink.getInvalidMessage());
-          continue;
-        }
-        final String label = urlLink.getLabel();
-        if (seq != null && urlLink.isDynamic())
-        {
+        urlLink = new UrlLink(link);
+      } catch (Exception foo)
+      {
+        Cache.log.error("Exception for URLLink '" + link + "'", foo);
+        continue;
+      }
+      ;
+      if (!urlLink.isValid())
+      {
+        Cache.log.error(urlLink.getInvalidMessage());
+        continue;
+      }
+      final String label = urlLink.getLabel();
 
-          // collect matching db-refs
-          DBRefEntry[] dbr = jalview.util.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;
-          }
+      // 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)
-                {
-                  if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-                  {
-                    linkset.addElement(urls[u] + "|" + urls[u + 1]);
-                    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)
-              {
-                if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-                {
-                  linkset.addElement(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)
+      if (seq != null && urlLink.usesSeqId()) // link is ID
+      {
+        // collect matching db-refs
+        DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
+                new String[] { urlLink.getTarget() });
+
+        // if there are any dbrefs which match up with the link
+        if (dbr != null)
+        {
+          for (int r = 0; r < dbr.length; r++)
           {
-            // create link for this URL from description where regex matches
-            String[] urls = urlLink.makeUrls(descr, true);
-            if (urls != null)
+            if (id != null && dbr[r].getAccessionId().equals(id))
             {
-              for (int u = 0; u < urls.length; u += 2)
-              {
-                if (!linkset.contains(urls[u] + "|" + urls[u + 1]))
-                {
-                  linkset.addElement(urls[u] + "|" + urls[u + 1]);
-                  addshowLink(linkMenu, label, urls[u + 1]);
-                }
-              }
+              // suppress duplicate link creation for the bare sequence ID
+              // string with this link
+              id = null;
             }
+            // create Bare ID link for this URL
+            createBareURLLink(urlLink, dbr[r].getAccessionId(), linkset,
+                    linkMenu, label, true);
           }
         }
-        else
+
+        // Create urls from description but only for URL links which are regex
+        // links
+        if (descr != null && urlLink.getRegexReplace() != null)
         {
-          if (!linkset.contains(label + "|" + urlLink.getUrl_prefix()))
-          {
-            linkset.addElement(label + "|" + urlLink.getUrl_prefix());
-            // Add a non-dynamic link
-            addshowLink(linkMenu, label, urlLink.getUrl_prefix());
-          }
+          // create link for this URL from description where regex matches
+          createBareURLLink(urlLink, descr, linkset, linkMenu, label, false);
         }
+
       }
-      if (sequence != null)
+      else if (seq != null && !urlLink.usesSeqId()) // link is name
       {
-        sequenceMenu.add(linkMenu);
+        if (id != null)
+        {
+          // create Bare ID link for this URL
+          createBareURLLink(urlLink, id, linkset, linkMenu, label, false);
+        }
+        // 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
+          createBareURLLink(urlLink, descr, linkset, linkMenu, label, false);
+        }
       }
       else
       {
-        add(linkMenu);
+        if (!linkset.contains(label + "|" + urlLink.getUrl_prefix()))
+        {
+          linkset.add(label + "|" + urlLink.getUrl_prefix());
+          // Add a non-dynamic link
+          addshowLink(linkMenu, label, urlLink.getUrl_prefix());
+        }
+      }
+
+    }
+    if (sequence != null)
+    {
+      sequenceMenu.add(linkMenu);
+    }
+    else
+    {
+      add(linkMenu);
+    }
+  }
+
+  /*
+   * Create a bare URL Link
+   */
+  private void createBareURLLink(UrlLink urlLink, String id,
+          List<String> linkset, JMenu linkMenu, String label,
+          Boolean addSepToLabel)
+  {
+    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]);
+          if (addSepToLabel)
+          {
+            addshowLink(linkMenu, label + "|" + urls[u], urls[u + 1]);
+          }
+          else
+          {
+            addshowLink(linkMenu, label, urls[u + 1]);
+          }
+        }
       }
     }
   }
@@ -749,7 +762,8 @@ public class PopupMenu extends JPopupMenu
     showMenu.removeAll();
     hideMenu.removeAll();
 
-    final List<String> all = Arrays.asList(ALL_ANNOTATIONS);
+    final List<String> all = Arrays.asList(new String[] { MessageManager
+            .getString("label.all") });
     addAnnotationTypeToShowHide(showMenu, forSequences, "", all, true, true);
     addAnnotationTypeToShowHide(hideMenu, forSequences, "", all, true,
             false);
@@ -855,7 +869,7 @@ public class PopupMenu extends JPopupMenu
     showOrHideMenu.add(item);
   }
 
-  private void buildGroupURLMenu(SequenceGroup sg, Vector groupLinks)
+  private void buildGroupURLMenu(SequenceGroup sg, List<String> groupLinks)
   {
 
     // TODO: usability: thread off the generation of group url content so root
@@ -864,19 +878,15 @@ public class PopupMenu extends JPopupMenu
     // ID/regex match URLs
     groupLinksMenu = new JMenu(
             MessageManager.getString("action.group_link"));
+    // three types of url that might be created.
     JMenu[] linkMenus = new JMenu[] { null,
         new JMenu(MessageManager.getString("action.ids")),
         new JMenu(MessageManager.getString("action.sequences")),
-        new JMenu(MessageManager.getString("action.ids_sequences")) }; // three
-                                                                       // types
-                                                                       // of url
-                                                                       // that
-                                                                       // might
-                                                                       // be
-    // created.
+        new JMenu(MessageManager.getString("action.ids_sequences")) };
+
     SequenceI[] seqs = ap.av.getSelectionAsNewSequence();
     String[][] idandseqs = GroupUrlLink.formStrings(seqs);
-    Hashtable commonDbrefs = new Hashtable();
+    Hashtable<String, Object[]> commonDbrefs = new Hashtable<String, Object[]>();
     for (int sq = 0; sq < seqs.length; sq++)
     {
 
@@ -896,7 +906,7 @@ public class PopupMenu extends JPopupMenu
         for (int d = 0; d < dbr.length; d++)
         {
           String src = dbr[d].getSource(); // jalview.util.DBRefUtils.getCanonicalName(dbr[d].getSource()).toUpperCase();
-          Object[] sarray = (Object[]) commonDbrefs.get(src);
+          Object[] sarray = commonDbrefs.get(src);
           if (sarray == null)
           {
             sarray = new Object[2];
@@ -921,30 +931,28 @@ public class PopupMenu extends JPopupMenu
     // now create group links for all distinct ID/sequence sets.
     boolean addMenu = false; // indicates if there are any group links to give
                              // to user
-    for (int i = 0; i < groupLinks.size(); i++)
+    for (String link : groupLinks)
     {
-      String link = groupLinks.elementAt(i).toString();
       GroupUrlLink urlLink = null;
       try
       {
         urlLink = new GroupUrlLink(link);
       } catch (Exception foo)
       {
-        jalview.bin.Cache.log.error("Exception for GroupURLLink '" + link
-                + "'", foo);
+        Cache.log.error("Exception for GroupURLLink '" + link + "'", foo);
         continue;
       }
       ;
       if (!urlLink.isValid())
       {
-        jalview.bin.Cache.log.error(urlLink.getInvalidMessage());
+        Cache.log.error(urlLink.getInvalidMessage());
         continue;
       }
       final String label = urlLink.getLabel();
       boolean usingNames = false;
       // Now see which parts of the group apply for this URL
       String ltarget = urlLink.getTarget(); // jalview.util.DBRefUtils.getCanonicalName(urlLink.getTarget());
-      Object[] idset = (Object[]) commonDbrefs.get(ltarget.toUpperCase());
+      Object[] idset = commonDbrefs.get(ltarget.toUpperCase());
       String[] seqstr, ids; // input to makeUrl
       if (idset != null)
       {
@@ -1062,7 +1070,7 @@ public class PopupMenu extends JPopupMenu
             new Object[] { urlgenerator.getUrl_prefix(),
                 urlgenerator.getNumberInvolved(urlstub) }));
     // TODO: put in info about what is being sent.
-    item.addActionListener(new java.awt.event.ActionListener()
+    item.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
@@ -1076,7 +1084,7 @@ public class PopupMenu extends JPopupMenu
             try
             {
               showLink(urlgenerator.constructFrom(urlstub));
-            } catch (UrlStringTooLongException e)
+            } catch (UrlStringTooLongException e2)
             {
             }
           }
@@ -1096,7 +1104,6 @@ public class PopupMenu extends JPopupMenu
    */
   private void jbInit() throws Exception
   {
-    groupMenu.setText(MessageManager.getString("label.group"));
     groupMenu.setText(MessageManager.getString("label.selection"));
     groupName.setText(MessageManager.getString("label.name"));
     groupName.addActionListener(new java.awt.event.ActionListener()
@@ -2040,9 +2047,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", 3, sg.getSequences(ap.av
+              .getHiddenRepSequences()), sg.getStartRes(),
               sg.getEndRes() + 1);
 
       c.calculate();
@@ -2267,28 +2273,7 @@ public class PopupMenu extends JPopupMenu
 
   void hideSequences(boolean representGroup)
   {
-    SequenceGroup sg = ap.av.getSelectionGroup();
-    if (sg == null || sg.getSize() < 1)
-    {
-      ap.av.hideSequence(new SequenceI[] { sequence });
-      return;
-    }
-
-    ap.av.setSelectionGroup(null);
-
-    if (representGroup)
-    {
-      ap.av.hideRepSequences(sequence, sg);
-
-      return;
-    }
-
-    int gsize = sg.getSize();
-    SequenceI[] hseqs = sg.getSequences().toArray(new SequenceI[gsize]);
-
-    ap.av.hideSequence(hseqs);
-    // refresh(); TODO: ? needed ?
-    ap.av.sendSelection();
+    ap.av.hideSequences(sequence, representGroup);
   }
 
   public void copy_actionPerformed()
@@ -2360,45 +2345,6 @@ public class PopupMenu extends JPopupMenu
             ap, true));
   }
 
-  public void enterPDB_actionPerformed()
-  {
-    String id = JOptionPane.showInternalInputDialog(Desktop.desktop,
-            MessageManager.getString("label.enter_pdb_id"),
-            MessageManager.getString("label.enter_pdb_id"),
-            JOptionPane.QUESTION_MESSAGE);
-
-    if (id != null && id.length() > 0)
-    {
-      PDBEntry entry = new PDBEntry();
-      entry.setId(id.toUpperCase());
-      sequence.getDatasetSequence().addPDBId(entry);
-    }
-  }
-
-  public void discoverPDB_actionPerformed()
-  {
-
-    final SequenceI[] sequences = ((ap.av.getSelectionGroup() == null) ? new SequenceI[]
-    { sequence }
-            : ap.av.getSequenceSelection());
-    Thread discpdb = new Thread(new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        boolean isNuclueotide = ap.alignFrame.getViewport().getAlignment()
-                .isNucleotide();
-
-        new jalview.ws.DBRefFetcher(sequences, ap.alignFrame, null,
-                ap.alignFrame.featureSettings, isNuclueotide)
-                .fetchDBRefs(false);
-
-      }
-
-    });
-    discpdb.start();
-  }
-
   public void sequenceFeature_actionPerformed()
   {
     SequenceGroup sg = ap.av.getSelectionGroup();
index 8b33deb..b57b951 100755 (executable)
  */
 package jalview.gui;
 
+import static jalview.util.UrlConstants.EMBLEBI_STRING;
+import static jalview.util.UrlConstants.OLD_EMBLEBI_STRING;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+import static jalview.util.UrlConstants.SRS_STRING;
+
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
 import jalview.gui.Help.HelpId;
@@ -30,6 +36,7 @@ import jalview.jbgui.GPreferences;
 import jalview.jbgui.GSequenceLink;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.ws.sifts.SiftsSettings;
 
 import java.awt.BorderLayout;
@@ -40,7 +47,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.io.File;
-import java.util.Collection;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.StringTokenizer;
 import java.util.Vector;
@@ -88,8 +95,6 @@ public class Preferences extends GPreferences
 
   public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
 
-  public static final String HIDE_INTRONS = "HIDE_INTRONS";
-
   private static final int MIN_FONT_SIZE = 1;
 
   private static final int MAX_FONT_SIZE = 30;
@@ -98,7 +103,7 @@ public class Preferences extends GPreferences
    * Holds name and link separated with | character. Sequence ID must be
    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
    */
-  public static Vector sequenceURLLinks;
+  public static Vector<String> sequenceURLLinks;
 
   /**
    * Holds name and link separated with | character. Sequence IDS and Sequences
@@ -108,14 +113,11 @@ public class Preferences extends GPreferences
    * (TODO: proper escape for using | to separate ids or sequences
    */
 
-  public static Vector groupURLLinks;
+  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$");
-    sequenceURLLinks = new Vector();
+    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("$" + SEQUENCE_ID + "$");
+        if (rxstart == -1)
+        {
+          rxstart = url.indexOf("$" + SEQUENCE_NAME + "$");
+        }
         while (rxstart == -1 && url.indexOf("/=$") == -1)
         {
           url = url + "|" + st.nextToken();
@@ -138,14 +144,16 @@ 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);
+      }
+      // upgrade old EMBL-EBI link
+      int emblPos = sequenceURLLinks.indexOf(OLD_EMBLEBI_STRING);
+      if (emblPos > -1)
+      {
+        sequenceURLLinks.setElementAt(EMBLEBI_STRING, emblPos);
       }
     }
 
@@ -154,10 +162,10 @@ public class Preferences extends GPreferences
      * .properties file as '|' separated strings
      */
 
-    groupURLLinks = new Vector();
+    groupURLLinks = new ArrayList<String>();
   }
 
-  Vector nameLinks, urlLinks;
+  Vector<String> nameLinks, urlLinks;
 
   JInternalFrame frame;
 
@@ -165,6 +173,16 @@ public class Preferences extends GPreferences
 
   private WsPreferences wsPrefs;
 
+  private OptionsParam promptEachTimeOpt = new OptionsParam(
+          MessageManager.getString("label.prompt_each_time"),
+          "Prompt each time");
+
+  private OptionsParam lineArtOpt = new OptionsParam(
+          MessageManager.getString("label.lineart"), "Lineart");
+
+  private OptionsParam textOpt = new OptionsParam(
+          MessageManager.getString("action.text"), "Text");
+
   /**
    * Creates a new Preferences object.
    */
@@ -177,11 +195,12 @@ public class Preferences extends GPreferences
     dasTab.add(dasSource, BorderLayout.CENTER);
     wsPrefs = new WsPreferences();
     wsTab.add(wsPrefs, BorderLayout.CENTER);
-    int width = 500, height = 470;
-    if (new jalview.util.Platform().isAMac())
+    int width = 500, height = 450;
+    new jalview.util.Platform();
+    if (Platform.isAMac())
     {
       width = 570;
-      height = 500;
+      height = 480;
     }
 
     Desktop.addInternalFrame(frame,
@@ -243,7 +262,6 @@ public class Preferences extends GPreferences
     idItalics.setSelected(Cache.getDefault("ID_ITALICS", true));
 
     wrap.setSelected(Cache.getDefault("WRAP_ALIGNMENT", false));
-    hideIntrons.setSelected(Cache.getDefault(HIDE_INTRONS, true));
 
     gapSymbolCB.addItem("-");
     gapSymbolCB.addItem(".");
@@ -332,8 +350,8 @@ public class Preferences extends GPreferences
     /*
      * Set Connections tab defaults
      */
-    nameLinks = new Vector();
-    urlLinks = new Vector();
+    nameLinks = new Vector<String>();
+    urlLinks = new Vector<String>();
     for (int i = 0; i < sequenceURLLinks.size(); i++)
     {
       String link = sequenceURLLinks.elementAt(i).toString();
@@ -360,12 +378,23 @@ public class Preferences extends GPreferences
     /*
      * Set Output tab defaults
      */
-    epsRendering
-            .addItem(MessageManager.getString("label.prompt_each_time"));
-    epsRendering.addItem(MessageManager.getString("label.lineart"));
-    epsRendering.addItem(MessageManager.getString("action.text"));
-    epsRendering.setSelectedItem(Cache.getDefault("EPS_RENDERING",
-            "Prompt each time"));
+    epsRendering.addItem(promptEachTimeOpt);
+    epsRendering.addItem(lineArtOpt);
+    epsRendering.addItem(textOpt);
+    String defaultEPS = Cache.getDefault("EPS_RENDERING",
+            "Prompt each time");
+    if (defaultEPS.equalsIgnoreCase("Text"))
+    {
+      epsRendering.setSelectedItem(textOpt);
+    }
+    else if (defaultEPS.equalsIgnoreCase("Lineart"))
+    {
+      epsRendering.setSelectedItem(lineArtOpt);
+    }
+    else
+    {
+      epsRendering.setSelectedItem(promptEachTimeOpt);
+    }
     autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false));
     userIdWidth.setEnabled(!autoIdWidth.isSelected());
     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
@@ -461,8 +490,6 @@ public class Preferences extends GPreferences
 
     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT",
             Boolean.toString(wrap.isSelected()));
-    Cache.applicationProperties.setProperty(HIDE_INTRONS,
-            Boolean.toString(hideIntrons.isSelected()));
 
     Cache.applicationProperties.setProperty("STARTUP_FILE",
             startupFileTextfield.getText());
@@ -518,15 +545,8 @@ public class Preferences extends GPreferences
     /*
      * Save Output settings
      */
-    if (epsRendering.getSelectedItem().equals("Prompt each time"))
-    {
-      Cache.applicationProperties.remove("EPS_RENDERING");
-    }
-    else
-    {
-      Cache.applicationProperties.setProperty("EPS_RENDERING", epsRendering
-              .getSelectedItem().toString());
-    }
+    Cache.applicationProperties.setProperty("EPS_RENDERING",
+            ((OptionsParam) epsRendering.getSelectedItem()).getCode());
 
     /*
      * Save Connections settings
@@ -538,7 +558,7 @@ public class Preferences extends GPreferences
     if (nameLinks.size() > 0)
     {
       StringBuffer links = new StringBuffer();
-      sequenceURLLinks = new Vector();
+      sequenceURLLinks = new Vector<String>();
       for (int i = 0; i < nameLinks.size(); i++)
       {
         sequenceURLLinks.addElement(nameLinks.elementAt(i) + "|"
@@ -854,7 +874,7 @@ public class Preferences extends GPreferences
     super.showunconserved_actionPerformed(e);
   }
 
-  public static Collection getGroupURLLinks()
+  public static List<String> getGroupURLLinks()
   {
     return groupURLLinks;
   }
@@ -986,4 +1006,58 @@ public class Preferences extends GPreferences
     }
   }
 
+  public class OptionsParam
+  {
+    private String name;
+
+    private String code;
+
+    public OptionsParam(String name, String code)
+    {
+      this.name = name;
+      this.code = code;
+    }
+
+    public String getName()
+    {
+      return name;
+    }
+
+    public void setName(String name)
+    {
+      this.name = name;
+    }
+
+    public String getCode()
+    {
+      return code;
+    }
+
+    public void setCode(String code)
+    {
+      this.code = code;
+    }
+
+    @Override
+    public String toString()
+    {
+      return name;
+    }
+
+    @Override
+    public boolean equals(Object that)
+    {
+      if (!(that instanceof OptionsParam))
+      {
+        return false;
+      }
+      return this.code.equalsIgnoreCase(((OptionsParam) that).code);
+    }
+
+    @Override
+    public int hashCode()
+    {
+      return name.hashCode() + code.hashCode();
+    }
+  }
 }
index 7fb0593..a9d2690 100755 (executable)
@@ -172,7 +172,7 @@ public class RedundancyPanel extends GSliderPanel implements Runnable
     progress = null;
 
     label.setText(MessageManager
-            .getString("label.enter_redundancy_thereshold"));
+            .getString("label.enter_redundancy_threshold"));
     slider.setVisible(true);
     applyButton.setEnabled(true);
     valueField.setVisible(true);
index 41de58f..0aa2459 100755 (executable)
@@ -23,7 +23,10 @@ package jalview.gui;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.renderer.ScaleRenderer;
+import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 
 import java.awt.Color;
 import java.awt.FontMetrics;
@@ -35,6 +38,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.List;
 
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
@@ -43,17 +47,14 @@ import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
 /**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
+ * The panel containing the sequence ruler (when not in wrapped mode), and
+ * supports a range of mouse operations to select, hide or reveal columns.
  */
 public class ScalePanel extends JPanel implements MouseMotionListener,
         MouseListener
 {
   protected int offy = 4;
 
-  /** DOCUMENT ME!! */
   public int width;
 
   protected AlignViewport av;
@@ -62,13 +63,26 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
   boolean stretchingGroup = false;
 
-  int min; // used by mouseDragged to see if user
+  /*
+   * min, max hold the extent of a mouse drag action
+   */
+  int min;
 
-  int max; // used by mouseDragged to see if user
+  int max;
 
   boolean mouseDragging = false;
 
-  // wants to delete columns
+  /*
+   * holds a hidden column range when the mouse is over an adjacent column
+   */
+  int[] reveal;
+
+  /**
+   * Constructor
+   * 
+   * @param av
+   * @param ap
+   */
   public ScalePanel(AlignViewport av, AlignmentPanel ap)
   {
     this.av = av;
@@ -107,10 +121,19 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     min = res;
     max = res;
 
-    if (SwingUtilities.isRightMouseButton(evt))
+    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);
@@ -209,7 +232,12 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
    */
   protected void leftMouseButtonPressed(MouseEvent evt, final int res)
   {
-    if (!evt.isControlDown() && !evt.isShiftDown())
+    /*
+     * 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();
     }
@@ -268,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;
     }
 
@@ -393,6 +427,8 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
   @Override
   public void mouseMoved(MouseEvent evt)
   {
+    this.setToolTipText(null);
+    reveal = null;
     if (!av.hasHiddenColumns())
     {
       return;
@@ -402,7 +438,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
 
     res = av.getColumnSelection().adjustForHiddenColumns(res);
 
-    reveal = null;
     if (av.getColumnSelection().getHiddenColumns() != null)
     {
       for (int[] region : av.getColumnSelection().getHiddenColumns())
@@ -415,17 +450,11 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
                   .getString("label.reveal_hidden_columns"));
           break;
         }
-        else
-        {
-          this.setToolTipText(null);
-        }
       }
     }
     repaint();
   }
 
-  int[] reveal;
-
   /**
    * DOCUMENT ME!
    * 
@@ -460,7 +489,6 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
     ColumnSelection cs = av.getColumnSelection();
     int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
 
-    int s;
     if (cs != null)
     {
       gg.setColor(new Color(220, 0, 0));
@@ -489,50 +517,16 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
         }
       }
     }
-    // Draw the scale numbers
-    gg.setColor(Color.black);
 
-    int scalestartx = (startx / 10) * 10;
     int widthx = 1 + endx - startx;
 
     FontMetrics fm = gg.getFontMetrics(av.getFont());
-    int y = avCharHeight - fm.getDescent();
-
-    if ((scalestartx % 10) == 0)
-    {
-      scalestartx += 5;
-    }
-
-    String string;
-    int maxX = 0;
-
-    for (int i = scalestartx; i < endx; i += 5)
-    {
-      if ((i % 10) == 0)
-      {
-        string = String.valueOf(av.getColumnSelection()
-                .adjustForHiddenColumns(i));
-        if ((i - startx - 1) * avCharWidth > maxX)
-        {
-          gg.drawString(string, (i - startx - 1) * avCharWidth, y);
-          maxX = (i - startx + 1) * avCharWidth + fm.stringWidth(string);
-        }
-
-        gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2),
-                y + 2,
-                ((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
-                        + (fm.getDescent() * 2));
-      }
-      else
-      {
-        gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
-                + fm.getDescent(), ((i - startx - 1) * avCharWidth)
-                + (avCharWidth / 2), y + (fm.getDescent() * 2));
-      }
-    }
-
+    int y = avCharHeight;
+    int yOf = fm.getDescent();
+    y -= yOf;
     if (av.hasHiddenColumns())
     {
+      // draw any hidden column markers
       gg.setColor(Color.blue);
       int res;
       if (av.getShowHiddenMarkers()
@@ -549,20 +543,44 @@ public class ScalePanel extends JPanel implements MouseMotionListener,
             continue;
           }
 
-          gg.fillPolygon(new int[] { res * avCharWidth - avCharHeight / 4,
-              res * avCharWidth + avCharHeight / 4, res * avCharWidth },
-                  new int[] { y - avCharHeight / 2, y - avCharHeight / 2,
-                      y + 8 }, 3);
-
+          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);
         }
       }
+    }
+    // Draw the scale numbers
+    gg.setColor(Color.black);
+
+    int maxX = 0;
+    List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, startx,
+            endx);
 
-      if (reveal != null && reveal[0] > startx && reveal[0] < endx)
+    for (ScaleMark mark : marks)
+    {
+      boolean major = mark.major;
+      int mpos = mark.column; // (i - startx - 1)
+      String mstring = mark.text;
+      if (mstring != null)
       {
-        gg.drawString(MessageManager.getString("label.reveal_columns"),
-                reveal[0] * avCharWidth, 0);
+        if (mpos * avCharWidth > maxX)
+        {
+          gg.drawString(mstring, mpos * avCharWidth, y);
+          maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring);
+        }
+      }
+      if (major)
+      {
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
+      }
+      else
+      {
+        gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf,
+                (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
       }
     }
-
   }
+
 }
index 0f24b4b..760ece0 100755 (executable)
@@ -24,6 +24,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.renderer.ScaleRenderer;
+import jalview.renderer.ScaleRenderer.ScaleMark;
 
 import java.awt.BasicStroke;
 import java.awt.BorderLayout;
@@ -122,24 +124,26 @@ public class SeqCanvas extends JComponent
   private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
   {
     updateViewport();
-    int scalestartx = startx - (startx % 10) + 10;
-
-    g.setColor(Color.black);
-    // NORTH SCALE
-    for (int i = scalestartx; i < endx; i += 10)
+    for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx,
+            endx))
     {
-      int value = i;
-      if (av.hasHiddenColumns())
+      int mpos = mark.column; // (i - startx - 1)
+      if (mpos < 0)
       {
-        value = av.getColumnSelection().adjustForHiddenColumns(value);
+        continue;
       }
+      String mstring = mark.text;
 
-      g.drawString(String.valueOf(value), (i - startx - 1) * charWidth,
-              ypos - (charHeight / 2));
-
-      g.drawLine(((i - startx - 1) * charWidth) + (charWidth / 2),
-              (ypos + 2) - (charHeight / 2), ((i - startx - 1) * charWidth)
-                      + (charWidth / 2), ypos - 2);
+      if (mark.major)
+      {
+        if (mstring != null)
+        {
+          g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
+        }
+        g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
+                - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
+                ypos - 2);
+      }
     }
   }
 
index e94e94f..885aab2 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.gui;
 
 import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
@@ -42,6 +43,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;
@@ -54,11 +56,12 @@ import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Vector;
 
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
 import javax.swing.ToolTipManager;
 
 /**
@@ -509,6 +512,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   void insertNucAtCursor(boolean group, String nuc)
   {
+    // TODO not called - delete?
     groupEditing = group;
     startseq = seqCanvas.cursorY;
     lastres = seqCanvas.cursorX;
@@ -579,6 +583,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);
@@ -599,19 +610,20 @@ public class SeqPanel extends JPanel implements MouseListener,
   {
     lastMousePress = evt.getPoint();
 
-    if (javax.swing.SwingUtilities.isMiddleMouseButton(evt))
+    if (SwingUtilities.isMiddleMouseButton(evt))
     {
       mouseWheelPressed = true;
       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
     {
@@ -822,6 +834,21 @@ public class SeqPanel extends JPanel implements MouseListener,
   String lastTooltip;
 
   /**
+   * set when the current UI interaction has resulted in a change that requires
+   * overview shading to be recalculated. this could be changed to something
+   * more expressive that indicates what actually has changed, so selective
+   * redraws can be applied
+   */
+  private boolean needOverviewUpdate = false; // 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
+
+  /**
    * Set status message in alignment panel
    * 
    * @param sequence
@@ -840,7 +867,8 @@ public class SeqPanel extends JPanel implements MouseListener,
      * Sequence number (if known), and sequence name.
      */
     String seqno = seq == -1 ? "" : " " + (seq + 1);
-    text.append("Sequence" + seqno + " ID: " + sequence.getName());
+    text.append("Sequence").append(seqno).append(" ID: ")
+            .append(sequence.getName());
 
     String residue = null;
     /*
@@ -1171,8 +1199,7 @@ public class SeqPanel extends JPanel implements MouseListener,
           {
             for (int j = 0; j < startres - lastres; j++)
             {
-              if (!jalview.util.Comparison.isGap(groupSeqs[g]
-                      .getCharAt(fixedRight - j)))
+              if (!Comparison.isGap(groupSeqs[g].getCharAt(fixedRight - j)))
               {
                 blank = false;
                 break;
@@ -1234,7 +1261,7 @@ public class SeqPanel extends JPanel implements MouseListener,
               continue;
             }
 
-            if (!jalview.util.Comparison.isGap(groupSeqs[g].getCharAt(j)))
+            if (!Comparison.isGap(groupSeqs[g].getCharAt(j)))
             {
               // Not a gap, block edit not valid
               endEditing();
@@ -1366,7 +1393,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
       for (blankColumn = fixedColumn; blankColumn > j; blankColumn--)
       {
-        if (jalview.util.Comparison.isGap(seq[s].getCharAt(blankColumn)))
+        if (Comparison.isGap(seq[s].getCharAt(blankColumn)))
         {
           // Theres a space, so break and insert the gap
           break;
@@ -1529,9 +1556,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;
 
@@ -1594,28 +1622,21 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
 
       av.setSelectionGroup(stretchGroup);
-
     }
 
-    if (javax.swing.SwingUtilities.isRightMouseButton(evt))
+    if (evt.isPopupTrigger()) // Mac: mousePressed
     {
-      List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
-              .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(res));
-      Vector links = new Vector();
-      for (SequenceFeature sf : allFeatures)
-      {
-        if (sf.links != null)
-        {
-          for (int j = 0; j < sf.links.size(); j++)
-          {
-            links.addElement(sf.links.elementAt(j));
-          }
-        }
-      }
+      showPopupMenu(evt);
+      return;
+    }
 
-      jalview.gui.PopupMenu pop = new jalview.gui.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;
     }
 
@@ -1637,7 +1658,6 @@ public class SeqPanel extends JPanel implements MouseListener,
       sg.setEndRes(res);
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
-
       stretchGroup = sg;
 
       if (av.getConservationSelected())
@@ -1669,6 +1689,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
@@ -1680,9 +1731,10 @@ public class SeqPanel extends JPanel implements MouseListener,
     {
       return;
     }
-
-    stretchGroup.recalcConservation(); // always do this - annotation has own
-                                       // state
+    // always do this - annotation has own state
+    // but defer colourscheme update until hidden sequences are passed in
+    boolean vischange = stretchGroup.recalcConservation(true);
+    needOverviewUpdate |= vischange && av.isSelectionDefinedGroup();
     if (stretchGroup.cs != null)
     {
       stretchGroup.cs.alignmentChanged(stretchGroup,
@@ -1700,8 +1752,8 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
     PaintRefresher.Refresh(this, av.getSequenceSetId());
-    ap.paintAlignment(true);
-
+    ap.paintAlignment(needOverviewUpdate);
+    needOverviewUpdate = false;
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
@@ -1755,6 +1807,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (res > (stretchGroup.getStartRes() - 1))
       {
         stretchGroup.setEndRes(res);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
     else if (changeStartRes)
@@ -1762,6 +1815,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (res < (stretchGroup.getEndRes() + 1))
       {
         stretchGroup.setStartRes(res);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1795,6 +1849,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       if (stretchGroup.getSequences(null).contains(nextSeq))
       {
         stretchGroup.deleteSequence(seq, false);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
       else
       {
@@ -1804,6 +1859,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         }
 
         stretchGroup.addSequence(nextSeq, false);
+        needOverviewUpdate |= av.isSelectionDefinedGroup();
       }
     }
 
@@ -1945,28 +2001,28 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     // do we want to thread this ? (contention with seqsel and colsel locks, I
     // suspect)
-    // rules are: colsel is copied if there is a real intersection between
-    // sequence selection
+    /*
+     * only copy colsel if there is a real intersection between
+     * sequence selection and this panel's alignment
+     */
     boolean repaint = false;
-    boolean copycolsel = true;
+    boolean copycolsel = false;
 
     SequenceGroup sgroup = null;
     if (seqsel != null && seqsel.getSize() > 0)
     {
       if (av.getAlignment() == null)
       {
-        jalview.bin.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;
       }
       sgroup = seqsel.intersect(av.getAlignment(),
               (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
-      if ((sgroup == null || sgroup.getSize() == 0)
-              || (colsel == null || colsel.isEmpty()))
+      if ((sgroup != null && sgroup.getSize() > 0))
       {
-        // don't copy columns if the region didn't intersect.
-        copycolsel = false;
+        copycolsel = true;
       }
     }
     if (sgroup != null && sgroup.getSize() > 0)
@@ -2059,7 +2115,6 @@ public class SeqPanel extends JPanel implements MouseListener,
     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
             av);
     av.setColumnSelection(cs);
-    av.isColSelChanged(true);
 
     PaintRefresher.Refresh(this, av.getSequenceSetId());
 
index a5f218e..bbe2f68 100755 (executable)
@@ -26,9 +26,12 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.fts.service.pdb.PDBFTSPanel;
+import jalview.fts.service.uniprot.UniprotFTSPanel;
 import jalview.io.gff.SequenceOntologyI;
 import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
@@ -40,6 +43,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;
 
@@ -112,7 +116,10 @@ public class SequenceFetcher extends JPanel implements Runnable
 
   private static Thread initingThread = null;
 
-  int debounceTrap = 0;
+  public JTextArea getTextArea()
+  {
+    return textArea;
+  }
 
   /**
    * Blocking method that initialises and returns the shared instance of the
@@ -160,9 +167,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();
@@ -194,8 +200,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
@@ -207,7 +224,8 @@ public class SequenceFetcher extends JPanel implements Runnable
       {
         if (getSequenceFetcherSingleton(progressIndicator) != null)
         {
-          us.initGui(progressIndicator);
+          us.initGui(progressIndicator, selectedDb, queryString);
+          us._isConstructing = false;
         }
         else
         {
@@ -234,6 +252,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
   {
 
@@ -245,11 +289,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)
@@ -260,6 +350,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();
@@ -267,13 +367,13 @@ public class SequenceFetcher extends JPanel implements Runnable
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    if (new jalview.util.Platform().isAMac())
+    if (Platform.isAMac())
     {
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 240);
+      Desktop.addInternalFrame(frame, getFrameTitle(), false, 400, 240);
     }
     else
     {
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 180);
+      Desktop.addInternalFrame(frame, getFrameTitle(), false, 400, 180);
     }
   }
 
@@ -356,26 +456,46 @@ 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();
+    databaseButt = /*database.getDatabaseSelectorButton();
+                   final JButton viewdbs =*/new JButton(
+            MessageManager.getString("action.select_ddbb"));
+    databaseButt.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        hidePanel();
+        database.showDialog();
+      }
+    });
     databaseButt.setFont(JvSwingUtils.getLabelFont());
     database.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        debounceTrap++;
         String currentSelection = database.getSelectedItem();
-        if (!currentSelection.equalsIgnoreCase("pdb"))
+        if (currentSelection == null)
         {
-          otherSourceAction();
+          close_actionPerformed(null);
         }
-        if (currentSelection.equalsIgnoreCase("pdb")
-                && (database.action == KeyEvent.VK_ENTER || ((debounceTrap % 2) == 0)))
+
+        showPanel();
+
+        if ("pdb".equalsIgnoreCase(currentSelection))
         {
           pdbSourceAction();
         }
+        else if ("uniprot".equalsIgnoreCase(currentSelection))
+        {
+          uniprotSourceAction();
+        }
+        else
+        {
+          otherSourceAction();
+        }
         database.action = -1;
       }
     });
@@ -393,13 +513,19 @@ 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);
-
   }
 
   private void pdbSourceAction()
   {
     databaseButt.setText(database.getSelectedItem());
-    new PDBSearchPanel(this);
+    new PDBFTSPanel(this);
+    frame.dispose();
+  }
+
+  private void uniprotSourceAction()
+  {
+    databaseButt.setText(database.getSelectedItem());
+    new UniprotFTSPanel(this);
     frame.dispose();
   }
 
@@ -519,30 +645,31 @@ public class SequenceFetcher extends JPanel implements Runnable
     // TODO: Refactor to GUI independent code and write tests.
     // indicate if successive sources should be merged into one alignment.
     boolean addToLast = false;
-    ArrayList<String> aresultq = new ArrayList<String>(), presultTitle = new ArrayList<String>();
-    ArrayList<AlignmentI> presult = new ArrayList<AlignmentI>(), aresult = new ArrayList<AlignmentI>();
+    List<String> aresultq = new ArrayList<String>();
+    List<String> presultTitle = new ArrayList<String>();
+    List<AlignmentI> presult = new ArrayList<AlignmentI>();
+    List<AlignmentI> aresult = new ArrayList<AlignmentI>();
     Iterator<DbSourceProxy> proxies = database.getSelectedSources()
             .iterator();
     String[] qries;
-    List<String> nextfetch = Arrays.asList(qries = textArea.getText()
+    List<String> nextFetch = Arrays.asList(qries = textArea.getText()
             .split(";"));
     Iterator<String> en = Arrays.asList(new String[0]).iterator();
     int nqueries = qries.length;
 
     FeatureSettingsModelI preferredFeatureColours = null;
-    while (proxies.hasNext() && (en.hasNext() || nextfetch.size() > 0))
+    while (proxies.hasNext() && (en.hasNext() || nextFetch.size() > 0))
     {
-      if (!en.hasNext() && nextfetch.size() > 0)
+      if (!en.hasNext() && nextFetch.size() > 0)
       {
-        en = nextfetch.iterator();
-        nqueries = nextfetch.size();
+        en = nextFetch.iterator();
+        nqueries = nextFetch.size();
         // save the remaining queries in the original array
-        qries = nextfetch.toArray(new String[nqueries]);
-        nextfetch = new ArrayList<String>();
+        qries = nextFetch.toArray(new String[nqueries]);
+        nextFetch = new ArrayList<String>();
       }
 
       DbSourceProxy proxy = proxies.next();
-      boolean isAliSource = false;
       try
       {
         // update status
@@ -553,122 +680,27 @@ public class SequenceFetcher extends JPanel implements Runnable
                             Integer.valueOf(nqueries).toString(),
                             proxy.getDbName() }), Thread.currentThread()
                         .hashCode());
-        isAliSource = proxy.isAlignmentSource();
         if (proxy.getMaximumQueryCount() == 1)
         {
+          /*
+           * proxy only handles one accession id at a time
+           */
           while (en.hasNext())
           {
-            String item = en.next();
-            try
-            {
-              if (aresult != null)
-              {
-                try
-                {
-                  // give the server a chance to breathe
-                  Thread.sleep(5);
-                } catch (Exception e)
-                {
-                  //
-                }
-
-              }
-
-              AlignmentI indres = null;
-              try
-              {
-                indres = proxy.getSequenceRecords(item);
-              } catch (OutOfMemoryError oome)
-              {
-                new OOMWarning("fetching " + item + " from "
-                        + proxy.getDbName(), oome, this);
-              }
-              if (indres != null)
-              {
-                aresultq.add(item);
-                aresult.add(indres);
-              }
-              else
-              {
-                nextfetch.add(item);
-              }
-            } catch (Exception e)
+            String acc = en.next();
+            if (!fetchSingleAccession(proxy, acc, aresultq, aresult))
             {
-              Cache.log.info(
-                      "Error retrieving " + item
-                      + " from " + proxy.getDbName(), e);
-              nextfetch.add(item);
+              nextFetch.add(acc);
             }
           }
         }
         else
         {
-          StringBuffer multiacc = new StringBuffer();
-          ArrayList<String> tosend = new ArrayList<String>();
-          while (en.hasNext())
-          {
-            String nel = en.next();
-            tosend.add(nel);
-            multiacc.append(nel);
-            if (en.hasNext())
-            {
-              multiacc.append(proxy.getAccessionSeparator());
-            }
-          }
-          try
-          {
-            AlignmentI rslt;
-            SequenceI[] rs;
-            List<String> nores = new ArrayList<String>();
-            rslt = proxy.getSequenceRecords(multiacc.toString());
-            if (rslt == null || rslt.getHeight() == 0)
-            {
-              // no results - pass on all queries to next source
-              nextfetch.addAll(tosend);
-            }
-            else
-            {
-              aresultq.add(multiacc.toString());
-              aresult.add(rslt);
-
-              rs = rslt.getSequencesArray();
-              // search for each query in the dbrefs associated with each
-              // sequence
-              // returned.
-              // ones we do not find will be used to query next source (if any)
-              for (String q : tosend)
-              {
-                DBRefEntry dbr = new DBRefEntry(), found[] = null;
-                dbr.setSource(proxy.getDbSource());
-                dbr.setVersion(null);
-                String accId = proxy.getAccessionIdFromQuery(q);
-                dbr.setAccessionId(accId);
-                boolean rfound = false;
-                for (int r = 0; r < rs.length; r++)
-                {
-                  if (rs[r] != null)
-                  {
-                    found = DBRefUtils.searchRefs(rs[r].getDBRefs(), accId);
-                    if (found != null && found.length > 0)
-                    {
-                      rfound = true;
-                      rs[r] = null;
-                    }
-                  }
-                }
-                if (!rfound)
-                {
-                  nextfetch.add(q);
-                }
-              }
-            }
-          } catch (OutOfMemoryError oome)
-          {
-            new OOMWarning("fetching " + multiacc + " from "
-                    + database.getSelectedItem(), oome, this);
-          }
+          /*
+           * proxy can fetch multiple accessions at one time
+           */
+          fetchMultipleAccessions(proxy, en, aresultq, aresult, nextFetch);
         }
-
       } catch (Exception e)
       {
         showErrorMessage("Error retrieving " + textArea.getText()
@@ -681,7 +713,6 @@ public class SequenceFetcher extends JPanel implements Runnable
         e.printStackTrace();
       } catch (OutOfMemoryError e)
       {
-        // resets dialog box - so we don't use OOMwarning here.
         showErrorMessage("Out of Memory when retrieving "
                 + textArea.getText()
                 + " from "
@@ -694,6 +725,7 @@ public class SequenceFetcher extends JPanel implements Runnable
                 + " from " + database.getSelectedItem());
         e.printStackTrace();
       }
+
       // Stack results ready for opening in alignment windows
       if (aresult != null && aresult.size() > 0)
       {
@@ -705,7 +737,7 @@ public class SequenceFetcher extends JPanel implements Runnable
         }
 
         AlignmentI ar = null;
-        if (isAliSource)
+        if (proxy.isAlignmentSource())
         {
           addToLast = false;
           // new window for each result
@@ -735,7 +767,6 @@ public class SequenceFetcher extends JPanel implements Runnable
             {
               ar.append(aresult.remove(0));
             }
-            ;
           }
           addToLast = true;
           presult.add(ar);
@@ -759,14 +790,14 @@ public class SequenceFetcher extends JPanel implements Runnable
     }
     // only remove visual delay after we finished parsing.
     guiWindow.setProgressBar(null, Thread.currentThread().hashCode());
-    if (nextfetch.size() > 0)
+    if (nextFetch.size() > 0)
     {
       StringBuffer sb = new StringBuffer();
       sb.append("Didn't retrieve the following "
-              + (nextfetch.size() == 1 ? "query" : nextfetch.size()
+              + (nextFetch.size() == 1 ? "query" : nextFetch.size()
                       + " queries") + ": \n");
       int l = sb.length(), lr = 0;
-      for (String s : nextfetch)
+      for (String s : nextFetch)
       {
         if (l != sb.length())
         {
@@ -784,6 +815,159 @@ public class SequenceFetcher extends JPanel implements Runnable
   }
 
   /**
+   * Tries to fetch one or more accession ids from the database proxy
+   * 
+   * @param proxy
+   * @param accessions
+   *          the queries to fetch
+   * @param aresultq
+   *          a successful queries list to add to
+   * @param aresult
+   *          a list of retrieved alignments to add to
+   * @param nextFetch
+   *          failed queries are added to this list
+   * @throws Exception
+   */
+  void fetchMultipleAccessions(DbSourceProxy proxy,
+          Iterator<String> accessions, List<String> aresultq,
+          List<AlignmentI> aresult, List<String> nextFetch)
+          throws Exception
+  {
+    StringBuilder multiacc = new StringBuilder();
+    List<String> tosend = new ArrayList<String>();
+    while (accessions.hasNext())
+    {
+      String nel = accessions.next();
+      tosend.add(nel);
+      multiacc.append(nel);
+      if (accessions.hasNext())
+      {
+        multiacc.append(proxy.getAccessionSeparator());
+      }
+    }
+
+    try
+    {
+      String query = multiacc.toString();
+      AlignmentI rslt = proxy.getSequenceRecords(query);
+      if (rslt == null || rslt.getHeight() == 0)
+      {
+        // no results - pass on all queries to next source
+        nextFetch.addAll(tosend);
+      }
+      else
+      {
+        aresultq.add(query);
+        aresult.add(rslt);
+        if (tosend.size() > 1)
+        {
+          checkResultForQueries(rslt, tosend, nextFetch, proxy);
+        }
+      }
+    } catch (OutOfMemoryError oome)
+    {
+      new OOMWarning("fetching " + multiacc + " from "
+              + database.getSelectedItem(), oome, this);
+    }
+  }
+
+  /**
+   * Query for a single accession id via the database proxy
+   * 
+   * @param proxy
+   * @param accession
+   * @param aresultq
+   *          a list of successful queries to add to
+   * @param aresult
+   *          a list of retrieved alignments to add to
+   * @return true if the fetch was successful, else false
+   */
+  boolean fetchSingleAccession(DbSourceProxy proxy, String accession,
+          List<String> aresultq, List<AlignmentI> aresult)
+  {
+    boolean success = false;
+    try
+    {
+      if (aresult != null)
+      {
+        try
+        {
+          // give the server a chance to breathe
+          Thread.sleep(5);
+        } catch (Exception e)
+        {
+          //
+        }
+      }
+
+      AlignmentI indres = null;
+      try
+      {
+        indres = proxy.getSequenceRecords(accession);
+      } catch (OutOfMemoryError oome)
+      {
+        new OOMWarning("fetching " + accession + " from "
+                + proxy.getDbName(), oome, this);
+      }
+      if (indres != null)
+      {
+        aresultq.add(accession);
+        aresult.add(indres);
+        success = true;
+      }
+    } catch (Exception e)
+    {
+      Cache.log.info(
+              "Error retrieving " + accession + " from "
+                      + proxy.getDbName(), e);
+    }
+    return success;
+  }
+
+  /**
+   * Checks which of the queries were successfully retrieved by searching the
+   * DBRefs of the retrieved sequences for a match. Any not found are added to
+   * the 'nextFetch' list.
+   * 
+   * @param rslt
+   * @param queries
+   * @param nextFetch
+   * @param proxy
+   */
+  void checkResultForQueries(AlignmentI rslt, List<String> queries,
+          List<String> nextFetch, DbSourceProxy proxy)
+  {
+    SequenceI[] rs = rslt.getSequencesArray();
+
+    for (String q : queries)
+    {
+      DBRefEntry dbr = new DBRefEntry();
+      dbr.setSource(proxy.getDbSource());
+      dbr.setVersion(null);
+      String accId = proxy.getAccessionIdFromQuery(q);
+      dbr.setAccessionId(accId);
+      boolean rfound = false;
+      for (int r = 0; r < rs.length; r++)
+      {
+        if (rs[r] != null)
+        {
+          List<DBRefEntry> found = DBRefUtils.searchRefs(rs[r].getDBRefs(),
+                  accId);
+          if (!found.isEmpty())
+          {
+            rfound = true;
+            break;
+          }
+        }
+      }
+      if (!rfound)
+      {
+        nextFetch.add(q);
+      }
+    }
+  }
+
+  /**
    * 
    * @return a standard title for any results retrieved using the currently
    *         selected source and settings
@@ -840,11 +1024,12 @@ public class SequenceFetcher extends JPanel implements Runnable
         }
         if (Cache.getDefault("HIDE_INTRONS", true))
         {
-          af.avc.markColumnsContainingFeatures(true, false, false,
-                  SequenceOntologyI.EXON);
-          af.getViewport().hideSelectedColumns();
+          af.hideFeatureColumns(SequenceOntologyI.EXON, false);
+        }
+        if (newAlframes != null)
+        {
+          newAlframes.add(af);
         }
-
         Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH,
                 AlignFrame.DEFAULT_HEIGHT);
 
@@ -853,8 +1038,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)
         {
         }
@@ -891,4 +1075,22 @@ public class SequenceFetcher extends JPanel implements Runnable
   {
     this.progressIndicator = progressIndicator;
   }
+
+  /**
+   * Make this panel visible (after a selection has been made in the database
+   * chooser)
+   */
+  void showPanel()
+  {
+    frame.setVisible(true);
+  }
+
+  /**
+   * Hide this panel (on clicking the database button to open the database
+   * chooser)
+   */
+  void hidePanel()
+  {
+    frame.setVisible(false);
+  }
 }
index 258a229..64fe053 100755 (executable)
@@ -29,12 +29,6 @@ import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 
-/**
- * DOCUMENT ME!
- * 
- * @author $author$
- * @version $Revision$
- */
 public class SequenceRenderer implements jalview.api.SequenceRenderer
 {
   final static int CHAR_TO_UPPER = 'A' - 'a';
@@ -91,6 +85,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   @Override
   public Color getResidueBoxColour(SequenceI seq, int i)
   {
+    // rate limiting step when rendering overview for lots of groups
     allGroups = av.getAlignment().findAllGroups(seq);
 
     if (inCurrentSequenceGroup(i))
@@ -417,7 +412,7 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
           }
           if (!isarep && av.getShowUnconserved())
           {
-            s = getDisplayChar(srep, i, s, '.', currentSequenceGroup);
+            s = getDisplayChar(srep, i, s, '.', null);
 
           }
 
@@ -447,12 +442,17 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer
   {
     // TODO - use currentSequenceGroup rather than alignment
     // currentSequenceGroup.getConsensus()
-    char conschar = (usesrep) ? (currentGroup == null ? av.getAlignment()
+    char conschar = (usesrep) ? (currentGroup == null
+            || position < currentGroup.getStartRes()
+            || position > currentGroup.getEndRes() ? av.getAlignment()
             .getSeqrep().getCharAt(position)
             : (currentGroup.getSeqrep() != null ? currentGroup.getSeqrep()
                     .getCharAt(position) : av.getAlignment().getSeqrep()
                     .getCharAt(position)))
-            : (currentGroup != null && currentGroup.getConsensus() != null) ? currentGroup
+            : (currentGroup != null && currentGroup.getConsensus() != null
+                    && position >= currentGroup.getStartRes()
+                    && position <= currentGroup.getEndRes() && currentGroup
+                    .getConsensus().annotations.length > position) ? currentGroup
                     .getConsensus().annotations[position].displayCharacter
                     .charAt(0)
                     : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
index e1e70dc..a381e8b 100755 (executable)
@@ -219,8 +219,9 @@ public class SliderPanel extends GSliderPanel
       pid.cs = cs;
     }
 
-    PIDSlider.setTitle(MessageManager
-            .formatMessage("label.percentage_identity_thereshold",
+    PIDSlider
+            .setTitle(MessageManager.formatMessage(
+                    "label.percentage_identity_threshold",
                     new String[] { source }));
 
     if (ap.av.getAlignment().getGroups() != null)
index 617224f..6c849c3 100644 (file)
@@ -37,6 +37,8 @@ import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.beans.PropertyVetoException;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map.Entry;
 
 import javax.swing.AbstractAction;
@@ -68,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)
@@ -206,6 +210,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     boolean topAnnotations = topViewport.isShowAnnotation();
     boolean bottomAnnotations = bottomViewport.isShowAnnotation();
+    // TODO need number of visible sequences here, not #sequences - how?
     int topCount = topAlignment.getHeight();
     int bottomCount = bottomAlignment.getHeight();
     int topCharHeight = topViewport.getViewStyle().getCharHeight();
@@ -223,6 +228,11 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
             + (bottomAnnotations ? bottomViewport.calcPanelHeight() : 0);
     double ratio = ((double) topHeight) / (topHeight + bottomHeight);
 
+    /*
+     * limit to 0.2 <= ratio <= 0.8 to avoid concealing all sequences
+     */
+    ratio = Math.min(ratio, 0.8d);
+    ratio = Math.max(ratio, 0.2d);
     setRelativeDividerLocation(ratio);
   }
 
@@ -328,6 +338,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
         actioned = true;
         e.consume();
       }
+      break;
     default:
     }
     return actioned;
@@ -704,6 +715,18 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
   }
 
   /**
+   * return the AlignFrames held by this container
+   * 
+   * @return { Top alignFrame (Usually CDS), Bottom AlignFrame (Usually
+   *         Protein)}
+   */
+  public List<AlignFrame> getAlignFrames()
+  {
+    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
    * search in the half of the SplitFrame that has the mouse.
index 5709ac9..3350f6c 100644 (file)
@@ -26,16 +26,18 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSData;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.api.FTSRestClientI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
+import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.jbgui.GStructureChooser;
-import jalview.jbgui.PDBDocFieldPreferences;
+import jalview.structure.StructureMapping;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
-import jalview.ws.dbsources.PDBRestClient;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
+import jalview.ws.DBRefFetcher;
 import jalview.ws.sifts.SiftsSettings;
-import jalview.ws.uimodel.PDBRestRequest;
-import jalview.ws.uimodel.PDBRestResponse;
-import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary;
 
 import java.awt.event.ItemEvent;
 import java.util.ArrayList;
@@ -44,6 +46,7 @@ import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.Vector;
 
 import javax.swing.JCheckBox;
@@ -62,24 +65,24 @@ import javax.swing.table.AbstractTableModel;
 public class StructureChooser extends GStructureChooser implements
         IProgressIndicator
 {
-  private boolean structuresDiscovered = false;
-
   private SequenceI selectedSequence;
 
   private SequenceI[] selectedSequences;
 
   private IProgressIndicator progressIndicator;
 
-  private Collection<PDBResponseSummary> discoveredStructuresSet;
+  private Collection<FTSData> discoveredStructuresSet;
 
-  private PDBRestRequest lastPdbRequest;
+  private FTSRestRequest lastPdbRequest;
 
-  private PDBRestClient pdbRestCleint;
+  private FTSRestClientI pdbRestCleint;
 
   private String selectedPdbFileName;
 
   private boolean isValidPBDEntry;
 
+  private boolean cachedPDBExists;
+
   public StructureChooser(SequenceI[] selectedSeqs, SequenceI selectedSeq,
           AlignmentPanel ap)
   {
@@ -100,6 +103,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
@@ -114,7 +119,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();
@@ -146,22 +152,26 @@ public class StructureChooser extends GStructureChooser implements
   public void fetchStructuresMetaData()
   {
     long startTime = System.currentTimeMillis();
-    Collection<PDBDocField> wantedFields = PDBDocFieldPreferences
+    pdbRestCleint = PDBFTSRestClient.getInstance();
+    Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
             .getStructureSummaryFields();
 
-    discoveredStructuresSet = new LinkedHashSet<PDBResponseSummary>();
+    discoveredStructuresSet = new LinkedHashSet<FTSData>();
     HashSet<String> errors = new HashSet<String>();
     for (SequenceI seq : selectedSequences)
     {
-      PDBRestRequest pdbRequest = new PDBRestRequest();
+      FTSRestRequest pdbRequest = new FTSRestRequest();
       pdbRequest.setAllowEmptySeq(false);
       pdbRequest.setResponseSize(500);
       pdbRequest.setFieldToSearchBy("(");
+      FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
+              .getSelectedItem());
+      pdbRequest.setFieldToSortBy(selectedFilterOpt.getValue(),
+              !chk_invertFilter.isSelected());
       pdbRequest.setWantedFields(wantedFields);
       pdbRequest.setSearchTerm(buildQuery(seq) + ")");
       pdbRequest.setAssociatedSequence(seq);
-      pdbRestCleint = new PDBRestClient();
-      PDBRestResponse resultList;
+      FTSRestResponse resultList;
       try
       {
         resultList = pdbRestCleint.executeRequest(pdbRequest);
@@ -185,9 +195,9 @@ public class StructureChooser extends GStructureChooser implements
     if (discoveredStructuresSet != null
             && !discoveredStructuresSet.isEmpty())
     {
-      tbl_summary.setModel(PDBRestResponse.getTableModel(lastPdbRequest,
-              discoveredStructuresSet));
-      structuresDiscovered = true;
+      getResultTable().setModel(
+              FTSRestResponse.getTableModel(lastPdbRequest,
+                      discoveredStructuresSet));
       noOfStructuresFound = discoveredStructuresSet.size();
       mainFrame.setTitle(MessageManager.formatMessage(
               "label.structure_chooser_no_of_structures",
@@ -229,7 +239,7 @@ public class StructureChooser extends GStructureChooser implements
         }
       }
     }
-
+    cachedPDBExists = !entries.isEmpty();
     PDBEntryTableModel tableModelx = new PDBEntryTableModel(entries);
     tbl_local_pdb.setModel(tableModelx);
   }
@@ -247,7 +257,7 @@ public class StructureChooser extends GStructureChooser implements
     boolean isPDBRefsFound = false;
     boolean isUniProtRefsFound = false;
     StringBuilder queryBuilder = new StringBuilder();
-    HashSet<String> seqRefs = new LinkedHashSet<String>();
+    Set<String> seqRefs = new LinkedHashSet<String>();
 
     if (seq.getAllPDBEntries() != null)
     {
@@ -255,10 +265,8 @@ public class StructureChooser extends GStructureChooser implements
       {
         if (isValidSeqName(entry.getId()))
         {
-          queryBuilder.append(PDBRestClient.PDBDocField.PDB_ID.getCode())
-                  .append(":")
-.append(entry.getId().toLowerCase())
-                  .append(" OR ");
+          queryBuilder.append("pdb_id:")
+                  .append(entry.getId().toLowerCase()).append(" OR ");
           isPDBRefsFound = true;
           // seqRefs.add(entry.getId());
         }
@@ -273,23 +281,17 @@ public class StructureChooser extends GStructureChooser implements
         {
           if (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT))
           {
-            queryBuilder
-                    .append(PDBRestClient.PDBDocField.UNIPROT_ACCESSION
-                            .getCode()).append(":")
-                    .append(getDBRefId(dbRef))
-                    .append(" OR ");
-            queryBuilder
-                    .append(PDBRestClient.PDBDocField.UNIPROT_ID.getCode())
-                    .append(":")
+            queryBuilder.append("uniprot_accession:")
                     .append(getDBRefId(dbRef)).append(" OR ");
+            queryBuilder.append("uniprot_id:").append(getDBRefId(dbRef))
+                    .append(" OR ");
             isUniProtRefsFound = true;
           }
           else if (dbRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
           {
 
-            queryBuilder.append(PDBRestClient.PDBDocField.PDB_ID.getCode())
-                    .append(":").append(getDBRefId(dbRef).toLowerCase())
-                    .append(" OR ");
+            queryBuilder.append("pdb_id:")
+                    .append(getDBRefId(dbRef).toLowerCase()).append(" OR ");
             isPDBRefsFound = true;
           }
           else
@@ -331,20 +333,19 @@ public class StructureChooser extends GStructureChooser implements
   }
 
   /**
-   * Remove the following special characters from input string +, -, &, |, !, (,
-   * ), {, }, [, ], ^, ", ~, *, ?, :, \
+   * Remove the following special characters from input string +, -, &, !, (, ),
+   * {, }, [, ], ^, ", ~, *, ?, :, \
    * 
    * @param seqName
    * @return
    */
-  private static String sanitizeSeqName(String seqName)
+  static String sanitizeSeqName(String seqName)
   {
     Objects.requireNonNull(seqName);
     return seqName.replaceAll("\\[\\d*\\]", "")
-            .replaceAll("[^\\dA-Za-z|]", "").replaceAll("\\s+", "+");
+            .replaceAll("[^\\dA-Za-z|_]", "").replaceAll("\\s+", "+");
   }
 
-
   /**
    * Ensures sequence ref names are not less than 3 characters and does not
    * contain a database name
@@ -395,18 +396,18 @@ public class StructureChooser extends GStructureChooser implements
       public void run()
       {
         long startTime = System.currentTimeMillis();
+        pdbRestCleint = PDBFTSRestClient.getInstance();
         lbl_loading.setVisible(true);
-        Collection<PDBDocField> wantedFields = PDBDocFieldPreferences
+        Collection<FTSDataColumnI> wantedFields = pdbDocFieldPrefs
                 .getStructureSummaryFields();
-        Collection<PDBResponseSummary> filteredResponse = new HashSet<PDBResponseSummary>();
+        Collection<FTSData> filteredResponse = new HashSet<FTSData>();
         HashSet<String> errors = new HashSet<String>();
 
         for (SequenceI seq : selectedSequences)
         {
-          PDBRestRequest pdbRequest = new PDBRestRequest();
+          FTSRestRequest pdbRequest = new FTSRestRequest();
           if (fieldToFilterBy.equalsIgnoreCase("uniprot_coverage"))
           {
-            System.out.println(">>>>>> Filtering with uniprot coverate");
             pdbRequest.setAllowEmptySeq(false);
             pdbRequest.setResponseSize(1);
             pdbRequest.setFieldToSearchBy("(");
@@ -428,8 +429,7 @@ public class StructureChooser extends GStructureChooser implements
             pdbRequest.setWantedFields(wantedFields);
             pdbRequest.setAssociatedSequence(seq);
           }
-          pdbRestCleint = new PDBRestClient();
-          PDBRestResponse resultList;
+          FTSRestResponse resultList;
           try
           {
             resultList = pdbRestCleint.executeRequest(pdbRequest);
@@ -452,18 +452,21 @@ public class StructureChooser extends GStructureChooser implements
         if (!filteredResponse.isEmpty())
         {
           final int filterResponseCount = filteredResponse.size();
-          Collection<PDBResponseSummary> reorderedStructuresSet = new LinkedHashSet<PDBResponseSummary>();
+          Collection<FTSData> reorderedStructuresSet = new LinkedHashSet<FTSData>();
           reorderedStructuresSet.addAll(filteredResponse);
           reorderedStructuresSet.addAll(discoveredStructuresSet);
-          tbl_summary.setModel(PDBRestResponse.getTableModel(
-                  lastPdbRequest, reorderedStructuresSet));
-
-          PDBRestResponse.configureTableColumn(tbl_summary, wantedFields);
-          tbl_summary.getColumn("Ref Sequence").setPreferredWidth(120);
-          tbl_summary.getColumn("Ref Sequence").setMinWidth(100);
-          tbl_summary.getColumn("Ref Sequence").setMaxWidth(200);
+          getResultTable().setModel(
+                  FTSRestResponse.getTableModel(lastPdbRequest,
+                          reorderedStructuresSet));
+
+          FTSRestResponse.configureTableColumn(getResultTable(),
+                  wantedFields, tempUserPrefs);
+          getResultTable().getColumn("Ref Sequence").setPreferredWidth(120);
+          getResultTable().getColumn("Ref Sequence").setMinWidth(100);
+          getResultTable().getColumn("Ref Sequence").setMaxWidth(200);
           // Update table selection model here
-          tbl_summary.addRowSelectionInterval(0, filterResponseCount - 1);
+          getResultTable().addRowSelectionInterval(0,
+                  filterResponseCount - 1);
           mainFrame.setTitle(MessageManager.formatMessage(
                   "label.structure_chooser_filter_time", totalTime));
         }
@@ -523,36 +526,47 @@ 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",
-              PDBDocField.OVERALL_QUALITY.getCode(), VIEWS_FILTER));
-      cmb_filterOption.addItem(new FilterOption("Most UniProt Coverage",
-              PDBDocField.UNIPROT_COVERAGE.getCode(), VIEWS_FILTER));
+              "overall_quality", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Best Resolution",
-              PDBDocField.RESOLUTION.getCode(), VIEWS_FILTER));
+              "resolution", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Most Protein Chain",
-              PDBDocField.PROTEIN_CHAIN_COUNT.getCode(), VIEWS_FILTER));
+              "number_of_protein_chains", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Most Bound Molecules",
-              PDBDocField.BOUND_MOLECULE_COUNT.getCode(), VIEWS_FILTER));
+              "number_of_bound_molecules", VIEWS_FILTER));
       cmb_filterOption.addItem(new FilterOption("Most Polymer Residues",
-              PDBDocField.POLYMER_RESIDUE_COUNT.getCode(), VIEWS_FILTER));
+              "number_of_polymer_residues", VIEWS_FILTER));
     }
     cmb_filterOption.addItem(new FilterOption("Enter PDB Id", "-",
             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
@@ -592,7 +606,7 @@ public class StructureChooser extends GStructureChooser implements
     String currentView = selectedFilterOpt.getView();
     if (currentView == VIEWS_FILTER)
     {
-      if (tbl_summary.getSelectedRows().length > 0)
+      if (getResultTable().getSelectedRows().length > 0)
       {
         btn_view.setEnabled(true);
       }
@@ -718,6 +732,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()
@@ -725,108 +740,116 @@ public class StructureChooser extends GStructureChooser implements
       @Override
       public void run()
       {
-    FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption
-            .getSelectedItem());
-    String currentView = selectedFilterOpt.getView();
-    if (currentView == VIEWS_FILTER)
-    {
-      int pdbIdColIndex = tbl_summary.getColumn(
-              PDBRestClient.PDBDocField.PDB_ID.getName()).getModelIndex();
-      int refSeqColIndex = tbl_summary.getColumn("Ref Sequence")
-              .getModelIndex();
-      int[] selectedRows = tbl_summary.getSelectedRows();
-      PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
-      int count = 0;
-      ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
-      for (int row : selectedRows)
-      {
-        String pdbIdStr = tbl_summary.getValueAt(row, pdbIdColIndex)
-                .toString();
-        SequenceI selectedSeq = (SequenceI) tbl_summary.getValueAt(row,
-                refSeqColIndex);
-        selectedSeqsToView.add(selectedSeq);
+        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();
+          int[] selectedRows = getResultTable().getSelectedRows();
+          PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length];
+          int count = 0;
+          ArrayList<SequenceI> selectedSeqsToView = new ArrayList<SequenceI>();
+          for (int row : selectedRows)
+          {
+            String pdbIdStr = getResultTable().getValueAt(row,
+                    pdbIdColIndex).toString();
+            SequenceI selectedSeq = (SequenceI) getResultTable()
+                    .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;
-      int pdbIdColIndex = tbl_local_pdb.getColumn(
-              PDBRestClient.PDBDocField.PDB_ID.getName()).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()]);
+        }
+        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()]);
           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();
-        pdbEntry.setId(pdbIdStr);
-        pdbEntry.setType(PDBEntry.Type.PDB);
-        selectedSequence.getDatasetSequence().addPDBId(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]);
+              pdbEntry.setChainCode(pdbIdStr.split(":")[1].toUpperCase());
+            }
+            else
+            {
+              pdbEntry.setId(pdbIdStr);
+            }
+            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 });
-    }
-    else if (currentView == VIEWS_FROM_FILE)
-    {
-      SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
-              .getCmb_assSeq().getSelectedItem()).getSequence();
-      if (userSelectedSeq != null)
-      {
-        selectedSequence = userSelectedSeq;
-      }
-      PDBEntry fileEntry = new AssociatePdbFileWithSeq()
-              .associatePdbWithSeq(selectedPdbFileName,
-                      jalview.io.AppletFormatAdapter.FILE,
-                      selectedSequence, true, Desktop.instance);
+        }
+        else if (currentView == VIEWS_FROM_FILE)
+        {
+          SequenceI userSelectedSeq = ((AssociateSeqOptions) fileChooserAssSeqPanel
+                  .getCmb_assSeq().getSelectedItem()).getSequence();
+          if (userSelectedSeq != null)
+          {
+            selectedSequence = userSelectedSeq;
+          }
+          PDBEntry fileEntry = new AssociatePdbFileWithSeq()
+                  .associatePdbWithSeq(selectedPdbFileName,
+                          jalview.io.AppletFormatAdapter.FILE,
+                          selectedSequence, true, Desktop.instance);
 
           launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap,
                   new SequenceI[] { selectedSequence });
-    }
-    mainFrame.dispose();
+        }
+        closeAction(preferredHeight);
       }
     }).start();
   }
@@ -850,42 +873,78 @@ public class StructureChooser extends GStructureChooser implements
           final PDBEntry[] pdbEntriesToView,
           final AlignmentPanel alignPanel, SequenceI[] sequences)
   {
-    ssm.setProgressBar("Launching PDB structure viewer..");
+    ssm.setProgressBar(MessageManager
+            .getString("status.launching_3d_structure_viewer"));
     final StructureViewer sViewer = new StructureViewer(ssm);
 
     if (SiftsSettings.isMapWithSifts())
     {
+      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)
-        {
-          ssm.setProgressBar(null);
-          ssm.setProgressBar("Fetching Database refs..");
-          new jalview.ws.DBRefFetcher(sequences, null, null, null, false)
-                  .fetchDBRefs(true);
-          break;
-        }
-      }
-    }
-        if (pdbEntriesToView.length > 1)
+        PDBEntry pdbe = pdbEntriesToView[p++];
+        if (pdbe != null && pdbe.getFile() != null)
         {
-          ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
-          for (SequenceI seq : sequences)
+          StructureMapping[] smm = ssm.getMapping(pdbe.getFile());
+          if (smm != null && smm.length > 0)
           {
-            seqsMap.add(new SequenceI[] { seq });
+            for (StructureMapping sm : smm)
+            {
+              if (sm.getSequence() == seq)
+              {
+                continue;
+              }
+            }
           }
-          SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
-      ssm.setProgressBar(null);
-      ssm.setProgressBar("Fetching PDB Structures for selected entries..");
-          sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
         }
-        else
+        if (seq.getPrimaryDBRefs().size() == 0)
         {
-      ssm.setProgressBar(null);
-      ssm.setProgressBar("Fetching PDB Structure for "
-              + pdbEntriesToView[0].getId());
-          sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+          seqsWithoutSourceDBRef.add(seq);
+          continue;
+        }
+      }
+      if (!seqsWithoutSourceDBRef.isEmpty())
+      {
+        int y = seqsWithoutSourceDBRef.size();
+        ssm.setProgressBar(null);
+        ssm.setProgressBar(MessageManager.formatMessage(
+                "status.fetching_dbrefs_for_sequences_without_valid_refs",
+                y));
+        SequenceI[] seqWithoutSrcDBRef = new SequenceI[y];
+        int x = 0;
+        for (SequenceI fSeq : seqsWithoutSourceDBRef)
+        {
+          seqWithoutSrcDBRef[x++] = fSeq;
         }
+        DBRefFetcher dbRefFetcher = new DBRefFetcher(seqWithoutSrcDBRef);
+        dbRefFetcher.fetchDBRefs(true);
+      }
+    }
+    if (pdbEntriesToView.length > 1)
+    {
+      ArrayList<SequenceI[]> seqsMap = new ArrayList<SequenceI[]>();
+      for (SequenceI seq : sequences)
+      {
+        seqsMap.add(new SequenceI[] { seq });
+      }
+      SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
+      ssm.setProgressBar(null);
+      ssm.setProgressBar(MessageManager
+              .getString("status.fetching_3d_structures_for_selected_entries"));
+      sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
+    }
+    else
+    {
+      ssm.setProgressBar(null);
+      ssm.setProgressBar(MessageManager.formatMessage(
+              "status.fetching_3d_structures_for",
+              pdbEntriesToView[0].getId()));
+      sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel);
+    }
   }
 
   /**
@@ -919,15 +978,11 @@ 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<PDBResponseSummary> getDiscoveredStructuresSet()
+  public Collection<FTSData> getDiscoveredStructuresSet()
   {
     return discoveredStructuresSet;
   }
@@ -944,18 +999,20 @@ public class StructureChooser extends GStructureChooser implements
         isValidPBDEntry = false;
         if (txt_search.getText().length() > 0)
         {
-          List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-          wantedFields.add(PDBDocField.PDB_ID);
-          PDBRestRequest pdbRequest = new PDBRestRequest();
+          String searchTerm = txt_search.getText().toLowerCase();
+          searchTerm = searchTerm.split(":")[0];
+          // System.out.println(">>>>> search term : " + searchTerm);
+          List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+          FTSRestRequest pdbRequest = new FTSRestRequest();
           pdbRequest.setAllowEmptySeq(false);
           pdbRequest.setResponseSize(1);
           pdbRequest.setFieldToSearchBy("(pdb_id:");
           pdbRequest.setWantedFields(wantedFields);
-          pdbRequest
-                  .setSearchTerm(txt_search.getText().toLowerCase() + ")");
+          pdbRequest.setSearchTerm(searchTerm + ")");
           pdbRequest.setAssociatedSequence(selectedSequence);
-          pdbRestCleint = new PDBRestClient();
-          PDBRestResponse resultList;
+          pdbRestCleint = PDBFTSRestClient.getInstance();
+          wantedFields.add(pdbRestCleint.getPrimaryKeyColumn());
+          FTSRestResponse resultList;
           try
           {
             resultList = pdbRestCleint.executeRequest(pdbRequest);
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 6bac6df..39d9c1d 100644 (file)
@@ -72,7 +72,7 @@ public class TextColourChooser
     final JPanel col2 = new JPanel();
     col2.setPreferredSize(new Dimension(40, 20));
     col2.setBorder(BorderFactory.createEtchedBorder());
-    col2.setToolTipText(MessageManager.getString("label.ligth_colour"));
+    col2.setToolTipText(MessageManager.getString("label.light_colour"));
     col2.setBackground(new Color(original2));
     final JPanel bigpanel = new JPanel(new BorderLayout());
     JPanel panel = new JPanel();
@@ -81,7 +81,7 @@ public class TextColourChooser
             new JLabel(
                     "<html>"
                             + MessageManager
-                                    .getString("label.select_dark_light_set_thereshold")
+                                    .getString("label.select_dark_light_set_threshold")
                             + "</html>"), BorderLayout.NORTH);
     panel.add(col1);
     panel.add(slider);
@@ -89,6 +89,7 @@ public class TextColourChooser
 
     col1.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         Color col = JColorChooser.showDialog(bigpanel,
@@ -104,6 +105,7 @@ public class TextColourChooser
 
     col2.addMouseListener(new MouseAdapter()
     {
+      @Override
       public void mousePressed(MouseEvent e)
       {
         Color col = JColorChooser.showDialog(bigpanel,
@@ -119,6 +121,7 @@ public class TextColourChooser
 
     slider.addChangeListener(new ChangeListener()
     {
+      @Override
       public void stateChanged(ChangeEvent evt)
       {
         thresholdChanged(slider.getValue());
@@ -130,7 +133,7 @@ public class TextColourChooser
                     ap,
                     bigpanel,
                     MessageManager
-                            .getString("label.adjunst_foreground_text_colour_thereshold"),
+                            .getString("label.adjunst_foreground_text_colour_threshold"),
                     JOptionPane.OK_CANCEL_OPTION,
                     JOptionPane.QUESTION_MESSAGE, null, null, null);
 
index 90c74be..0e513f7 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;
@@ -175,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())
       {
@@ -748,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)
@@ -770,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)
@@ -781,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 (SwingUtilities.isRightMouseButton(evt))
-      {
-        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();
     }
   }
@@ -858,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();
 
@@ -926,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))
         {
@@ -979,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),
-                  sg.getStartRes(), sg.getEndRes());
-
+          Conservation c = new Conservation("Group", 3,
+                  sg.getSequences(null), sg.getStartRes(), sg.getEndRes());
           c.calculate();
           c.verdict(false, aps[a].av.getConsPercGaps());
           sg.cs.setConservation(c);
@@ -994,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());
             }
           }
         }
@@ -1023,11 +1056,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       {
         ((AlignViewport) codingComplement).getAlignPanel()
                 .updateAnnotation();
-
       }
-
     }
-
   }
 
   /**
index 9522144..fafa610 100755 (executable)
@@ -161,6 +161,7 @@ public class TreePanel extends GTreePanel
 
     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
     {
+      @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
         if (evt.getPropertyName().equals("alignment"))
@@ -196,6 +197,7 @@ public class TreePanel extends GTreePanel
 
   }
 
+  @Override
   public void viewMenu_menuSelected()
   {
     buildAssociatedViewMenu();
@@ -231,6 +233,7 @@ public class TreePanel extends GTreePanel
       buttonGroup.add(item);
       item.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent evt)
         {
           treeCanvas.applyToAllViews = false;
@@ -249,6 +252,7 @@ public class TreePanel extends GTreePanel
     itemf.setSelected(treeCanvas.applyToAllViews);
     itemf.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent evt)
       {
         treeCanvas.applyToAllViews = itemf.isSelected();
@@ -276,6 +280,7 @@ public class TreePanel extends GTreePanel
       }
     }
 
+    @Override
     public void run()
     {
 
@@ -389,6 +394,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void textbox_actionPerformed(ActionEvent e)
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
@@ -434,6 +440,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void saveAsNewick_actionPerformed(ActionEvent e)
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
@@ -474,12 +481,14 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void printMenu_actionPerformed(ActionEvent e)
   {
     // Putting in a thread avoids Swing painting problems
     treeCanvas.startPrinting();
   }
 
+  @Override
   public void originalSeqData_actionPerformed(ActionEvent e)
   {
     if (!tree.hasOriginalSequenceData())
@@ -511,8 +520,8 @@ public class TreePanel extends GTreePanel
     {
       // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
 
-      Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
-      Alignment dataset = (av != null && av.getAlignment() != null) ? av
+      AlignmentI al = new Alignment((SequenceI[]) alAndColsel[0]);
+      AlignmentI dataset = (av != null && av.getAlignment() != null) ? av
               .getAlignment().getDataset() : null;
       if (dataset != null)
       {
@@ -547,6 +556,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void fitToWindow_actionPerformed(ActionEvent e)
   {
     treeCanvas.fitToWindow = fitToWindow.isSelected();
@@ -637,6 +647,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void font_actionPerformed(ActionEvent e)
   {
     if (treeCanvas == null)
@@ -666,6 +677,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void distanceMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowDistances(distanceMenu.isSelected());
@@ -677,6 +689,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void bootstrapMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());
@@ -688,6 +701,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void placeholdersMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());
@@ -699,6 +713,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void epsTree_actionPerformed(ActionEvent e)
   {
     boolean accurateText = true;
@@ -772,6 +787,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void pngTree_actionPerformed(ActionEvent e)
   {
     int width = treeCanvas.getWidth();
@@ -828,6 +844,7 @@ public class TreePanel extends GTreePanel
     tree.applyToNodes(new NodeTransformI()
     {
 
+      @Override
       public void transform(BinaryNode node)
       {
         if (node instanceof SequenceNode
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 984eff6..5760fbe 100755 (executable)
@@ -89,14 +89,14 @@ public abstract class AlignFile extends FileParse
   /**
    * Constructor which parses the data from a file of some specified type.
    * 
-   * @param inFile
-   *          Filename to read from.
+   * @param dataObject
+   *          Filename, URL or Pasted String to read from.
    * @param type
-   *          What type of file to read from (File, URL)
+   *          What type of file to read from (File, URL, Pasted String)
    */
-  public AlignFile(String inFile, String type) throws IOException
+  public AlignFile(String dataObject, String type) throws IOException
   {
-    this(true, inFile, type);
+    this(true, dataObject, type);
   }
 
   /**
@@ -105,16 +105,16 @@ public abstract class AlignFile extends FileParse
    * 
    * @param parseImmediately
    *          if false, need to call 'doParse()' to begin parsing data
-   * @param inFile
-   *          Filename to read from.
+   * @param dataObject
+   *          Filename, URL or Pasted String to read from.
    * @param type
    *          What type of file to read from (File, URL)
    * @throws IOException
    */
-  public AlignFile(boolean parseImmediately, String inFile, String type)
+  public AlignFile(boolean parseImmediately, String dataObject, String type)
           throws IOException
   {
-    super(inFile, type);
+    super(dataObject, type);
     initData();
     if (parseImmediately)
     {
index 8b3aa98..34fdabe 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,9 +1637,9 @@ 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),
-                  sg.getStartRes(), sg.getEndRes() + 1);
+          Conservation c = new Conservation("Group", 3,
+                  sg.getSequences(null), sg.getStartRes(),
+                  sg.getEndRes() + 1);
 
           c.calculate();
           c.verdict(false, 25); // TODO: refer to conservation percent threshold
@@ -1760,6 +1759,10 @@ public class AnnotationFile
    */
   public String printCSVAnnotations(AlignmentAnnotation[] annotations)
   {
+    if (annotations == null)
+    {
+      return "";
+    }
     StringBuffer sp = new StringBuffer();
     for (int i = 0; i < annotations.length; i++)
     {
index 65fd72f..9695891 100755 (executable)
@@ -26,7 +26,9 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
-import jalview.structure.StructureViewSettings;
+import jalview.datamodel.PDBEntry.Type;
+import jalview.ext.jmol.JmolParser;
+import jalview.structure.StructureImportSettings;
 import jalview.util.MessageManager;
 
 import java.io.File;
@@ -280,29 +282,33 @@ public class AppletFormatAdapter
       {
         // TODO obtain config value from preference settings.
         // Set value to 'true' to test PDB processing with Jmol: JAL-1213
-        boolean isParseWithJMOL = false;
+        boolean isParseWithJMOL = StructureImportSettings
+                .getDefaultPDBFileParser().equalsIgnoreCase(
+                        StructureImportSettings.StructureParser.JMOL_PARSER
+                                .toString());
         if (isParseWithJMOL)
         {
-          StructureViewSettings.addSettings(annotFromStructure,
+          StructureImportSettings.addSettings(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct);
-          alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
-                  localSecondaryStruct, serviceSecondaryStruct, inFile,
-                  type);
+          alignFile = new jalview.ext.jmol.JmolParser(inFile, type);
         }
         else
         {
-          StructureViewSettings.setShowSeqFeatures(true);
+          StructureImportSettings.addSettings(annotFromStructure,
+                  localSecondaryStruct, serviceSecondaryStruct);
+          StructureImportSettings.setShowSeqFeatures(true);
           alignFile = new MCview.PDBfile(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct, inFile,
                   type);
         }
+        ((StructureFile) alignFile).setDbRefType(format);
       }
-      else if (format.equals("mmCIF"))
+      else if (format.equalsIgnoreCase("mmCIF"))
       {
-        StructureViewSettings.addSettings(annotFromStructure,
+        StructureImportSettings.addSettings(annotFromStructure,
                 localSecondaryStruct, serviceSecondaryStruct);
-        alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
-                localSecondaryStruct, serviceSecondaryStruct, inFile, type);
+        alignFile = new jalview.ext.jmol.JmolParser(inFile, type);
+        ((StructureFile) alignFile).setDbRefType(format);
       }
       else if (format.equals("STH"))
       {
@@ -330,7 +336,7 @@ public class AppletFormatAdapter
       }
       else if (format.equals(IdentifyFile.FeaturesFile))
       {
-        alignFile = new FeaturesFile(inFile, type);
+        alignFile = new FeaturesFile(true, inFile, type);
       }
       return buildAlignmentFrom(alignFile);
     } catch (Exception e)
@@ -433,24 +439,24 @@ public class AppletFormatAdapter
         boolean isParseWithJMOL = false;
         if (isParseWithJMOL)
         {
-          StructureViewSettings.addSettings(annotFromStructure,
+          StructureImportSettings.addSettings(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct);
-          alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
-                  localSecondaryStruct, serviceSecondaryStruct, source);
+          alignFile = new JmolParser(source);
         }
         else
         {
-          StructureViewSettings.setShowSeqFeatures(true);
+          StructureImportSettings.setShowSeqFeatures(true);
           alignFile = new MCview.PDBfile(annotFromStructure,
                   localSecondaryStruct, serviceSecondaryStruct, source);
         }
+        ((StructureFile) alignFile).setDbRefType(Type.PDB);
       }
-      else if (format.equals("mmCIF"))
+      else if (format.equalsIgnoreCase("mmCIF"))
       {
-        StructureViewSettings.addSettings(annotFromStructure,
+        StructureImportSettings.addSettings(annotFromStructure,
                 localSecondaryStruct, serviceSecondaryStruct);
-        alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
-                localSecondaryStruct, serviceSecondaryStruct, source);
+        alignFile = new JmolParser(source);
+        ((StructureFile) alignFile).setDbRefType(Type.MMCIF);
       }
       else if (format.equals("STH"))
       {
index f8fa1f5..817f75c 100644 (file)
@@ -80,12 +80,15 @@ public class BioJsHTMLOutput
     }
   }
 
-  public void exportJalviewAlignmentAsBioJsHtmlFile()
+  public void exportJalviewAlignmentAsBioJsHtmlFile(String outputFile)
   {
-    String outputFile = null;
+    // String outputFile = null;
     try
     {
-      outputFile = getOutputFile();
+      if (outputFile == null)
+      {
+        outputFile = getOutputFile();
+      }
       AlignExportSettingI exportSettings = new AlignExportSettingI()
       {
         @Override
@@ -159,8 +162,11 @@ public class BioJsHTMLOutput
       new OOMWarning("Creating Image for " + outputFile, err);
     } catch (Exception e)
     {
+      if (pIndicator != null && !headless)
+      {
       pIndicator.setProgressBar(MessageManager.formatMessage(
               "info.error_creating_file", "HTML"), pSessionId);
+      }
       e.printStackTrace();
     }
   }
index 4c2265c..ec1c82e 100755 (executable)
@@ -174,8 +174,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 2dd5f26..73783e5 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.io;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.SequenceIdMatcher;
 import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
 import jalview.api.FeaturesSourceI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
@@ -33,15 +34,12 @@ import jalview.datamodel.SequenceI;
 import jalview.io.gff.GffHelperBase;
 import jalview.io.gff.GffHelperFactory;
 import jalview.io.gff.GffHelperI;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.UserColourScheme;
-import jalview.util.Format;
 import jalview.util.MapList;
 import jalview.util.ParseHtmlBodyAndLinks;
 import jalview.util.StringUtils;
 
-import java.awt.Color;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -50,7 +48,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.StringTokenizer;
 
 /**
  * Parses and writes features files, which may be in Jalview, GFF2 or GFF3
@@ -140,8 +137,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    *          - process html strings into plain text
    * @return true if features were added
    */
-  public boolean parse(AlignmentI align, Map<String, Object> colours,
-          boolean removeHTML)
+  public boolean parse(AlignmentI align,
+          Map<String, FeatureColourI> colours, boolean removeHTML)
   {
     return parse(align, colours, removeHTML, false);
   }
@@ -177,8 +174,9 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    *          - when true, ID matches to compound sequence IDs are allowed
    * @return true if features were added
    */
-  public boolean parse(AlignmentI align, Map<String, Object> colours,
-          boolean removeHTML, boolean relaxedIdmatching)
+  public boolean parse(AlignmentI align,
+          Map<String, FeatureColourI> colours, boolean removeHTML,
+          boolean relaxedIdmatching)
   {
     Map<String, String> gffProps = new HashMap<String, String>();
     /*
@@ -232,12 +230,18 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
           else if (ft.equalsIgnoreCase("endgroup"))
           {
             // We should check whether this is the current group,
-            // but at present theres no way of showing more than 1 group
+            // but at present there's no way of showing more than 1 group
             featureGroup = null;
           }
           else
           {
-            parseFeatureColour(line, ft, gffColumns, colours);
+            String colscheme = gffColumns[1];
+            FeatureColourI colour = FeatureColour
+                    .parseJalviewFeatureColour(colscheme);
+            if (colour != null)
+            {
+              colours.put(ft, colour);
+            }
           }
           continue;
         }
@@ -297,7 +301,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @param featureGroup
    */
   protected boolean parseJalviewFeature(String line, String[] gffColumns,
-          AlignmentI alignment, Map<String, Object> featureColours,
+          AlignmentI alignment, Map<String, FeatureColourI> featureColours,
           boolean removeHTML, boolean relaxedIdMatching, String featureGroup)
   {
     /*
@@ -350,7 +354,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
        * synthesize a colour from the feature type
        */
       UserColourScheme ucs = new UserColourScheme(ft);
-      featureColours.put(ft, ucs.findColour('A'));
+      featureColours.put(ft, new FeatureColour(ucs.findColour('A')));
     }
     SequenceFeature sf = new SequenceFeature(ft, desc, "", startPos,
             endPos, featureGroup);
@@ -381,225 +385,6 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
   }
 
   /**
-   * Process a feature type colour specification
-   * 
-   * @param line
-   *          the current input line (for error messages only)
-   * @param featureType
-   *          the first token on the line
-   * @param gffColumns
-   *          holds tokens on the line
-   * @param colours
-   *          map to which to add derived colour specification
-   */
-  protected void parseFeatureColour(String line, String featureType,
-          String[] gffColumns, Map<String, Object> colours)
-  {
-    Object colour = null;
-    String colscheme = gffColumns[1];
-    if (colscheme.indexOf("|") > -1
-            || colscheme.trim().equalsIgnoreCase("label"))
-    {
-      colour = parseGraduatedColourScheme(line, colscheme);
-    }
-    else
-    {
-      UserColourScheme ucs = new UserColourScheme(colscheme);
-      colour = ucs.findColour('A');
-    }
-    if (colour != null)
-    {
-      colours.put(featureType, colour);
-    }
-  }
-
-  /**
-   * Parse a Jalview graduated colour descriptor
-   * 
-   * @param line
-   * @param colourDescriptor
-   * @return
-   */
-  protected GraduatedColor parseGraduatedColourScheme(String line,
-          String colourDescriptor)
-  {
-    // Parse '|' separated graduated colourscheme fields:
-    // [label|][mincolour|maxcolour|[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue]
-    // can either provide 'label' only, first is optional, next two
-    // colors are required (but may be
-    // left blank), next is optional, nxt two min/max are required.
-    // first is either 'label'
-    // first/second and third are both hexadecimal or word equivalent
-    // colour.
-    // next two are values parsed as floats.
-    // fifth is either 'above','below', or 'none'.
-    // sixth is a float value and only required when fifth is either
-    // 'above' or 'below'.
-    StringTokenizer gcol = new StringTokenizer(colourDescriptor, "|", true);
-    // set defaults
-    float min = Float.MIN_VALUE, max = Float.MAX_VALUE;
-    boolean labelCol = false;
-    // Parse spec line
-    String mincol = gcol.nextToken();
-    if (mincol == "|")
-    {
-      System.err
-              .println("Expected either 'label' or a colour specification in the line: "
-                      + line);
-      return null;
-    }
-    String maxcol = null;
-    if (mincol.toLowerCase().indexOf("label") == 0)
-    {
-      labelCol = true;
-      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null); // skip '|'
-      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
-    }
-    String abso = null, minval, maxval;
-    if (mincol != null)
-    {
-      // at least four more tokens
-      if (mincol.equals("|"))
-      {
-        mincol = "";
-      }
-      else
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      // continue parsing rest of line
-      maxcol = gcol.nextToken();
-      if (maxcol.equals("|"))
-      {
-        maxcol = "";
-      }
-      else
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      abso = gcol.nextToken();
-      gcol.nextToken(); // skip next '|'
-      if (abso.toLowerCase().indexOf("abso") != 0)
-      {
-        minval = abso;
-        abso = null;
-      }
-      else
-      {
-        minval = gcol.nextToken();
-        gcol.nextToken(); // skip next '|'
-      }
-      maxval = gcol.nextToken();
-      if (gcol.hasMoreTokens())
-      {
-        gcol.nextToken(); // skip next '|'
-      }
-      try
-      {
-        if (minval.length() > 0)
-        {
-          min = Float.valueOf(minval);
-        }
-      } catch (Exception e)
-      {
-        System.err
-                .println("Couldn't parse the minimum value for graduated colour for type ("
-                        + colourDescriptor
-                        + ") - did you misspell 'auto' for the optional automatic colour switch ?");
-        e.printStackTrace();
-      }
-      try
-      {
-        if (maxval.length() > 0)
-        {
-          max = Float.valueOf(maxval);
-        }
-      } catch (Exception e)
-      {
-        System.err
-                .println("Couldn't parse the maximum value for graduated colour for type ("
-                        + colourDescriptor + ")");
-        e.printStackTrace();
-      }
-    }
-    else
-    {
-      // add in some dummy min/max colours for the label-only
-      // colourscheme.
-      mincol = "FFFFFF";
-      maxcol = "000000";
-    }
-
-    GraduatedColor colour = null;
-    try
-    {
-      colour = new GraduatedColor(
-              new UserColourScheme(mincol).findColour('A'),
-              new UserColourScheme(maxcol).findColour('A'), min, max);
-    } catch (Exception e)
-    {
-      System.err.println("Couldn't parse the graduated colour scheme ("
-              + colourDescriptor + ")");
-      e.printStackTrace();
-    }
-    if (colour != null)
-    {
-      colour.setColourByLabel(labelCol);
-      colour.setAutoScaled(abso == null);
-      // add in any additional parameters
-      String ttype = null, tval = null;
-      if (gcol.hasMoreTokens())
-      {
-        // threshold type and possibly a threshold value
-        ttype = gcol.nextToken();
-        if (ttype.toLowerCase().startsWith("below"))
-        {
-          colour.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
-        }
-        else if (ttype.toLowerCase().startsWith("above"))
-        {
-          colour.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
-        }
-        else
-        {
-          colour.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
-          if (!ttype.toLowerCase().startsWith("no"))
-          {
-            System.err.println("Ignoring unrecognised threshold type : "
-                    + ttype);
-          }
-        }
-      }
-      if (colour.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
-      {
-        try
-        {
-          gcol.nextToken();
-          tval = gcol.nextToken();
-          colour.setThresh(new Float(tval).floatValue());
-        } catch (Exception e)
-        {
-          System.err.println("Couldn't parse threshold value as a float: ("
-                  + tval + ")");
-          e.printStackTrace();
-        }
-      }
-      // parse the thresh-is-min token ?
-      if (gcol.hasMoreTokens())
-      {
-        System.err
-                .println("Ignoring additional tokens in parameters in graduated colour specification\n");
-        while (gcol.hasMoreTokens())
-        {
-          System.err.println("|" + gcol.nextToken());
-        }
-        System.err.println("\n");
-      }
-    }
-    return colour;
-  }
-
-  /**
    * clear any temporary handles used to speed up ID matching
    */
   protected void resetMatcher()
@@ -703,7 +488,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return features file contents
    */
   public String printJalviewFormat(SequenceI[] sequences,
-          Map<String, Object> visible)
+          Map<String, FeatureColourI> visible)
   {
     return printJalviewFormat(sequences, visible, true, true);
   }
@@ -723,7 +508,8 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return features file contents
    */
   public String printJalviewFormat(SequenceI[] sequences,
-          Map<String, Object> visible, boolean visOnly, boolean nonpos)
+          Map<String, FeatureColourI> visible, boolean visOnly,
+          boolean nonpos)
   {
     StringBuilder out = new StringBuilder(256);
     boolean featuresGen = false;
@@ -739,58 +525,14 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
       // viewed features
       // TODO: decide if feature links should also be written here ?
       Iterator<String> en = visible.keySet().iterator();
-      String featureType, color;
       while (en.hasNext())
       {
-        featureType = en.next().toString();
-
-        if (visible.get(featureType) instanceof GraduatedColor)
-        {
-          GraduatedColor gc = (GraduatedColor) visible.get(featureType);
-          color = (gc.isColourByLabel() ? "label|" : "")
-                  + Format.getHexString(gc.getMinColor()) + "|"
-                  + Format.getHexString(gc.getMaxColor())
-                  + (gc.isAutoScale() ? "|" : "|abso|") + gc.getMin() + "|"
-                  + gc.getMax() + "|";
-          if (gc.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
-          {
-            if (gc.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
-            {
-              color += "below";
-            }
-            else
-            {
-              if (gc.getThreshType() != AnnotationColourGradient.ABOVE_THRESHOLD)
-              {
-                System.err.println("WARNING: Unsupported threshold type ("
-                        + gc.getThreshType() + ") : Assuming 'above'");
-              }
-              color += "above";
-            }
-            // add the value
-            color += "|" + gc.getThresh();
-          }
-          else
-          {
-            color += "none";
-          }
-        }
-        else if (visible.get(featureType) instanceof Color)
-        {
-          color = Format.getHexString((Color) visible.get(featureType));
-        }
-        else
-        {
-          // legacy support for integer objects containing colour triplet values
-          color = Format.getHexString(new Color(Integer.parseInt(visible
-                  .get(featureType).toString())));
-        }
-        out.append(featureType);
-        out.append(TAB);
-        out.append(color);
-        out.append(newline);
+        String featureType = en.next().toString();
+        FeatureColourI colour = visible.get(featureType);
+        out.append(colour.toJalviewFormat(featureType)).append(newline);
       }
     }
+
     // Work out which groups are both present and visible
     List<String> groups = new ArrayList<String>();
     int groupIndex = 0;
@@ -842,12 +584,13 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
         features = sequences[i].getSequenceFeatures();
         if (features != null)
         {
-          for (int j = 0; j < features.length; j++)
+          for (SequenceFeature sequenceFeature : features)
           {
-            isnonpos = features[j].begin == 0 && features[j].end == 0;
+            isnonpos = sequenceFeature.begin == 0
+                    && sequenceFeature.end == 0;
             if ((!nonpos && isnonpos)
                     || (!isnonpos && visOnly && !visible
-                            .containsKey(features[j].type)))
+                            .containsKey(sequenceFeature.type)))
             {
               // skip if feature is nonpos and we ignore them or if we only
               // output visible and it isn't non-pos and it's not visible
@@ -855,47 +598,48 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
             }
 
             if (group != null
-                    && (features[j].featureGroup == null || !features[j].featureGroup
+                    && (sequenceFeature.featureGroup == null || !sequenceFeature.featureGroup
                             .equals(group)))
             {
               continue;
             }
 
-            if (group == null && features[j].featureGroup != null)
+            if (group == null && sequenceFeature.featureGroup != null)
             {
               continue;
             }
             // we have features to output
             featuresGen = true;
-            if (features[j].description == null
-                    || features[j].description.equals(""))
+            if (sequenceFeature.description == null
+                    || sequenceFeature.description.equals(""))
             {
-              out.append(features[j].type).append(TAB);
+              out.append(sequenceFeature.type).append(TAB);
             }
             else
             {
-              if (features[j].links != null
-                      && features[j].getDescription().indexOf("<html>") == -1)
+              if (sequenceFeature.links != null
+                      && sequenceFeature.getDescription().indexOf("<html>") == -1)
               {
                 out.append("<html>");
               }
 
-              out.append(features[j].description + " ");
-              if (features[j].links != null)
+              out.append(sequenceFeature.description);
+              if (sequenceFeature.links != null)
               {
-                for (int l = 0; l < features[j].links.size(); l++)
+                for (int l = 0; l < sequenceFeature.links.size(); l++)
                 {
-                  String label = features[j].links.elementAt(l).toString();
+                  String label = sequenceFeature.links.elementAt(l);
                   String href = label.substring(label.indexOf("|") + 1);
                   label = label.substring(0, label.indexOf("|"));
 
-                  if (features[j].description.indexOf(href) == -1)
+                  if (sequenceFeature.description.indexOf(href) == -1)
                   {
-                    out.append("<a href=\"" + href + "\">" + label + "</a>");
+                    out.append(" <a href=\"" + href + "\">" + label
+                            + "</a>");
                   }
                 }
 
-                if (features[j].getDescription().indexOf("</html>") == -1)
+                if (sequenceFeature.getDescription().indexOf("</html>") == -1)
                 {
                   out.append("</html>");
                 }
@@ -905,15 +649,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
             }
             out.append(sequences[i].getName());
             out.append("\t-1\t");
-            out.append(features[j].begin);
+            out.append(sequenceFeature.begin);
             out.append(TAB);
-            out.append(features[j].end);
+            out.append(sequenceFeature.end);
             out.append(TAB);
-            out.append(features[j].type);
-            if (!Float.isNaN(features[j].score))
+            out.append(sequenceFeature.type);
+            if (!Float.isNaN(sequenceFeature.score))
             {
               out.append(TAB);
-              out.append(features[j].score);
+              out.append(sequenceFeature.score);
             }
             out.append(newline);
           }
@@ -1003,7 +747,7 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return
    */
   public String printGffFormat(SequenceI[] sequences,
-          Map<String, Object> visible)
+          Map<String, FeatureColourI> visible)
   {
     return printGffFormat(sequences, visible, true, true);
   }
@@ -1020,11 +764,12 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * @return
    */
   public String printGffFormat(SequenceI[] sequences,
-          Map<String, Object> visible, boolean outputVisibleOnly,
+          Map<String, FeatureColourI> visible, boolean outputVisibleOnly,
           boolean includeNonPositionalFeatures)
   {
     StringBuilder out = new StringBuilder(256);
-    out.append(String.format("%s %d\n", GFF_VERSION, gffVersion));
+    int version = gffVersion == 0 ? 2 : gffVersion;
+    out.append(String.format("%s %d\n", GFF_VERSION, version));
     String source;
     boolean isnonpos;
     for (SequenceI seq : sequences)
index 4ec077f..6d94616 100755 (executable)
@@ -305,20 +305,6 @@ public class FormatAdapter extends AppletFormatAdapter
     return this.formatSequences(format, alignment, suffix);
   }
 
-  public AlignmentI readFile(String inFile, String type, String format)
-          throws java.io.IOException
-  {
-    AlignmentI al = super.readFile(inFile, type, format);
-    return al;
-  }
-
-  public AlignmentI readFromFile(FileParse source, String format)
-          throws java.io.IOException
-  {
-    AlignmentI al = super.readFromFile(source, format);
-    return al;
-  }
-
   /**
    * validate format is valid for IO in Application. This is basically the
    * AppletFormatAdapter.isValidFormat call with additional checks for
index e554b8e..decb06f 100644 (file)
@@ -51,6 +51,12 @@ public class HtmlSvgOutput
 
   AlignmentPanel ap;
 
+  private IProgressIndicator pIndicator;
+
+  private long pSessionId;
+
+  private boolean headless;
+
   public HtmlSvgOutput(File file, AlignmentPanel ap)
   {
     this.av = ap.av;
@@ -61,20 +67,16 @@ public class HtmlSvgOutput
 
   public void generateHtmlSvgOutput(File file)
   {
-    IProgressIndicator pIndicator = ap.alignFrame;
-    long pSessionId = System.currentTimeMillis();
+    pIndicator = ap.alignFrame;
+    pSessionId = System.currentTimeMillis();
     try
     {
-      boolean headless = (System.getProperty("java.awt.headless") != null && System
+      headless = (System.getProperty("java.awt.headless") != null && System
               .getProperty("java.awt.headless").equals("true"));
       if (file == null)
       {
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(MessageManager.formatMessage(
-                  "status.waiting_for_user_to_select_output_file", "HTML"),
-                  pSessionId);
-        }
+        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());
@@ -86,135 +88,172 @@ public class HtmlSvgOutput
           jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
                   .getSelectedFile().getParent());
           file = chooser.getSelectedFile();
+          ap.alignFrame.repaint();
         }
         else
         {
-
-          if (pIndicator != null && !headless)
-        {
-            pIndicator.setProgressBar(MessageManager.formatMessage(
-                    "status.cancelled_image_export_operation", "HTML"),
-                    pSessionId);
-          }
-          return;
-        }
-      }
-
-      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)
+    } catch (Exception e)
+    {
+      pIndicator.setProgressBar(MessageManager.formatMessage(
+              "info.error_creating_file", "HTML"), pSessionId);
+      e.printStackTrace();
+      return;
+    }
+    final File fileX = file;
+    new Thread()
+    {
+      @Override
+      public void run()
       {
-        AlignExportSettingI exportSettings = new AlignExportSettingI()
+        try
         {
-          @Override
-          public boolean isExportHiddenSequences()
+          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")))
           {
-            return true;
+            HTMLOptions svgOption = new HTMLOptions();
+            renderStyle = svgOption.getValue();
+
+            if (renderStyle == null || svgOption.cancelled)
+            {
+              setProgressMessage(MessageManager.formatMessage(
+                      "status.cancelled_image_export_operation", "HTML"));
+              return;
+            }
           }
 
-          @Override
-          public boolean isExportHiddenColumns()
+          if (renderStyle.equalsIgnoreCase("Lineart"))
           {
-            return true;
+            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);
           }
-
-          @Override
-          public boolean isExportAnnotations()
+          if (av.getWrapAlignment())
           {
-            return true;
+            printWrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
+                    g1, g2);
           }
-
-          @Override
-          public boolean isExportFeatures()
+          else
           {
-            return true;
+          printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0,
+                  g1, g2);
           }
 
-          @Override
-          public boolean isExportGroups()
+          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)
           {
-            return true;
+            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(JSONFile.FILE_DESC, av,
+                            exportSettings);
+            jsonData = new FormatAdapter(ap, exportData.getSettings())
+                    .formatSequences(JSONFile.FILE_DESC,
+                            exportData.getAlignment(),
+                            exportData.getOmitHidden(),
+                            exportData.getStartEndPostions(),
+                            av.getColumnSelection());
           }
-
-          @Override
-          public boolean isCancelled()
+          String htmlData = getHtml(titleSvgData, alignSvgData, jsonData,
+                  av.getWrapAlignment());
+          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")))
           {
-            return false;
+            jalview.util.BrowserLauncher.openURL("file:///" + fileX);
           }
-
-        };
-        AlignmentExportData exportData = jalview.gui.AlignFrame
-                .getAlignmentForExport(JSONFile.FILE_DESC, av,
-                        exportSettings);
-        jsonData = new FormatAdapter(ap, exportData.getSettings())
-                .formatSequences(JSONFile.FILE_DESC,
-                        exportData.getAlignment(),
-                        exportData.getOmitHidden(),
-                        exportData.getStartEndPostions(),
-                        av.getColumnSelection());
-      }
-      String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
-      FileOutputStream out = new FileOutputStream(file);
-      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:///" + file);
-      }
-      if (pIndicator != null && !headless)
-      {
-        pIndicator.setProgressBar(MessageManager.formatMessage(
-                "status.export_complete", "HTML"), pSessionId);
+        } 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"));
       }
-    } catch (OutOfMemoryError err)
+    }.start();
+
+  }
+
+  private void setProgressMessage(String message)
+  {
+    if (pIndicator != null && !headless)
     {
-      System.out.println("########################\n" + "OUT OF MEMORY "
-              + file + "\n" + "########################");
-      new OOMWarning("Creating Image for " + file, err);
-    } catch (Exception e)
+      pIndicator.setProgressBar(message, pSessionId);
+    }
+    else
     {
-      e.printStackTrace();
-      pIndicator.setProgressBar(MessageManager.formatMessage(
-              "info.error_creating_file", "HTML"), pSessionId);
+      System.out.println(message);
     }
   }
 
@@ -358,8 +397,14 @@ public class HtmlSvgOutput
     return Printable.PAGE_EXISTS;
   }
 
+  public int printWrapped(int pwidth, int pheight, int pi, Graphics... pg)
+          throws PrinterException
+  {
+    return ap.printWrappedAlignment(pg[1], pwidth, pheight, pi);
+  }
+
   private String getHtml(String titleSvg, String alignmentSvg,
-          String jsonData)
+          String jsonData, boolean wrapped)
   {
     StringBuilder htmlSvg = new StringBuilder();
     htmlSvg.append("<html>\n");
@@ -399,8 +444,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");
@@ -421,6 +467,15 @@ 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
 
index 71f4237..deae9ae 100755 (executable)
@@ -230,7 +230,6 @@ public class IdentifyFile
                 } catch (IOException ex)
                 {
                 }
-                ;
                 if (dta != null && dta.indexOf("*") > -1)
                 {
                   starterm = true;
@@ -250,34 +249,19 @@ public class IdentifyFile
           // read as a FASTA (probably)
           break;
         }
-        if ((data.indexOf("<") > -1)) // possible Markup Language data i.e HTML,
-                                      // RNAML, XML
+        int lessThan = data.indexOf("<");
+        if ((lessThan > -1)) // possible Markup Language data i.e HTML,
+                             // RNAML, XML
         {
-          // FIXME this is nuts - it consumes the rest of the file if no match
-          boolean identified = false;
-          do
-          {
-            if (data.matches("<(?i)html(\"[^\"]*\"|'[^']*'|[^'\">])*>"))
-            {
-              reply = HtmlFile.FILE_DESC;
-              identified = true;
-              break;
-            }
-
-            if (data.matches("<(?i)rnaml (\"[^\"]*\"|'[^']*'|[^'\">])*>"))
-            {
-              reply = "RNAML";
-              identified = true;
-              break;
-            }
-          } while ((data = source.nextLine()) != null);
-
-          if (identified)
+          String upper = data.toUpperCase();
+          if (upper.substring(lessThan).startsWith("<HTML"))
           {
+            reply = HtmlFile.FILE_DESC;
             break;
           }
-          if (data == null)
+          if (upper.substring(lessThan).startsWith("<RNAML"))
           {
+            reply = "RNAML";
             break;
           }
         }
@@ -377,8 +361,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
    */
@@ -389,14 +374,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 36980f8..653c071 100644 (file)
@@ -735,6 +735,10 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
   @Override
   public void configureForView(AlignmentViewPanel avpanel)
   {
+    if (avpanel == null)
+    {
+      return;
+    }
     super.configureForView(avpanel);
     AlignViewportI viewport = avpanel.getAlignViewport();
     AlignmentI alignment = viewport.getAlignment();
@@ -744,11 +748,14 @@ public class JSONFile extends AlignFile implements ComplexAlignFile
     fr = avpanel.cloneFeatureRenderer();
 
     // Add non auto calculated annotation to AlignFile
-    for (AlignmentAnnotation annot : annots)
+    if (annots != null)
     {
-      if (annot != null && !annot.autoCalculated)
+      for (AlignmentAnnotation annot : annots)
       {
-        annotations.add(annot);
+        if (annot != null && !annot.autoCalculated)
+        {
+          annotations.add(annot);
+        }
       }
     }
     globalColourScheme = ColourSchemeProperty.getColourName(viewport
index f62ad81..7e46978 100755 (executable)
@@ -22,12 +22,14 @@ package jalview.io;
 
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 import jalview.util.Format;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.StringTokenizer;
-import java.util.Vector;
 
 /**
  * DOCUMENT ME!
@@ -67,24 +69,23 @@ public class MSFfile extends AlignFile
   }
 
   /**
-   * DOCUMENT ME!
+   * Read and parse MSF sequence data
    */
   @Override
   public void parse() throws IOException
   {
-    int i = 0;
     boolean seqFlag = false;
-    String key = new String();
-    Vector headers = new Vector();
-    Hashtable seqhash = new Hashtable();
-    String line;
+    List<String> headers = new ArrayList<String>();
+    Hashtable<String, StringBuilder> seqhash = new Hashtable<String, StringBuilder>();
 
     try
     {
+      String line;
       while ((line = nextLine()) != null)
       {
         StringTokenizer str = new StringTokenizer(line);
 
+        String key = null;
         while (str.hasMoreTokens())
         {
           String inStr = str.nextToken();
@@ -93,31 +94,31 @@ public class MSFfile extends AlignFile
           if (inStr.indexOf("Name:") != -1)
           {
             key = str.nextToken();
-            headers.addElement(key);
+            headers.add(key);
           }
 
-          // if line has // set SeqFlag to 1 so we know sequences are coming
+          // if line has // set SeqFlag so we know sequences are coming
           if (inStr.indexOf("//") != -1)
           {
             seqFlag = true;
           }
 
           // Process lines as sequence lines if seqFlag is set
-          if ((inStr.indexOf("//") == -1) && (seqFlag == true))
+          if ((inStr.indexOf("//") == -1) && seqFlag)
           {
-            // seqeunce id is the first field
+            // sequence id is the first field
             key = inStr;
 
-            StringBuffer tempseq;
+            StringBuilder tempseq;
 
             // Get sequence from hash if it exists
             if (seqhash.containsKey(key))
             {
-              tempseq = (StringBuffer) seqhash.get(key);
+              tempseq = seqhash.get(key);
             }
             else
             {
-              tempseq = new StringBuffer();
+              tempseq = new StringBuilder(64);
               seqhash.put(key, tempseq);
             }
 
@@ -125,7 +126,8 @@ public class MSFfile extends AlignFile
             while (str.hasMoreTokens())
             {
               // append the word to the sequence
-              tempseq.append(str.nextToken());
+              String sequenceBlock = str.nextToken();
+              tempseq.append(sequenceBlock);
             }
           }
         }
@@ -139,11 +141,11 @@ public class MSFfile extends AlignFile
     this.noSeqs = headers.size();
 
     // Add sequences to the hash
-    for (i = 0; i < headers.size(); i++)
+    for (int i = 0; i < headers.size(); i++)
     {
-      if (seqhash.get(headers.elementAt(i)) != null)
+      if (seqhash.get(headers.get(i)) != null)
       {
-        String head = headers.elementAt(i).toString();
+        String head = headers.get(i);
         String seq = seqhash.get(head).toString();
 
         if (maxLength < head.length())
@@ -151,8 +153,11 @@ public class MSFfile extends AlignFile
           maxLength = head.length();
         }
 
-        // Replace ~ with a sensible gap character
-        seq = seq.replace('~', '-');
+        /*
+         * replace ~ (leading/trailing positions) with the gap character;
+         * use '.' as this is the internal gap character required by MSF
+         */
+        seq = seq.replace('~', '.');
 
         Sequence newSeq = parseId(head);
 
@@ -163,7 +168,7 @@ public class MSFfile extends AlignFile
       else
       {
         System.err.println("MSFFile Parser: Can't find sequence for "
-                + headers.elementAt(i));
+                + headers.get(i));
       }
     }
   }
@@ -211,15 +216,16 @@ public class MSFfile extends AlignFile
    * 
    * @return DOCUMENT ME!
    */
-  public String print(SequenceI[] seqs)
+  public String print(SequenceI[] sqs)
   {
 
-    boolean is_NA = jalview.util.Comparison.isNucleotide(seqs);
+    boolean is_NA = Comparison.isNucleotide(sqs);
 
-    SequenceI[] s = new SequenceI[seqs.length];
+    SequenceI[] s = new SequenceI[sqs.length];
 
-    StringBuffer out = new StringBuffer("!!" + (is_NA ? "NA" : "AA")
-            + "_MULTIPLE_ALIGNMENT 1.0");
+    StringBuilder out = new StringBuilder(256);
+    out.append("!!").append(is_NA ? "NA" : "AA")
+            .append("_MULTIPLE_ALIGNMENT 1.0");
     // TODO: JBPNote : Jalview doesn't remember NA or AA yet.
     out.append(newline);
     out.append(newline);
@@ -227,14 +233,15 @@ public class MSFfile extends AlignFile
     int maxid = 0;
     int i = 0;
 
-    while ((i < seqs.length) && (seqs[i] != null))
+    while ((i < sqs.length) && (sqs[i] != null))
     {
-      // Replace all internal gaps with . and external spaces with ~
-      s[i] = new Sequence(seqs[i].getName(), seqs[i].getSequenceAsString()
-              .replace('-', '.'), seqs[i].getStart(), seqs[i].getEnd());
+      /*
+       * modify to MSF format: uses '.' for internal gaps, 
+       * and '~' for leading or trailing gaps
+       */
+      String seqString = sqs[i].getSequenceAsString().replace('-', '.');
 
-      StringBuffer sb = new StringBuffer();
-      sb.append(s[i].getSequence());
+      StringBuilder sb = new StringBuilder(seqString);
 
       for (int ii = 0; ii < sb.length(); ii++)
       {
@@ -259,12 +266,12 @@ public class MSFfile extends AlignFile
           break;
         }
       }
+      s[i] = new Sequence(sqs[i].getName(), sb.toString(),
+              sqs[i].getStart(), sqs[i].getEnd());
 
-      s[i].setSequence(sb.toString());
-
-      if (s[i].getSequence().length > max)
+      if (sb.length() > max)
       {
-        max = s[i].getSequence().length;
+        max = sb.length();
       }
 
       i++;
index 83bb37e..746c4a7 100644 (file)
@@ -1,17 +1,37 @@
+/*
+ * 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;
-import jalview.schemes.FeatureColourAdapter;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.FeatureSettingsAdapter;
 
 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)
@@ -25,7 +45,7 @@ public class PDBFeatureSettings extends FeatureSettingsAdapter
   {
     if (type.equalsIgnoreCase(FEATURE_INSERTION))
     {
-      return new FeatureColourAdapter()
+      return new FeatureColour()
       {
 
         @Override
@@ -63,4 +83,3 @@ public class PDBFeatureSettings extends FeatureSettingsAdapter
     return 0;
   }
 }
-
index 71cc7f0..e71bb4b 100755 (executable)
@@ -108,7 +108,7 @@ public class PfamFile extends AlignFile
       }
       if (spces + 1 < line.length())
       {
-        tempseq.append(line.substring(spces + 1));
+        tempseq.append(line.substring(spces + 1).trim());
       }
     }
 
@@ -124,8 +124,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 0941a6f..f48f825 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.io;
 
-import jalview.analysis.SecStrConsensus.SimpleBP;
+import jalview.analysis.Rna;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.Sequence;
@@ -32,6 +32,7 @@ import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.List;
 
 import com.stevesoft.pat.Regex;
 
@@ -79,6 +80,7 @@ public class RnamlFile extends AlignFile
    * 
    * @see jalview.io.AlignFile#parse()
    */
+  @Override
   public void parse() throws IOException
   {
     if (System.getProperty("java.version").indexOf("1.6") > -1
@@ -134,10 +136,10 @@ public class RnamlFile extends AlignFile
 
     result = RNAFactory.loadSecStrRNAML(getReader());
 
-    ArrayList<ArrayList> allarray = new ArrayList();
-    ArrayList<ArrayList<SimpleBP>> BP = new ArrayList();
-    ArrayList strucinarray = new ArrayList();
-    SequenceI[] seqs = new SequenceI[result.size()];
+    // ArrayList<ArrayList> allarray = new ArrayList();
+    // ArrayList<ArrayList<SimpleBP>> BP = new ArrayList();
+    // ArrayList strucinarray = new ArrayList();
+    SequenceI[] sqs = new SequenceI[result.size()];
 
     for (int i = 0; i < result.size(); i++)
     {
@@ -157,9 +159,9 @@ public class RnamlFile extends AlignFile
           id += "." + i;
         }
       }
-      seqs[i] = new Sequence(id, seq, begin, end);
+      sqs[i] = new Sequence(id, seq, begin, end);
 
-      seqs[i].setEnd(seqs[i].findPosition(seqs[i].getLength()));
+      sqs[i].setEnd(sqs[i].findPosition(sqs[i].getLength()));
       String[] annot = new String[rna.length()];
       Annotation[] ann = new Annotation[rna.length()];
 
@@ -170,9 +172,8 @@ public class RnamlFile extends AlignFile
       }
       for (int k = 0; k < rna.length(); k++)
       {
-        ann[k] = new Annotation(annot[k], "",
-                jalview.schemes.ResidueProperties.getRNASecStrucState(
-                        annot[k]).charAt(0), 0f);
+        ann[k] = new Annotation(annot[k], "", Rna.getRNASecStrucState(
+                annot[k]).charAt(0), 0f);
       }
 
       AlignmentAnnotation align = new AlignmentAnnotation(
@@ -181,17 +182,17 @@ public class RnamlFile extends AlignFile
                       + current.getID()
                       : "", ann);
 
-      seqs[i].addAlignmentAnnotation(align);
-      seqs[i].setRNA(result.get(i));
+      sqs[i].addAlignmentAnnotation(align);
+      sqs[i].setRNA(result.get(i));
 
-      allarray.add(strucinarray);
+      // allarray.add(strucinarray);
 
       annotations.addElement(align);
-      BP.add(align.bps);
+      // BP.add(align.bps);
 
     }
 
-    setSeqs(seqs);
+    setSeqs(sqs);
   }
 
   public static String print(SequenceI[] s)
@@ -199,13 +200,14 @@ public class RnamlFile extends AlignFile
     return "not yet implemented";
   }
 
+  @Override
   public String print()
   {
     System.out.print("print :");
     return print(getSeqsAsArray());
   }
 
-  public ArrayList getRNA()
+  public List<RNA> getRNA()
   {
     return result;
   }
index 96d71f6..59daa87 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.Collections;
 import java.util.Comparator;
-import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 
 /**
  * generate HTML reports for a sequence
@@ -39,6 +42,18 @@ import java.util.List;
  */
 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;
 
   /*
@@ -46,11 +61,22 @@ public class SequenceAnnotationReport
    */
   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)
@@ -62,6 +88,21 @@ public class SequenceAnnotationReport
       }
       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)
@@ -70,160 +111,182 @@ public class SequenceAnnotationReport
   }
 
   /**
-   * appends the features at rpos to the given stringbuffer ready for display in
-   * a tooltip
+   * Append text for the list of features to the tooltip
    * 
-   * @param tooltipText
-   * @param linkImageURL
+   * @param sb
    * @param rpos
    * @param features
    * @param minmax
-   *          TODO refactor to Jalview 'utilities' somehow.
    */
-  public void appendFeatures(final StringBuilder tooltipText, int rpos,
-          List<SequenceFeature> features, Hashtable minmax)
+  public void appendFeatures(final StringBuilder sb, int rpos,
+          List<SequenceFeature> features, Map<String, float[][]> minmax)
   {
-    String tmpString;
     if (features != null)
     {
       for (SequenceFeature feature : features)
       {
-        if (feature.getType().equals("disulfide bond"))
+        appendFeature(sb, rpos, minmax, feature);
+      }
+    }
+  }
+
+  /**
+   * Appends the feature at rpos to the given buffer
+   * 
+   * @param sb
+   * @param rpos
+   * @param minmax
+   * @param feature
+   */
+  void appendFeature(final StringBuilder sb, int rpos,
+          Map<String, float[][]> minmax, SequenceFeature feature)
+  {
+    String tmpString;
+    if (feature.getType().equals("disulfide bond"))
+    {
+      if (feature.getBegin() == rpos || feature.getEnd() == rpos)
+      {
+        if (sb.length() > 6)
         {
-          if (feature.getBegin() == rpos || feature.getEnd() == rpos)
-          {
-            if (tooltipText.length() > 6)
-            {
-              tooltipText.append("<br>");
-            }
-            tooltipText.append("disulfide bond " + feature.getBegin()
-                    + ":" + feature.getEnd());
-          }
+          sb.append("<br>");
         }
-        else
+        sb.append("disulfide bond ").append(feature.getBegin()).append(":")
+                .append(feature.getEnd());
+      }
+    }
+    else
+    {
+      if (sb.length() > 6)
+      {
+        sb.append("<br>");
+      }
+      // TODO: remove this hack to display link only features
+      boolean linkOnly = feature.getValue("linkonly") != null;
+      if (!linkOnly)
+      {
+        sb.append(feature.getType()).append(" ");
+        if (rpos != 0)
         {
-          if (tooltipText.length() > 6)
+          // we are marking a positional feature
+          sb.append(feature.begin);
+        }
+        if (feature.begin != feature.end)
+        {
+          sb.append(" ").append(feature.end);
+        }
+
+        if (feature.getDescription() != null
+                && !feature.description.equals(feature.getType()))
+        {
+          tmpString = feature.getDescription();
+          String tmp2up = tmpString.toUpperCase();
+          int startTag = tmp2up.indexOf("<HTML>");
+          if (startTag > -1)
           {
-            tooltipText.append("<br>");
+            tmpString = tmpString.substring(startTag + 6);
+            tmp2up = tmp2up.substring(startTag + 6);
           }
-          // TODO: remove this hack to display link only features
-          boolean linkOnly = feature.getValue("linkonly") != null;
-          if (!linkOnly)
+          int endTag = tmp2up.indexOf("</BODY>");
+          if (endTag > -1)
           {
-            tooltipText.append(feature.getType() + " ");
-            if (rpos != 0)
-            {
-              // we are marking a positional feature
-              tooltipText.append(feature.begin);
-            }
-            if (feature.begin != feature.end)
-            {
-              tooltipText.append(" " + feature.end);
-            }
+            tmpString = tmpString.substring(0, endTag);
+            tmp2up = tmp2up.substring(0, endTag);
+          }
+          endTag = tmp2up.indexOf("</HTML>");
+          if (endTag > -1)
+          {
+            tmpString = tmpString.substring(0, endTag);
+          }
 
-            if (feature.getDescription() != null
-                    && !feature.description.equals(feature.getType()))
+          if (startTag > -1)
+          {
+            sb.append("; ").append(tmpString);
+          }
+          else
+          {
+            if (tmpString.indexOf("<") > -1 || tmpString.indexOf(">") > -1)
             {
-              tmpString = feature.getDescription();
-              String tmp2up = tmpString.toUpperCase();
-              int startTag = tmp2up.indexOf("<HTML>");
-              if (startTag > -1)
-              {
-                tmpString = tmpString.substring(startTag + 6);
-                tmp2up = tmp2up.substring(startTag + 6);
-              }
-              int endTag = tmp2up.indexOf("</BODY>");
-              if (endTag > -1)
-              {
-                tmpString = tmpString.substring(0, endTag);
-                tmp2up = tmp2up.substring(0, endTag);
-              }
-              endTag = tmp2up.indexOf("</HTML>");
-              if (endTag > -1)
-              {
-                tmpString = tmpString.substring(0, endTag);
-              }
-
-              if (startTag > -1)
-              {
-                tooltipText.append("; " + tmpString);
-              }
-              else
-              {
-                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;");
+              // The description does not specify html is to
+              // be used, so we must remove < > symbols
+              tmpString = tmpString.replaceAll("<", "&lt;");
+              tmpString = tmpString.replaceAll(">", "&gt;");
 
-                  tooltipText.append("; ");
-                  tooltipText.append(tmpString);
-
-                }
-                else
-                {
-                  tooltipText.append("; " + tmpString);
-                }
-              }
+              sb.append("; ");
+              sb.append(tmpString);
             }
-            // check score should be shown
-            if (!Float.isNaN(feature.getScore()))
+            else
             {
-              float[][] rng = (minmax == null) ? null : ((float[][]) minmax
-                      .get(feature.getType()));
-              if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
-              {
-                tooltipText.append(" Score=" + feature.getScore());
-              }
-            }
-            if (feature.getValue("status") != null)
-            {
-              String status = feature.getValue("status").toString();
-              if (status.length() > 0)
-              {
-                tooltipText.append("; (" + feature.getValue("status")
-                        + ")");
-              }
+              sb.append("; ").append(tmpString);
             }
           }
         }
-        if (feature.links != null)
+        // check score should be shown
+        if (!Float.isNaN(feature.getScore()))
         {
-          if (linkImageURL != null)
+          float[][] rng = (minmax == null) ? null : ((float[][]) minmax
+                  .get(feature.getType()));
+          if (rng != null && rng[0] != null && rng[0][0] != rng[0][1])
           {
-            tooltipText.append(" <img src=\"" + linkImageURL + "\">");
+            sb.append(" Score=" + feature.getScore());
           }
-          else
+        }
+        String status = (String) feature.getValue("status");
+        if (status != null && status.length() > 0)
+        {
+          sb.append("; (").append(status).append(")");
+        }
+        String clinSig = (String) feature
+                .getValue(GffConstants.CLINICAL_SIGNIFICANCE);
+        if (clinSig != null)
+        {
+          sb.append("; ").append(clinSig);
+        }
+      }
+    }
+  }
+
+  /**
+   * Format and appends any hyperlinks for the sequence feature to the string
+   * buffer
+   * 
+   * @param sb
+   * @param feature
+   */
+  void appendLinks(final StringBuffer sb, SequenceFeature feature)
+  {
+    if (feature.links != null)
+    {
+      if (linkImageURL != null)
+      {
+        sb.append(" <img src=\"" + linkImageURL + "\">");
+      }
+      else
+      {
+        for (String urlstring : feature.links)
+        {
+          try
           {
-            for (String urlstring : feature.links)
+            for (String[] urllink : createLinksFrom(null, urlstring))
             {
-              try
-              {
-                for (String[] urllink : createLinksFrom(null, urlstring))
-                {
-                  tooltipText.append("<br/> <a href=\""
-                          + urllink[3]
-                          + "\" target=\""
-                          + urllink[0]
-                          + "\">"
-                          + (urllink[0].toLowerCase().equals(
-                                  urllink[1].toLowerCase()) ? urllink[0]
-                                  : (urllink[0] + ":" + urllink[1]))
-                          + "</a></br>");
-                }
-              } catch (Exception x)
-              {
-                System.err.println("problem when creating links from "
-                        + urlstring);
-                x.printStackTrace();
-              }
+              sb.append("<br/> <a href=\""
+                      + urllink[3]
+                      + "\" target=\""
+                      + urllink[0]
+                      + "\">"
+                      + (urllink[0].toLowerCase().equals(
+                              urllink[1].toLowerCase()) ? urllink[0]
+                              : (urllink[0] + ":" + urllink[1]))
+                      + "</a></br>");
             }
+          } catch (Exception x)
+          {
+            System.err.println("problem when creating links from "
+                    + urlstring);
+            x.printStackTrace();
           }
-
         }
       }
+
     }
   }
 
@@ -234,10 +297,10 @@ public class SequenceAnnotationReport
    * @return String[][] { String[] { link target, link label, dynamic component
    *         inserted (if any), url }}
    */
-  public String[][] createLinksFrom(SequenceI seq, String link)
+  String[][] createLinksFrom(SequenceI seq, String link)
   {
-    ArrayList<String[]> urlSets = new ArrayList<String[]>();
-    ArrayList<String> uniques = new ArrayList<String>();
+    List<String[]> urlSets = new ArrayList<String[]>();
+    List<String> uniques = new ArrayList<String>();
     UrlLink urlLink = new UrlLink(link);
     if (!urlLink.isValid())
     {
@@ -249,48 +312,58 @@ public class SequenceAnnotationReport
     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)
+      urlSets.addAll(createDynamicLinks(seq, urlLink, uniques));
+    }
+    else
+    {
+      String unq = label + "|" + urlLink.getUrl_prefix();
+      if (!uniques.contains(unq))
       {
-        descr = null;
+        uniques.add(unq);
+        urlSets.add(new String[] { target, label, null,
+            urlLink.getUrl_prefix() });
       }
-      if (dbr != null)
+    }
+
+    return urlSets.toArray(new String[][] {});
+  }
+
+  /**
+   * 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++)
       {
-        for (int r = 0; r < dbr.length; r++)
+        if (id != null && dbr[r].getAccessionId().equals(id))
         {
-          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)
-            {
-              String unq = urls[u] + "|" + urls[u + 1];
-              if (!uniques.contains(unq))
-              {
-                urlSets.add(new String[] { target, label, urls[u],
-                    urls[u + 1] });
-                uniques.add(unq);
-              }
-            }
-          }
+          // suppress duplicate link creation for the bare sequence ID
+          // string with this link
+          id = null;
         }
-      }
-      if (id != null)
-      {
-        // create Bare ID link for this RUL
-        String[] urls = urlLink.makeUrls(id, true);
+        // 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)
@@ -298,88 +371,77 @@ public class SequenceAnnotationReport
             String unq = urls[u] + "|" + urls[u + 1];
             if (!uniques.contains(unq))
             {
-              urlSets.add(new String[] { target, label, urls[u],
-                  urls[u + 1] });
+              result.add(new String[] { target, label, urls[u], urls[u + 1] });
               uniques.add(unq);
             }
           }
         }
       }
-      if (descr != null && urlLink.getRegexReplace() != null)
+    }
+    if (id != null)
+    {
+      // create Bare ID link for this URL
+      String[] urls = urlLink.makeUrls(id, true);
+      if (urls != 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)
         {
-          for (int u = 0; u < urls.length; u += 2)
+          String unq = urls[u] + "|" + urls[u + 1];
+          if (!uniques.contains(unq))
           {
-            String unq = urls[u] + "|" + urls[u + 1];
-            if (!uniques.contains(unq))
-            {
-              urlSets.add(new String[] { target, label, urls[u],
-                  urls[u + 1] });
-              uniques.add(unq);
-            }
+            result.add(new String[] { target, label, urls[u], urls[u + 1] });
+            uniques.add(unq);
           }
         }
       }
-
     }
-    else
+    if (descr != null && urlLink.getRegexReplace() != null)
     {
-      String unq = label + "|" + urlLink.getUrl_prefix();
-      if (!uniques.contains(unq))
+      // create link for this URL from description only if regex matches
+      String[] urls = urlLink.makeUrls(descr, true);
+      if (urls != null)
       {
-        uniques.add(unq);
-        // Add a non-dynamic link
-        urlSets.add(new String[] { target, label, null,
-            urlLink.getUrl_prefix() });
+        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 urlSets.toArray(new String[][] {});
+    return result;
   }
 
-  public void createTooltipAnnotationReport(final StringBuilder tip,
+  public void createSequenceAnnotationReport(final StringBuilder tip,
           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
-          Hashtable minmax)
+          Map<String, float[][]> minmax)
   {
-    int maxWidth = createSequenceAnnotationReport(tip, sequence,
-            showDbRefs, showNpFeats, minmax, true);
-
-    if (maxWidth > 60)
-    {
-      tip.insert(0, "<table width=350 border=0><tr><td><i>");
-      tip.append("</i></td></tr></table>");
-    }
-  }
-
-  public int createSequenceAnnotationReport(final StringBuilder tip,
-          SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
-          Hashtable minmax)
-  {
-    return createSequenceAnnotationReport(tip, sequence, showDbRefs,
-            showNpFeats, minmax, false);
+    createSequenceAnnotationReport(tip, sequence, showDbRefs, showNpFeats,
+            minmax, false);
   }
 
   /**
-   * Adds an html-formatted sequence annotation report to the provided string
-   * buffer, and returns the longest line length added
+   * 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
-   *          if true, include database references
+   *          whether to include database references for the sequence
    * @param showNpFeats
-   *          if true, include non-positional sequence features
+   *          whether to include non-positional sequence features
    * @param minmax
    * @param summary
-   *          if true, build a shortened summary report (for tooltip)
    * @return
    */
   int createSequenceAnnotationReport(final StringBuilder sb,
           SequenceI sequence, boolean showDbRefs, boolean showNpFeats,
-          Hashtable minmax, boolean summary)
+          Map<String, float[][]> minmax, boolean summary)
   {
     String tmp;
     sb.append("<i>");
@@ -397,15 +459,21 @@ public class SequenceAnnotationReport
       ds = ds.getDatasetSequence();
     }
     DBRefEntry[] dbrefs = ds.getDBRefs();
-    Arrays.sort(dbrefs, comparator);
     if (showDbRefs && dbrefs != null)
     {
+      // 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)
       {
-        String source = ref.getSource();
+        source = ref.getSource();
         if (source == null)
         {
           // shouldn't happen
@@ -414,7 +482,15 @@ public class SequenceAnnotationReport
         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++;
@@ -422,34 +498,44 @@ public class SequenceAnnotationReport
         {
           sb.append("<br>");
         }
-        if (countForSource < 3 || !summary)
+        if (countForSource <= MAX_REFS_PER_SOURCE || !summary)
         {
           String accessionId = ref.getAccessionId();
-          int len = accessionId.length() + 1;
+          lineLength += accessionId.length() + 1;
           if (countForSource > 1 && summary)
           {
             sb.append(", ").append(accessionId);
-            len++;
+            lineLength++;
           }
           else
           {
             sb.append(source).append(" ").append(accessionId);
-            len += source.length();
+            lineLength += source.length();
           }
-          maxWidth = Math.max(maxWidth, len);
+          maxWidth = Math.max(maxWidth, lineLength);
         }
-        if (countForSource == 3 && summary)
+        if (countForSource == MAX_REFS_PER_SOURCE && summary)
         {
-          sb.append(", ...");
+          sb.append(COMMA).append(ELLIPSIS);
           ellipsis = true;
         }
       }
-      if (ellipsis) {
-        sb.append("<br>(Output Sequence Details to list all database references)");
+      if (moreSources)
+      {
+        sb.append("<br>").append(ELLIPSIS).append(COMMA).append(source)
+                .append(COMMA).append(ELLIPSIS);
+      }
+      if (ellipsis)
+      {
+        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)
     {
@@ -458,14 +544,28 @@ public class SequenceAnnotationReport
         if (features[i].begin == 0 && features[i].end == 0)
         {
           int sz = -sb.length();
-          List<SequenceFeature> tfeat = Collections
-                  .singletonList(features[i]);
-          appendFeatures(sb, 0, tfeat, minmax);
+          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 (maxWidth > 60)
+    {
+      // ? not sure this serves any useful purpose
+      // tip.insert(0, "<table width=350 border=0><tr><td>");
+      // tip.append("</td></tr></table>");
+    }
+  }
 }
index 23c4d21..27be358 100644 (file)
@@ -23,6 +23,7 @@
  */
 package jalview.io;
 
+import jalview.analysis.Rna;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
@@ -31,6 +32,7 @@ import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.schemes.ResidueProperties;
 import jalview.util.Format;
 import jalview.util.MessageManager;
 
@@ -72,8 +74,12 @@ import fr.orsay.lri.varna.models.rna.RNA;
  */
 public class StockholmFile extends AlignFile
 {
-  // static Logger logger = Logger.getLogger("jalview.io.StockholmFile");
-  protected ArrayList<RNA> result;
+  private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "(");
+
+  private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")");
+
+  private static final Regex DETECT_BRACKETS = new Regex(
+          "(<|>|\\[|\\]|\\(|\\))");
 
   StringBuffer out; // output buffer
 
@@ -101,6 +107,7 @@ public class StockholmFile extends AlignFile
     super(source);
   }
 
+  @Override
   public void initData()
   {
     super.initData();
@@ -118,7 +125,7 @@ public class StockholmFile extends AlignFile
     fr = new FileReader(inFile);
 
     BufferedReader r = new BufferedReader(fr);
-    result = null;
+    List<RNA> result = null;
     try
     {
       result = RNAFactory.loadSecStrStockholm(r);
@@ -155,9 +162,8 @@ public class StockholmFile extends AlignFile
 
       for (int k = 0; k < rna.length(); k++)
       {
-        ann[k] = new Annotation(annot[k], "",
-                jalview.schemes.ResidueProperties.getRNASecStrucState(
-                        annot[k]).charAt(0), 0f);
+        ann[k] = new Annotation(annot[k], "", Rna.getRNASecStrucState(
+                annot[k]).charAt(0), 0f);
 
       }
       AlignmentAnnotation align = new AlignmentAnnotation("Sec. str.",
@@ -178,6 +184,7 @@ public class StockholmFile extends AlignFile
    * @throws IOException
    *           If there is an error with the input file
    */
+  @Override
   public void parse() throws IOException
   {
     StringBuffer treeString = new StringBuffer();
@@ -533,8 +540,7 @@ public class StockholmFile extends AlignFile
           }
           else
           {
-            // throw new IOException(MessageManager.formatMessage(
-            // "exception.error_parsing_line", new String[] { line }));
+            // throw new IOException("Error parsing " + line);
             System.err.println(">> missing annotation: " + line);
           }
         }
@@ -788,19 +794,13 @@ public class StockholmFile extends AlignFile
   }
 
   protected static AlignmentAnnotation parseAnnotationRow(
-          Vector annotation, String label, String annots)
+          Vector<AlignmentAnnotation> annotation, String label,
+          String annots)
   {
     String convert1, convert2 = null;
 
-    // Convert all bracket types to parentheses
-    Regex openparen = new Regex("(<|\\[)", "(");
-    Regex closeparen = new Regex("(>|\\])", ")");
-
-    // Detect if file is RNA by looking for bracket types
-    Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))");
-
-    convert1 = openparen.replaceAll(annots);
-    convert2 = closeparen.replaceAll(convert1);
+    convert1 = OPEN_PAREN.replaceAll(annots);
+    convert2 = CLOSE_PAREN.replaceAll(convert1);
     annots = convert2;
 
     String type = label;
@@ -827,15 +827,14 @@ public class StockholmFile extends AlignFile
       {
         // if (" .-_".indexOf(pos) == -1)
         {
-          if (detectbrackets.search(pos))
+          if (DETECT_BRACKETS.search(pos))
           {
-            ann.secondaryStructure = jalview.schemes.ResidueProperties
-                    .getRNASecStrucState(pos).charAt(0);
+            ann.secondaryStructure = Rna.getRNASecStrucState(pos).charAt(0);
           }
           else
           {
-            ann.secondaryStructure = jalview.schemes.ResidueProperties
-                    .getDssp3state(pos).charAt(0);
+            ann.secondaryStructure = ResidueProperties.getDssp3state(pos)
+                    .charAt(0);
           }
 
           if (ann.secondaryStructure == pos.charAt(0))
@@ -853,10 +852,10 @@ public class StockholmFile extends AlignFile
       els[i] = ann;
     }
     AlignmentAnnotation annot = null;
-    Enumeration e = annotation.elements();
+    Enumeration<AlignmentAnnotation> e = annotation.elements();
     while (e.hasMoreElements())
     {
-      annot = (AlignmentAnnotation) e.nextElement();
+      annot = e.nextElement();
       if (annot.label.equals(type))
       {
         break;
@@ -1106,6 +1105,7 @@ public class StockholmFile extends AlignFile
     return seq;
   }
 
+  @Override
   public String print()
   {
     out = new StringBuffer();
@@ -1119,6 +1119,7 @@ public class StockholmFile extends AlignFile
   }
 
   private static Hashtable typeIds = null;
+
   static
   {
     if (typeIds == null)
index 3a7419c..26c202c 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;
@@ -8,13 +28,13 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceI;
-import jalview.structure.StructureViewSettings;
+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;
 
@@ -25,7 +45,8 @@ public abstract class StructureFile extends AlignFile
 
   private String id;
 
-  private String dbRefType;
+  private PDBEntry.Type dbRefType;
+
   /**
    * set to true to add derived sequence annotations (temp factor read from
    * file, or computed secondary structure) to the alignment
@@ -46,6 +67,8 @@ public abstract class StructureFile extends AlignFile
 
   private Vector<PDBChain> chains;
 
+  private boolean pdbIdAvailable;
+
   public StructureFile(String inFile, String type) throws IOException
   {
     super(inFile, type);
@@ -66,19 +89,19 @@ public abstract class StructureFile extends AlignFile
 
   public void xferSettings()
   {
-    this.visibleChainAnnotation = StructureViewSettings
+    this.visibleChainAnnotation = StructureImportSettings
             .isVisibleChainAnnotation();
-    this.predictSecondaryStructure = StructureViewSettings
-            .isPredictSecondaryStructure();
-    this.externalSecondaryStructure = StructureViewSettings
+    this.predictSecondaryStructure = StructureImportSettings
+            .isProcessSecondaryStructure();
+    this.externalSecondaryStructure = StructureImportSettings
             .isExternalSecondaryStructure();
 
   }
 
-  public StructureFile(boolean parseImmediately, String inFile, String type)
-          throws IOException
+  public StructureFile(boolean parseImmediately, String dataObject,
+          String type) throws IOException
   {
-    super(parseImmediately, inFile, type);
+    super(parseImmediately, dataObject, type);
   }
 
   public StructureFile(boolean a, FileParse fp) throws IOException
@@ -90,18 +113,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)
     {
@@ -115,16 +136,13 @@ public abstract class StructureFile extends AlignFile
     DBRefEntry sourceDBRef = new DBRefEntry();
     sourceDBRef.setAccessionId(getId());
     sourceDBRef.setSource(DBRefSource.PDB);
-    sourceDBRef.setStartRes(pdbSequence.getStart());
-    sourceDBRef.setEndRes(pdbSequence.getEnd());
-
-    SequenceI chainseq = pdbSequence.deriveSequence();
-    chainseq.setSourceDBRef(sourceDBRef);
-    chainseq.addPDBId(entry);
-    chainseq.addDBRef(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;
     seqs.addElement(chainseq);
-
     AlignmentAnnotation[] chainannot = chainseq.getAnnotation();
 
     if (chainannot != null && visibleChainAnnotation)
@@ -138,6 +156,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
@@ -185,8 +223,7 @@ public abstract class StructureFile extends AlignFile
 
   @SuppressWarnings("unchecked")
   protected void replaceAndUpdateChains(List<SequenceI> prot,
-          AlignmentI al,
-          String pep, boolean b)
+          AlignmentI al, String pep, boolean b)
   {
     List<List<? extends Object>> replaced = AlignSeq
             .replaceMatchingSeqsWith(seqs, annotations, prot, al, pep,
@@ -259,8 +296,7 @@ public abstract class StructureFile extends AlignFile
   }
 
   @SuppressWarnings({ "unchecked", "rawtypes" })
-  private void processWithJmolParser(List<SequenceI> prot)
-          throws Exception
+  private void processWithJmolParser(List<SequenceI> prot) throws Exception
   {
     try
     {
@@ -269,18 +305,15 @@ public abstract class StructureFile extends AlignFile
       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(),
+                .getConstructor(new Class[] { FileParse.class });
+        final Object[] args = new Object[] { new FileParse(getDataName(),
                 type) };
 
-        StructureViewSettings.setShowSeqFeatures(false);
-        StructureViewSettings.setVisibleChainAnnotation(false);
-        StructureViewSettings
-                .setPredictSecondaryStructure(predictSecondaryStructure);
-        StructureViewSettings
+        StructureImportSettings.setShowSeqFeatures(false);
+        StructureImportSettings.setVisibleChainAnnotation(false);
+        StructureImportSettings
+                .setProcessSecondaryStructure(predictSecondaryStructure);
+        StructureImportSettings
                 .setExternalSecondaryStructure(externalSecondaryStructure);
         Object jmf = constructor.newInstance(args);
         AlignmentI al = new Alignment((SequenceI[]) cl.getMethod(
@@ -303,13 +336,14 @@ public abstract class StructureFile extends AlignFile
     } catch (ClassNotFoundException q)
     {
     }
+    StructureImportSettings.setShowSeqFeatures(true);
   }
 
   public PDBChain findChain(String id) throws Exception
   {
     for (PDBChain chain : getChains())
     {
-      if (chain.id.equalsIgnoreCase(id))
+      if (chain.id.equals(id))
       {
         return chain;
       }
@@ -406,13 +440,18 @@ public abstract class StructureFile extends AlignFile
     this.chains = chains;
   }
 
-  public String getDbRefType()
+  public Type getDbRefType()
   {
     return dbRefType;
   }
 
   public void setDbRefType(String dbRefType)
   {
+    this.dbRefType = Type.getType(dbRefType);
+  }
+
+  public void setDbRefType(Type dbRefType)
+  {
     this.dbRefType = dbRefType;
   }
 
@@ -430,4 +469,19 @@ 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;
+  }
 }
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"),
+              ",");
     }
 
     /*
diff --git a/src/jalview/io/gff/GffConstants.java b/src/jalview/io/gff/GffConstants.java
new file mode 100644 (file)
index 0000000..571f0ea
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 class to hold constants shared by creators and consumers of GFF or feature
+ * data
+ */
+public class GffConstants
+{
+  // SequenceOntology terms are to be found in SequenceOntologyI
+
+  /*
+   * clinical_significance may be an attribute of 
+   * sequence_variant data from Ensembl
+   */
+  public static final String CLINICAL_SIGNIFICANCE = "clinical_significance";
+
+  /*
+   * not instantiable
+   */
+  private GffConstants()
+  {
+  }
+}
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 817ba9c..c1ca1b7 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.packed;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.io.NewickFile;
@@ -57,7 +58,7 @@ public class JalviewDataset
   /**
    * @return the featureColours
    */
-  public Map<String, Object> getFeatureColours()
+  public Map<String, FeatureColourI> getFeatureColours()
   {
     return featureColours;
   }
@@ -66,7 +67,7 @@ public class JalviewDataset
    * @param featureColours
    *          the featureColours to set
    */
-  public void setFeatureColours(Map<String, Object> featureColours)
+  public void setFeatureColours(Map<String, FeatureColourI> featureColours)
   {
     this.featureColours = featureColours;
   }
@@ -187,7 +188,7 @@ public class JalviewDataset
   /**
    * current set of feature colours
    */
-  Map<String, Object> featureColours;
+  Map<String, FeatureColourI> featureColours;
 
   /**
    * original identity of each sequence in results
@@ -201,7 +202,7 @@ public class JalviewDataset
     seqDetails = new Hashtable();
     al = new ArrayList<AlignmentSet>();
     parentDataset = null;
-    featureColours = new HashMap<String, Object>();
+    featureColours = new HashMap<String, FeatureColourI>();
   }
 
   /**
@@ -209,8 +210,8 @@ public class JalviewDataset
    * 
    * @param parentAlignment
    */
-  public JalviewDataset(AlignmentI aldataset, Map<String, Object> fc,
-          Hashtable seqDets)
+  public JalviewDataset(AlignmentI aldataset,
+          Map<String, FeatureColourI> fc, Hashtable seqDets)
   {
     // TODO not used - remove?
     this(aldataset, fc, seqDets, null);
@@ -231,8 +232,9 @@ public class JalviewDataset
    *          (may be null) alignment to associate new annotation and trees
    *          with.
    */
-  public JalviewDataset(AlignmentI aldataset, Map<String, Object> fc,
-          Hashtable seqDets, AlignmentI parentAlignment)
+  public JalviewDataset(AlignmentI aldataset,
+          Map<String, FeatureColourI> fc, Hashtable seqDets,
+          AlignmentI parentAlignment)
   {
     this();
     parentDataset = aldataset;
index 01369b9..71999f0 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io.packed;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentI;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FileParse;
@@ -157,7 +158,7 @@ public class ParsePackedSet
         // if not, create one.
         if (context.featureColours == null)
         {
-          context.featureColours = new HashMap<String, Object>();
+          context.featureColours = new HashMap<String, FeatureColourI>();
         }
         try
         {
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 205b9c6..6b94559 100755 (executable)
@@ -55,7 +55,6 @@ import javax.swing.JPanel;
 import javax.swing.JRadioButtonMenuItem;
 import javax.swing.JTabbedPane;
 import javax.swing.KeyStroke;
-import javax.swing.SwingUtilities;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.MenuEvent;
 import javax.swing.event.MenuListener;
@@ -137,8 +136,6 @@ public class GAlignFrame extends JInternalFrame
 
   public JCheckBoxMenuItem showSeqFeatures = new JCheckBoxMenuItem();
 
-  public JCheckBoxMenuItem showSeqFeaturesHeight = new JCheckBoxMenuItem();
-
   JMenuItem copy = new JMenuItem();
 
   JMenuItem cut = new JMenuItem();
@@ -179,6 +176,8 @@ public class GAlignFrame extends JInternalFrame
 
   protected JMenu showProducts = new JMenu();
 
+  protected JMenuItem runGroovy = new JMenuItem();
+
   protected JMenuItem rnahelicesColour = new JMenuItem();
 
   protected JCheckBoxMenuItem autoCalculate = new JCheckBoxMenuItem();
@@ -293,35 +292,50 @@ public class GAlignFrame extends JInternalFrame
           @Override
           public void mousePressed(MouseEvent evt)
           {
-            if (evt.isControlDown()
-                    || SwingUtilities.isRightMouseButton(evt))
+            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);
+                }
+              });
             }
           }
         });
@@ -1591,7 +1605,7 @@ public class GAlignFrame extends JInternalFrame
     });
 
     JMenuItem modifyPID = new JMenuItem(
-            MessageManager.getString("label.modify_identity_thereshold"));
+            MessageManager.getString("label.modify_identity_threshold"));
     modifyPID.addActionListener(new ActionListener()
     {
       @Override
@@ -1601,7 +1615,7 @@ public class GAlignFrame extends JInternalFrame
       }
     });
     modifyConservation.setText(MessageManager
-            .getString("label.modify_conservation_thereshold"));
+            .getString("label.modify_conservation_threshold"));
     modifyConservation.addActionListener(new ActionListener()
     {
       @Override
@@ -1726,6 +1740,18 @@ public class GAlignFrame extends JInternalFrame
     // for show products actions see AlignFrame.canShowProducts
     showProducts.setText(MessageManager.getString("label.get_cross_refs"));
 
+    runGroovy.setText(MessageManager.getString("label.run_groovy"));
+    runGroovy.setToolTipText(MessageManager
+            .getString("label.run_groovy_tip"));
+    runGroovy.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        runGroovy_actionPerformed();
+      }
+    });
+
     JMenuItem openFeatureSettings = new JMenuItem(
             MessageManager.getString("action.feature_settings"));
     openFeatureSettings.addActionListener(new ActionListener()
@@ -2021,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()
@@ -2160,6 +2198,7 @@ public class GAlignFrame extends JInternalFrame
     alignFrameMenuBar.add(colourMenu);
     alignFrameMenuBar.add(calculateMenu);
     alignFrameMenuBar.add(webService);
+
     fileMenu.add(fetchSequence);
     fileMenu.add(addSequenceMenu);
     fileMenu.add(reload);
@@ -2178,6 +2217,9 @@ public class GAlignFrame extends JInternalFrame
     fileMenu.add(associatedData);
     fileMenu.addSeparator();
     fileMenu.add(closeMenuItem);
+
+    pasteMenu.add(pasteNew);
+    pasteMenu.add(pasteThis);
     editMenu.add(undoMenuItem);
     editMenu.add(redoMenuItem);
     editMenu.add(cut);
@@ -2198,6 +2240,13 @@ public class GAlignFrame extends JInternalFrame
     // editMenu.addSeparator();
     editMenu.add(padGapsMenuitem);
 
+    showMenu.add(showAllColumns);
+    showMenu.add(showAllSeqs);
+    showMenu.add(showAllhidden);
+    hideMenu.add(hideSelColumns);
+    hideMenu.add(hideSelSequences);
+    hideMenu.add(hideAllSelection);
+    hideMenu.add(hideAllButSelection);
     viewMenu.add(newView);
     viewMenu.add(expandViews);
     viewMenu.add(gatherViews);
@@ -2268,6 +2317,12 @@ public class GAlignFrame extends JInternalFrame
     colourMenu.add(modifyPID);
     colourMenu.add(annotationColour);
     colourMenu.add(rnahelicesColour);
+
+    sort.add(sortIDMenuItem);
+    sort.add(sortLengthMenuItem);
+    sort.add(sortGroupMenuItem);
+    sort.add(sortPairwiseMenuItem);
+    sort.add(sortByTreeMenu);
     calculateMenu.add(sort);
     calculateMenu.add(calculateTree);
     calculateMenu.addSeparator();
@@ -2281,17 +2336,14 @@ public class GAlignFrame extends JInternalFrame
     calculateMenu.add(autoCalculate);
     calculateMenu.add(sortByTree);
     calculateMenu.addSeparator();
+    calculateMenu.add(expandAlignment);
     calculateMenu.add(extractScores);
+    calculateMenu.addSeparator();
+    calculateMenu.add(runGroovy);
+
     webServiceNoServices = new JMenuItem(
             MessageManager.getString("label.no_services"));
     webService.add(webServiceNoServices);
-    pasteMenu.add(pasteNew);
-    pasteMenu.add(pasteThis);
-    sort.add(sortIDMenuItem);
-    sort.add(sortLengthMenuItem);
-    sort.add(sortGroupMenuItem);
-    sort.add(sortPairwiseMenuItem);
-    sort.add(sortByTreeMenu);
     exportImageMenu.add(htmlMenuItem);
     exportImageMenu.add(epsFile);
     exportImageMenu.add(createPNG);
@@ -2303,13 +2355,6 @@ public class GAlignFrame extends JInternalFrame
     this.getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH);
     statusPanel.add(statusBar, null);
     this.getContentPane().add(tabbedPane, java.awt.BorderLayout.CENTER);
-    showMenu.add(showAllColumns);
-    showMenu.add(showAllSeqs);
-    showMenu.add(showAllhidden);
-    hideMenu.add(hideSelColumns);
-    hideMenu.add(hideSelSequences);
-    hideMenu.add(hideAllSelection);
-    hideMenu.add(hideAllButSelection);
 
     formatMenu.add(font);
     formatMenu.addSeparator();
@@ -2337,7 +2382,6 @@ public class GAlignFrame extends JInternalFrame
     selectMenu.add(grpsFromSelection);
     selectMenu.add(deleteGroups);
     selectMenu.add(annotationColumn);
-    calculateMenu.add(expandAlignment);
     // TODO - determine if the listenToViewSelections button is needed : see bug
     // JAL-574
     // selectMenu.addSeparator();
@@ -2355,6 +2399,15 @@ public class GAlignFrame extends JInternalFrame
   }
 
   /**
+   * Try to run script in a Groovy console, having first ensured that this
+   * alignframe is set as currentAlignFrame in Desktop
+   */
+  protected void runGroovy_actionPerformed()
+  {
+
+  }
+
+  /**
    * 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.
    * 
@@ -2495,13 +2548,6 @@ public class GAlignFrame extends JInternalFrame
 
   }
 
-  protected void showSeqFeaturesHeight_actionPerformed(
-          ActionEvent actionEvent)
-  {
-    // TODO Auto-generated method stub
-
-  }
-
   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
   {
     // TODO Auto-generated method stub
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);
diff --git a/src/jalview/jbgui/GPDBSearchPanel.java b/src/jalview/jbgui/GPDBSearchPanel.java
deleted file mode 100644 (file)
index d640df8..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 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.jbgui;
-
-import jalview.gui.Desktop;
-import jalview.gui.JvSwingUtils;
-import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource;
-import jalview.util.MessageManager;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
-
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.Arrays;
-
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JFrame;
-import javax.swing.JInternalFrame;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.DocumentEvent;
-import javax.swing.event.DocumentListener;
-
-/**
- * GUI layout for PDB Fetch Panel
- * 
- * @author tcnofoegbu
- *
- */
-@SuppressWarnings("serial")
-public abstract class GPDBSearchPanel extends JPanel
-{
-  protected String frameTitle = MessageManager
-          .getString("label.pdb_sequence_getcher");
-
-  protected JInternalFrame mainFrame = new JInternalFrame(frameTitle);
-
-  protected JComboBox<PDBDocField> cmb_searchTarget = new JComboBox<PDBDocField>();
-
-  protected JButton btn_ok = new JButton();
-
-  protected JButton btn_back = new JButton();
-
-  protected JButton btn_cancel = new JButton();
-
-  protected JTextField txt_search = new JTextField(20);
-
-  protected JTable tbl_summary = new JTable()
-  {
-    @Override
-    public String getToolTipText(MouseEvent evt)
-    {
-      String toolTipText = null;
-      java.awt.Point pnt = evt.getPoint();
-      int rowIndex = rowAtPoint(pnt);
-      int colIndex = columnAtPoint(pnt);
-
-      try
-      {
-        if (getValueAt(rowIndex, colIndex) == null)
-        {
-          return null;
-        }
-        toolTipText = getValueAt(rowIndex, colIndex).toString();
-
-      } catch (Exception e)
-      {
-        e.printStackTrace();
-      }
-      toolTipText = (toolTipText == null ? null
-              : (toolTipText.length() > 500 ? JvSwingUtils.wrapTooltip(
-                      true, toolTipText.subSequence(0, 500) + "...")
-                      : JvSwingUtils.wrapTooltip(true, toolTipText)));
-
-      return toolTipText;
-    }
-  };
-
-  protected StringBuilder errorWarning = new StringBuilder();
-
-  protected JScrollPane scrl_searchResult = new JScrollPane(tbl_summary);
-
-  protected ImageIcon warningImage = new ImageIcon(getClass().getResource(
-          "/images/warning.gif"));
-
-  protected ImageIcon loadingImage = new ImageIcon(getClass().getResource(
-          "/images/loading.gif"));
-
-  protected JLabel lbl_warning = new JLabel(warningImage);
-
-  protected JLabel lbl_loading = new JLabel(loadingImage);
-
-  private JTabbedPane tabbedPane = new JTabbedPane();
-
-  private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences(
-          PreferenceSource.SEARCH_SUMMARY);
-
-  private JPanel pnl_actions = new JPanel();
-
-  private JPanel pnl_results = new JPanel(new CardLayout());
-
-  private JPanel pnl_inputs = new JPanel();
-
-  private BorderLayout mainLayout = new BorderLayout();
-
-  protected PDBDocField[] previousWantedFields;
-
-  public GPDBSearchPanel()
-  {
-    try
-    {
-      jbInit();
-      mainFrame.invalidate();
-      mainFrame.pack();
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-    }
-  }
-
-  /**
-   * Initializes the GUI default properties
-   * 
-   * @throws Exception
-   */
-  private void jbInit() throws Exception
-  {
-    lbl_warning.setVisible(false);
-    lbl_warning.setFont(new java.awt.Font("Verdana", 0, 12));
-    lbl_loading.setVisible(false);
-    lbl_loading.setFont(new java.awt.Font("Verdana", 0, 12));
-
-    tbl_summary.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
-    tbl_summary.setAutoCreateRowSorter(true);
-    tbl_summary.getTableHeader().setReorderingAllowed(false);
-    tbl_summary.addMouseListener(new MouseAdapter()
-    {
-      @Override
-      public void mouseClicked(MouseEvent e)
-      {
-        validateSelection();
-      }
-
-      @Override
-      public void mouseReleased(MouseEvent e)
-      {
-        validateSelection();
-      }
-    });
-    tbl_summary.addKeyListener(new KeyAdapter()
-    {
-      @Override
-      public void keyPressed(KeyEvent evt)
-      {
-        validateSelection();
-        switch (evt.getKeyCode())
-        {
-        case KeyEvent.VK_ESCAPE: // escape key
-          btn_back_ActionPerformed();
-          break;
-        case KeyEvent.VK_ENTER: // enter key
-          if (btn_ok.isEnabled())
-          {
-            btn_ok_ActionPerformed();
-          }
-          evt.consume();
-          break;
-        case KeyEvent.VK_TAB: // tab key
-          if (evt.isShiftDown())
-          {
-            tabbedPane.requestFocus();
-          }
-          else
-          {
-            btn_back.requestFocus();
-          }
-          evt.consume();
-          break;
-        default:
-          return;
-        }
-      }
-    });
-
-    btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
-    btn_back.setText(MessageManager.getString("action.back"));
-    btn_back.addActionListener(new java.awt.event.ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        btn_back_ActionPerformed();
-      }
-    });
-    btn_back.addKeyListener(new KeyAdapter()
-    {
-      @Override
-      public void keyPressed(KeyEvent evt)
-      {
-        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
-        {
-          btn_back_ActionPerformed();
-        }
-      }
-    });
-
-    btn_ok.setEnabled(false);
-    btn_ok.setFont(new java.awt.Font("Verdana", 0, 12));
-    btn_ok.setText(MessageManager.getString("action.ok"));
-    btn_ok.addActionListener(new java.awt.event.ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        btn_ok_ActionPerformed();
-      }
-    });
-    btn_ok.addKeyListener(new KeyAdapter()
-    {
-      @Override
-      public void keyPressed(KeyEvent evt)
-      {
-        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
-        {
-          btn_ok_ActionPerformed();
-        }
-      }
-    });
-
-    btn_cancel.setFont(new java.awt.Font("Verdana", 0, 12));
-    btn_cancel.setText(MessageManager.getString("action.cancel"));
-    btn_cancel.addActionListener(new java.awt.event.ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        btn_cancel_ActionPerformed();
-      }
-    });
-    btn_cancel.addKeyListener(new KeyAdapter()
-    {
-      @Override
-      public void keyPressed(KeyEvent evt)
-      {
-        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
-        {
-          btn_cancel_ActionPerformed();
-        }
-      }
-    });
-
-    scrl_searchResult.setPreferredSize(new Dimension(500, 300));
-    scrl_searchResult
-            .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-
-    cmb_searchTarget.setFont(new java.awt.Font("Verdana", 0, 12));
-    cmb_searchTarget.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        String tooltipText;
-        if ("all".equalsIgnoreCase(getCmbSearchTarget().getSelectedItem()
-                .toString()))
-        {
-          tooltipText = MessageManager.getString("label.search_all");
-        }
-        else if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
-                .getSelectedItem().toString()))
-        {
-          tooltipText = MessageManager
-                  .getString("label.separate_multiple_accession_ids");
-        }
-        else
-        {
-          tooltipText = MessageManager.formatMessage(
-                  "label.separate_multiple_query_values",
-                  new Object[] { getCmbSearchTarget().getSelectedItem()
-                          .toString() });
-        }
-        txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
-                tooltipText));
-        txt_search_ActionPerformed();
-      }
-    });
-
-    populateCmbSearchTargetOptions();
-
-    txt_search.setFont(new java.awt.Font("Verdana", 0, 12));
-
-    txt_search.addKeyListener(new KeyAdapter()
-    {
-      @Override
-      public void keyPressed(KeyEvent e)
-      {
-        if (e.getKeyCode() == KeyEvent.VK_ENTER)
-        {
-          if (txt_search.getText() == null
-                  || txt_search.getText().isEmpty())
-          {
-            return;
-          }
-          if ("pdb id".equalsIgnoreCase(getCmbSearchTarget()
-                  .getSelectedItem().toString()))
-          {
-            transferToSequenceFetcher(txt_search.getText());
-          }
-        }
-      }
-    });
-
-    txt_search.getDocument().addDocumentListener(new DocumentListener()
-    {
-      @Override
-      public void insertUpdate(DocumentEvent e)
-      {
-        txt_search_ActionPerformed();
-      }
-
-      @Override
-      public void removeUpdate(DocumentEvent e)
-      {
-        txt_search_ActionPerformed();
-      }
-
-      @Override
-      public void changedUpdate(DocumentEvent e)
-      {
-        txt_search_ActionPerformed();
-      }
-    });
-
-    final String searchTabTitle = MessageManager
-            .getString("label.search_result");
-    final String configureCols = MessageManager
-            .getString("label.configure_displayed_columns");
-    ChangeListener changeListener = new ChangeListener()
-    {
-      @Override
-      public void stateChanged(ChangeEvent changeEvent)
-      {
-        JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
-                .getSource();
-        int index = sourceTabbedPane.getSelectedIndex();
-
-        btn_back.setVisible(true);
-        btn_cancel.setVisible(true);
-        btn_ok.setVisible(true);
-        if (sourceTabbedPane.getTitleAt(index).equals(configureCols))
-        {
-          btn_back.setVisible(false);
-          btn_cancel.setVisible(false);
-          btn_ok.setVisible(false);
-          btn_back.setEnabled(false);
-          btn_cancel.setEnabled(false);
-          btn_ok.setEnabled(false);
-          previousWantedFields = PDBDocFieldPreferences
-                  .getSearchSummaryFields().toArray(new PDBDocField[0]);
-        }
-        if (sourceTabbedPane.getTitleAt(index).equals(searchTabTitle))
-        {
-          btn_back.setEnabled(true);
-          btn_cancel.setEnabled(true);
-          if (wantedFieldsUpdated())
-          {
-            txt_search_ActionPerformed();
-          }
-          else
-          {
-            validateSelection();
-          }
-        }
-      }
-    };
-    tabbedPane.addChangeListener(changeListener);
-    tabbedPane.setPreferredSize(new Dimension(500, 300));
-    tabbedPane.add(searchTabTitle, scrl_searchResult);
-    tabbedPane.add(configureCols, pdbDocFieldPrefs);
-
-    pnl_actions.add(btn_back);
-    pnl_actions.add(btn_ok);
-    pnl_actions.add(btn_cancel);
-
-    pnl_results.add(tabbedPane);
-    pnl_inputs.add(cmb_searchTarget);
-    pnl_inputs.add(txt_search);
-    pnl_inputs.add(lbl_loading);
-    pnl_inputs.add(lbl_warning);
-
-    this.setLayout(mainLayout);
-    this.add(pnl_inputs, java.awt.BorderLayout.NORTH);
-    this.add(pnl_results, java.awt.BorderLayout.CENTER);
-    this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
-    mainFrame.setVisible(true);
-    mainFrame.setContentPane(this);
-    mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-    Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400);
-  }
-
-  public boolean wantedFieldsUpdated()
-  {
-    if (previousWantedFields == null)
-    {
-      return true;
-    }
-
-    return Arrays.equals(PDBDocFieldPreferences.getSearchSummaryFields()
-            .toArray(new PDBDocField[0]), previousWantedFields) ? false
-            : true;
-
-  }
-
-  public void validateSelection()
-  {
-    if (tbl_summary.getSelectedRows().length > 0)
-    {
-      btn_ok.setEnabled(true);
-    }
-    else
-    {
-      btn_ok.setEnabled(false);
-    }
-  }
-
-  public JComboBox<PDBDocField> getCmbSearchTarget()
-  {
-    return cmb_searchTarget;
-  }
-
-  public JTextField getTxtSearch()
-  {
-    return txt_search;
-  }
-
-  public JInternalFrame getMainFrame()
-  {
-    return mainFrame;
-  }
-
-  public abstract void transferToSequenceFetcher(String ids);
-
-  public abstract void txt_search_ActionPerformed();
-
-  public abstract void btn_ok_ActionPerformed();
-
-  public abstract void btn_back_ActionPerformed();
-
-  public abstract void btn_cancel_ActionPerformed();
-
-  public abstract void populateCmbSearchTargetOptions();
-
-}
index 0aafe50..90053f5 100755 (executable)
  */
 package jalview.jbgui;
 
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.gui.JvSwingUtils;
 import jalview.gui.StructureViewer.ViewerType;
-import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
@@ -110,8 +112,6 @@ public class GPreferences extends JPanel
 
   protected JCheckBox wrap = new JCheckBox();
 
-  protected JCheckBox hideIntrons = new JCheckBox();
-
   protected JComboBox<String> sortby = new JComboBox<String>();
 
   protected JComboBox<String> sortAnnBy = new JComboBox<String>();
@@ -201,7 +201,7 @@ public class GPreferences extends JPanel
   /*
    * Output tab components
    */
-  protected JComboBox<String> epsRendering = new JComboBox<String>();
+  protected JComboBox<Object> epsRendering = new JComboBox<Object>();
 
   protected JLabel userIdWidthlabel = new JLabel();
 
@@ -901,8 +901,8 @@ public class GPreferences extends JPanel
 
     ypos += lineSpacing;
     ypos += lineSpacing;
-    PDBDocFieldPreferences docFieldPref = new PDBDocFieldPreferences(
-            PreferenceSource.PREFERENCES);
+    FTSDataColumnPreferences docFieldPref = new FTSDataColumnPreferences(
+            PreferenceSource.PREFERENCES, PDBFTSRestClient.getInstance());
     docFieldPref.setBounds(new Rectangle(10, ypos, 450, 120));
     structureTab.add(docFieldPref);
 
@@ -1151,7 +1151,7 @@ public class GPreferences extends JPanel
     startupCheckbox.setHorizontalTextPosition(SwingConstants.LEFT);
     startupCheckbox.setSelected(true);
     startupFileTextfield.setFont(LABEL_FONT);
-    startupFileTextfield.setBounds(new Rectangle(173, 328, 330, 20));
+    startupFileTextfield.setBounds(new Rectangle(172, 310, 330, 20));
     startupFileTextfield.addMouseListener(new MouseAdapter()
     {
       @Override
@@ -1165,19 +1165,19 @@ public class GPreferences extends JPanel
     });
 
     sortby.setFont(LABEL_FONT);
-    sortby.setBounds(new Rectangle(172, 280, 155, 20));
+    sortby.setBounds(new Rectangle(172, 260, 155, 21));
     JLabel sortLabel = new JLabel();
     sortLabel.setFont(LABEL_FONT);
     sortLabel.setHorizontalAlignment(SwingConstants.RIGHT);
     sortLabel.setText(MessageManager.getString("label.sort_by"));
     sortAnnBy.setFont(LABEL_FONT);
-    sortAnnBy.setBounds(new Rectangle(172, 305, 110, 20));
+    sortAnnBy.setBounds(new Rectangle(172, 285, 110, 21));
     JLabel sortAnnLabel = new JLabel();
     sortAnnLabel.setFont(LABEL_FONT);
     sortAnnLabel.setHorizontalAlignment(SwingConstants.RIGHT);
     sortAnnLabel.setText(MessageManager.getString("label.sort_ann_by"));
     sortAutocalc.setFont(LABEL_FONT);
-    sortAutocalc.setBounds(new Rectangle(290, 305, 165, 20));
+    sortAutocalc.setBounds(new Rectangle(290, 285, 165, 21));
 
     JPanel annsettingsPanel = new JPanel();
     annsettingsPanel.setBounds(new Rectangle(173, 34, 320, 75));
@@ -1221,12 +1221,6 @@ public class GPreferences extends JPanel
     wrap.setHorizontalAlignment(SwingConstants.TRAILING);
     wrap.setHorizontalTextPosition(SwingConstants.LEADING);
     wrap.setText(MessageManager.getString("label.wrap_alignment"));
-    hideIntrons.setFont(LABEL_FONT);
-    hideIntrons.setHorizontalAlignment(SwingConstants.TRAILING);
-    hideIntrons.setHorizontalTextPosition(SwingConstants.LEADING);
-    hideIntrons.setText(MessageManager.getString("label.hide_introns"));
-    hideIntrons.setToolTipText(MessageManager
-            .getString("label.hide_introns_tip"));
     rightAlign.setFont(LABEL_FONT);
     rightAlign.setForeground(Color.black);
     rightAlign.setHorizontalAlignment(SwingConstants.RIGHT);
@@ -1242,10 +1236,10 @@ public class GPreferences extends JPanel
             .getString("label.open_overview"));
     openoverv.setHorizontalAlignment(SwingConstants.RIGHT);
     openoverv.setHorizontalTextPosition(SwingConstants.LEFT);
-    openoverv.setText(MessageManager.getString(("label.open_overview")));
+    openoverv.setText(MessageManager.getString("label.open_overview"));
     JPanel jPanel2 = new JPanel();
-    jPanel2.setBounds(new Rectangle(7, 17, 158, 330));
-    jPanel2.setLayout(new GridLayout(15, 1));
+    jPanel2.setBounds(new Rectangle(7, 17, 158, 310));
+    jPanel2.setLayout(new GridLayout(14, 1));
     jPanel2.add(fullScreen);
     jPanel2.add(openoverv);
     jPanel2.add(seqLimit);
@@ -1257,7 +1251,6 @@ public class GPreferences extends JPanel
     jPanel2.add(scaleProteinToCdna);
     jPanel2.add(gapLabel);
     jPanel2.add(wrap);
-    jPanel2.add(hideIntrons);
     jPanel2.add(sortLabel);
     jPanel2.add(sortAnnLabel);
     jPanel2.add(startupCheckbox);
index 46580a2..b27752e 100755 (executable)
@@ -60,6 +60,7 @@ 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);
@@ -70,6 +71,7 @@ public class GSequenceLink extends Panel
     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 8430557..3a064d2 100644 (file)
 package jalview.jbgui;
 
 import jalview.datamodel.SequenceI;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.core.FTSDataColumnPreferences;
+import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
+import jalview.fts.service.pdb.PDBFTSRestClient;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.JvSwingUtils;
-import jalview.jbgui.PDBDocFieldPreferences.PreferenceSource;
 import jalview.util.MessageManager;
-import jalview.ws.dbsources.PDBRestClient;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
 
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
@@ -43,6 +44,8 @@ import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
@@ -60,6 +63,8 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import javax.swing.event.InternalFrameEvent;
+import javax.swing.table.TableColumn;
 
 @SuppressWarnings("serial")
 /**
@@ -157,8 +162,69 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected static final String VIEWS_LOCAL_PDB = "VIEWS_LOCAL_PDB";
 
-  protected JTable tbl_summary = new JTable()
+  protected JTable tbl_local_pdb = new JTable();
+
+  protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
+
+  protected JTabbedPane pnl_filter = new JTabbedPane();
+
+  protected FTSDataColumnPreferences pdbDocFieldPrefs = new FTSDataColumnPreferences(
+          PreferenceSource.STRUCTURE_CHOOSER,
+          PDBFTSRestClient.getInstance());
+
+  protected FTSDataColumnI[] previousWantedFields;
+
+  protected static Map<String, Integer> tempUserPrefs = new HashMap<String, Integer>();
+
+  private JTable tbl_summary = new JTable()
   {
+    private boolean inLayout;
+
+    @Override
+    public boolean getScrollableTracksViewportWidth()
+    {
+      return hasExcessWidth();
+
+    }
+
+    @Override
+    public void doLayout()
+    {
+      if (hasExcessWidth())
+      {
+        autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
+      }
+      inLayout = true;
+      super.doLayout();
+      inLayout = false;
+      autoResizeMode = AUTO_RESIZE_OFF;
+    }
+
+    protected boolean hasExcessWidth()
+    {
+      return getPreferredSize().width < getParent().getWidth();
+    }
+
+    @Override
+    public void columnMarginChanged(ChangeEvent e)
+    {
+      if (isEditing())
+      {
+        removeEditor();
+      }
+      TableColumn resizingColumn = getTableHeader().getResizingColumn();
+      // Need to do this here, before the parent's
+      // layout manager calls getPreferredSize().
+      if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF
+              && !inLayout)
+      {
+        resizingColumn.setPreferredWidth(resizingColumn.getWidth());
+        String colHeader = resizingColumn.getHeaderValue().toString();
+        tempUserPrefs.put(colHeader, resizingColumn.getWidth());
+      }
+      resizeAndRepaint();
+    }
+
     @Override
     public String getToolTipText(MouseEvent evt)
     {
@@ -189,17 +255,6 @@ public abstract class GStructureChooser extends JPanel implements
 
   protected JScrollPane scrl_foundStructures = new JScrollPane(tbl_summary);
 
-  protected JTable tbl_local_pdb = new JTable();
-
-  protected JScrollPane scrl_localPDB = new JScrollPane(tbl_local_pdb);
-
-  private JTabbedPane pnl_filter = new JTabbedPane();
-
-  private PDBDocFieldPreferences pdbDocFieldPrefs = new PDBDocFieldPreferences(
-          PreferenceSource.STRUCTURE_CHOOSER);
-
-  protected PDBDocField[] previousWantedFields;
-
   public GStructureChooser()
   {
     try
@@ -221,6 +276,10 @@ public abstract class GStructureChooser extends JPanel implements
    */
   private void jbInit() throws Exception
   {
+    Integer width = tempUserPrefs.get("structureChooser.width") == null ? 800
+            : tempUserPrefs.get("structureChooser.width");
+    Integer height = tempUserPrefs.get("structureChooser.height") == null ? 400
+            : tempUserPrefs.get("structureChooser.height");
     tbl_summary.setAutoCreateRowSorter(true);
     tbl_summary.getTableHeader().setReorderingAllowed(false);
     tbl_summary.addMouseListener(new MouseAdapter()
@@ -320,6 +379,7 @@ public abstract class GStructureChooser extends JPanel implements
             }
           }
           evt.consume();
+          break;
         default:
           return;
         }
@@ -354,7 +414,7 @@ public abstract class GStructureChooser extends JPanel implements
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        mainFrame.dispose();
+        closeAction(pnl_filter.getHeight());
       }
     });
     btn_cancel.addKeyListener(new KeyAdapter()
@@ -364,7 +424,7 @@ public abstract class GStructureChooser extends JPanel implements
       {
         if (evt.getKeyCode() == KeyEvent.VK_ENTER)
         {
-          mainFrame.dispose();
+          closeAction(pnl_filter.getHeight());
         }
       }
     });
@@ -392,11 +452,9 @@ public abstract class GStructureChooser extends JPanel implements
       }
     });
 
-    scrl_foundStructures.setPreferredSize(new Dimension(500, 300));
-    scrl_foundStructures
-            .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    scrl_foundStructures.setPreferredSize(new Dimension(width, height));
 
-    scrl_localPDB.setPreferredSize(new Dimension(500, 300));
+    scrl_localPDB.setPreferredSize(new Dimension(width, height));
     scrl_localPDB
             .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 
@@ -404,9 +462,8 @@ public abstract class GStructureChooser extends JPanel implements
     chk_invertFilter.setFont(new java.awt.Font("Verdana", 0, 12));
     chk_rememberSettings.setFont(new java.awt.Font("Verdana", 0, 12));
     chk_rememberSettings.setVisible(false);
-
-    txt_search.setToolTipText(MessageManager
-            .getString("label.enter_pdb_id"));
+    txt_search.setToolTipText(JvSwingUtils.wrapTooltip(true,
+            MessageManager.getString("label.enter_pdb_id")));
     cmb_filterOption.setToolTipText(MessageManager
             .getString("info.select_filter_option"));
     txt_search.getDocument().addDocumentListener(new DocumentListener()
@@ -473,9 +530,9 @@ public abstract class GStructureChooser extends JPanel implements
           btn_cancel.setEnabled(false);
           btn_view.setVisible(false);
           btn_cancel.setVisible(false);
-          previousWantedFields = PDBDocFieldPreferences
+          previousWantedFields = pdbDocFieldPrefs
                   .getStructureSummaryFields().toArray(
-                          new PDBRestClient.PDBDocField[0]);
+                          new FTSDataColumnI[0]);
         }
         if (sourceTabbedPane.getTitleAt(index)
                 .equals(foundStructureSummary))
@@ -493,7 +550,7 @@ public abstract class GStructureChooser extends JPanel implements
       }
     };
     pnl_filter.addChangeListener(changeListener);
-    pnl_filter.setPreferredSize(new Dimension(500, 300));
+    pnl_filter.setPreferredSize(new Dimension(width, height));
     pnl_filter.add(foundStructureSummary, scrl_foundStructures);
     pnl_filter.add(configureCols, pdbDocFieldPrefs);
 
@@ -514,10 +571,39 @@ public abstract class GStructureChooser extends JPanel implements
     statusPanel.add(statusBar, null);
     this.add(pnl_actionsAndStatus, java.awt.BorderLayout.SOUTH);
 
+    mainFrame
+            .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+            {
+              @Override
+              public void internalFrameClosing(InternalFrameEvent e)
+              {
+                closeAction(pnl_filter.getHeight());
+              }
+            });
     mainFrame.setVisible(true);
     mainFrame.setContentPane(this);
     mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-    Desktop.addInternalFrame(mainFrame, frameTitle, 800, 400);
+    Integer x = tempUserPrefs.get("structureChooser.x");
+    Integer y = tempUserPrefs.get("structureChooser.y");
+    if (x != null && y != null)
+    {
+      mainFrame.setLocation(x, y);
+    }
+    Desktop.addInternalFrame(mainFrame, frameTitle, width, height);
+  }
+
+  protected void closeAction(int preferredHeight)
+  {
+    // System.out.println(">>>>>>>>>> closing internal frame!!!");
+    // System.out.println("width : " + mainFrame.getWidth());
+    // System.out.println("heigh : " + mainFrame.getHeight());
+    // System.out.println("x : " + mainFrame.getX());
+    // System.out.println("y : " + mainFrame.getY());
+    tempUserPrefs.put("structureChooser.width", pnl_filter.getWidth());
+    tempUserPrefs.put("structureChooser.height", preferredHeight);
+    tempUserPrefs.put("structureChooser.x", mainFrame.getX());
+    tempUserPrefs.put("structureChooser.y", mainFrame.getY());
+    mainFrame.dispose();
   }
 
   public boolean wantedFieldsUpdated()
@@ -527,9 +613,10 @@ public abstract class GStructureChooser extends JPanel implements
       return true;
     }
 
-    return Arrays.equals(PDBDocFieldPreferences.getStructureSummaryFields()
-            .toArray(new PDBRestClient.PDBDocField[0]),
-            previousWantedFields) ? false : true;
+    FTSDataColumnI[] currentWantedFields = pdbDocFieldPrefs
+            .getStructureSummaryFields().toArray(new FTSDataColumnI[0]);
+    return Arrays.equals(currentWantedFields, previousWantedFields) ? false
+            : true;
 
   }
 
@@ -703,6 +790,11 @@ public abstract class GStructureChooser extends JPanel implements
     }
   }
 
+  public JTable getResultTable()
+  {
+    return tbl_summary;
+  }
+
   public JComboBox<FilterOption> getCmbFilterOption()
   {
     return cmb_filterOption;
@@ -710,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 75099c2..ed758c5 100644 (file)
@@ -22,6 +22,8 @@ package jalview.renderer;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.CodingUtils;
+import jalview.analysis.Profile;
+import jalview.analysis.Rna;
 import jalview.analysis.StructureFrequency;
 import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
@@ -29,6 +31,7 @@ import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
+import jalview.util.Platform;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -43,8 +46,6 @@ import java.awt.image.ImageObserver;
 import java.util.BitSet;
 import java.util.Hashtable;
 
-import com.stevesoft.pat.Regex;
-
 public class AnnotationRenderer
 {
   private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32
@@ -58,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 Profile[] 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);
@@ -75,15 +140,26 @@ public class AnnotationRenderer
     this.debugRedraw = debugRedraw;
   }
 
-  public 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;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("(\\))");
 
     char dc = (column == 0 || row_annotations[column - 1] == null) ? ' '
             : row_annotations[column - 1].secondaryStructure;
@@ -93,15 +169,17 @@ public class AnnotationRenderer
     boolean diffdownstream = !validRes || !validEnd
             || row_annotations[column] == null
             || dc != row_annotations[column].secondaryStructure;
-    // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
-    // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && ResidueProperties.isCloseParenRNA(dc))
-    {
 
+    if (column > 0 && Rna.isClosingParenthesis(dc))
+    {
       if (diffupstream)
       // if (validRes && column>1 && row_annotations[column-2]!=null &&
       // dc.equals(row_annotations[column-2].displayCharacter))
       {
+        /*
+         * if new annotation with a closing base pair half of the stem, 
+         * display a backward arrow
+         */
         g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX },
                 new int[] { y + iconOffset, y + 14 + iconOffset,
                     y + 8 + iconOffset }, 3);
@@ -114,10 +192,13 @@ public class AnnotationRenderer
     }
     else
     {
-
       // display a forward arrow
       if (diffdownstream)
       {
+        /*
+         * if annotation ending with an opeing base pair half of the stem, 
+         * display a forward arrow
+         */
         g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] {
             y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3);
         x2 -= 5;
@@ -131,71 +212,7 @@ 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;
-
-  public void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
+  void drawNotCanonicalAnnot(Graphics g, Color nonCanColor,
           Annotation[] row_annotations, int lastSSX, int x, int y,
           int iconOffset, int startRes, int column, boolean validRes,
           boolean validEnd)
@@ -206,7 +223,6 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("}|]|<|[a-z]");
 
     String dc = (column == 0 || row_annotations[column - 1] == null) ? ""
             : row_annotations[column - 1].displayCharacter;
@@ -218,8 +234,7 @@ public class AnnotationRenderer
             || !dc.equals(row_annotations[column].displayCharacter);
     // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream);
     // If a closing base pair half of the stem, display a backward arrow
-    if (column > 0 && closeparen.search(dc))// closeletter_b.search(dc)||closeletter_c.search(dc)||closeletter_d.search(dc)||closecrochet.search(dc))
-                                            // )
+    if (column > 0 && Rna.isClosingParenthesis(dc))
     {
 
       if (diffupstream)
@@ -321,7 +336,7 @@ public class AnnotationRenderer
    * @param column
    * @return
    */
-  public int[] getProfileFor(AlignmentAnnotation aa, int column)
+  int[] getProfileFor(AlignmentAnnotation aa, int column)
   {
     // TODO : consider refactoring the global alignment calculation
     // properties/rendering attributes as a global 'alignment group' which holds
@@ -750,7 +765,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
-
+                  // no break if isRNA - falls through to drawNotCanonicalAnnot!
                 case 'E':
                   if (!isRNA)
                   {
@@ -759,6 +774,7 @@ public class AnnotationRenderer
                             validEnd);
                     break;
                   }
+                  // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
                 case '{':
                 case '}':
@@ -866,7 +882,6 @@ public class AnnotationRenderer
         {
           validRes = true;
         }
-
         // x ++;
 
         if (row.hasIcons)
@@ -881,6 +896,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case 'E':
             if (!isRNA)
@@ -889,6 +905,7 @@ public class AnnotationRenderer
                       startRes, column, validRes, validEnd);
               break;
             }
+            // no break if isRNA - fall through to drawNotCanonicalAnnot!
 
           case '(':
           case ')': // Stem case for RNA secondary structure
@@ -1069,15 +1086,15 @@ public class AnnotationRenderer
 
   private Color sdNOTCANONICAL_COLOUR;
 
-  public 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);
     g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2);
   }
 
-  public void drawSheetAnnot(Graphics g, Annotation[] row,
+  void drawSheetAnnot(Graphics g, Annotation[] row,
 
   int lastSSX, int x, int y, int iconOffset, int startRes, int column,
           boolean validRes, boolean validEnd)
@@ -1101,8 +1118,8 @@ public class AnnotationRenderer
 
   }
 
-  public 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);
@@ -1161,7 +1178,7 @@ public class AnnotationRenderer
     g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
   }
 
-  public void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawLineGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, int y,
           float min, float max, int graphHeight)
   {
@@ -1254,7 +1271,7 @@ public class AnnotationRenderer
     }
   }
 
-  public void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
+  void drawBarGraph(Graphics g, AlignmentAnnotation _aa,
           Annotation[] aa_annotations, int sRes, int eRes, float min,
           float max, int y, boolean renderHistogram, boolean renderProfile,
           boolean normaliseProfile)
@@ -1385,8 +1402,9 @@ public class AnnotationRenderer
             scl = htn * scale * profl[c++];
             lm = ofont.getLineMetrics(dc, 0, 1, g.getFontMetrics()
                     .getFontRenderContext());
-            g.setFont(ofont.deriveFont(AffineTransform.getScaleInstance(
-                    wdth, scl / lm.getAscent())));
+            Font font = ofont.deriveFont(AffineTransform.getScaleInstance(
+                    wdth, scl / lm.getAscent()));
+            g.setFont(font);
             lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g);
 
             // Debug - render boxes around characters
diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java
new file mode 100644 (file)
index 0000000..82536d4
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.renderer;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.SequenceI;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Calculate and display alignment rulers
+ * 
+ * @author jprocter
+ *
+ */
+public class ScaleRenderer
+{
+  public final class ScaleMark
+  {
+    public final boolean major;
+
+    public final int column;
+
+    public final String text;
+
+    ScaleMark(boolean isMajor, int col, String txt)
+    {
+      major = isMajor;
+      column = col;
+      text = txt;
+    }
+  }
+
+  /**
+   * calculate positions markers on the alignment ruler
+   * 
+   * @param av
+   * @param startx
+   *          left-most column in visible view
+   * @param endx
+   *          - right-most column in visible view
+   * @return List of ScaleMark holding boolean: true/false for major/minor mark,
+   *         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)
+  {
+    int scalestartx = (startx / 10) * 10;
+
+    SequenceI refSeq = av.getAlignment().getSeqrep();
+    int refSp = 0, refStartI = 0, refEndI = -1;
+    if (refSeq != null)
+    {
+      // find bounds and set origin appopriately
+      // locate first visible position for this sequence
+      int[] refbounds = av.getColumnSelection()
+              .locateVisibleBoundsOfSequence(refSeq);
+
+      refSp = refbounds[0];
+      refStartI = refbounds[4];
+      refEndI = refbounds[5];
+      scalestartx = refSp + ((scalestartx - refSp) / 10) * 10;
+    }
+
+    if (refSeq == null && scalestartx % 10 == 0)
+    {
+      scalestartx += 5;
+    }
+    List<ScaleMark> marks = new ArrayList<ScaleMark>();
+    String string;
+    int refN, iadj;
+    // todo: add a 'reference origin column' to set column number relative to
+    for (int i = scalestartx; i < endx; i += 5)
+    {
+      if (((i - refSp) % 10) == 0)
+      {
+        if (refSeq == null)
+        {
+          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1;
+          string = String.valueOf(iadj);
+        }
+        else
+        {
+          iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1);
+          refN = refSeq.findPosition(iadj);
+          // TODO show bounds if position is a gap
+          // - ie L--R -> "1L|2R" for
+          // marker
+          if (iadj < refStartI)
+          {
+            string = String.valueOf(iadj - refStartI);
+          }
+          else if (iadj > refEndI)
+          {
+            string = "+" + String.valueOf(iadj - refEndI);
+          }
+          else
+          {
+            string = String.valueOf(refN) + refSeq.getCharAt(iadj);
+          }
+        }
+        marks.add(new ScaleMark(true, i - startx - 1, string));
+      }
+      else
+      {
+        marks.add(new ScaleMark(false, i - startx - 1, null));
+      }
+    }
+    return marks;
+  }
+
+}
index 2276913..b007365 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.renderer.seqfeatures;
 
+import jalview.api.AlignViewportI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
@@ -50,6 +51,18 @@ public class FeatureRenderer extends FeatureRendererModel
 
   boolean av_validCharWidth, av_isShowSeqFeatureHeight;
 
+  private Integer currentColour;
+
+  /**
+   * Constructor given a viewport
+   * 
+   * @param viewport
+   */
+  public FeatureRenderer(AlignViewportI viewport)
+  {
+    this.av = viewport;
+  }
+
   protected void updateAvConfig()
   {
     av_charHeight = av.getCharHeight();
@@ -175,8 +188,8 @@ public class FeatureRenderer extends FeatureRendererModel
   }
 
   /**
-   * This is used by the Molecule Viewer and Overview to get the accurate
-   * colourof the rendered sequence
+   * This is used by the Molecule Viewer and Overview to get the accurate colour
+   * of the rendered sequence
    */
   public synchronized int findFeatureColour(int initialCol,
           final SequenceI seq, int column)
@@ -246,7 +259,7 @@ public class FeatureRenderer extends FeatureRendererModel
       }
       else
       {
-        return ((Integer) currentColour).intValue();
+        return currentColour.intValue();
       }
     }
 
@@ -390,7 +403,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
     }
 
-    if (transparency != 1.0f && g != null && transparencyAvailable)
+    if (transparency != 1.0f && g != null)
     {
       Graphics2D g2 = (Graphics2D) g;
       g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
@@ -398,19 +411,6 @@ public class FeatureRenderer extends FeatureRendererModel
     }
   }
 
-  boolean transparencyAvailable = true;
-
-  protected void setTransparencyAvailable(boolean isTransparencyAvailable)
-  {
-    transparencyAvailable = isTransparencyAvailable;
-  }
-
-  @Override
-  public boolean isTransparencyAvailable()
-  {
-    return transparencyAvailable;
-  }
-
   /**
    * Called when alignment in associated view has new/modified features to
    * discover and display.
index 361fb7c..0a01103 100644 (file)
@@ -1,4 +1,4 @@
-#Thu Sep 03 10:55:37 BST 2015
+#Mon Jun 20 15:44:52 BST 2016
 jalview.schemabinding.version2.ThresholdLine=jalview.schemabinding.version2.descriptors.ThresholdLineDescriptor
 jalview.schemabinding.version2.SequenceSetProperties=jalview.schemabinding.version2.descriptors.SequenceSetPropertiesDescriptor
 jalview.schemabinding.version2.StructureState=jalview.schemabinding.version2.descriptors.StructureStateDescriptor
index 9ca6708..7c6308e 100644 (file)
@@ -72,6 +72,16 @@ public class JSeq implements java.io.Serializable
   private boolean _has_hidden;
 
   /**
+   * Field _viewreference.
+   */
+  private boolean _viewreference;
+
+  /**
+   * keeps track of state for field: _viewreference
+   */
+  private boolean _has_viewreference;
+
+  /**
    * Field _featuresList.
    */
   private java.util.Vector _featuresList;
@@ -256,6 +266,13 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+     */
+  public void deleteViewreference()
+  {
+    this._has_viewreference = false;
+  }
+
+  /**
    * Method enumerateFeatures.
    * 
    * @return an Enumeration over all jalview.schemabinding.version2.Features
@@ -549,6 +566,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Returns the value of field 'viewreference'.
+   * 
+   * @return the value of field 'Viewreference'.
+   */
+  public boolean getViewreference()
+  {
+    return this._viewreference;
+  }
+
+  /**
    * Method hasColour.
    * 
    * @return true if at least one Colour has been added
@@ -589,6 +616,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Method hasViewreference.
+   * 
+   * @return true if at least one Viewreference has been added
+   */
+  public boolean hasViewreference()
+  {
+    return this._has_viewreference;
+  }
+
+  /**
    * Returns the value of field 'hidden'.
    * 
    * @return the value of field 'Hidden'.
@@ -616,6 +653,16 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Returns the value of field 'viewreference'.
+   * 
+   * @return the value of field 'Viewreference'.
+   */
+  public boolean isViewreference()
+  {
+    return this._viewreference;
+  }
+
+  /**
    * 
    * 
    * @param out
@@ -1004,6 +1051,18 @@ public class JSeq implements java.io.Serializable
   }
 
   /**
+   * Sets the value of field 'viewreference'.
+   * 
+   * @param viewreference
+   *          the value of field 'viewreference'.
+   */
+  public void setViewreference(final boolean viewreference)
+  {
+    this._viewreference = viewreference;
+    this._has_viewreference = true;
+  }
+
+  /**
    * Method unmarshal.
    * 
    * @param reader
index 1d2aad3..5739d90 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.AnnotationColours;
+
 /**
  * Class AnnotationColoursDescriptor.
  * 
index a7ffaba..107c06d 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.Features;
+
 /**
  * Class FeaturesDescriptor.
  * 
index 0f000bb..28f23b2 100644 (file)
@@ -334,6 +334,61 @@ public class JSeqDescriptor extends
       fieldValidator.setValidator(typeValidator);
     }
     desc.setValidator(fieldValidator);
+    // -- _viewreference
+    desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(
+            java.lang.Boolean.TYPE, "_viewreference", "viewreference",
+            org.exolab.castor.xml.NodeType.Attribute);
+    handler = new org.exolab.castor.xml.XMLFieldHandler()
+    {
+      public java.lang.Object getValue(java.lang.Object object)
+              throws IllegalStateException
+      {
+        JSeq target = (JSeq) object;
+        if (!target.hasViewreference())
+        {
+          return null;
+        }
+        return (target.getViewreference() ? java.lang.Boolean.TRUE
+                : java.lang.Boolean.FALSE);
+      }
+
+      public void setValue(java.lang.Object object, java.lang.Object value)
+              throws IllegalStateException, IllegalArgumentException
+      {
+        try
+        {
+          JSeq target = (JSeq) object;
+          // if null, use delete method for optional primitives
+          if (value == null)
+          {
+            target.deleteViewreference();
+            return;
+          }
+          target.setViewreference(((java.lang.Boolean) value)
+                  .booleanValue());
+        } catch (java.lang.Exception ex)
+        {
+          throw new IllegalStateException(ex.toString());
+        }
+      }
+
+      public java.lang.Object newInstance(java.lang.Object parent)
+      {
+        return null;
+      }
+    };
+    desc.setHandler(handler);
+    desc.setMultivalued(false);
+    addFieldDescriptor(desc);
+
+    // -- validation code for: _viewreference
+    fieldValidator = new org.exolab.castor.xml.FieldValidator();
+    { // -- local scope
+      org.exolab.castor.xml.validators.BooleanValidator typeValidator;
+      typeValidator = new org.exolab.castor.xml.validators.BooleanValidator();
+      fieldValidator.setValidator(typeValidator);
+    }
+    desc.setValidator(fieldValidator);
     // -- initialize element descriptors
 
     // -- _featuresList
index 77efa7e..d65de13 100644 (file)
@@ -72,6 +72,7 @@ public class JalviewUserColoursDescriptor extends
     desc.setImmutable(true);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -79,6 +80,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getSchemeName();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -92,6 +94,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return null;
@@ -119,6 +122,7 @@ public class JalviewUserColoursDescriptor extends
     desc.setImmutable(true);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -126,6 +130,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getVersion();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -139,6 +144,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return null;
@@ -163,6 +169,7 @@ public class JalviewUserColoursDescriptor extends
             org.exolab.castor.xml.NodeType.Element);
     handler = new org.exolab.castor.xml.XMLFieldHandler()
     {
+      @Override
       public java.lang.Object getValue(java.lang.Object object)
               throws IllegalStateException
       {
@@ -170,6 +177,7 @@ public class JalviewUserColoursDescriptor extends
         return target.getColour();
       }
 
+      @Override
       public void setValue(java.lang.Object object, java.lang.Object value)
               throws IllegalStateException, IllegalArgumentException
       {
@@ -183,6 +191,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public void resetValue(Object object) throws IllegalStateException,
               IllegalArgumentException
       {
@@ -196,6 +205,7 @@ public class JalviewUserColoursDescriptor extends
         }
       }
 
+      @Override
       public java.lang.Object newInstance(java.lang.Object parent)
       {
         return new Colour();
@@ -222,6 +232,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the access mode specified for this class.
    */
+  @Override
   public org.exolab.castor.mapping.AccessMode getAccessMode()
   {
     return null;
@@ -232,6 +243,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the identity field, null if this class has no identity.
    */
+  @Override
   public org.exolab.castor.mapping.FieldDescriptor getIdentity()
   {
     return super.getIdentity();
@@ -242,6 +254,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the Java class represented by this descriptor.
    */
+  @Override
   public java.lang.Class getJavaClass()
   {
     return jalview.schemabinding.version2.JalviewUserColours.class;
@@ -252,6 +265,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the namespace prefix to use when marshaling as XML.
    */
+  @Override
   public java.lang.String getNameSpacePrefix()
   {
     return _nsPrefix;
@@ -262,6 +276,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the namespace URI used when marshaling and unmarshaling as XML.
    */
+  @Override
   public java.lang.String getNameSpaceURI()
   {
     return _nsURI;
@@ -273,6 +288,7 @@ public class JalviewUserColoursDescriptor extends
    * @return a specific validator for the class described by this
    *         ClassDescriptor.
    */
+  @Override
   public org.exolab.castor.xml.TypeValidator getValidator()
   {
     return this;
@@ -283,6 +299,7 @@ public class JalviewUserColoursDescriptor extends
    * 
    * @return the XML Name for the Class being described.
    */
+  @Override
   public java.lang.String getXMLName()
   {
     return _xmlName;
@@ -294,6 +311,7 @@ public class JalviewUserColoursDescriptor extends
    * @return true if XML schema definition of this Class is that of a global
    *         element or element with anonymous type definition.
    */
+  @Override
   public boolean isElementDefinition()
   {
     return _elementDefinition;
index ece728a..df9ab07 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.UserColourScheme;
+
 /**
  * Class UserColourSchemeDescriptor.
  * 
index 86e6992..3e26611 100644 (file)
@@ -11,6 +11,8 @@ package jalview.schemabinding.version2.descriptors;
 //- Imported classes and packages -/
 //---------------------------------/
 
+import jalview.schemabinding.version2.VamsasModel;
+
 /**
  * Class VamsasModelDescriptor.
  * 
index 9d09259..37c31f9 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();
@@ -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[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..165ece9 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.schemes;
 
+import jalview.analysis.Profile;
 import jalview.datamodel.AnnotatedCollectionI;
 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(Profile[] hconsensus);
 
   /**
    * assign the given conservation to the colourscheme
diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java
new file mode 100644 (file)
index 0000000..23087a8
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * 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;
+import jalview.datamodel.SequenceFeature;
+import jalview.util.Format;
+
+import java.awt.Color;
+import java.util.StringTokenizer;
+
+/**
+ * A class that wraps either a simple colour or a graduated colour
+ */
+public class FeatureColour implements FeatureColourI
+{
+  private static final String BAR = "|";
+
+  final private Color colour;
+
+  final private Color minColour;
+
+  final private Color maxColour;
+
+  private boolean graduatedColour;
+
+  private boolean colourByLabel;
+
+  private float threshold;
+
+  private float base;
+
+  private float range;
+
+  private boolean belowThreshold;
+
+  private boolean aboveThreshold;
+
+  private boolean thresholdIsMinOrMax;
+
+  private boolean isHighToLow;
+
+  private boolean autoScaled;
+
+  final private float minRed;
+
+  final private float minGreen;
+
+  final private float minBlue;
+
+  final private float deltaRed;
+
+  final private float deltaGreen;
+
+  final private float deltaBlue;
+
+  /**
+   * Parses a Jalview features file format colour descriptor
+   * [label|][mincolour|maxcolour
+   * |[absolute|]minvalue|maxvalue|thresholdtype|thresholdvalue] Examples:
+   * <ul>
+   * <li>red</li>
+   * <li>a28bbb</li>
+   * <li>25,125,213</li>
+   * <li>label</li>
+   * <li>label|||0.0|0.0|above|12.5</li>
+   * <li>label|||0.0|0.0|below|12.5</li>
+   * <li>red|green|12.0|26.0|none</li>
+   * <li>a28bbb|3eb555|12.0|26.0|above|12.5</li>
+   * <li>a28bbb|3eb555|abso|12.0|26.0|below|12.5</li>
+   * </ul>
+   * 
+   * @param descriptor
+   * @return
+   * @throws IllegalArgumentException
+   *           if not parseable
+   */
+  public static FeatureColour parseJalviewFeatureColour(String descriptor)
+  {
+    StringTokenizer gcol = new StringTokenizer(descriptor, "|", true);
+    float min = Float.MIN_VALUE;
+    float max = Float.MAX_VALUE;
+    boolean labelColour = false;
+
+    String mincol = gcol.nextToken();
+    if (mincol == "|")
+    {
+      throw new IllegalArgumentException(
+              "Expected either 'label' or a colour specification in the line: "
+                      + descriptor);
+    }
+    String maxcol = null;
+    if (mincol.toLowerCase().indexOf("label") == 0)
+    {
+      labelColour = true;
+      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+      // skip '|'
+      mincol = (gcol.hasMoreTokens() ? gcol.nextToken() : null);
+    }
+
+    if (!labelColour && !gcol.hasMoreTokens())
+    {
+      /*
+       * only a simple colour specification - parse it
+       */
+      Color colour = UserColourScheme.getColourFromString(descriptor);
+      if (colour == null)
+      {
+        throw new IllegalArgumentException("Invalid colour descriptor: "
+                + descriptor);
+      }
+      return new FeatureColour(colour);
+    }
+
+    /*
+     * autoScaled == true: colours range over actual score range
+     * autoScaled == false ('abso'): colours range over min/max range
+     */
+    boolean autoScaled = true;
+    String tok = null, minval, maxval;
+    if (mincol != null)
+    {
+      // at least four more tokens
+      if (mincol.equals("|"))
+      {
+        mincol = "";
+      }
+      else
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      maxcol = gcol.nextToken();
+      if (maxcol.equals("|"))
+      {
+        maxcol = "";
+      }
+      else
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      tok = gcol.nextToken();
+      gcol.nextToken(); // skip next '|'
+      if (tok.toLowerCase().startsWith("abso"))
+      {
+        minval = gcol.nextToken();
+        gcol.nextToken(); // skip next '|'
+        autoScaled = false;
+      }
+      else
+      {
+        minval = tok;
+      }
+      maxval = gcol.nextToken();
+      if (gcol.hasMoreTokens())
+      {
+        gcol.nextToken(); // skip next '|'
+      }
+      try
+      {
+        if (minval.length() > 0)
+        {
+          min = new Float(minval).floatValue();
+        }
+      } catch (Exception e)
+      {
+        throw new IllegalArgumentException(
+                "Couldn't parse the minimum value for graduated colour ("
+                        + descriptor + ")");
+      }
+      try
+      {
+        if (maxval.length() > 0)
+        {
+          max = new Float(maxval).floatValue();
+        }
+      } catch (Exception e)
+      {
+        throw new IllegalArgumentException(
+                "Couldn't parse the maximum value for graduated colour ("
+                        + descriptor + ")");
+      }
+    }
+    else
+    {
+      // add in some dummy min/max colours for the label-only
+      // colourscheme.
+      mincol = "FFFFFF";
+      maxcol = "000000";
+    }
+
+    /*
+     * construct the FeatureColour
+     */
+    FeatureColour featureColour;
+    try
+    {
+      featureColour = new FeatureColour(
+              new UserColourScheme(mincol).findColour('A'),
+              new UserColourScheme(maxcol).findColour('A'), min, max);
+      featureColour.setColourByLabel(labelColour);
+      featureColour.setAutoScaled(autoScaled);
+      // add in any additional parameters
+      String ttype = null, tval = null;
+      if (gcol.hasMoreTokens())
+      {
+        // threshold type and possibly a threshold value
+        ttype = gcol.nextToken();
+        if (ttype.toLowerCase().startsWith("below"))
+        {
+          featureColour.setBelowThreshold(true);
+        }
+        else if (ttype.toLowerCase().startsWith("above"))
+        {
+          featureColour.setAboveThreshold(true);
+        }
+        else
+        {
+          if (!ttype.toLowerCase().startsWith("no"))
+          {
+            System.err.println("Ignoring unrecognised threshold type : "
+                    + ttype);
+          }
+        }
+      }
+      if (featureColour.hasThreshold())
+      {
+        try
+        {
+          gcol.nextToken();
+          tval = gcol.nextToken();
+          featureColour.setThreshold(new Float(tval).floatValue());
+        } catch (Exception e)
+        {
+          System.err.println("Couldn't parse threshold value as a float: ("
+                  + tval + ")");
+        }
+      }
+      if (gcol.hasMoreTokens())
+      {
+        System.err
+                .println("Ignoring additional tokens in parameters in graduated colour specification\n");
+        while (gcol.hasMoreTokens())
+        {
+          System.err.println("|" + gcol.nextToken());
+        }
+        System.err.println("\n");
+      }
+      return featureColour;
+    } catch (Exception e)
+    {
+      throw new IllegalArgumentException(e.getMessage());
+    }
+  }
+
+  /**
+   * Default constructor
+   */
+  public FeatureColour()
+  {
+    this((Color) null);
+  }
+
+  /**
+   * Constructor given a simple colour
+   * 
+   * @param c
+   */
+  public FeatureColour(Color c)
+  {
+    minColour = Color.WHITE;
+    maxColour = Color.BLACK;
+    minRed = 0f;
+    minGreen = 0f;
+    minBlue = 0f;
+    deltaRed = 0f;
+    deltaGreen = 0f;
+    deltaBlue = 0f;
+    colour = c;
+  }
+
+  /**
+   * Constructor given a colour range and a score range
+   * 
+   * @param low
+   * @param high
+   * @param min
+   * @param max
+   */
+  public FeatureColour(Color low, Color high, float min, float max)
+  {
+    graduatedColour = true;
+    colour = null;
+    minColour = low;
+    maxColour = high;
+    threshold = Float.NaN;
+    isHighToLow = min >= max;
+    minRed = low.getRed() / 255f;
+    minGreen = low.getGreen() / 255f;
+    minBlue = low.getBlue() / 255f;
+    deltaRed = (high.getRed() / 255f) - minRed;
+    deltaGreen = (high.getGreen() / 255f) - minGreen;
+    deltaBlue = (high.getBlue() / 255f) - minBlue;
+    if (isHighToLow)
+    {
+      base = max;
+      range = min - max;
+    }
+    else
+    {
+      base = min;
+      range = max - min;
+    }
+  }
+
+  /**
+   * Copy constructor
+   * 
+   * @param fc
+   */
+  public FeatureColour(FeatureColour fc)
+  {
+    graduatedColour = fc.graduatedColour;
+    colour = fc.colour;
+    minColour = fc.minColour;
+    maxColour = fc.maxColour;
+    minRed = fc.minRed;
+    minGreen = fc.minGreen;
+    minBlue = fc.minBlue;
+    deltaRed = fc.deltaRed;
+    deltaGreen = fc.deltaGreen;
+    deltaBlue = fc.deltaBlue;
+    base = fc.base;
+    range = fc.range;
+    isHighToLow = fc.isHighToLow;
+    setAboveThreshold(fc.isAboveThreshold());
+    setBelowThreshold(fc.isBelowThreshold());
+    setThreshold(fc.getThreshold());
+    setAutoScaled(fc.isAutoScaled());
+    setColourByLabel(fc.isColourByLabel());
+  }
+
+  /**
+   * Copy constructor with new min/max ranges
+   * 
+   * @param fc
+   * @param min
+   * @param max
+   */
+  public FeatureColour(FeatureColour fc, float min, float max)
+  {
+    this(fc);
+    graduatedColour = true;
+    updateBounds(min, max);
+  }
+
+  @Override
+  public boolean isGraduatedColour()
+  {
+    return graduatedColour;
+  }
+
+  /**
+   * Sets the 'graduated colour' flag. If true, also sets 'colour by label' to
+   * false.
+   */
+  void setGraduatedColour(boolean b)
+  {
+    graduatedColour = b;
+    if (b)
+    {
+      setColourByLabel(false);
+    }
+  }
+
+  @Override
+  public Color getColour()
+  {
+    return colour;
+  }
+
+  @Override
+  public Color getMinColour()
+  {
+    return minColour;
+  }
+
+  @Override
+  public Color getMaxColour()
+  {
+    return maxColour;
+  }
+
+  @Override
+  public boolean isColourByLabel()
+  {
+    return colourByLabel;
+  }
+
+  /**
+   * Sets the 'colour by label' flag. If true, also sets 'graduated colour' to
+   * false.
+   */
+  @Override
+  public void setColourByLabel(boolean b)
+  {
+    colourByLabel = b;
+    if (b)
+    {
+      setGraduatedColour(false);
+    }
+  }
+
+  @Override
+  public boolean isBelowThreshold()
+  {
+    return belowThreshold;
+  }
+
+  @Override
+  public void setBelowThreshold(boolean b)
+  {
+    belowThreshold = b;
+    if (b)
+    {
+      setAboveThreshold(false);
+    }
+  }
+
+  @Override
+  public boolean isAboveThreshold()
+  {
+    return aboveThreshold;
+  }
+
+  @Override
+  public void setAboveThreshold(boolean b)
+  {
+    aboveThreshold = b;
+    if (b)
+    {
+      setBelowThreshold(false);
+    }
+  }
+
+  @Override
+  public boolean isThresholdMinMax()
+  {
+    return thresholdIsMinOrMax;
+  }
+
+  @Override
+  public void setThresholdMinMax(boolean b)
+  {
+    thresholdIsMinOrMax = b;
+  }
+
+  @Override
+  public float getThreshold()
+  {
+    return threshold;
+  }
+
+  @Override
+  public void setThreshold(float f)
+  {
+    threshold = f;
+  }
+
+  @Override
+  public boolean isAutoScaled()
+  {
+    return autoScaled;
+  }
+
+  @Override
+  public void setAutoScaled(boolean b)
+  {
+    this.autoScaled = b;
+  }
+
+  /**
+   * Updates the base and range appropriately for the given minmax range
+   * 
+   * @param min
+   * @param max
+   */
+  @Override
+  public void updateBounds(float min, float max)
+  {
+    if (max < min)
+    {
+      base = max;
+      range = min - max;
+      isHighToLow = true;
+    }
+    else
+    {
+      base = min;
+      range = max - min;
+      isHighToLow = false;
+    }
+  }
+
+  /**
+   * Returns the colour for the given instance of the feature. This may be a
+   * simple colour, a colour generated from the feature description (if
+   * isColourByLabel()), or a colour derived from the feature score (if
+   * isGraduatedColour()).
+   * 
+   * @param feature
+   * @return
+   */
+  @Override
+  public Color getColor(SequenceFeature feature)
+  {
+    if (isColourByLabel())
+    {
+      return UserColourScheme
+              .createColourFromName(feature.getDescription());
+    }
+
+    if (!isGraduatedColour())
+    {
+      return getColour();
+    }
+
+    // todo should we check for above/below threshold here?
+    if (range == 0.0)
+    {
+      return getMaxColour();
+    }
+    float scr = feature.getScore();
+    if (Float.isNaN(scr))
+    {
+      return getMinColour();
+    }
+    float scl = (scr - base) / range;
+    if (isHighToLow)
+    {
+      scl = -scl;
+    }
+    if (scl < 0f)
+    {
+      scl = 0f;
+    }
+    if (scl > 1f)
+    {
+      scl = 1f;
+    }
+    return new Color(minRed + scl * deltaRed, minGreen + scl * deltaGreen,
+            minBlue + scl * deltaBlue);
+  }
+
+  /**
+   * Returns the maximum score of the graduated colour range
+   * 
+   * @return
+   */
+  @Override
+  public float getMax()
+  {
+    // regenerate the original values passed in to the constructor
+    return (isHighToLow) ? base : (base + range);
+  }
+
+  /**
+   * Returns the minimum score of the graduated colour range
+   * 
+   * @return
+   */
+  @Override
+  public float getMin()
+  {
+    // regenerate the original value passed in to the constructor
+    return (isHighToLow) ? (base + range) : base;
+  }
+
+  /**
+   * Answers true if the feature has a simple colour, or is coloured by label,
+   * or has a graduated colour and the score of this feature instance is within
+   * the range to render (if any), i.e. does not lie below or above any
+   * threshold set.
+   * 
+   * @param feature
+   * @return
+   */
+  @Override
+  public boolean isColored(SequenceFeature feature)
+  {
+    if (isColourByLabel() || !isGraduatedColour())
+    {
+      return true;
+    }
+
+    float val = feature.getScore();
+    if (Float.isNaN(val))
+    {
+      return true;
+    }
+    if (Float.isNaN(this.threshold))
+    {
+      return true;
+    }
+
+    if (isAboveThreshold() && val <= threshold)
+    {
+      return false;
+    }
+    if (isBelowThreshold() && val >= threshold)
+    {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public boolean isSimpleColour()
+  {
+    return (!isColourByLabel() && !isGraduatedColour());
+  }
+
+  @Override
+  public boolean hasThreshold()
+  {
+    return isAboveThreshold() || isBelowThreshold();
+  }
+
+  @Override
+  public String toJalviewFormat(String featureType)
+  {
+    String colourString = null;
+    if (isSimpleColour())
+    {
+      colourString = Format.getHexString(getColour());
+    }
+    else
+    {
+      StringBuilder sb = new StringBuilder(32);
+      if (isColourByLabel())
+      {
+        sb.append("label");
+        if (hasThreshold())
+        {
+          sb.append(BAR).append(BAR).append(BAR);
+        }
+      }
+      if (isGraduatedColour())
+      {
+        sb.append(Format.getHexString(getMinColour())).append(BAR);
+        sb.append(Format.getHexString(getMaxColour())).append(BAR);
+        if (!isAutoScaled())
+        {
+          sb.append("abso").append(BAR);
+        }
+      }
+      if (hasThreshold() || isGraduatedColour())
+      {
+        sb.append(getMin()).append(BAR);
+        sb.append(getMax()).append(BAR);
+        if (isBelowThreshold())
+        {
+          sb.append("below").append(BAR).append(getThreshold());
+        }
+        else if (isAboveThreshold())
+        {
+          sb.append("above").append(BAR).append(getThreshold());
+        }
+        else
+        {
+          sb.append("none");
+        }
+      }
+      colourString = sb.toString();
+    }
+    return String.format("%s\t%s", featureType, colourString);
+  }
+
+}
diff --git a/src/jalview/schemes/FeatureColourAdapter.java b/src/jalview/schemes/FeatureColourAdapter.java
deleted file mode 100644 (file)
index a86bee4..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-package jalview.schemes;
-
-import jalview.api.FeatureColourI;
-
-import java.awt.Color;
-
-/**
- * A convenience class with implementations of FeatureColourI methods. Override
- * methods as required in subclasses.
- */
-public class FeatureColourAdapter implements FeatureColourI
-{
-  @Override
-  public boolean isGraduatedColour()
-  {
-    return isColourByLabel() || isAboveThreshold() || isBelowThreshold();
-  }
-
-  @Override
-  public Color getColour()
-  {
-    return Color.BLACK;
-  }
-
-  @Override
-  public Color getMinColour()
-  {
-    return Color.WHITE;
-  }
-
-  @Override
-  public Color getMaxColour()
-  {
-    return Color.BLACK;
-  }
-
-  @Override
-  public boolean isColourByLabel()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isBelowThreshold()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isAboveThreshold()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean isThresholdMinMax()
-  {
-    return false;
-  }
-
-  @Override
-  public float getThreshold()
-  {
-    return 0f;
-  }
-
-  @Override
-  public boolean isLowToHigh()
-  {
-    return true;
-  }
-
-}
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..0dcf960 100644 (file)
@@ -21,8 +21,7 @@
 package jalview.schemes;
 
 import jalview.analysis.Conservation;
-
-import java.util.Hashtable;
+import jalview.analysis.Profile;
 
 /**
  * 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(Profile[] consensus)
   {
     if (colourScheme != null)
     {
diff --git a/src/jalview/schemes/GraduatedColor.java b/src/jalview/schemes/GraduatedColor.java
deleted file mode 100644 (file)
index 2d1c572..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.schemes;
-
-import jalview.api.FeatureColourI;
-import jalview.datamodel.SequenceFeature;
-
-import java.awt.Color;
-
-/**
- * Value and/or thresholded colour scale used for colouring by annotation and
- * feature score
- * 
- * @author JimP
- * 
- */
-public class GraduatedColor
-{
-  int thresholdState = AnnotationColourGradient.NO_THRESHOLD; // or
-                                                              // ABOVE_THRESHOLD
-                                                              // or
-                                                              // BELOW_THRESHOLD
-
-  float lr, lg, lb, dr, dg, db;
-
-  /**
-   * linear scaling parameters, base, minimum colour threshold, range of linear
-   * scale from lower to upper
-   */
-  float base, range, thrsh;
-
-  /**
-   * when true, colour from u to u-d rather than u to u+d
-   */
-  boolean tolow = false;
-
-  /**
-   * when false, min/max range has been manually set so should not be
-   * dynamically adjusted.
-   */
-  boolean autoScale = true;
-
-  /**
-   * construct a graduatedColor object from simple parameters
-   * 
-   * @param low
-   * @param high
-   * @param min
-   * @param max
-   *          color low->high from min->max
-   */
-  public GraduatedColor(Color low, Color high, float min, float max)
-  {
-    thrsh = Float.NaN;
-    tolow = min >= max;
-    lr = low.getRed() / 255f;
-    lg = low.getGreen() / 255f;
-    lb = low.getBlue() / 255f;
-    dr = (high.getRed() / 255f) - lr;
-    dg = (high.getGreen() / 255f) - lg;
-    db = (high.getBlue() / 255f) - lb;
-    if (tolow)
-    {
-      base = max;
-      range = min - max;
-    }
-    else
-    {
-      base = min;
-      range = max - min;
-    }
-  }
-
-  public GraduatedColor(GraduatedColor oldcs)
-  {
-    lr = oldcs.lr;
-    lg = oldcs.lg;
-    lb = oldcs.lb;
-    dr = oldcs.dr;
-    dg = oldcs.dg;
-    db = oldcs.db;
-    base = oldcs.base;
-    range = oldcs.range;
-    tolow = oldcs.tolow;
-    thresholdState = oldcs.thresholdState;
-    thrsh = oldcs.thrsh;
-    autoScale = oldcs.autoScale;
-    colourByLabel = oldcs.colourByLabel;
-  }
-
-  /**
-   * make a new gradient from an old one with a different scale range
-   * 
-   * @param oldcs
-   * @param min
-   * @param max
-   */
-  public GraduatedColor(GraduatedColor oldcs, float min, float max)
-  {
-    this(oldcs);
-    updateBounds(min, max);
-  }
-
-  public GraduatedColor(FeatureColourI col)
-  {
-    setColourByLabel(col.isColourByLabel());
-  }
-
-  public Color getMinColor()
-  {
-    return new Color(lr, lg, lb);
-  }
-
-  public Color getMaxColor()
-  {
-    return new Color(lr + dr, lg + dg, lb + db);
-  }
-
-  /**
-   * 
-   * @return true if original min/max scale was from high to low
-   */
-  public boolean getTolow()
-  {
-    return tolow;
-  }
-
-  public void setTolow(boolean tolower)
-  {
-    tolow = tolower;
-  }
-
-  public boolean isColored(SequenceFeature feature)
-  {
-    float val = feature.getScore();
-    if (Float.isNaN(val))
-    {
-      return true;
-    }
-    if (this.thresholdState == AnnotationColourGradient.NO_THRESHOLD)
-    {
-      return true;
-    }
-    if (Float.isNaN(this.thrsh))
-    {
-      return true;
-    }
-    boolean rtn = thresholdState == AnnotationColourGradient.ABOVE_THRESHOLD;
-    if (val <= thrsh)
-    {
-      return !rtn; // ? !tolow : tolow;
-    }
-    else
-    {
-      return rtn; // ? tolow : !tolow;
-    }
-  }
-
-  /**
-   * default implementor of a getColourFromString method. TODO: abstract an
-   * interface enabling pluggable colour from string
-   */
-  private UserColourScheme ucs = null;
-
-  private boolean colourByLabel = false;
-
-  /**
-   * 
-   * @return true if colourByLabel style is set
-   */
-  public boolean isColourByLabel()
-  {
-    return colourByLabel;
-  }
-
-  /**
-   * @param colourByLabel
-   *          the colourByLabel to set
-   */
-  public void setColourByLabel(boolean colourByLabel)
-  {
-    this.colourByLabel = colourByLabel;
-  }
-
-  public Color findColor(SequenceFeature feature)
-  {
-    if (colourByLabel)
-    {
-      // TODO: allow user defined feature label colourschemes. Colour space is
-      // {type,regex,%anytype%}x{description string, regex, keyword}
-      if (ucs == null)
-      {
-        ucs = new UserColourScheme();
-      }
-      return ucs.createColourFromName(feature.getDescription());
-    }
-    if (range == 0.0)
-    {
-      return getMaxColor();
-    }
-    float scr = feature.getScore();
-    if (Float.isNaN(scr))
-    {
-      return getMinColor();
-    }
-    float scl = (scr - base) / range;
-    if (tolow)
-    {
-      scl = -scl;
-    }
-    if (scl < 0f)
-    {
-      scl = 0f;
-    }
-    if (scl > 1f)
-    {
-      scl = 1f;
-    }
-    return new Color(lr + scl * dr, lg + scl * dg, lb + scl * db);
-  }
-
-  public void setThresh(float value)
-  {
-    thrsh = value;
-  }
-
-  public float getThresh()
-  {
-    return thrsh;
-  }
-
-  public void setThreshType(int aboveThreshold)
-  {
-    thresholdState = aboveThreshold;
-  }
-
-  public int getThreshType()
-  {
-    return thresholdState;
-  }
-
-  public float getMax()
-  {
-    // regenerate the original values passed in to the constructor
-    return (tolow) ? base : (base + range);
-  }
-
-  public float getMin()
-  {
-    // regenerate the original value passed in to the constructor
-    return (tolow) ? (base + range) : base;
-  }
-
-  public boolean isAutoScale()
-  {
-    return autoScale;
-  }
-
-  public void setAutoScaled(boolean autoscale)
-  {
-    autoScale = autoscale;
-  }
-
-  /**
-   * update the base and range appropriatly for the given minmax range
-   * 
-   * @param a
-   *          float[] {min,max} array containing minmax range for the associated
-   *          score values
-   */
-  public void updateBounds(float min, float max)
-  {
-    if (max < min)
-    {
-      base = max;
-      range = min - max;
-      tolow = true;
-    }
-    else
-    {
-      base = min;
-      range = max - min;
-      tolow = false;
-    }
-  }
-}
index 9dd763d..ccc69c2 100755 (executable)
@@ -20,9 +20,9 @@
  */
 package jalview.schemes;
 
-import jalview.analysis.AAFrequency;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.util.Comparison;
 
 import java.awt.Color;
 
@@ -67,20 +67,22 @@ public class PIDColourScheme extends ResidueColourScheme
       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
+     */
+    boolean matchesConsensus = consensus[j].getModalResidue().contains(
+            String.valueOf(c));
+    if (matchesConsensus)
     {
-      sc = ((Float) consensus[j].get(ignoreGaps)).floatValue();
+      sc = consensus[j].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 d17f510..9729a83 100644 (file)
@@ -91,6 +91,10 @@ public class RNAHelicesColour extends ResidueColourScheme
     // This loop will find the first rna structure annotation by which to colour
     // the sequences.
     AlignmentAnnotation[] annotations = alignment.getAlignmentAnnotation();
+    if (annotations == null)
+    {
+      return;
+    }
     for (int i = 0; i < annotations.length; i++)
     {
 
index 1a13bbe..b1b3c5a 100644 (file)
@@ -22,6 +22,7 @@ package jalview.schemes;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceGroup;
 
 import java.awt.event.ActionEvent;
@@ -77,16 +78,20 @@ public class RNAHelicesColourChooser
     adjusting = true;
     Vector list = new Vector();
     int index = 1;
-    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
+    if (anns != null)
     {
-      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
-      if (!list.contains(label))
+      for (int i = 0; i < anns.length; i++)
       {
-        list.addElement(label);
-      }
-      else
-      {
-        list.addElement(label + "_" + (index++));
+        String label = anns[i].label;
+        if (!list.contains(label))
+        {
+          list.addElement(label);
+        }
+        else
+        {
+          list.addElement(label + "_" + (index++));
+        }
       }
     }
 
index bca98cf..a15ca20 100755 (executable)
  */
 package jalview.schemes;
 
-import jalview.analysis.AAFrequency;
 import jalview.analysis.Conservation;
+import jalview.analysis.Profile;
 import jalview.datamodel.AnnotatedCollectionI;
 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 +49,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
+   */
+  Profile[] 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 +105,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 +139,62 @@ 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 || consensus.length < column
+            || consensus[column] == null)
     {
       return false;
     }
 
-    if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
-            && consensus[j].contains(String.valueOf(c)))
+    /*
+     * test whether this is the consensus (or joint consensus) residue
+     */
+    if (consensus[column].getModalResidue().contains(
+            String.valueOf(residue)))
     {
-      if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
+      if (consensus[column].getPercentageIdentity(ignoreGaps) >= threshold)
       {
         return true;
       }
@@ -193,6 +203,7 @@ public class ResidueColourScheme implements ColourSchemeI
     return false;
   }
 
+  @Override
   public boolean conservationApplied()
   {
     return conservationColouring;
@@ -204,11 +215,13 @@ public class ResidueColourScheme implements ColourSchemeI
     conservationColouring = conservationApplied;
   }
 
+  @Override
   public void setConservationInc(int i)
   {
     inc = i;
   }
 
+  @Override
   public int getConservationInc()
   {
     return inc;
@@ -220,7 +233,8 @@ public class ResidueColourScheme implements ColourSchemeI
    * @param consensus
    *          DOCUMENT ME!
    */
-  public void setConsensus(Hashtable[] consensus)
+  @Override
+  public void setConsensus(Profile[] consensus)
   {
     if (consensus == null)
     {
@@ -230,6 +244,7 @@ public class ResidueColourScheme implements ColourSchemeI
     this.consensus = consensus;
   }
 
+  @Override
   public void setConservation(Conservation cons)
   {
     if (cons == null)
@@ -240,73 +255,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 2aa24a1..90a7952 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;
@@ -223,36 +224,36 @@ public class ResidueProperties
 
   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", Integer.valueOf(0));
+    aa3Hash.put("ARG", Integer.valueOf(1));
+    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 +306,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 +573,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 +619,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 +628,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 +818,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 +883,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", Integer.valueOf(1));
+    hydrophobic.put("L", Integer.valueOf(1));
+    hydrophobic.put("V", Integer.valueOf(1));
+    hydrophobic.put("C", Integer.valueOf(1));
+    hydrophobic.put("A", Integer.valueOf(1));
+    hydrophobic.put("G", Integer.valueOf(1));
+    hydrophobic.put("M", Integer.valueOf(1));
+    hydrophobic.put("F", Integer.valueOf(1));
+    hydrophobic.put("Y", Integer.valueOf(1));
+    hydrophobic.put("W", Integer.valueOf(1));
+    hydrophobic.put("H", Integer.valueOf(1));
+    hydrophobic.put("K", Integer.valueOf(1));
+    hydrophobic.put("X", Integer.valueOf(1));
+    hydrophobic.put("-", Integer.valueOf(1));
+    hydrophobic.put("*", Integer.valueOf(1));
+    hydrophobic.put("R", Integer.valueOf(0));
+    hydrophobic.put("E", Integer.valueOf(0));
+    hydrophobic.put("Q", Integer.valueOf(0));
+    hydrophobic.put("D", Integer.valueOf(0));
+    hydrophobic.put("N", Integer.valueOf(0));
+    hydrophobic.put("S", Integer.valueOf(0));
+    hydrophobic.put("T", Integer.valueOf(0));
+    hydrophobic.put("P", Integer.valueOf(0));
   }
 
   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", Integer.valueOf(1));
+    polar.put("W", Integer.valueOf(1));
+    polar.put("H", Integer.valueOf(1));
+    polar.put("K", Integer.valueOf(1));
+    polar.put("R", Integer.valueOf(1));
+    polar.put("E", Integer.valueOf(1));
+    polar.put("Q", Integer.valueOf(1));
+    polar.put("D", Integer.valueOf(1));
+    polar.put("N", Integer.valueOf(1));
+    polar.put("S", Integer.valueOf(1));
+    polar.put("T", Integer.valueOf(1));
+    polar.put("X", Integer.valueOf(1));
+    polar.put("-", Integer.valueOf(1));
+    polar.put("*", Integer.valueOf(1));
+    polar.put("I", Integer.valueOf(0));
+    polar.put("L", Integer.valueOf(0));
+    polar.put("V", Integer.valueOf(0));
+    polar.put("C", Integer.valueOf(0));
+    polar.put("A", Integer.valueOf(0));
+    polar.put("G", Integer.valueOf(0));
+    polar.put("M", Integer.valueOf(0));
+    polar.put("F", Integer.valueOf(0));
+    polar.put("P", Integer.valueOf(0));
   }
 
   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", Integer.valueOf(0));
+    small.put("L", Integer.valueOf(0));
+    small.put("V", Integer.valueOf(1));
+    small.put("C", Integer.valueOf(1));
+    small.put("A", Integer.valueOf(1));
+    small.put("G", Integer.valueOf(1));
+    small.put("M", Integer.valueOf(0));
+    small.put("F", Integer.valueOf(0));
+    small.put("Y", Integer.valueOf(0));
+    small.put("W", Integer.valueOf(0));
+    small.put("H", Integer.valueOf(0));
+    small.put("K", Integer.valueOf(0));
+    small.put("R", Integer.valueOf(0));
+    small.put("E", Integer.valueOf(0));
+    small.put("Q", Integer.valueOf(0));
+    small.put("D", Integer.valueOf(1));
+    small.put("N", Integer.valueOf(1));
+    small.put("S", Integer.valueOf(1));
+    small.put("T", Integer.valueOf(1));
+    small.put("P", Integer.valueOf(1));
+    small.put("-", Integer.valueOf(1));
+    small.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    positive.put("L", Integer.valueOf(0));
+    positive.put("V", Integer.valueOf(0));
+    positive.put("C", Integer.valueOf(0));
+    positive.put("A", Integer.valueOf(0));
+    positive.put("G", Integer.valueOf(0));
+    positive.put("M", Integer.valueOf(0));
+    positive.put("F", Integer.valueOf(0));
+    positive.put("Y", Integer.valueOf(0));
+    positive.put("W", Integer.valueOf(0));
+    positive.put("H", Integer.valueOf(1));
+    positive.put("K", Integer.valueOf(1));
+    positive.put("R", Integer.valueOf(1));
+    positive.put("E", Integer.valueOf(0));
+    positive.put("Q", Integer.valueOf(0));
+    positive.put("D", Integer.valueOf(0));
+    positive.put("N", Integer.valueOf(0));
+    positive.put("S", Integer.valueOf(0));
+    positive.put("T", Integer.valueOf(0));
+    positive.put("P", Integer.valueOf(0));
+    positive.put("-", Integer.valueOf(1));
+    positive.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    negative.put("L", Integer.valueOf(0));
+    negative.put("V", Integer.valueOf(0));
+    negative.put("C", Integer.valueOf(0));
+    negative.put("A", Integer.valueOf(0));
+    negative.put("G", Integer.valueOf(0));
+    negative.put("M", Integer.valueOf(0));
+    negative.put("F", Integer.valueOf(0));
+    negative.put("Y", Integer.valueOf(0));
+    negative.put("W", Integer.valueOf(0));
+    negative.put("H", Integer.valueOf(0));
+    negative.put("K", Integer.valueOf(0));
+    negative.put("R", Integer.valueOf(0));
+    negative.put("E", Integer.valueOf(1));
+    negative.put("Q", Integer.valueOf(0));
+    negative.put("D", Integer.valueOf(1));
+    negative.put("N", Integer.valueOf(0));
+    negative.put("S", Integer.valueOf(0));
+    negative.put("T", Integer.valueOf(0));
+    negative.put("P", Integer.valueOf(0));
+    negative.put("-", Integer.valueOf(1));
+    negative.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    charged.put("L", Integer.valueOf(0));
+    charged.put("V", Integer.valueOf(0));
+    charged.put("C", Integer.valueOf(0));
+    charged.put("A", Integer.valueOf(0));
+    charged.put("G", Integer.valueOf(0));
+    charged.put("M", Integer.valueOf(0));
+    charged.put("F", Integer.valueOf(0));
+    charged.put("Y", Integer.valueOf(0));
+    charged.put("W", Integer.valueOf(0));
+    charged.put("H", Integer.valueOf(1));
+    charged.put("K", Integer.valueOf(1));
+    charged.put("R", Integer.valueOf(1));
+    charged.put("E", Integer.valueOf(1));
+    charged.put("Q", Integer.valueOf(0));
+    charged.put("D", Integer.valueOf(1));
+    charged.put("N", Integer.valueOf(0)); // Asparagine is polar but not
+                                          // charged.
+    // Alternative would be charged and
+    // negative (in basic form)?
+    charged.put("S", Integer.valueOf(0));
+    charged.put("T", Integer.valueOf(0));
+    charged.put("P", Integer.valueOf(0));
+    charged.put("-", Integer.valueOf(1));
+    charged.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    aromatic.put("L", Integer.valueOf(0));
+    aromatic.put("V", Integer.valueOf(0));
+    aromatic.put("C", Integer.valueOf(0));
+    aromatic.put("A", Integer.valueOf(0));
+    aromatic.put("G", Integer.valueOf(0));
+    aromatic.put("M", Integer.valueOf(0));
+    aromatic.put("F", Integer.valueOf(1));
+    aromatic.put("Y", Integer.valueOf(1));
+    aromatic.put("W", Integer.valueOf(1));
+    aromatic.put("H", Integer.valueOf(1));
+    aromatic.put("K", Integer.valueOf(0));
+    aromatic.put("R", Integer.valueOf(0));
+    aromatic.put("E", Integer.valueOf(0));
+    aromatic.put("Q", Integer.valueOf(0));
+    aromatic.put("D", Integer.valueOf(0));
+    aromatic.put("N", Integer.valueOf(0));
+    aromatic.put("S", Integer.valueOf(0));
+    aromatic.put("T", Integer.valueOf(0));
+    aromatic.put("P", Integer.valueOf(0));
+    aromatic.put("-", Integer.valueOf(1));
+    aromatic.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(1));
+    aliphatic.put("L", Integer.valueOf(1));
+    aliphatic.put("V", Integer.valueOf(1));
+    aliphatic.put("C", Integer.valueOf(0));
+    aliphatic.put("A", Integer.valueOf(0));
+    aliphatic.put("G", Integer.valueOf(0));
+    aliphatic.put("M", Integer.valueOf(0));
+    aliphatic.put("F", Integer.valueOf(0));
+    aliphatic.put("Y", Integer.valueOf(0));
+    aliphatic.put("W", Integer.valueOf(0));
+    aliphatic.put("H", Integer.valueOf(0));
+    aliphatic.put("K", Integer.valueOf(0));
+    aliphatic.put("R", Integer.valueOf(0));
+    aliphatic.put("E", Integer.valueOf(0));
+    aliphatic.put("Q", Integer.valueOf(0));
+    aliphatic.put("D", Integer.valueOf(0));
+    aliphatic.put("N", Integer.valueOf(0));
+    aliphatic.put("S", Integer.valueOf(0));
+    aliphatic.put("T", Integer.valueOf(0));
+    aliphatic.put("P", Integer.valueOf(0));
+    aliphatic.put("-", Integer.valueOf(1));
+    aliphatic.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    tiny.put("L", Integer.valueOf(0));
+    tiny.put("V", Integer.valueOf(0));
+    tiny.put("C", Integer.valueOf(0));
+    tiny.put("A", Integer.valueOf(1));
+    tiny.put("G", Integer.valueOf(1));
+    tiny.put("M", Integer.valueOf(0));
+    tiny.put("F", Integer.valueOf(0));
+    tiny.put("Y", Integer.valueOf(0));
+    tiny.put("W", Integer.valueOf(0));
+    tiny.put("H", Integer.valueOf(0));
+    tiny.put("K", Integer.valueOf(0));
+    tiny.put("R", Integer.valueOf(0));
+    tiny.put("E", Integer.valueOf(0));
+    tiny.put("Q", Integer.valueOf(0));
+    tiny.put("D", Integer.valueOf(0));
+    tiny.put("N", Integer.valueOf(0));
+    tiny.put("S", Integer.valueOf(1));
+    tiny.put("T", Integer.valueOf(0));
+    tiny.put("P", Integer.valueOf(0));
+    tiny.put("-", Integer.valueOf(1));
+    tiny.put("*", Integer.valueOf(1));
   }
 
   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", Integer.valueOf(0));
+    proline.put("L", Integer.valueOf(0));
+    proline.put("V", Integer.valueOf(0));
+    proline.put("C", Integer.valueOf(0));
+    proline.put("A", Integer.valueOf(0));
+    proline.put("G", Integer.valueOf(0));
+    proline.put("M", Integer.valueOf(0));
+    proline.put("F", Integer.valueOf(0));
+    proline.put("Y", Integer.valueOf(0));
+    proline.put("W", Integer.valueOf(0));
+    proline.put("H", Integer.valueOf(0));
+    proline.put("K", Integer.valueOf(0));
+    proline.put("R", Integer.valueOf(0));
+    proline.put("E", Integer.valueOf(0));
+    proline.put("Q", Integer.valueOf(0));
+    proline.put("D", Integer.valueOf(0));
+    proline.put("N", Integer.valueOf(0));
+    proline.put("S", Integer.valueOf(0));
+    proline.put("T", Integer.valueOf(0));
+    proline.put("P", Integer.valueOf(1));
+    proline.put("-", Integer.valueOf(1));
+    proline.put("*", Integer.valueOf(1));
   }
 
   static
@@ -1368,11 +1215,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 +1315,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 +1325,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 +1372,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 +1405,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
       {
@@ -1603,87 +1415,6 @@ public class ResidueProperties
     return ss.toString();
   }
 
-  /**
-   * Used by getRNASecStrucState
-   * 
-   */
-  public static Hashtable<String, String> toRNAssState;
-
-  public static boolean RNAcloseParen[] = new boolean[255];
-  static
-  {
-    toRNAssState = new Hashtable<String, String>();
-    toRNAssState.put(")", "(");
-    toRNAssState.put("(", "(");
-    toRNAssState.put("]", "[");
-    toRNAssState.put("[", "[");
-    toRNAssState.put("{", "{");
-    toRNAssState.put("}", "{");
-    toRNAssState.put(">", ">");
-    toRNAssState.put("<", ">");
-    toRNAssState.put("A", "A");
-    toRNAssState.put("a", "A");
-    toRNAssState.put("B", "B");
-    toRNAssState.put("b", "B");
-    toRNAssState.put("C", "C");
-    toRNAssState.put("c", "C");
-    toRNAssState.put("D", "D");
-    toRNAssState.put("d", "D");
-    toRNAssState.put("E", "E");
-    toRNAssState.put("e", "E");
-    toRNAssState.put("F", "F");
-    toRNAssState.put("f", "F");
-    toRNAssState.put("G", "G");
-    toRNAssState.put("g", "G");
-    toRNAssState.put("H", "H");
-    toRNAssState.put("h", "H");
-    toRNAssState.put("I", "I");
-    toRNAssState.put("i", "I");
-    toRNAssState.put("J", "J");
-    toRNAssState.put("j", "J");
-    toRNAssState.put("K", "K");
-    toRNAssState.put("k", "K");
-    toRNAssState.put("L", "L");
-    toRNAssState.put("l", "L");
-    toRNAssState.put("M", "M");
-    toRNAssState.put("m", "M");
-    toRNAssState.put("N", "N");
-    toRNAssState.put("n", "N");
-    toRNAssState.put("O", "O");
-    toRNAssState.put("o", "O");
-    toRNAssState.put("P", "P");
-    toRNAssState.put("p", "P");
-    toRNAssState.put("Q", "Q");
-    toRNAssState.put("q", "Q");
-    toRNAssState.put("R", "R");
-    toRNAssState.put("r", "R");
-    toRNAssState.put("S", "S");
-    toRNAssState.put("s", "S");
-    toRNAssState.put("T", "T");
-    toRNAssState.put("t", "T");
-    toRNAssState.put("U", "U");
-    toRNAssState.put("u", "U");
-    toRNAssState.put("V", "V");
-    toRNAssState.put("v", "V");
-    toRNAssState.put("W", "W");
-    toRNAssState.put("w", "W");
-    toRNAssState.put("X", "X");
-    toRNAssState.put("x", "X");
-    toRNAssState.put("Y", "Y");
-    toRNAssState.put("y", "Y");
-    toRNAssState.put("Z", "Z");
-    toRNAssState.put("z", "Z");
-    for (int p = 0; p < RNAcloseParen.length; p++)
-    {
-      RNAcloseParen[p] = false;
-    }
-    for (String k : toRNAssState.keySet())
-    {
-      RNAcloseParen[k.charAt(0)] = k.charAt(0) != toRNAssState.get(k)
-              .charAt(0);
-    }
-  }
-
   static
   {
     modifications.put("MSE", "MET"); // Selenomethionine
@@ -3002,85 +2733,47 @@ public class ResidueProperties
 
   }
 
-  public static String getCanonicalAminoAcid(String aa)
-  {
-    String canonical = modifications.get(aa);
-    return canonical == null ? aa : canonical;
-  }
-
-  /**
-   * translate to RNA secondary structure representation
-   * 
-   * @param ssstring
-   * @return ssstring as a RNA-state secondary structure assignment.
-   */
-  public static String getRNASecStrucState(String ssstring)
-  {
-    if (ssstring == null)
-    {
-      return null;
-    }
-    StringBuffer ss = new StringBuffer();
-    for (int i = 0; i < ssstring.length(); i++)
-    {
-      String ssc = ssstring.substring(i, i + 1);
-      if (toRNAssState.containsKey(ssc))
-      {
-        // valid ss character - so return it
-        ss.append(ssc); // (String) toRNAssState.get(ssc));
-      }
-      else
-      {
-        ss.append(" ");
-      }
-    }
-    return ss.toString();
-  }
-
-  public static boolean isCloseParenRNA(char dc)
+  public static String getCanonicalAminoAcid(String aA)
   {
-    return RNAcloseParen[dc];
+    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(", ");
@@ -3096,15 +2789,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 b1e4d58..9ae14ca 100755 (executable)
@@ -101,6 +101,10 @@ public class UserColourScheme extends ResidueColourScheme
 
   public static Color getColourFromString(String colour)
   {
+    if (colour == null)
+    {
+      return null;
+    }
     colour = colour.trim();
 
     Color col = null;
@@ -136,7 +140,7 @@ public class UserColourScheme extends ResidueColourScheme
 
   }
 
-  public Color createColourFromName(String name)
+  public static Color createColourFromName(String name)
   {
     int r, g, b;
 
diff --git a/src/jalview/structure/StructureImportSettings.java b/src/jalview/structure/StructureImportSettings.java
new file mode 100644 (file)
index 0000000..6254b43
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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;
+import jalview.datamodel.PDBEntry.Type;
+
+/**
+ * bean holding settings for structure IO. TODO: tests for validation of values
+ * TODO: tests for race conditions (all fields are static, is that correct ?)
+ * 
+ * @author tcofoegbu
+ *
+ */
+public class StructureImportSettings
+{
+  /**
+   * set to true to add derived sequence annotations (temp factor read from
+   * file, or computed secondary structure) to the alignment
+   */
+  private static boolean visibleChainAnnotation = false;
+
+  /**
+   * Set true to predict secondary structure (using JMol for protein, Annotate3D
+   * for RNA)
+   */
+  private static boolean processSecStr = false;
+
+  /**
+   * Set true (with predictSecondaryStructure=true) to predict secondary
+   * structure using an external service (currently Annotate3D for RNA only)
+   */
+  private static boolean externalSecondaryStructure = false;
+
+  private static boolean showSeqFeatures = true;
+
+  public enum StructureParser
+  {
+    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
+   */
+  private static PDBEntry.Type defaultStructureFileFormat = Type.PDB;
+
+  /**
+   * Determines the parser used for parsing PDB format file. Possible options
+   * are : JMolParser|JalveiwParser
+   */
+  private static StructureParser defaultPDBFileParser = StructureParser.JMOL_PARSER;
+
+  public static void addSettings(boolean addAlignmentAnnotations,
+          boolean processSecStr, boolean externalSecStr)
+  {
+    StructureImportSettings.visibleChainAnnotation = addAlignmentAnnotations;
+    StructureImportSettings.processSecStr = processSecStr;
+    StructureImportSettings.externalSecondaryStructure = externalSecStr;
+    StructureImportSettings.showSeqFeatures = true;
+  }
+
+  public static boolean isVisibleChainAnnotation()
+  {
+    return visibleChainAnnotation;
+  }
+
+  public static void setVisibleChainAnnotation(
+          boolean visibleChainAnnotation)
+  {
+    StructureImportSettings.visibleChainAnnotation = visibleChainAnnotation;
+  }
+
+  public static boolean isProcessSecondaryStructure()
+  {
+    return processSecStr;
+  }
+
+  public static void setProcessSecondaryStructure(
+          boolean processSecondaryStructure)
+  {
+    StructureImportSettings.processSecStr = processSecondaryStructure;
+  }
+
+  public static boolean isExternalSecondaryStructure()
+  {
+    return externalSecondaryStructure;
+  }
+
+  public static void setExternalSecondaryStructure(
+          boolean externalSecondaryStructure)
+  {
+    StructureImportSettings.externalSecondaryStructure = externalSecondaryStructure;
+  }
+
+  public static boolean isShowSeqFeatures()
+  {
+    return showSeqFeatures;
+  }
+
+  public static void setShowSeqFeatures(boolean showSeqFeatures)
+  {
+    StructureImportSettings.showSeqFeatures = showSeqFeatures;
+  }
+
+  public static String getDefaultStructureFileFormat()
+  {
+    return defaultStructureFileFormat.toString();
+  }
+
+  public static void setDefaultStructureFileFormat(
+          String defaultStructureFileFormat)
+  {
+    StructureImportSettings.defaultStructureFileFormat = PDBEntry.Type
+            .valueOf(defaultStructureFileFormat.toUpperCase());
+  }
+
+  public static String getDefaultPDBFileParser()
+  {
+    return defaultPDBFileParser.toString();
+  }
+
+  public static void setDefaultPDBFileParser(
+          StructureParser defaultPDBFileParser)
+  {
+    StructureImportSettings.defaultPDBFileParser = defaultPDBFileParser;
+  }
+
+  public static void setDefaultPDBFileParser(String defaultPDBFileParser)
+  {
+    StructureImportSettings.defaultPDBFileParser = StructureParser
+            .valueOf(defaultPDBFileParser.toUpperCase());
+  }
+
+}
index 3fcb5e9..78634e0 100644 (file)
@@ -159,4 +159,14 @@ public class StructureMapping
     }
     return ala_copy;
   }
+
+  public String getMappingDetailsOutput()
+  {
+    return mappingDetails;
+  }
+
+  public HashMap<Integer, int[]> getMapping()
+  {
+    return mapping;
+  }
 }
index a5d9736..7e691be 100644 (file)
@@ -32,6 +32,7 @@ import jalview.datamodel.Annotation;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceI;
+import jalview.ext.jmol.JmolParser;
 import jalview.gui.IProgressIndicator;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.StructureFile;
@@ -326,7 +327,6 @@ public class StructureSelectionManager
     return setMapping(true, sequence, targetChains, pdbFile, protocol);
   }
 
-
   /**
    * create sequence structure mappings between each sequence and the given
    * pdbFile (retrieved via the given protocol).
@@ -347,8 +347,7 @@ public class StructureSelectionManager
    */
   synchronized public StructureFile setMapping(boolean forStructureView,
           SequenceI[] sequenceArray, String[] targetChainIds,
-          String pdbFile,
-          String protocol)
+          String pdbFile, String protocol)
   {
     /*
      * There will be better ways of doing this in the future, for now we'll use
@@ -384,23 +383,16 @@ public class StructureSelectionManager
     boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts();
     try
     {
-
-      if (pdbFile != null && isCIFFile(pdbFile))
-      {
-        pdb = new jalview.ext.jmol.JmolParser(addTempFacAnnot, parseSecStr,
-                secStructServices, pdbFile, protocol);
-      }
-      else
-      {
-        pdb = new PDBfile(addTempFacAnnot, parseSecStr, secStructServices,
-                pdbFile, protocol);
-      }
+      pdb = new JmolParser(pdbFile, protocol);
 
       if (pdb.getId() != null && pdb.getId().trim().length() > 0
               && AppletFormatAdapter.FILE.equals(protocol))
       {
         registerPDBFile(pdb.getId().trim(), pdbFile);
       }
+      // if PDBId is unavailable then skip SIFTS mapping execution path
+      isMapUsingSIFTs = pdb.isPPDBIdAvailable();
+
     } catch (Exception ex)
     {
       ex.printStackTrace();
@@ -424,6 +416,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;
@@ -498,34 +496,88 @@ public class StructureSelectionManager
       }
 
       ArrayList<StructureMapping> seqToStrucMapping = new ArrayList<StructureMapping>();
-      if (isMapUsingSIFTs)
+      if (isMapUsingSIFTs && seq.isProtein())
       {
         setProgressBar(null);
-        setProgressBar("Obtaining mapping with SIFTS");
+        setProgressBar(MessageManager
+                .getString("status.obtaining_mapping_with_sifts"));
         jalview.datamodel.Mapping sqmpping = maxAlignseq
                 .getMappingFromS1(false);
         if (targetChainId != null && !targetChainId.trim().isEmpty())
         {
-          StructureMapping mapping = getStructureMapping(seq, pdbFile,
-                  targetChainId, pdb, maxChain, sqmpping, maxAlignseq);
-          seqToStrucMapping.add(mapping);
+          StructureMapping siftsMapping;
+          try
+          {
+            siftsMapping = getStructureMapping(seq, pdbFile, targetChainId,
+                    pdb, maxChain, sqmpping, maxAlignseq);
+            seqToStrucMapping.add(siftsMapping);
+            maxChain.makeExactMapping(maxAlignseq, seq);
+            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
+            System.err.println(e.getMessage());
+            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>();
           for (PDBChain chain : pdb.getChains())
           {
-            StructureMapping mapping = getStructureMapping(seq, pdbFile,
-                    chain.id, pdb, chain, sqmpping, maxAlignseq);
-            seqToStrucMapping.add(mapping);
+            try
+            {
+              StructureMapping siftsMapping = getStructureMapping(seq,
+                      pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq);
+              foundSiftsMappings.add(siftsMapping);
+            } catch (SiftsException e)
+            {
+              System.err.println(e.getMessage());
+            }
+          }
+          if (!foundSiftsMappings.isEmpty())
+          {
+            seqToStrucMapping.addAll(foundSiftsMappings);
+            maxChain.makeExactMapping(maxAlignseq, seq);
+            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));
           }
         }
       }
       else
       {
         setProgressBar(null);
-        setProgressBar("Obtaining mapping with NW alignment");
-        seqToStrucMapping.add(getNWMappings(seq, pdbFile, maxChainId,
-                maxChain, pdb, maxAlignseq));
+        setProgressBar(MessageManager
+                .getString("status.obtaining_mapping_with_nw_alignment"));
+        StructureMapping nwMapping = getNWMappings(seq, pdbFile,
+                maxChainId, maxChain, pdb, maxAlignseq);
+        seqToStrucMapping.add(nwMapping);
+        ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0));
+
       }
 
       if (forStructureView)
@@ -543,41 +595,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)
+          AlignSeq maxAlignseq) throws SiftsException
   {
-    String maxChainId = targetChainId;
+    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 (SiftsException e)
+    } catch (Exception e)
     {
-      System.err.println(e.getMessage());
-      System.err.println(">>> Now switching mapping with NW alignment...");
-      setProgressBar(null);
-      setProgressBar(">>> Now switching mapping with NW alignment...");
-      return getNWMappings(seq, pdbFile, maxChainId, maxChain, pdb,
-              maxAlignseq);
+      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)
   {
diff --git a/src/jalview/structure/StructureViewSettings.java b/src/jalview/structure/StructureViewSettings.java
deleted file mode 100644 (file)
index 2fcb3e5..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-package jalview.structure;
-
-public class StructureViewSettings
-{
-  private String dbRefType;
-
-  /**
-   * set to true to add derived sequence annotations (temp factor read from
-   * file, or computed secondary structure) to the alignment
-   */
-  private static boolean visibleChainAnnotation = false;
-
-  /**
-   * Set true to predict secondary structure (using JMol for protein, Annotate3D
-   * for RNA)
-   */
-  private static boolean predictSecStr = false;
-
-  /**
-   * Set true (with predictSecondaryStructure=true) to predict secondary
-   * structure using an external service (currently Annotate3D for RNA only)
-   */
-  private static boolean externalSecondaryStructure = false;
-
-  private static boolean showSeqFeatures = true;
-
-  public static void addSettings(boolean addAlignmentAnnotations,
-          boolean predictSecStr, boolean externalSecStr)
-  {
-    StructureViewSettings.visibleChainAnnotation = addAlignmentAnnotations;
-    StructureViewSettings.predictSecStr = predictSecStr;
-    StructureViewSettings.externalSecondaryStructure = externalSecStr;
-    StructureViewSettings.showSeqFeatures = true;
-  }
-
-  public static boolean isVisibleChainAnnotation()
-  {
-    return visibleChainAnnotation;
-  }
-
-  public static void setVisibleChainAnnotation(
-          boolean visibleChainAnnotation)
-  {
-    StructureViewSettings.visibleChainAnnotation = visibleChainAnnotation;
-  }
-
-  public static boolean isPredictSecondaryStructure()
-  {
-    return predictSecStr;
-  }
-
-  public static void setPredictSecondaryStructure(
-          boolean predictSecondaryStructure)
-  {
-    StructureViewSettings.predictSecStr = predictSecondaryStructure;
-  }
-
-  public static boolean isExternalSecondaryStructure()
-  {
-    return externalSecondaryStructure;
-  }
-
-  public static void setExternalSecondaryStructure(
-          boolean externalSecondaryStructure)
-  {
-    StructureViewSettings.externalSecondaryStructure = externalSecondaryStructure;
-  }
-
-  public static boolean isShowSeqFeatures()
-  {
-    return showSeqFeatures;
-  }
-
-  public static void setShowSeqFeatures(boolean showSeqFeatures)
-  {
-    StructureViewSettings.showSeqFeatures = showSeqFeatures;
-  }
-
-}
index 42fbfa9..b00f1bc 100644 (file)
@@ -51,6 +51,10 @@ public abstract class AAStructureBindingModel extends
 
   private StructureSelectionManager ssm;
 
+  /*
+   * distinct PDB entries (pdb files) associated
+   * with sequences
+   */
   private PDBEntry[] pdbEntry;
 
   /*
@@ -75,6 +79,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
@@ -239,24 +248,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();
@@ -521,6 +527,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]);
@@ -565,7 +575,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;
           }
@@ -598,6 +612,10 @@ public abstract class AAStructureBindingModel extends
       for (String file : files)
       {
         notLoaded = file;
+        if (file == null)
+        {
+          continue;
+        }
         try
         {
           StructureMapping[] sm = getSsm().getMapping(file);
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 b8cd563..525bfdb 100644 (file)
@@ -103,4 +103,92 @@ public class ColorUtils
     return col == null ? null : col.brighter().brighter().brighter();
   }
 
+  /**
+   * Returns a color between minColour and maxColour; the RGB values are in
+   * proportion to where 'value' lies between minValue and maxValue
+   * 
+   * @param value
+   * @param minValue
+   * @param minColour
+   * @param maxValue
+   * @param maxColour
+   * @return
+   */
+  public static Color getGraduatedColour(float value, float minValue,
+          Color minColour, float maxValue, Color maxColour)
+  {
+    if (minValue == maxValue)
+    {
+      return minColour;
+    }
+    if (value < minValue)
+    {
+      value = minValue;
+    }
+    if (value > maxValue)
+    {
+      value = maxValue;
+    }
+
+    /*
+     * prop = proportion of the way value is from minValue to maxValue
+     */
+    float prop = (value - minValue) / (maxValue - minValue);
+    float r = minColour.getRed() + prop
+            * (maxColour.getRed() - minColour.getRed());
+    float g = minColour.getGreen() + prop
+            * (maxColour.getGreen() - minColour.getGreen());
+    float b = minColour.getBlue() + prop
+            * (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 8902e2c..0beb45b 100644 (file)
@@ -249,6 +249,18 @@ public class Comparison
   }
 
   /**
+   * Overloaded method signature to test whether a single sequence is nucleotide
+   * (that is, more than 85% CGTA)
+   * 
+   * @param seq
+   * @return
+   */
+  public static final boolean isNucleotide(SequenceI seq)
+  {
+    return isNucleotide(new SequenceI[] { seq });
+  }
+
+  /**
    * Answers true if more than 85% of the sequence residues (ignoring gaps) are
    * A, G, C, T or U, else false. This is just a heuristic guess and may give a
    * wrong answer (as AGCT are also amino acid codes).
@@ -286,7 +298,7 @@ public class Comparison
    * @param letters
    * @return
    */
-  public static final boolean areNucleotide(char[][] letters)
+  static final boolean areNucleotide(char[][] letters)
   {
     int ntCount = 0;
     int aaCount = 0;
@@ -300,16 +312,11 @@ public class Comparison
       // to save a lengthy calculation
       for (char c : seq)
       {
-        if ('a' <= c && c <= 'z')
-        {
-          c -= TO_UPPER_CASE;
-        }
-
-        if (c == 'A' || c == 'G' || c == 'C' || c == 'T' || c == 'U')
+        if (isNucleotide(c))
         {
           ntCount++;
         }
-        else if (!Comparison.isGap(c))
+        else if (!isGap(c))
         {
           aaCount++;
         }
@@ -332,6 +339,59 @@ public class Comparison
   }
 
   /**
+   * Answers true if the character is one of aAcCgGtTuU
+   * 
+   * @param c
+   * @return
+   */
+  public static boolean isNucleotide(char c)
+  {
+    if ('a' <= c && c <= 'z')
+    {
+      c -= TO_UPPER_CASE;
+    }
+
+    switch (c)
+    {
+    case 'A':
+    case 'C':
+    case 'G':
+    case 'T':
+    case 'U':
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Answers true if every character in the string is one of aAcCgGtTuU, or
+   * (optionally) a gap character (dot, dash, space), else false
+   * 
+   * @param s
+   * @param allowGaps
+   * @return
+   */
+  public static boolean isNucleotideSequence(String s, boolean allowGaps)
+  {
+    if (s == null)
+    {
+      return false;
+    }
+    for (int i = 0; i < s.length(); i++)
+    {
+      char c = s.charAt(i);
+      if (!isNucleotide(c))
+      {
+        if (!allowGaps || !isGap(c))
+        {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  /**
    * Convenience overload of isNucleotide
    * 
    * @param seqs
index 424d40b..e6aa472 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);
@@ -67,11 +80,14 @@ public class DBRefUtils
   }
 
   /**
+   * Returns those DBRefEntry objects whose source identifier (once converted to
+   * Jalview's canonical form) is in the list of sources to search for. Returns
+   * null if no matches found.
    * 
    * @param dbrefs
-   *          array of DBRef objects to search
+   *          DBRefEntry objects to search
    * @param sources
-   *          String[] array of source DBRef IDs to retrieve
+   *          array of sources to select
    * @return
    */
   public static DBRefEntry[] selectRefs(DBRefEntry[] dbrefs,
@@ -148,8 +164,8 @@ public class DBRefUtils
   }
 
   /**
-   * Returns an array of those references that match the given entry, or null if
-   * no matches. Currently uses a comparator which matches if
+   * Returns a (possibly empty) list of those references that match the given
+   * entry. Currently uses a comparator which matches if
    * <ul>
    * <li>database sources are the same</li>
    * <li>accession ids are the same</li>
@@ -162,34 +178,35 @@ public class DBRefUtils
    *          pattern to match
    * @return
    */
-  public static DBRefEntry[] searchRefs(DBRefEntry[] ref, DBRefEntry entry)
+  public static List<DBRefEntry> searchRefs(DBRefEntry[] ref,
+          DBRefEntry entry)
   {
     return searchRefs(ref, entry,
             matchDbAndIdAndEitherMapOrEquivalentMapList);
   }
 
   /**
-   * Returns an array of those references that match the given accession id
+   * Returns a list of those references that match the given accession id
    * <ul>
    * <li>database sources are the same</li>
    * <li>accession ids are the same</li>
    * <li>both have no mapping, or the mappings are the same</li>
    * </ul>
    * 
-   * @param ref
+   * @param refs
    *          Set of references to search
-   * @param entry
-   *          pattern to match
+   * @param accId
+   *          accession id to match
    * @return
    */
-  public static DBRefEntry[] searchRefs(DBRefEntry[] ref, String accId)
+  public static List<DBRefEntry> searchRefs(DBRefEntry[] refs, String accId)
   {
-    return searchRefs(ref, new DBRefEntry("", "", accId), matchId);
+    return searchRefs(refs, new DBRefEntry("", "", accId), matchId);
   }
 
   /**
-   * Returns an array of those references that match the given entry, according
-   * to the given comparator. Returns null if no matches.
+   * Returns a (possibly empty) list of those references that match the given
+   * entry, according to the given comparator.
    * 
    * @param refs
    *          an array of database references to search
@@ -198,14 +215,14 @@ public class DBRefUtils
    * @param comparator
    * @return
    */
-  static DBRefEntry[] searchRefs(DBRefEntry[] refs, DBRefEntry entry,
+  static List<DBRefEntry> searchRefs(DBRefEntry[] refs, DBRefEntry entry,
           DbRefComp comparator)
   {
+    List<DBRefEntry> rfs = new ArrayList<DBRefEntry>();
     if (refs == null || entry == null)
     {
-      return null;
+      return rfs;
     }
-    List<DBRefEntry> rfs = new ArrayList<DBRefEntry>();
     for (int i = 0; i < refs.length; i++)
     {
       if (comparator.matches(entry, refs[i]))
@@ -213,7 +230,7 @@ public class DBRefUtils
         rfs.add(refs[i]);
       }
     }
-    return rfs.size() == 0 ? null : rfs.toArray(new DBRefEntry[rfs.size()]);
+    return rfs;
   }
 
   interface DbRefComp
@@ -231,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()))
@@ -262,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()))
@@ -283,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
@@ -314,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
@@ -350,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)
@@ -380,21 +404,24 @@ public class DBRefUtils
   };
 
   /**
-   * accession ID and DB must be identical. Version is ignored. No map on either
-   * or map but no maplist on either or maplist of map on a is equivalent to the
-   * maplist of map on b.
+   * accession ID and DB must be identical, or null on a. Version is ignored. No
+   * map on either or map but no maplist on either or maplist of map on a is
+   * equivalent to the maplist of map on b.
    */
   public static DbRefComp matchDbAndIdAndEitherMapOrEquivalentMapList = new DbRefComp()
   {
     @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
-                && refb.getAccessionId().equals(refa.getAccessionId()))
+
+        if (refa.getAccessionId() == null
+                || refa.getAccessionId().equals(refb.getAccessionId()))
         {
           if (refa.getMap() == null || refb.getMap() == null)
           {
@@ -406,7 +433,7 @@ public class DBRefUtils
                   || (refb.getMap().getMap() != null
                           && refa.getMap().getMap() != null && (refb
                           .getMap().getMap().equals(refa.getMap().getMap()))))
-          { // getMap().getMap().containsEither(false,refa.getMap().getMap())
+          {
             return true;
           }
         }
@@ -480,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
@@ -516,7 +541,196 @@ 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));
+  }
+
+  /**
+   * Selects just the DNA or protein references from a set of references
+   * 
+   * @param selectDna
+   *          if true, select references to 'standard' DNA databases, else to
+   *          'standard' peptide databases
+   * @param refs
+   *          a set of references to select from
+   * @return
+   */
+  public static DBRefEntry[] selectDbRefs(boolean selectDna,
+          DBRefEntry[] refs)
+  {
+    return selectRefs(refs, selectDna ? DBRefSource.DNACODINGDBS
+            : DBRefSource.PROTEINDBS);
+    // could attempt to find other cross
+    // refs here - ie PDB xrefs
+    // (not dna, not protein seq)
+  }
+
+  /**
+   * Returns the (possibly empty) list of those supplied dbrefs which have the
+   * specified source database, with a case-insensitive match of source name
+   * 
+   * @param dbRefs
+   * @param source
+   * @return
+   */
+  public static List<DBRefEntry> searchRefsForSource(DBRefEntry[] dbRefs,
+          String source)
+  {
+    List<DBRefEntry> matches = new ArrayList<DBRefEntry>();
+    if (dbRefs != null && source != null)
+    {
+      for (DBRefEntry dbref : dbRefs)
+      {
+        if (source.equalsIgnoreCase(dbref.getSource()))
+        {
+          matches.add(dbref);
+        }
+      }
+    }
+    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());
+          }
+        }
+      }
+    }
   }
 
 }
diff --git a/src/jalview/util/DnaUtils.java b/src/jalview/util/DnaUtils.java
new file mode 100644 (file)
index 0000000..284ec10
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class DnaUtils
+{
+
+  /**
+   * Parses an ENA/GenBank format location specifier and returns a list of
+   * [start, end] ranges. Throws an exception if not able to parse.
+   * <p>
+   * Currently we do not parse "order()" specifiers, or indeterminate ranges of
+   * the format "&lt;start..end" or "start..&gt;end" or "start.end" or
+   * "start^end"
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   *           if unable to parse the location (the exception message is the
+   *           location specifier being parsed); we use ParseException in
+   *           preference to the unchecked IllegalArgumentException
+   * @see http://www.insdc.org/files/feature_table.html#3.4
+   */
+  public static List<int[]> parseLocation(String location)
+          throws ParseException
+  {
+    if (location.startsWith("join("))
+    {
+      return parseJoin(location);
+    }
+    else if (location.startsWith("complement("))
+    {
+      return parseComplement(location);
+    }
+    if (location.startsWith("order("))
+    {
+      throw new ParseException(location, 0);
+    }
+
+    /*
+     * try to parse m..n (or simply m)
+     */
+    String[] range = location.split("\\.\\.");
+    if (range.length == 1 || range.length == 2)
+    {
+      try
+      {
+        int start = Integer.valueOf(range[0]);
+        int end = range.length == 1 ? start : Integer.valueOf(range[1]);
+        return Collections.singletonList(new int[] { start, end });
+      } catch (NumberFormatException e)
+      {
+        /*
+         * could be a location like <1..888 or 1..>888
+         */
+        throw new ParseException(location, 0);
+      }
+    }
+    else
+    {
+      /*
+       * could be a location like 102.110 or 123^124
+       */
+      throw new ParseException(location, 0);
+    }
+  }
+
+  /**
+   * Parses a complement(locationSpec) into a list of start-end ranges
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   */
+  static List<int[]> parseComplement(String location) throws ParseException
+  {
+    /*
+     * take what is inside complement()
+     */
+    if (!location.endsWith(")"))
+    {
+      throw new ParseException(location, 0);
+    }
+    String toComplement = location.substring("complement(".length(),
+            location.length() - 1);
+    List<int[]> ranges = parseLocation(toComplement);
+
+    /*
+     * reverse the order and direction of ranges
+     */
+    Collections.reverse(ranges);
+    for (int[] range : ranges)
+    {
+      int temp = range[0];
+      range[0] = range[1];
+      range[1] = temp;
+    }
+    return ranges;
+  }
+
+  /**
+   * Parses a join(loc1,loc2,...,locn) into a list of start-end ranges
+   * 
+   * @param location
+   * @return
+   * @throws ParseException
+   */
+  static List<int[]> parseJoin(String location) throws ParseException
+  {
+    List<int[]> ranges = new ArrayList<int[]>();
+
+    /*
+     * take what is inside join()
+     */
+    if (!location.endsWith(")"))
+    {
+      throw new ParseException(location, 0);
+    }
+    String joinedLocs = location.substring("join(".length(),
+            location.length() - 1);
+    String[] locations = joinedLocs.split(",");
+    for (String loc : locations)
+    {
+      List<int[]> range = parseLocation(loc);
+      ranges.addAll(range);
+    }
+    return ranges;
+  }
+
+}
index d14e4ad..7121985 100755 (executable)
@@ -947,4 +947,29 @@ 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)
+  {
+    sb.append((int) value);
+    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 b7aa4ca..9532230 100755 (executable)
@@ -54,11 +54,17 @@ public class ImageMaker
 
   TYPE type;
 
+  private IProgressIndicator pIndicator;
+
+  private long pSessionId;
+
+  private boolean headless;
+
   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;
 
@@ -94,17 +100,14 @@ public class ImageMaker
           int height, File file, String fileTitle,
           IProgressIndicator pIndicator, long pSessionId, boolean headless)
   {
+    this.pIndicator = pIndicator;
     this.type = type;
-
+    this.pSessionId = pSessionId;
+    this.headless = headless;
     if (file == null)
     {
-      if (pIndicator != null && !headless)
-      {
-        pIndicator.setProgressBar(
-                MessageManager.formatMessage(
-                        "status.waiting_for_user_to_select_output_file",
-                        type.name), pSessionId);
-      }
+      setProgressMessage(MessageManager.formatMessage(
+              "status.waiting_for_user_to_select_output_file", type.name));
       JalviewFileChooser chooser;
       chooser = type.getChooser();
       chooser.setFileView(new jalview.io.JalviewFileView());
@@ -120,12 +123,8 @@ public class ImageMaker
       }
       else
       {
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(MessageManager.formatMessage(
-                  "status.cancelled_image_export_operation", type.name),
-                  pSessionId);
-        }
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", type.name));
       }
     }
 
@@ -134,6 +133,9 @@ public class ImageMaker
       try
       {
         out = new FileOutputStream(file);
+        setProgressMessage(null);
+        setProgressMessage(MessageManager.formatMessage(
+                "status.exporting_alignment_as_x_file", type.getName()));
         if (type == TYPE.SVG)
         {
           setupSVG(width, height, fileTitle);
@@ -146,19 +148,13 @@ public class ImageMaker
         {
           setupPNG(width, height);
         }
-        if (pIndicator != null && !headless)
-        {
-          pIndicator.setProgressBar(
-MessageManager.formatMessage(
-                  "status.export_complete", type.getName()),
-                  pSessionId);
-        }
+
       } catch (Exception ex)
       {
         System.out.println("Error creating " + type.getName() + " file.");
 
-        pIndicator.setProgressBar(MessageManager.formatMessage(
-                "info.error_creating_file", type.getName()), pSessionId);
+        setProgressMessage(MessageManager.formatMessage(
+                "info.error_creating_file", type.getName()));
       }
     }
   }
@@ -214,6 +210,8 @@ MessageManager.formatMessage(
 
       if (renderStyle == null || eps.cancelled)
       {
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", "EPS"));
         return;
       }
     }
@@ -233,6 +231,8 @@ MessageManager.formatMessage(
       pg.setAccurateTextMode(accurateText);
 
       graphics = pg;
+      setProgressMessage(MessageManager.formatMessage(
+              "status.export_complete", type.getName()));
     } catch (Exception ex)
     {
     }
@@ -245,6 +245,8 @@ MessageManager.formatMessage(
     Graphics2D ig2 = (Graphics2D) graphics;
     ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
             RenderingHints.VALUE_ANTIALIAS_ON);
+    setProgressMessage(MessageManager.formatMessage(
+            "status.export_complete", type.getName()));
 
   }
 
@@ -268,16 +270,20 @@ MessageManager.formatMessage(
 
       if (renderStyle == null || svgOption.cancelled)
       {
+        setProgressMessage(MessageManager.formatMessage(
+                "status.cancelled_image_export_operation", "SVG"));
         return;
       }
     }
 
-    if (renderStyle.equalsIgnoreCase("lineart"))
+    if (renderStyle.equalsIgnoreCase("Lineart"))
     {
       ig2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
               SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
     }
 
+    setProgressMessage(MessageManager.formatMessage(
+            "status.export_complete", type.getName()));
     graphics = g2;
   }
 
@@ -307,6 +313,14 @@ MessageManager.formatMessage(
             "Encapsulated Postscript");
   }
 
+  private void setProgressMessage(String message)
+  {
+    if (pIndicator != null && !headless)
+    {
+      pIndicator.setProgressBar(message, pSessionId);
+    }
+  }
+
   static JalviewFileChooser getSVGChooser()
   {
     if (Jalview.isHeadlessMode())
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 e51442c..58abdc3 100644 (file)
@@ -88,8 +88,6 @@ public class MapList
   @Override
   public boolean equals(Object o)
   {
-    // TODO should also override hashCode to ensure equal objects have equal
-    // hashcodes
     if (o == null || !(o instanceof MapList))
     {
       return false;
@@ -112,6 +110,19 @@ public class MapList
   }
 
   /**
+   * Returns a hashcode made from the fromRatio, toRatio, and from/to ranges
+   */
+  @Override
+  public int hashCode()
+  {
+    int hashCode = 31 * fromRatio;
+    hashCode = 31 * hashCode + toRatio;
+    hashCode = 31 * hashCode + fromShifts.toArray().hashCode();
+    hashCode = 31 * hashCode + toShifts.toArray().hashCode();
+    return hashCode;
+  }
+
+  /**
    * Returns the 'from' ranges as {[start1, end1], [start2, end2], ...}
    * 
    * @return
@@ -215,7 +226,7 @@ public class MapList
     {
       /*
        * note lowest and highest values - bearing in mind the
-       * direction may be revesed
+       * direction may be reversed
        */
       fromLowest = Math.min(fromLowest, Math.min(from[i], from[i + 1]));
       fromHighest = Math.max(fromHighest, Math.max(from[i], from[i + 1]));
@@ -331,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;
     }
 
@@ -342,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)
@@ -376,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]);
@@ -393,7 +406,7 @@ public class MapList
         lastDirection = (range[1] == range[0]) ? lastDirection : direction;
       }
     }
-    
+
     return changed ? merged : ranges;
   }
 
@@ -992,6 +1005,10 @@ public class MapList
    */
   public void addMapList(MapList map)
   {
+    if (this.equals(map))
+    {
+      return;
+    }
     this.fromLowest = Math.min(fromLowest, map.fromLowest);
     this.toLowest = Math.min(toLowest, map.toLowest);
     this.fromHighest = Math.max(fromHighest, map.fromHighest);
@@ -1087,4 +1104,15 @@ 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 ae4e55d..1fe452d 100644 (file)
@@ -374,7 +374,8 @@ public final class MappingUtils
               /*
                * Found a sequence mapping. Locate the start/end mapped residues.
                */
-              List<AlignedCodonFrame> mapping = Arrays.asList(new AlignedCodonFrame[] { acf });
+              List<AlignedCodonFrame> mapping = Arrays
+                      .asList(new AlignedCodonFrame[] { acf });
               SearchResults sr = buildSearchResults(selected,
                       startResiduePos, mapping);
               for (Match m : sr.getResults())
@@ -555,9 +556,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 +590,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,8 +647,7 @@ public final class MappingUtils
        * Get the residue position and find the mapped position.
        */
       int residuePos = fromSeq.findPosition(col);
-      SearchResults sr = buildSearchResults(fromSeq, residuePos,
-              mappings);
+      SearchResults sr = buildSearchResults(fromSeq, residuePos, mappings);
       for (Match m : sr.getResults())
       {
         int mappedStartResidue = m.getStart();
@@ -754,6 +754,23 @@ public final class MappingUtils
   public static List<AlignedCodonFrame> findMappingsForSequence(
           SequenceI sequence, List<AlignedCodonFrame> mappings)
   {
+    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,
+          List<SequenceI> filterList)
+  {
     List<AlignedCodonFrame> result = new ArrayList<AlignedCodonFrame>();
     if (sequence == null || mappings == null)
     {
@@ -763,7 +780,31 @@ public final class MappingUtils
     {
       if (mapping.involvesSequence(sequence))
       {
-        result.add(mapping);
+        if (filterList != null)
+        {
+          for (SequenceI otherseq : filterList)
+          {
+            SequenceI otherDataset = otherseq.getDatasetSequence();
+            if (otherseq == sequence
+                    || otherseq == sequence.getDatasetSequence()
+                    || (otherDataset != null && (otherDataset == sequence || otherDataset == sequence
+                            .getDatasetSequence())))
+            {
+              // skip sequences in subset which directly relate to sequence
+              continue;
+            }
+            if (mapping.involvesSequence(otherseq))
+            {
+              // selected a mapping contained in subselect alignment
+              result.add(mapping);
+              break;
+            }
+          }
+        }
+        else
+        {
+          result.add(mapping);
+        }
       }
     }
     return result;
@@ -852,7 +893,7 @@ public final class MappingUtils
     {
       return ranges;
     }
-  
+
     int[] copy = Arrays.copyOf(ranges, ranges.length);
     int sxpos = -1;
     int cdspos = 0;
@@ -880,7 +921,7 @@ public final class MappingUtils
         break;
       }
     }
-  
+
     if (sxpos > 0)
     {
       /*
index b812feb..3fb384f 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import java.awt.Toolkit;
+import java.awt.event.MouseEvent;
+
 /**
  * System platform information used by Applet and Application
  * 
@@ -74,4 +77,24 @@ public class Platform
     f.append(file.substring(lastp));
     return f.toString();
   }
+
+  /**
+   * 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())
+    {
+      return (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() & e
+              .getModifiers()) != 0;
+      // could we use e.isMetaDown() here?
+    }
+    return e.isControlDown();
+  }
 }
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..e6b45f2
--- /dev/null
@@ -0,0 +1,154 @@
+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 6044655..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
@@ -299,4 +299,108 @@ public class StringUtils
     }
     return result;
   }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @return
+   */
+  public static int compareVersions(String v1, String v2)
+  {
+    return compareVersions(v1, v2, null);
+  }
+
+  /**
+   * Compares two versions formatted as e.g. "3.4.5b1" and returns -1, 0 or 1 as
+   * the first version precedes, is equal to, or follows the second
+   * 
+   * @param v1
+   * @param v2
+   * @param pointSeparator
+   *          a string used to delimit point increments in sub-tokens of the
+   *          version
+   * @return
+   */
+  public static int compareVersions(String v1, String v2,
+          String pointSeparator)
+  {
+    if (v1 == null || v2 == null)
+    {
+      return 0;
+    }
+    String[] toks1 = v1.split("\\.");
+    String[] toks2 = v2.split("\\.");
+    int i = 0;
+    for (; i < toks1.length; i++)
+    {
+      if (i >= toks2.length)
+      {
+        /*
+         * extra tokens in v1
+         */
+        return 1;
+      }
+      String tok1 = toks1[i];
+      String tok2 = toks2[i];
+      if (pointSeparator != null)
+      {
+        /*
+         * convert e.g. 5b2 into decimal 5.2 for comparison purposes
+         */
+        tok1 = tok1.replace(pointSeparator, ".");
+        tok2 = tok2.replace(pointSeparator, ".");
+      }
+      try
+      {
+        float f1 = Float.valueOf(tok1);
+        float f2 = Float.valueOf(tok2);
+        int comp = Float.compare(f1, f2);
+        if (comp != 0)
+        {
+          return comp;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.err.println("Invalid version format found: "
+                + e.getMessage());
+        return 0;
+      }
+    }
+
+    if (i < toks2.length)
+    {
+      /*
+       * extra tokens in v2 
+       */
+      return -1;
+    }
+
+    /*
+     * same length, all tokens match
+     */
+    return 0;
+  }
+
+  /**
+   * Converts the string to all lower-case except the first character which is
+   * upper-cased
+   * 
+   * @param s
+   * @return
+   */
+  public static String toSentenceCase(String s)
+  {
+    if (s == null)
+    {
+      return s;
+    }
+    if (s.length() <= 1)
+    {
+      return s.toUpperCase();
+    }
+    return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+  }
 }
diff --git a/src/jalview/util/UrlConstants.java b/src/jalview/util/UrlConstants.java
new file mode 100644 (file)
index 0000000..ce6d980
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 SEQUENCE_ID = "SEQUENCE_ID";
+
+  /*
+   * Sequence Name string
+   */
+  public static final String SEQUENCE_NAME = "SEQUENCE_NAME";
+
+  /*
+   * 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_NAME$";
+
+  /*
+   * Default sequence URL link string for EMBL-EBI search
+   */
+  public static final String OLD_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..872f432 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+
 import java.util.Vector;
 
 public class UrlLink
@@ -37,6 +40,8 @@ public class UrlLink
 
   private boolean dynamic = false;
 
+  private boolean uses_seq_id = false;
+
   private String invalidMessage = null;
 
   /**
@@ -48,81 +53,40 @@ public class UrlLink
    */
   public UrlLink(String link)
   {
-    int sep = link.indexOf("|"), psqid = link.indexOf("$SEQUENCE_ID");
+    int sep = link.indexOf("|");
+    int psqid = link.indexOf("$" + SEQUENCE_ID);
+    int nsqid = link.indexOf("$" + SEQUENCE_NAME);
     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;
-        }
-      }
+      uses_seq_id = true;
+
+      sep = parseTargetAndLabel(sep, psqid, link);
+
+      parseUrl(link, SEQUENCE_ID, psqid, sep);
+    }
+    else if (nsqid > -1)
+    {
+      dynamic = true;
+      sep = parseTargetAndLabel(sep, nsqid, link);
+
+      parseUrl(link, SEQUENCE_NAME, nsqid, sep);
     }
     else
     {
       target = link.substring(0, sep);
-      label = link.substring(0, sep = link.lastIndexOf("|"));
+      sep = link.lastIndexOf("|");
+      label = link.substring(0, sep);
       url_prefix = link.substring(sep + 1);
       regexReplace = null; // implies we trim any prefix if necessary //
       // regexReplace=".*\\|?(.*)";
       url_suffix = null;
     }
+
+    label = label.trim();
+    target = target.trim();
+    target = target.toUpperCase(); // DBRefEntry uppercases DB names
+    // NB getCanonicalName might be better but does not currently change case
   }
 
   /**
@@ -295,15 +259,122 @@ public class UrlLink
     }
   }
 
+  @Override
   public String toString()
   {
+    String var = (uses_seq_id ? SEQUENCE_ID : SEQUENCE_NAME);
+
     return label
             + "|"
             + url_prefix
-            + (dynamic ? ("$SEQUENCE_ID" + ((regexReplace != null) ? "="
+            + (dynamic ? ("$" + var + ((regexReplace != null) ? "="
                     + regexReplace + "=$" : "$")) : "")
             + ((url_suffix == null) ? "" : url_suffix);
+  }
+
+  /**
+   * 
+   * @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 + 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;
+    }
+    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)
+  {
+    url_prefix = link.substring(sep + 1, sqidPos);
+
+    // delimiter at start of regex: e.g. $SEQUENCE_ID=/
+    String startDelimiter = "$" + varName + "=/";
 
+    // delimiter at end of regex: /=$
+    String endDelimiter = "/=$";
+
+    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
+      url_suffix = 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("$" + varName + "$") == sqidPos)
+      {
+        url_suffix = link.substring(sqidPos + startLength - 1);
+        regexReplace = null;
+      }
+      else
+      {
+        invalidMessage = "Warning: invalid regex structure for URL link : "
+                + link;
+      }
+    }
   }
 
   private static void testUrls(UrlLink ul, String idstring, String[] urls)
@@ -341,7 +412,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/$" + SEQUENCE_ID
+            + "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
     String[] idstrings = new String[] {
     /*
      * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
@@ -389,6 +461,11 @@ public class UrlLink
     return dynamic;
   }
 
+  public boolean usesSeqId()
+  {
+    return uses_seq_id;
+  }
+
   public void setLabel(String newlabel)
   {
     this.label = newlabel;
index b70e92b..c01be4e 100644 (file)
@@ -22,6 +22,7 @@ package jalview.viewmodel;
 
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
+import jalview.analysis.Profile;
 import jalview.api.AlignCalcManagerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -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 Profile[] 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(Profile[] hconsensus)
   {
     this.hconsensus = hconsensus;
   }
@@ -745,7 +747,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public Hashtable[] getSequenceConsensusHash()
+  public Profile[] 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;
@@ -844,14 +847,22 @@ public abstract class AlignmentViewport implements AlignViewportI,
             && !al.getCodonFrames().isEmpty())
     {
       /*
-       * fudge - check first mapping is protein-to-nucleotide
+       * fudge - check first for protein-to-nucleotide mappings
        * (we don't want to do this for protein-to-protein)
        */
-      AlignedCodonFrame mapping = al.getCodonFrames().iterator().next();
-      // TODO hold mapping type e.g. dna-to-protein in AlignedCodonFrame?
-      MapList[] mapLists = mapping.getdnaToProt();
-      // mapLists can be empty if project load has not finished resolving seqs
-      if (mapLists.length > 0 && mapLists[0].getFromRatio() == 3)
+      boolean doConsensus = false;
+      for (AlignedCodonFrame mapping : al.getCodonFrames())
+      {
+        // TODO hold mapping type e.g. dna-to-protein in AlignedCodonFrame?
+        MapList[] mapLists = mapping.getdnaToProt();
+        // mapLists can be empty if project load has not finished resolving seqs
+        if (mapLists.length > 0 && mapLists[0].getFromRatio() == 3)
+        {
+          doConsensus = true;
+          break;
+        }
+      }
+      if (doConsensus)
       {
         if (calculator
                 .getRegisteredWorkersOfClass(ComplementConsensusThread.class) == null)
@@ -905,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()
   {
@@ -1078,6 +1120,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       updateHiddenColumns();
     }
+    isColSelChanged(true);
   }
 
   /**
@@ -1098,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();
@@ -1206,8 +1256,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   public boolean isColSelChanged(boolean b)
   {
-    int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel
-            .hashCode();
+    int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode();
     if (hc != -1 && hc != colselhash)
     {
       if (b)
@@ -1225,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;
@@ -1308,7 +1356,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
     colSel.hideSelectedColumns();
     setSelectionGroup(null);
-
+    isColSelChanged(true);
   }
 
   public void hideColumns(int start, int end)
@@ -1321,17 +1369,19 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       colSel.hideColumns(start, end);
     }
+    isColSelChanged(true);
   }
 
   public void showColumn(int col)
   {
     colSel.revealHiddenColumns(col);
-
+    isColSelChanged(true);
   }
 
   public void showAllHiddenColumns()
   {
     colSel.revealAllHiddenColumns();
+    isColSelChanged(true);
   }
 
   // common hide/show seq stuff
@@ -1411,6 +1461,39 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * Hides the specified sequence, or the sequences it represents
+   * 
+   * @param sequence
+   *          the sequence to hide, or keep as representative
+   * @param representGroup
+   *          if true, hide the current selection group except for the
+   *          representative sequence
+   */
+  public void hideSequences(SequenceI sequence, boolean representGroup)
+  {
+    if (selectionGroup == null || selectionGroup.getSize() < 1)
+    {
+      hideSequence(new SequenceI[] { sequence });
+      return;
+    }
+
+    if (representGroup)
+    {
+      hideRepSequences(sequence, selectionGroup);
+      setSelectionGroup(null);
+      return;
+    }
+
+    int gsize = selectionGroup.getSize();
+    SequenceI[] hseqs = selectionGroup.getSequences().toArray(
+            new SequenceI[gsize]);
+
+    hideSequence(hseqs);
+    setSelectionGroup(null);
+    sendSelection();
+  }
+
+  /**
    * Set visibility for any annotations for the given sequence.
    * 
    * @param sequenceI
@@ -1418,11 +1501,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
   protected void setSequenceAnnotationsVisible(SequenceI sequenceI,
           boolean visible)
   {
-    for (AlignmentAnnotation ann : alignment.getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
+    if (anns != null)
     {
-      if (ann.sequenceRef == sequenceI)
+      for (AlignmentAnnotation ann : anns)
       {
-        ann.visible = visible;
+        if (ann.sequenceRef == sequenceI)
+        {
+          ann.visible = visible;
+        }
       }
     }
   }
@@ -1463,13 +1550,42 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   }
 
+  /**
+   * 
+   * @return null or the current reference sequence
+   */
+  public SequenceI getReferenceSeq()
+  {
+    return alignment.getSeqrep();
+  }
+
+  /**
+   * @param seq
+   * @return true iff seq is the reference for the alignment
+   */
+  public boolean isReferenceSeq(SequenceI seq)
+  {
+    return alignment.getSeqrep() == seq;
+  }
+
+  /**
+   * 
+   * @param seq
+   * @return true if there are sequences represented by this sequence that are
+   *         currently hidden
+   */
   public boolean isHiddenRepSequence(SequenceI seq)
   {
-    return alignment.getSeqrep() == seq
-            || (hiddenRepSequences != null && hiddenRepSequences
-                    .containsKey(seq));
+    return (hiddenRepSequences != null && hiddenRepSequences
+            .containsKey(seq));
   }
 
+  /**
+   * 
+   * @param seq
+   * @return null or a sequence group containing the sequences that seq
+   *         represents
+   */
   public SequenceGroup getRepresentedSequences(SequenceI seq)
   {
     return (SequenceGroup) (hiddenRepSequences == null ? null
@@ -1557,6 +1673,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public String[] getViewAsString(boolean selectedRegionOnly)
   {
+    return getViewAsString(selectedRegionOnly, true);
+  }
+
+  @Override
+  public String[] getViewAsString(boolean selectedRegionOnly,
+          boolean exportHiddenSeqs)
+  {
     String[] selection = null;
     SequenceI[] seqs = null;
     int i, iSize;
@@ -1570,13 +1693,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
     else
     {
-      if (hasHiddenRows())
+      if (hasHiddenRows() && exportHiddenSeqs)
       {
-        iSize = alignment.getHiddenSequences().getFullAlignment()
-                .getHeight();
-        seqs = alignment.getHiddenSequences().getFullAlignment()
-                .getSequencesArray();
-        end = alignment.getHiddenSequences().getFullAlignment().getWidth();
+        AlignmentI fullAlignment = alignment.getHiddenSequences()
+                .getFullAlignment();
+        iSize = fullAlignment.getHeight();
+        seqs = fullAlignment.getSequencesArray();
+        end = fullAlignment.getWidth();
       }
       else
       {
@@ -1744,9 +1867,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
       cs.setConsensus(hconsensus);
       if (cs.conservationApplied())
       {
-        cs.setConservation(Conservation.calculateConservation("All",
-                ResidueProperties.propHash, 3, alignment.getSequences(), 0,
-                alignment.getWidth(), false, getConsPercGaps(), false));
+        cs.setConservation(Conservation.calculateConservation("All", 3,
+                alignment.getSequences(), 0, alignment.getWidth(), false,
+                getConsPercGaps(), false));
       }
     }
 
@@ -1797,12 +1920,20 @@ public abstract class AlignmentViewport implements AlignViewportI,
               .getCodonFrames();
       if (codonMappings != null && !codonMappings.isEmpty())
       {
-        // fudge: check mappings are not protein-to-protein
-        // TODO: nicer
-        AlignedCodonFrame mapping = codonMappings.iterator().next();
-        MapList[] mapLists = mapping.getdnaToProt();
-        // mapLists can be empty if project load has not finished resolving seqs
-        if (mapLists.length > 0 && mapLists[0].getFromRatio() == 3)
+        boolean doConsensus = false;
+        for (AlignedCodonFrame mapping : codonMappings)
+        {
+          // TODO hold mapping type e.g. dna-to-protein in AlignedCodonFrame?
+          MapList[] mapLists = mapping.getdnaToProt();
+          // mapLists can be empty if project load has not finished resolving
+          // seqs
+          if (mapLists.length > 0 && mapLists[0].getFromRatio() == 3)
+          {
+            doConsensus = true;
+            break;
+          }
+        }
+        if (doConsensus)
         {
           complementConsensus = new AlignmentAnnotation("cDNA Consensus",
                   "PID for cDNA", new Annotation[1], 0f, 100f,
@@ -2625,6 +2756,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
      * all gapped visible regions
      */
     int lastSeq = alignment.getHeight() - 1;
+    List<AlignedCodonFrame> seqMappings = null;
     for (int seqNo = getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
     {
       sequence = getAlignment().getSequenceAt(seqNo);
@@ -2636,15 +2768,16 @@ public abstract class AlignmentViewport implements AlignViewportI,
       {
         continue;
       }
-      List<AlignedCodonFrame> seqMappings = MappingUtils
-              .findMappingsForSequence(sequence, mappings);
+      seqMappings = MappingUtils
+              .findMappingsForSequenceAndOthers(sequence, mappings,
+                      getCodingComplement().getAlignment().getSequences());
       if (!seqMappings.isEmpty())
       {
         break;
       }
     }
 
-    if (sequence == null)
+    if (sequence == null || seqMappings == null || seqMappings.isEmpty())
     {
       /*
        * No ungapped mapped sequence in middle column - do nothing
@@ -2652,7 +2785,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
       return 0;
     }
     MappingUtils.addSearchResults(sr, sequence,
-            sequence.findPosition(middleColumn), mappings);
+            sequence.findPosition(middleColumn), seqMappings);
     return seqOffset;
   }
 
@@ -2667,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))
       {
@@ -2688,4 +2819,33 @@ 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;
+  }
 }
index 5b55e05..4ac4804 100644 (file)
@@ -27,8 +27,8 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureRenderer;
-import jalview.schemes.GraduatedColor;
-import jalview.viewmodel.AlignmentViewport;
+import jalview.schemes.FeatureColour;
+import jalview.schemes.UserColourScheme;
 
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
@@ -52,21 +52,18 @@ public abstract class FeatureRendererModel implements
    */
   protected float transparency = 1.0f;
 
-  protected Map<String, Object> featureColours = new ConcurrentHashMap<String, Object>();
+  protected Map<String, FeatureColourI> featureColours = new ConcurrentHashMap<String, FeatureColourI>();
 
   protected Map<String, Boolean> featureGroups = new ConcurrentHashMap<String, Boolean>();
 
-  protected Object currentColour;
-
-  /*
-   * feature types in ordering of rendering, where last means on top
-   */
   protected String[] renderOrder;
 
+  Map<String, Float> featureOrder = null;
+
   protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
-  protected AlignmentViewport av;
+  protected AlignViewportI av;
 
   @Override
   public AlignViewportI getViewport()
@@ -194,9 +191,9 @@ public abstract class FeatureRendererModel implements
     renderOrder = neworder;
   }
 
-  protected Hashtable minmax = new Hashtable();
+  protected Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
 
-  public Hashtable getMinMax()
+  public Map<String, float[][]> getMinMax()
   {
     return minmax;
   }
@@ -210,7 +207,7 @@ public abstract class FeatureRendererModel implements
    */
   protected final byte[] normaliseScore(SequenceFeature sequenceFeature)
   {
-    float[] mm = ((float[][]) minmax.get(sequenceFeature.type))[0];
+    float[] mm = minmax.get(sequenceFeature.type)[0];
     final byte[] r = new byte[] { 0, (byte) 255 };
     if (mm != null)
     {
@@ -341,7 +338,7 @@ public abstract class FeatureRendererModel implements
     }
     if (minmax == null)
     {
-      minmax = new Hashtable();
+      minmax = new Hashtable<String, float[][]>();
     }
     AlignmentI alignment = av.getAlignment();
     for (int i = 0; i < alignment.getHeight(); i++)
@@ -396,7 +393,7 @@ public abstract class FeatureRendererModel implements
         if (!Float.isNaN(features[index].score))
         {
           int nonpos = features[index].getBegin() >= 1 ? 0 : 1;
-          float[][] mm = (float[][]) minmax.get(features[index].getType());
+          float[][] mm = minmax.get(features[index].getType());
           if (mm == null)
           {
             mm = new float[][] { null, null };
@@ -445,7 +442,6 @@ public abstract class FeatureRendererModel implements
     List<String> allfeatures = new ArrayList<String>(allFeatures);
     String[] oldRender = renderOrder;
     renderOrder = new String[allfeatures.size()];
-    Object mmrange, fc = null;
     boolean initOrders = (featureOrder == null);
     int opos = 0;
     if (oldRender != null && oldRender.length > 0)
@@ -465,16 +461,13 @@ public abstract class FeatureRendererModel implements
             allfeatures.remove(oldRender[j]);
             if (minmax != null)
             {
-              mmrange = minmax.get(oldRender[j]);
+              float[][] mmrange = minmax.get(oldRender[j]);
               if (mmrange != null)
               {
-                fc = featureColours.get(oldRender[j]);
-                if (fc != null && fc instanceof GraduatedColor
-                        && ((GraduatedColor) fc).isAutoScale())
+                FeatureColourI fc = featureColours.get(oldRender[j]);
+                if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
                 {
-                  ((GraduatedColor) fc).updateBounds(
-                          ((float[][]) mmrange)[0][0],
-                          ((float[][]) mmrange)[0][1]);
+                  fc.updateBounds(mmrange[0][0], mmrange[0][1]);
                 }
               }
             }
@@ -498,15 +491,13 @@ public abstract class FeatureRendererModel implements
       if (minmax != null)
       {
         // update from new features minmax if necessary
-        mmrange = minmax.get(newf[i]);
+        float[][] mmrange = minmax.get(newf[i]);
         if (mmrange != null)
         {
-          fc = featureColours.get(newf[i]);
-          if (fc != null && fc instanceof GraduatedColor
-                  && ((GraduatedColor) fc).isAutoScale())
+          FeatureColourI fc = featureColours.get(newf[i]);
+          if (fc != null && !fc.isSimpleColour() && fc.isAutoScaled())
           {
-            ((GraduatedColor) fc).updateBounds(((float[][]) mmrange)[0][0],
-                    ((float[][]) mmrange)[0][1]);
+            fc.updateBounds(mmrange[0][0], mmrange[0][1]);
           }
         }
       }
@@ -518,7 +509,7 @@ public abstract class FeatureRendererModel implements
         setOrder(newf[i], i / (float) denom);
       }
       // set order from newly found feature from persisted ordering.
-      sortOrder[i] = 2 - ((Float) featureOrder.get(newf[i])).floatValue();
+      sortOrder[i] = 2 - featureOrder.get(newf[i]).floatValue();
       if (i < iSize)
       {
         // only sort if we need to
@@ -536,52 +527,25 @@ public abstract class FeatureRendererModel implements
 
   /**
    * get a feature style object for the given type string. Creates a
-   * java.awt.Color for a featureType with no existing colourscheme. TODO:
-   * replace return type with object implementing standard abstract colour/style
-   * interface
+   * java.awt.Color for a featureType with no existing colourscheme.
    * 
    * @param featureType
-   * @return java.awt.Color or GraduatedColor
+   * @return
    */
   @Override
-  public Object getFeatureStyle(String featureType)
+  public FeatureColourI getFeatureStyle(String featureType)
   {
-    Object fc = featureColours.get(featureType);
+    FeatureColourI fc = featureColours.get(featureType);
     if (fc == null)
     {
-      jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
-      Color col = ucs.createColourFromName(featureType);
-      featureColours.put(featureType, fc = col);
+      Color col = UserColourScheme.createColourFromName(featureType);
+      fc = new FeatureColour(col);
+      featureColours.put(featureType, fc);
     }
     return fc;
   }
 
   /**
-   * return a nominal colour for this feature
-   * 
-   * @param featureType
-   * @return standard color, or maximum colour for graduated colourscheme
-   */
-  public Color getColour(String featureType)
-  {
-    Object fc = getFeatureStyle(featureType);
-
-    if (fc instanceof Color)
-    {
-      return (Color) fc;
-    }
-    else
-    {
-      if (fc instanceof GraduatedColor)
-      {
-        return ((GraduatedColor) fc).getMaxColor();
-      }
-    }
-    throw new Error("Implementation Error: Unrecognised render object "
-            + fc.getClass() + " for features of type " + featureType);
-  }
-
-  /**
    * calculate the render colour for a specific feature using current feature
    * settings.
    * 
@@ -590,33 +554,14 @@ public abstract class FeatureRendererModel implements
    */
   public Color getColour(SequenceFeature feature)
   {
-    Object fc = getFeatureStyle(feature.getType());
-    if (fc instanceof Color)
-    {
-      return (Color) fc;
-    }
-    else
-    {
-      if (fc instanceof GraduatedColor)
-      {
-        return ((GraduatedColor) fc).findColor(feature);
-      }
-    }
-    throw new Error("Implementation Error: Unrecognised render object "
-            + fc.getClass() + " for features of type " + feature.getType());
+    FeatureColourI fc = getFeatureStyle(feature.getType());
+    return fc.getColor(feature);
   }
 
   protected boolean showFeature(SequenceFeature sequenceFeature)
   {
-    Object fc = getFeatureStyle(sequenceFeature.type);
-    if (fc instanceof GraduatedColor)
-    {
-      return ((GraduatedColor) fc).isColored(sequenceFeature);
-    }
-    else
-    {
-      return true;
-    }
+    FeatureColourI fc = getFeatureStyle(sequenceFeature.type);
+    return fc.isColored(sequenceFeature);
   }
 
   protected boolean showFeatureOfType(String type)
@@ -625,26 +570,9 @@ public abstract class FeatureRendererModel implements
   }
 
   @Override
-  public void setColour(String featureType, Object col)
+  public void setColour(String featureType, FeatureColourI col)
   {
-    // overwrite
-    // Color _col = (col instanceof Color) ? ((Color) col) : (col instanceof
-    // GraduatedColor) ? ((GraduatedColor) col).getMaxColor() : null;
-    // Object c = featureColours.get(featureType);
-    // if (c == null || c instanceof Color || (c instanceof GraduatedColor &&
-    // !((GraduatedColor)c).getMaxColor().equals(_col)))
-    if (col instanceof FeatureColourI)
-    {
-      if (((FeatureColourI) col).isGraduatedColour())
-      {
-        col = new GraduatedColor((FeatureColourI) col);
-      }
-      else
-      {
-        col = ((FeatureColourI) col).getColour();
-      }
-    }
-      featureColours.put(featureType, col);
+    featureColours.put(featureType, col);
   }
 
   public void setTransparency(float value)
@@ -657,8 +585,6 @@ public abstract class FeatureRendererModel implements
     return transparency;
   }
 
-  Map featureOrder = null;
-
   /**
    * analogous to colour - store a normalized ordering for all feature types in
    * this rendering context.
@@ -673,7 +599,7 @@ public abstract class FeatureRendererModel implements
   {
     if (featureOrder == null)
     {
-      featureOrder = new Hashtable();
+      featureOrder = new Hashtable<String, Float>();
     }
     featureOrder.put(type, new Float(position));
     return position;
@@ -691,14 +617,14 @@ public abstract class FeatureRendererModel implements
     {
       if (featureOrder.containsKey(type))
       {
-        return ((Float) featureOrder.get(type)).floatValue();
+        return featureOrder.get(type).floatValue();
       }
     }
     return -1;
   }
 
   @Override
-  public Map<String, Object> getFeatureColours()
+  public Map<String, FeatureColourI> getFeatureColours()
   {
     return featureColours;
   }
@@ -731,7 +657,7 @@ public abstract class FeatureRendererModel implements
      * note visible feature ordering and colours before update
      */
     List<String> visibleFeatures = getDisplayedFeatureTypes();
-    Map<String, Object> visibleColours = new HashMap<String, Object>(
+    Map<String, FeatureColourI> visibleColours = new HashMap<String, FeatureColourI>(
             getFeatureColours());
 
     FeaturesDisplayedI av_featuresdisplayed = null;
@@ -764,8 +690,7 @@ public abstract class FeatureRendererModel implements
       for (int i = 0; i < data.length; i++)
       {
         String type = data[i][0].toString();
-        setColour(type, data[i][1]); // todo : typesafety - feature color
-        // interface object
+        setColour(type, (FeatureColourI) data[i][1]);
         if (((Boolean) data[i][2]).booleanValue())
         {
           av_featuresdisplayed.setVisible(type);
@@ -819,7 +744,7 @@ public abstract class FeatureRendererModel implements
     changeSupport.removePropertyChangeListener(listener);
   }
 
-  public Set getAllFeatureColours()
+  public Set<String> getAllFeatureColours()
   {
     return featureColours.keySet();
   }
@@ -834,6 +759,9 @@ public abstract class FeatureRendererModel implements
     return renderOrder != null;
   }
 
+  /**
+   * Returns feature types in ordering of rendering, where last means on top
+   */
   public List<String> getRenderOrder()
   {
     if (renderOrder == null)
@@ -887,9 +815,9 @@ public abstract class FeatureRendererModel implements
   {
     if (featureGroups != null)
     {
-      ArrayList gp = new ArrayList();
+      List<String> gp = new ArrayList<String>();
 
-      for (Object grp : featureGroups.keySet())
+      for (String grp : featureGroups.keySet())
       {
         Boolean state = featureGroups.get(grp);
         if (state.booleanValue() == visible)
@@ -931,19 +859,19 @@ public abstract class FeatureRendererModel implements
   }
 
   @Override
-  public Hashtable getDisplayedFeatureCols()
+  public Map<String, FeatureColourI> getDisplayedFeatureCols()
   {
-    Hashtable fcols = new Hashtable();
+    Map<String, FeatureColourI> fcols = new Hashtable<String, FeatureColourI>();
     if (getViewport().getFeaturesDisplayed() == null)
     {
       return fcols;
     }
-    Iterator<String> en = getViewport().getFeaturesDisplayed()
+    Iterator<String> features = getViewport().getFeaturesDisplayed()
             .getVisibleFeatures();
-    while (en.hasNext())
+    while (features.hasNext())
     {
-      String col = en.next();
-      fcols.put(col, getColour(col));
+      String feature = features.next();
+      fcols.put(feature, getFeatureStyle(feature));
     }
     return fcols;
   }
index 1985b6d..dc2ae11 100644 (file)
  */
 package jalview.viewmodel.seqfeatures;
 
-import jalview.schemes.GraduatedColor;
+import jalview.api.FeatureColourI;
+import jalview.schemes.FeatureColour;
 
 import java.util.Arrays;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -32,24 +32,33 @@ public class FeatureRendererSettings implements Cloneable
 {
   String[] renderOrder;
 
-  Map featureGroups;
+  /*
+   * map of {groupName, isDisplayed}
+   */
+  Map<String, Boolean> featureGroups;
 
-  Map featureColours;
+  /*
+   * map of {featureType, colourScheme}
+   */
+  Map<String, FeatureColourI> featureColours;
 
   float transparency;
 
-  Map featureOrder;
+  Map<String, Float> featureOrder;
 
   public FeatureRendererSettings(String[] renderOrder,
-          Hashtable featureGroups, Hashtable featureColours,
-          float transparency, Hashtable featureOrder)
+          Map<String, Boolean> featureGroups,
+          Map<String, FeatureColourI> featureColours, float transparency,
+          Map<String, Float> featureOrder)
   {
     super();
     this.renderOrder = Arrays.copyOf(renderOrder, renderOrder.length);
-    this.featureGroups = new ConcurrentHashMap(featureGroups);
-    this.featureColours = new ConcurrentHashMap(featureColours);
+    this.featureGroups = new ConcurrentHashMap<String, Boolean>(
+            featureGroups);
+    this.featureColours = new ConcurrentHashMap<String, FeatureColourI>(
+            featureColours);
     this.transparency = transparency;
-    this.featureOrder = new ConcurrentHashMap(featureOrder);
+    this.featureOrder = new ConcurrentHashMap<String, Float>(featureOrder);
   }
 
   /**
@@ -61,9 +70,9 @@ public class FeatureRendererSettings implements Cloneable
           jalview.viewmodel.seqfeatures.FeatureRendererModel fr)
   {
     renderOrder = null;
-    featureGroups = new ConcurrentHashMap();
-    featureColours = new ConcurrentHashMap();
-    featureOrder = new ConcurrentHashMap();
+    featureGroups = new ConcurrentHashMap<String, Boolean>();
+    featureColours = new ConcurrentHashMap<String, FeatureColourI>();
+    featureOrder = new ConcurrentHashMap<String, Float>();
     if (fr.renderOrder != null)
     {
       this.renderOrder = new String[fr.renderOrder.length];
@@ -72,26 +81,30 @@ public class FeatureRendererSettings implements Cloneable
     }
     if (fr.featureGroups != null)
     {
-      this.featureGroups = new ConcurrentHashMap(fr.featureGroups);
+      this.featureGroups = new ConcurrentHashMap<String, Boolean>(
+              fr.featureGroups);
     }
     if (fr.featureColours != null)
     {
-      this.featureColours = new ConcurrentHashMap(fr.featureColours);
+      this.featureColours = new ConcurrentHashMap<String, FeatureColourI>(
+              fr.featureColours);
     }
-    Iterator en = fr.featureColours.keySet().iterator();
+    Iterator<String> en = fr.featureColours.keySet().iterator();
     while (en.hasNext())
     {
-      Object next = en.next();
-      Object val = featureColours.get(next);
-      if (val instanceof GraduatedColor)
+      String next = en.next();
+      FeatureColourI val = featureColours.get(next);
+      // if (val instanceof GraduatedColor)
+      if (val.isGraduatedColour() || val.isColourByLabel()) // why this test?
       {
-        featureColours.put(next, new GraduatedColor((GraduatedColor) val));
+        featureColours.put(next, new FeatureColour((FeatureColour) val));
       }
     }
     this.transparency = fr.transparency;
     if (fr.featureOrder != null)
     {
-      this.featureOrder = new ConcurrentHashMap(fr.featureOrder);
+      this.featureOrder = new ConcurrentHashMap<String, Float>(
+              fr.featureOrder);
     }
   }
 }
index 1063706..addb372 100644 (file)
@@ -34,23 +34,48 @@ import java.util.Set;
 
 public class AlignCalcManager implements AlignCalcManagerI
 {
-  private volatile List<AlignCalcWorkerI> restartable = Collections
-          .synchronizedList(new ArrayList<AlignCalcWorkerI>());
+  /*
+   * list of registered workers
+   */
+  private volatile List<AlignCalcWorkerI> restartable;
 
-  private volatile List<Class> blackList = Collections
-          .synchronizedList(new ArrayList<Class>());
+  /*
+   * types of worker _not_ to run (for example, because they have
+   * previously thrown errors)
+   */
+  private volatile List<Class<? extends AlignCalcWorkerI>> blackList;
 
-  /**
+  /*
    * global record of calculations in progress
    */
-  private volatile Map<Class, AlignCalcWorkerI> inProgress = Collections
-          .synchronizedMap(new Hashtable<Class, AlignCalcWorkerI>());
+  private volatile List<AlignCalcWorkerI> inProgress;
 
-  /**
+  /*
    * record of calculations pending or in progress in the current context
    */
-  private volatile Map<Class, List<AlignCalcWorkerI>> updating = Collections
-          .synchronizedMap(new Hashtable<Class, List<AlignCalcWorkerI>>());
+  private volatile Map<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>> updating;
+
+  /*
+   * workers that have run to completion so are candidates for visual-only 
+   * update of their results
+   */
+  private HashSet<AlignCalcWorkerI> canUpdate;
+
+  /**
+   * Constructor
+   */
+  public AlignCalcManager()
+  {
+    restartable = Collections
+            .synchronizedList(new ArrayList<AlignCalcWorkerI>());
+    blackList = Collections
+            .synchronizedList(new ArrayList<Class<? extends AlignCalcWorkerI>>());
+    inProgress = Collections
+            .synchronizedList(new ArrayList<AlignCalcWorkerI>());
+    updating = Collections
+            .synchronizedMap(new Hashtable<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>>());
+    canUpdate = new HashSet<AlignCalcWorkerI>();
+  }
 
   @Override
   public void notifyStart(AlignCalcWorkerI worker)
@@ -72,15 +97,6 @@ public class AlignCalcManager implements AlignCalcManagerI
     }
   }
 
-  @Override
-  public boolean alreadyDoing(AlignCalcWorkerI worker)
-  {
-    synchronized (inProgress)
-    {
-      return inProgress.containsKey(worker.getClass());
-    }
-  }
-
   /*
    * (non-Javadoc)
    * 
@@ -108,52 +124,30 @@ public class AlignCalcManager implements AlignCalcManagerI
     }
   }
 
-  // TODO make into api method if needed ?
-  public int numberLive(AlignCalcWorkerI worker)
-  {
-    synchronized (updating)
-    {
-      List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
-      if (upd == null)
-      {
-        return 0;
-      }
-      ;
-      return upd.size();
-    }
-  }
-
   @Override
   public boolean notifyWorking(AlignCalcWorkerI worker)
   {
     synchronized (inProgress)
     {
-      // TODO: decide if we should throw exceptions here if multiple workers
-      // start to work
-      if (inProgress.get(worker.getClass()) != null)
+      if (inProgress.contains(worker))
       {
-        if (false)
-        {
-          System.err
-                  .println("Warning: Multiple workers are running of type "
-                          + worker.getClass());
-        }
-        return false;
+        return false; // worker is already working, so ask caller to wait around
+      }
+      else
+      {
+        inProgress.add(worker);
       }
-      inProgress.put(worker.getClass(), worker);
     }
     return true;
   }
 
-  private final HashSet<AlignCalcWorkerI> canUpdate = new HashSet<AlignCalcWorkerI>();
-
   @Override
   public void workerComplete(AlignCalcWorkerI worker)
   {
     synchronized (inProgress)
     {
-      // System.err.println("Worker "+worker.getClass()+" marked as complete.");
-      inProgress.remove(worker.getClass());
+      // System.err.println("Worker " + worker + " marked as complete.");
+      inProgress.remove(worker);
       List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
       if (upd != null)
       {
@@ -167,7 +161,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   }
 
   @Override
-  public void workerCannotRun(AlignCalcWorkerI worker)
+  public void disableWorker(AlignCalcWorkerI worker)
   {
     synchronized (blackList)
     {
@@ -175,22 +169,24 @@ public class AlignCalcManager implements AlignCalcManagerI
     }
   }
 
-  public boolean isBlackListed(Class workerType)
+  @Override
+  public boolean isDisabled(AlignCalcWorkerI worker)
   {
     synchronized (blackList)
     {
-      return blackList.contains(workerType);
+      return blackList.contains(worker.getClass());
     }
   }
 
   @Override
   public void startWorker(AlignCalcWorkerI worker)
   {
-    // System.err.println("Starting "+worker.getClass());
-    // new Exception("").printStackTrace();
-    Thread tw = new Thread(worker);
-    tw.setName(worker.getClass().toString());
-    tw.start();
+    if (!isDisabled(worker))
+    {
+      Thread tw = new Thread(worker);
+      tw.setName(worker.getClass().toString());
+      tw.start();
+    }
   }
 
   @Override
@@ -199,7 +195,7 @@ public class AlignCalcManager implements AlignCalcManagerI
     synchronized (inProgress)
     {// System.err.println("isWorking : worker "+(worker!=null ?
      // worker.getClass():"null")+ " "+hashCode());
-      return worker != null && inProgress.get(worker.getClass()) == worker;
+      return worker != null && inProgress.contains(worker);
     }
   }
 
@@ -243,7 +239,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   {
     synchronized (inProgress)
     {
-      for (AlignCalcWorkerI worker : inProgress.values())
+      for (AlignCalcWorkerI worker : inProgress)
       {
         if (worker.involves(alignmentAnnotation))
         {
@@ -268,7 +264,8 @@ public class AlignCalcManager implements AlignCalcManagerI
   }
 
   @Override
-  public void updateAnnotationFor(Class workerClass)
+  public void updateAnnotationFor(
+          Class<? extends AlignCalcWorkerI> workerClass)
   {
 
     AlignCalcWorkerI[] workers;
@@ -287,62 +284,35 @@ public class AlignCalcManager implements AlignCalcManagerI
 
   @Override
   public List<AlignCalcWorkerI> getRegisteredWorkersOfClass(
-          Class workerClass)
+          Class<? extends AlignCalcWorkerI> workerClass)
   {
     List<AlignCalcWorkerI> workingClass = new ArrayList<AlignCalcWorkerI>();
-    AlignCalcWorkerI[] workers;
     synchronized (canUpdate)
     {
-      workers = canUpdate.toArray(new AlignCalcWorkerI[canUpdate.size()]);
-    }
-    for (AlignCalcWorkerI worker : workers)
-    {
-      if (workerClass.equals(worker.getClass()))
+      for (AlignCalcWorkerI worker : canUpdate)
       {
-        workingClass.add(worker);
+        if (workerClass.equals(worker.getClass()))
+        {
+          workingClass.add(worker);
+        }
       }
     }
     return (workingClass.size() == 0) ? null : workingClass;
   }
 
   @Override
-  public boolean startRegisteredWorkersOfClass(Class workerClass)
-  {
-    List<AlignCalcWorkerI> workers = getRegisteredWorkersOfClass(workerClass);
-    if (workers == null)
-    {
-      return false;
-    }
-    for (AlignCalcWorkerI worker : workers)
-    {
-      if (!isPending(worker))
-      {
-        startWorker(worker);
-      }
-      else
-      {
-        System.err.println("Pending exists for " + workerClass);
-      }
-    }
-    return true;
-  }
-
-  @Override
-  public void workerMayRun(AlignCalcWorkerI worker)
+  public void enableWorker(AlignCalcWorkerI worker)
   {
     synchronized (blackList)
     {
-      if (blackList.contains(worker.getClass()))
-      {
-        blackList.remove(worker.getClass());
-      }
+      blackList.remove(worker.getClass());
     }
   }
 
   @Override
-  public void removeRegisteredWorkersOfClass(Class typeToRemove)
+  public void removeRegisteredWorkersOfClass(
+          Class<? extends AlignCalcWorkerI> typeToRemove)
   {
-    List<AlignCalcWorkerI> workers = getRegisteredWorkersOfClass(typeToRemove);
     List<AlignCalcWorkerI> removable = new ArrayList<AlignCalcWorkerI>();
     Set<AlignCalcWorkerI> toremovannot = new HashSet<AlignCalcWorkerI>();
     synchronized (restartable)
@@ -382,4 +352,48 @@ public class AlignCalcManager implements AlignCalcManagerI
      * else { System.err.println("Pending exists for " + workerClass); } }
      */
   }
+
+  /**
+   * Deletes the worker that update the given annotation, provided it is marked
+   * as deletable.
+   */
+  @Override
+  public void removeWorkerForAnnotation(AlignmentAnnotation ann)
+  {
+    /*
+     * first just find those to remove (to avoid
+     * ConcurrentModificationException)
+     */
+    List<AlignCalcWorkerI> toRemove = new ArrayList<AlignCalcWorkerI>();
+    for (AlignCalcWorkerI worker : restartable)
+    {
+      if (worker.involves(ann))
+      {
+        if (worker.isDeletable())
+        {
+          toRemove.add(worker);
+        }
+      }
+    }
+
+    /*
+     * remove all references to deleted workers so any references 
+     * they hold to annotation data can be garbage collected 
+     */
+    for (AlignCalcWorkerI worker : toRemove)
+    {
+      restartable.remove(worker);
+      blackList.remove(worker.getClass());
+      inProgress.remove(worker);
+      canUpdate.remove(worker);
+      synchronized (updating)
+      {
+        List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
+        if (upd != null)
+        {
+          upd.remove(worker);
+        }
+      }
+    }
+  }
 }
index bca3145..0ad8726 100644 (file)
@@ -26,6 +26,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
 
 import java.util.List;
 
@@ -46,7 +47,7 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
 
   protected AlignmentViewPanel ap;
 
-  protected List<AlignmentAnnotation> ourAnnots = null;
+  protected List<AlignmentAnnotation> ourAnnots;
 
   public AlignCalcWorker(AlignViewportI alignViewport,
           AlignmentViewPanel alignPanel)
@@ -68,17 +69,18 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
 
   }
 
+  @Override
   public boolean involves(AlignmentAnnotation i)
   {
     return ourAnnots != null && ourAnnots.contains(i);
   }
 
   /**
-   * permanently remove from the alignment all annotation rows managed by this
+   * Permanently removes from the alignment all annotation rows managed by this
    * worker
    */
   @Override
-  public void removeOurAnnotation()
+  public void removeAnnotation()
   {
     if (ourAnnots != null && alignViewport != null)
     {
@@ -90,9 +92,48 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
           alignment.deleteAnnotation(aa, true);
         }
       }
+      ourAnnots.clear();
     }
   }
+
   // TODO: allow GUI to query workers associated with annotation to add items to
   // annotation label panel popup menu
 
+  @Override
+  public boolean isDeletable()
+  {
+    return false;
+  }
+
+  /**
+   * Calculate min and max values of annotations and set as graphMin, graphMax
+   * on the AlignmentAnnotation. This is needed because otherwise, well, bad
+   * things happen.
+   * 
+   * @param ann
+   * @param anns
+   */
+  protected void setGraphMinMax(AlignmentAnnotation ann, Annotation[] anns)
+  {
+    // TODO feels like this belongs inside AlignmentAnnotation!
+    float max = Float.MIN_VALUE;
+    float min = Float.MAX_VALUE;
+    boolean set = false;
+    for (Annotation a : anns)
+    {
+      if (a != null)
+      {
+        set = true;
+        float val = a.value;
+        max = Math.max(max, val);
+        min = Math.min(min, val);
+      }
+    }
+    if (set)
+    {
+      ann.graphMin = min;
+      ann.graphMax = max;
+    }
+  }
+
 }
diff --git a/src/jalview/workers/AlignmentAnnotationFactory.java b/src/jalview/workers/AlignmentAnnotationFactory.java
new file mode 100644 (file)
index 0000000..beee1eb
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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;
+import jalview.api.AlignmentViewPanel;
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.gui.AlignFrame;
+
+import java.awt.Color;
+
+/**
+ * Factory class with methods which allow clients (including external scripts
+ * such as Groovy) to 'register and forget' an alignment annotation calculator. <br>
+ * Currently supports two flavours of calculator:
+ * <ul>
+ * <li>a simple 'feature counter' which counts any desired score derivable from
+ * residue value and any sequence features at each position of the alignment</li>
+ * <li>a 'general purpose' calculator which computes one or more complete
+ * AlignmentAnnotation objects</li>
+ * </ul>
+ */
+public class AlignmentAnnotationFactory
+{
+  /**
+   * Constructs and registers a new alignment annotation worker
+   * 
+   * @param counter
+   *          provider of feature counts per alignment position
+   */
+  public static void newCalculator(FeatureCounterI counter)
+  {
+    // TODO need an interface for AlignFrame by which to access
+    // its AlignViewportI and AlignmentViewPanel
+    AlignmentViewPanel currentAlignFrame = Jalview.getCurrentAlignFrame().alignPanel;
+    if (currentAlignFrame != null)
+    {
+      newCalculator(currentAlignFrame.getAlignViewport(),
+              currentAlignFrame, counter);
+    }
+    else
+    {
+      System.err
+              .println("Can't register calculator as no alignment window has focus");
+    }
+  }
+
+  /**
+   * Constructs and registers a new alignment annotation worker
+   * 
+   * @param viewport
+   * @param panel
+   * @param counter
+   *          provider of feature counts per alignment position
+   */
+  public static void newCalculator(AlignViewportI viewport,
+          AlignmentViewPanel panel, FeatureCounterI counter)
+  {
+    new ColumnCounterWorker(viewport, panel, counter);
+  }
+
+  /**
+   * Constructs and registers a new alignment annotation worker
+   * 
+   * @param calculator
+   *          provider of AlignmentAnnotation for the alignment
+   */
+  public static void newCalculator(AnnotationProviderI calculator)
+  {
+    // TODO need an interface for AlignFrame by which to access
+    // its AlignViewportI and AlignmentViewPanel
+    AlignFrame currentAlignFrame = Jalview.getCurrentAlignFrame();
+    if (currentAlignFrame != null)
+    {
+      newCalculator(currentAlignFrame.getViewport(), currentAlignFrame
+              .getAlignPanels().get(0), calculator);
+    }
+    else
+    {
+      System.err
+              .println("Can't register calculator as no alignment window has focus");
+    }
+  }
+
+  /**
+   * Constructs and registers a new alignment annotation worker
+   * 
+   * @param viewport
+   * @param panel
+   * @param calculator
+   *          provider of AlignmentAnnotation for the alignment
+   */
+  public static void newCalculator(AlignViewportI viewport,
+          AlignmentViewPanel panel, AnnotationProviderI calculator)
+  {
+    new AnnotationWorker(viewport, panel, calculator);
+  }
+
+  /**
+   * Factory method to construct an Annotation object
+   * 
+   * @param displayChar
+   * @param desc
+   * @param secondaryStructure
+   * @param val
+   * @param color
+   * @return
+   */
+  public static Annotation newAnnotation(String displayChar, String desc,
+          char secondaryStructure, float val, Color color)
+  {
+    return new Annotation(displayChar, desc, secondaryStructure, val, color);
+  }
+
+  /**
+   * Factory method to construct an AlignmentAnnotation object
+   * 
+   * @param name
+   * @param desc
+   * @param anns
+   * @return
+   */
+  public static AlignmentAnnotation newAlignmentAnnotation(String name,
+          String desc, Annotation[] anns)
+  {
+    return new AlignmentAnnotation(name, desc, anns);
+  }
+}
diff --git a/src/jalview/workers/AnnotationProviderI.java b/src/jalview/workers/AnnotationProviderI.java
new file mode 100644 (file)
index 0000000..d11429e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+
+import java.util.List;
+
+/**
+ * Interface to be satisfied by any class which computes one or more alignment
+ * annotations
+ */
+public interface AnnotationProviderI
+{
+  List<AlignmentAnnotation> calculateAnnotation(AlignmentI al,
+          FeatureRenderer fr);
+}
diff --git a/src/jalview/workers/AnnotationWorker.java b/src/jalview/workers/AnnotationWorker.java
new file mode 100644 (file)
index 0000000..4d81307
--- /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.workers;
+
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class to create and update one or more alignment annotations, given a
+ * 'calculator'. Intended to support a 'plug-in' annotation worker which
+ * implements the AnnotationProviderI interface.
+ */
+class AnnotationWorker extends AlignCalcWorker
+{
+  /*
+   * the provider of the annotation calculations
+   */
+  AnnotationProviderI counter;
+
+  /**
+   * Constructor
+   * 
+   * @param af
+   * @param counter
+   */
+  public AnnotationWorker(AlignViewportI viewport,
+          AlignmentViewPanel panel, AnnotationProviderI counter)
+  {
+    super(viewport, panel);
+    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    this.counter = counter;
+    calcMan.registerWorker(this);
+  }
+
+  @Override
+  public void run()
+  {
+    try
+    {
+      calcMan.notifyStart(this);
+
+      while (!calcMan.notifyWorking(this))
+      {
+        try
+        {
+          Thread.sleep(200);
+        } catch (InterruptedException ex)
+        {
+          ex.printStackTrace();
+        }
+      }
+      if (alignViewport.isClosed())
+      {
+        abortAndDestroy();
+        return;
+      }
+
+      // removeAnnotation();
+      AlignmentI alignment = alignViewport.getAlignment();
+      if (alignment != null)
+      {
+        try
+        {
+          List<AlignmentAnnotation> anns = counter.calculateAnnotation(
+                  alignment, new FeatureRenderer(alignViewport));
+          for (AlignmentAnnotation ann : anns)
+          {
+            AlignmentAnnotation theAnn = alignment.findOrCreateAnnotation(
+                    ann.label, ann.description, false, null, null);
+            theAnn.showAllColLabels = true;
+            theAnn.graph = AlignmentAnnotation.BAR_GRAPH;
+            theAnn.scaleColLabel = true;
+            theAnn.annotations = ann.annotations;
+            setGraphMinMax(theAnn, theAnn.annotations);
+            theAnn.validateRangeAndDisplay();
+            if (!ourAnnots.contains(theAnn))
+            {
+              ourAnnots.add(theAnn);
+            }
+            // alignment.addAnnotation(ann);
+          }
+        } catch (IndexOutOfBoundsException x)
+        {
+          // probable race condition. just finish and return without any fuss.
+          return;
+        }
+      }
+    } catch (OutOfMemoryError error)
+    {
+      ap.raiseOOMWarning("calculating annotations", error);
+      calcMan.disableWorker(this);
+    } finally
+    {
+      calcMan.workerComplete(this);
+    }
+
+    if (ap != null)
+    {
+      ap.adjustAnnotationHeight();
+      ap.paintAlignment(true);
+    }
+  }
+
+  @Override
+  public void updateAnnotation()
+  {
+    // do nothing
+  }
+
+  /**
+   * Answers true to indicate that if this worker's annotation is deleted from
+   * the display, the worker should also be removed. This prevents it running
+   * and recreating the annotation when the alignment changes.
+   */
+  @Override
+  public boolean isDeletable()
+  {
+    return true;
+  }
+}
diff --git a/src/jalview/workers/ColumnCounterWorker.java b/src/jalview/workers/ColumnCounterWorker.java
new file mode 100644 (file)
index 0000000..dd56aaf
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureRenderer;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class to compute an alignment annotation with column counts of any
+ * properties of interest of positions in an alignment. <br>
+ * This is designed to be extensible, by supplying to the constructor an object
+ * that computes a count for each residue position, based on the residue value
+ * and any sequence features at that position.
+ * 
+ */
+class ColumnCounterWorker extends AlignCalcWorker
+{
+  FeatureCounterI counter;
+
+  /**
+   * Constructor registers the annotation for the given alignment frame
+   * 
+   * @param af
+   * @param counter
+   */
+  public ColumnCounterWorker(AlignViewportI viewport,
+          AlignmentViewPanel panel, FeatureCounterI counter)
+  {
+    super(viewport, panel);
+    ourAnnots = new ArrayList<AlignmentAnnotation>();
+    this.counter = counter;
+    calcMan.registerWorker(this);
+  }
+
+  /**
+   * method called under control of AlignCalcManager to recompute the annotation
+   * when the alignment changes
+   */
+  @Override
+  public void run()
+  {
+    try
+    {
+      calcMan.notifyStart(this);
+
+      while (!calcMan.notifyWorking(this))
+      {
+        try
+        {
+          Thread.sleep(200);
+        } catch (InterruptedException ex)
+        {
+          ex.printStackTrace();
+        }
+      }
+      if (alignViewport.isClosed())
+      {
+        abortAndDestroy();
+        return;
+      }
+
+      if (alignViewport.getAlignment() != null)
+      {
+        try
+        {
+          computeAnnotations();
+        } catch (IndexOutOfBoundsException x)
+        {
+          // probable race condition. just finish and return without any fuss.
+          return;
+        }
+      }
+    } catch (OutOfMemoryError error)
+    {
+      ap.raiseOOMWarning("calculating feature counts", error);
+      calcMan.disableWorker(this);
+    } finally
+    {
+      calcMan.workerComplete(this);
+    }
+
+    if (ap != null)
+    {
+      ap.adjustAnnotationHeight();
+      ap.paintAlignment(true);
+    }
+
+  }
+
+  /**
+   * Scan each column of the alignment to calculate a count by feature type. Set
+   * the count as the value of the alignment annotation for that feature type.
+   */
+  void computeAnnotations()
+  {
+    FeatureRenderer fr = new FeatureRenderer(alignViewport);
+    // TODO use the commented out code once JAL-2075 is fixed
+    // to get adequate performance on genomic length sequence
+    AlignmentI alignment = alignViewport.getAlignment();
+    // AlignmentView alignmentView = alignViewport.getAlignmentView(false);
+    // AlignmentI alignment = alignmentView.getVisibleAlignment(' ');
+
+    // int width = alignmentView.getWidth();
+    int width = alignment.getWidth();
+    int height = alignment.getHeight();
+    int[] counts = new int[width];
+    int max = 0;
+
+    for (int col = 0; col < width; col++)
+    {
+      int count = 0;
+      for (int row = 0; row < height; row++)
+      {
+        count += countFeaturesAt(alignment, col, row, fr);
+      }
+      counts[col] = count;
+      max = Math.max(count, max);
+    }
+
+    Annotation[] anns = new Annotation[width];
+    /*
+     * add non-zero counts as annotations
+     */
+    for (int i = 0; i < counts.length; i++)
+    {
+      int count = counts[i];
+      if (count > 0)
+      {
+        Color color = ColorUtils.getGraduatedColour(count, 0, Color.cyan,
+                max, Color.blue);
+        String str = String.valueOf(count);
+        anns[i] = new Annotation(str, str, '0', count, color);
+      }
+    }
+
+    /*
+     * construct or update the annotation
+     */
+    AlignmentAnnotation ann = alignViewport.getAlignment()
+            .findOrCreateAnnotation(counter.getName(),
+                    counter.getDescription(), false, null, null);
+    ann.description = counter.getDescription();
+    ann.showAllColLabels = true;
+    ann.scaleColLabel = true;
+    ann.graph = AlignmentAnnotation.BAR_GRAPH;
+    ann.annotations = anns;
+    setGraphMinMax(ann, anns);
+    ann.validateRangeAndDisplay();
+    if (!ourAnnots.contains(ann))
+    {
+      ourAnnots.add(ann);
+    }
+  }
+
+  /**
+   * Returns a count of any feature types present at the specified position of
+   * the alignment
+   * 
+   * @param alignment
+   * @param col
+   * @param row
+   * @param fr
+   */
+  int countFeaturesAt(AlignmentI alignment, int col, int row,
+          FeatureRenderer fr)
+  {
+    SequenceI seq = alignment.getSequenceAt(row);
+    if (seq == null)
+    {
+      return 0;
+    }
+    if (col >= seq.getLength())
+    {
+      return 0;// sequence doesn't extend this far
+    }
+    char res = seq.getCharAt(col);
+    if (Comparison.isGap(res))
+    {
+      return 0;
+    }
+    int pos = seq.findPosition(col);
+
+    /*
+     * compute a count for any displayed features at residue
+     */
+    // NB have to adjust pos if using AlignmentView.getVisibleAlignment
+    // see JAL-2075
+    List<SequenceFeature> features = fr.findFeaturesAtRes(seq, pos);
+    int count = this.counter.count(String.valueOf(res), features);
+    return count;
+  }
+
+  /**
+   * Method called when the user changes display options that may affect how the
+   * annotation is rendered, but do not change its values. Currently no such
+   * options affect user-defined annotation, so this method does nothing.
+   */
+  @Override
+  public void updateAnnotation()
+  {
+    // do nothing
+  }
+
+  /**
+   * Answers true to indicate that if this worker's annotation is deleted from
+   * the display, the worker should also be removed. This prevents it running
+   * and recreating the annotation when the alignment changes.
+   */
+  @Override
+  public boolean isDeletable()
+  {
+    return 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 a8698e6..c88a24a 100644 (file)
@@ -21,7 +21,7 @@
 package jalview.workers;
 
 import jalview.analysis.AAFrequency;
-import jalview.api.AlignCalcWorkerI;
+import jalview.analysis.Profile;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.AlignmentAnnotation;
@@ -30,10 +30,7 @@ import jalview.datamodel.Annotation;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 
-import java.util.Hashtable;
-
-public class ConsensusThread extends AlignCalcWorker implements
-        AlignCalcWorkerI
+public class ConsensusThread extends AlignCalcWorker
 {
   public ConsensusThread(AlignViewportI alignViewport,
           AlignmentViewPanel alignPanel)
@@ -98,7 +95,7 @@ public class ConsensusThread extends AlignCalcWorker implements
       }
     } catch (OutOfMemoryError error)
     {
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
       ap.raiseOOMWarning("calculating consensus", error);
     } finally
     {
@@ -127,7 +124,7 @@ public class ConsensusThread extends AlignCalcWorker implements
    */
   protected void computeConsensus(AlignmentI alignment)
   {
-    Hashtable[] hconsensus = new Hashtable[alignment.getWidth()];
+    Profile[] hconsensus = new Profile[alignment.getWidth()];
 
     SequenceI[] aseqs = getSequences();
     AAFrequency.calculate(aseqs, 0, alignment.getWidth(), hconsensus, true);
@@ -147,7 +144,7 @@ public class ConsensusThread extends AlignCalcWorker implements
   /**
    * @param hconsensus
    */
-  protected void setColourSchemeConsensus(Hashtable[] hconsensus)
+  protected void setColourSchemeConsensus(Profile[] hconsensus)
   {
     ColourSchemeI globalColourScheme = alignViewport
             .getGlobalColourScheme();
@@ -180,7 +177,7 @@ public class ConsensusThread extends AlignCalcWorker implements
   public void updateResultAnnotation(boolean immediate)
   {
     AlignmentAnnotation consensus = getConsensusAnnotation();
-    Hashtable[] hconsensus = getViewportConsensus();
+    Profile[] hconsensus = (Profile[]) getViewportConsensus();
     if (immediate || !calcMan.isWorking(this) && consensus != null
             && hconsensus != null)
     {
@@ -194,15 +191,15 @@ public class ConsensusThread extends AlignCalcWorker implements
    * 
    * @param consensusAnnotation
    *          the annotation to be populated
-   * @param consensusData
+   * @param hconsensus
    *          the computed consensus data
    */
   protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
-          Hashtable[] consensusData)
+          Profile[] hconsensus)
   {
     long nseq = getSequences().length;
-    AAFrequency.completeConsensus(consensusAnnotation, consensusData, 0,
-            consensusData.length, alignViewport.isIgnoreGapsConsensus(),
+    AAFrequency.completeConsensus(consensusAnnotation, hconsensus, 0,
+            hconsensus.length, alignViewport.isIgnoreGapsConsensus(),
             alignViewport.isShowSequenceLogo(), nseq);
   }
 
@@ -211,8 +208,9 @@ public class ConsensusThread extends AlignCalcWorker implements
    * 
    * @return
    */
-  protected Hashtable[] getViewportConsensus()
+  protected Object[] getViewportConsensus()
   {
+    // TODO convert ComplementConsensusThread to use Profile
     return alignViewport.getSequenceConsensusHash();
   }
 }
index 236bccf..11ec521 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.workers;
 
 import jalview.analysis.Conservation;
-import jalview.api.AlignCalcWorkerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.AlignmentAnnotation;
@@ -30,8 +29,7 @@ import jalview.datamodel.AlignmentI;
 import java.util.ArrayList;
 import java.util.List;
 
-public class ConservationThread extends AlignCalcWorker implements
-        AlignCalcWorkerI
+public class ConservationThread extends AlignCalcWorker
 {
 
   private int ConsPercGaps = 25; // JBPNote : This should be a configurable
@@ -96,8 +94,7 @@ public class ConservationThread extends AlignCalcWorker implements
       }
       try
       {
-        cons = Conservation.calculateConservation("All",
-                jalview.schemes.ResidueProperties.propHash, 3,
+        cons = Conservation.calculateConservation("All", 3,
                 alignment.getSequences(), 0, alWidth - 1, false,
                 ConsPercGaps, quality != null);
       } catch (IndexOutOfBoundsException x)
@@ -110,7 +107,7 @@ public class ConservationThread extends AlignCalcWorker implements
     } catch (OutOfMemoryError error)
     {
       ap.raiseOOMWarning("calculating conservation", error);
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
       // alignViewport.conservation = null;
       // this.alignViewport.quality = null;
 
diff --git a/src/jalview/workers/FeatureCounterI.java b/src/jalview/workers/FeatureCounterI.java
new file mode 100644 (file)
index 0000000..3a080ec
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import java.util.List;
+
+/**
+ * An interface for a type that returns counts of any value of interest at a
+ * sequence position that can be determined from the sequence character and any
+ * features present at that position
+ * 
+ */
+public interface FeatureCounterI
+{
+  /**
+   * Returns a count of some property of interest, for example
+   * <ul>
+   * <li>the number of variant features at the position</li>
+   * <li>the number of Cath features of status 'True Positive'</li>
+   * <li>1 if the residue is hydrophobic, else 0</li>
+   * <li>etc</li>
+   * </ul>
+   * 
+   * @param residue
+   *          the residue (or gap) at the position
+   * @param a
+   *          list of any sequence features which include the position
+   */
+  int count(String residue, List<SequenceFeature> features);
+
+  /**
+   * Returns a name for the annotation that this is counting, for use as the
+   * displayed label
+   * 
+   * @return
+   */
+  String getName();
+
+  /**
+   * Returns a description for the annotation, for display as a tooltip
+   * 
+   * @return
+   */
+  String getDescription();
+
+  /**
+   * Returns the colour (as [red, green, blue] values in the range 0-255) to use
+   * for the minimum value on histogram bars. If this is different to
+   * getMaxColour(), then bars will have a graduated colour.
+   * 
+   * @return
+   */
+  int[] getMinColour();
+
+  /**
+   * Returns the colour (as [red, green, blue] values in the range 0-255) to use
+   * for the maximum value on histogram bars. If this is the same as
+   * getMinColour(), then bars will have a single colour (not graduated).
+   * 
+   * @return
+   */
+  int[] getMaxColour();
+}
index e0b3833..5ed2885 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.workers;
 
 import jalview.analysis.StructureFrequency;
-import jalview.api.AlignCalcWorkerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.AlignmentAnnotation;
@@ -31,8 +30,7 @@ import jalview.datamodel.SequenceI;
 
 import java.util.Hashtable;
 
-public class StrucConsensusThread extends AlignCalcWorker implements
-        AlignCalcWorkerI
+public class StrucConsensusThread extends AlignCalcWorker
 {
   public StrucConsensusThread(AlignViewportI alignViewport,
           AlignmentViewPanel alignPanel)
@@ -96,12 +94,15 @@ public class StrucConsensusThread extends AlignCalcWorker implements
               .getAlignmentAnnotation();
       AlignmentAnnotation rnaStruc = null;
       // select rna struct to use for calculation
-      for (int i = 0; i < aa.length; i++)
+      if (aa != null)
       {
-        if (aa[i].visible && aa[i].isRNA() && aa[i].isValidStruc())
+        for (int i = 0; i < aa.length; i++)
         {
-          rnaStruc = aa[i];
-          break;
+          if (aa[i].visible && aa[i].isRNA() && aa[i].isValidStruc())
+          {
+            rnaStruc = aa[i];
+            break;
+          }
         }
       }
       // check to see if its valid
@@ -128,7 +129,7 @@ public class StrucConsensusThread extends AlignCalcWorker implements
       updateResultAnnotation(true);
     } catch (OutOfMemoryError error)
     {
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
 
       // consensus = null;
       // hconsensus = null;
index b158448..2ef5256 100644 (file)
@@ -31,9 +31,8 @@ import jalview.gui.WebserviceInfo;
 import jalview.util.MessageManager;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 
-import java.util.LinkedHashSet;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 public abstract class AWSThread extends Thread
 {
@@ -61,7 +60,7 @@ public abstract class AWSThread extends Thread
   /**
    * dataset sequence relationships to be propagated onto new results
    */
-  protected Set<AlignedCodonFrame> codonframe = null;
+  protected List<AlignedCodonFrame> codonframe = null;
 
   /**
    * are there jobs still running in this thread.
@@ -384,7 +383,7 @@ public abstract class AWSThread extends Thread
               .getCodonFrames();
       if (cf != null)
       {
-        codonframe = new LinkedHashSet<AlignedCodonFrame>();
+        codonframe = new ArrayList<AlignedCodonFrame>();
         codonframe.addAll(cf);
       }
     }
index 40c88c1..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,84 @@ 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 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()]);
+  }
+
+  /**
+   * Constructor with only sequences provided
+   * 
+   * @param sequences
+   */
+  public DBRefFetcher(SequenceI[] sequences)
+  {
+    this(sequences, null, null, null, false);
   }
 
   /**
@@ -211,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
@@ -230,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;
@@ -261,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))
       {
@@ -272,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);
     }
 
@@ -304,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)
@@ -318,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)
+          {
+            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++)
           {
-            // 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());
                 }
               }
             }
@@ -469,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
 
@@ -498,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);
@@ -556,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());
@@ -590,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
@@ -603,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;
+                  }
                 }
               }
             }
@@ -674,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)
         {
@@ -691,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++)
@@ -709,6 +788,7 @@ public class DBRefFetcher implements Runnable
               {
                 alseqs[alsq].setEnd(ngAlsq.length()
                         + alseqs[alsq].getStart() - 1);
+                modified = true;
               }
             }
           }
@@ -725,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);
     }
   }
 
@@ -740,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 d7ba24d..7e069e3 100644 (file)
@@ -22,11 +22,13 @@ package jalview.ws;
 
 import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.FeatureSettings;
+import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
 import jalview.util.UrlLink;
 import jalview.ws.dbsources.das.api.DasSourceRegistryI;
@@ -186,8 +188,7 @@ public class DasSequenceFeatureFetcher
       {
         for (int j = 0; j < dbref.length; j++)
         {
-          if (dbref[j].getSource().equals(
-                  jalview.datamodel.DBRefSource.UNIPROT))
+          if (dbref[j].getSource().equals(DBRefSource.UNIPROT))
           {
             refCount++;
             break;
@@ -252,10 +253,9 @@ public class DasSequenceFeatureFetcher
     public void run()
     {
       running = true;
-      boolean isNuclueotide = af.getViewport().getAlignment()
-              .isNucleotide();
-      new jalview.ws.DBRefFetcher(sequences, af, null, af.featureSettings,
-              isNuclueotide).fetchDBRefs(true);
+      boolean isNucleotide = af.getViewport().getAlignment().isNucleotide();
+      new DBRefFetcher(sequences, af, null, af.featureSettings,
+              isNucleotide).fetchDBRefs(true);
 
       startFetching();
       setGuiFetchComplete();
@@ -286,8 +286,7 @@ public class DasSequenceFeatureFetcher
       {
         jalviewSourceI[] sources = sourceRegistry.getSources().toArray(
                 new jalviewSourceI[0]);
-        String active = jalview.bin.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;
@@ -643,10 +642,10 @@ public class DasSequenceFeatureFetcher
     {
       return null;
     }
-    DBRefEntry[] uprefs = jalview.util.DBRefUtils.selectRefs(
-            seq.getDBRefs(), new String[] {
+    DBRefEntry[] uprefs = DBRefUtils.selectRefs(seq.getDBRefs(),
+            new String[] {
             // jalview.datamodel.DBRefSource.PDB,
-            jalview.datamodel.DBRefSource.UNIPROT,
+            DBRefSource.UNIPROT,
             // jalview.datamodel.DBRefSource.EMBL - not tested on any EMBL coord
             // sys sources
             });
@@ -665,8 +664,8 @@ public class DasSequenceFeatureFetcher
 
         for (COORDINATES csys : dasSource.getVersion().getCOORDINATES())
         {
-          if (jalview.util.DBRefUtils.isDasCoordinateSystem(
-                  csys.getAuthority(), uprefs[j]))
+          if (DBRefUtils.isDasCoordinateSystem(csys.getAuthority(),
+                  uprefs[j]))
           {
             debug("Launched fetcher for coordinate system "
                     + csys.getAuthority());
index 1f8c28a..37946b1 100644 (file)
@@ -27,10 +27,8 @@ import jalview.ws.dbsources.EmblSource;
 import jalview.ws.dbsources.Pdb;
 import jalview.ws.dbsources.PfamFull;
 import jalview.ws.dbsources.PfamSeed;
-import jalview.ws.dbsources.RfamFull;
 import jalview.ws.dbsources.RfamSeed;
 import jalview.ws.dbsources.Uniprot;
-import jalview.ws.dbsources.UniprotName;
 import jalview.ws.dbsources.das.api.jalviewSourceI;
 import jalview.ws.seqfetcher.ASequenceFetcher;
 import jalview.ws.seqfetcher.DbSourceProxy;
@@ -62,13 +60,11 @@ public class SequenceFetcher extends ASequenceFetcher
     addDBRefSourceImpl(EmblSource.class);
     addDBRefSourceImpl(EmblCdsSource.class);
     addDBRefSourceImpl(Uniprot.class);
-    addDBRefSourceImpl(UniprotName.class);
     addDBRefSourceImpl(Pdb.class);
     addDBRefSourceImpl(PfamFull.class);
     addDBRefSourceImpl(PfamSeed.class);
-    // ensures Seed alignment is 'default' for PFAM
-    addDBRefSourceImpl(RfamFull.class);
     addDBRefSourceImpl(RfamSeed.class);
+
     if (addDas)
     {
       registerDasSequenceSources();
diff --git a/src/jalview/ws/SequenceFetcherFactory.java b/src/jalview/ws/SequenceFetcherFactory.java
new file mode 100644 (file)
index 0000000..9cc4960
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+public class SequenceFetcherFactory
+{
+
+  private static SequenceFetcher instance;
+
+  /**
+   * Returns a new SequenceFetcher object, or a mock object if one has been set
+   * 
+   * @return
+   */
+  public static ASequenceFetcher getSequenceFetcher()
+  {
+    return instance == null ? new SequenceFetcher() : instance;
+  }
+
+  /**
+   * Set the instance object to use (intended for unit testing with mock
+   * objects).
+   * 
+   * Be sure to reset to null in the tearDown method of any tests!
+   * 
+   * @param sf
+   */
+  public static void setSequenceFetcher(SequenceFetcher sf)
+  {
+    instance = sf;
+  }
+}
index 0085221..b139574 100644 (file)
@@ -63,7 +63,7 @@ public abstract class EmblXmlSource extends EbiFileRetrievedProxy
     try
     {
       reply = dbFetch.fetchDataAsFile(
-              emprefx.toLowerCase() + ":" + query.trim(), "emblxml", null,
+              emprefx.toLowerCase() + ":" + query.trim(), "display=xml",
               ".xml");
     } catch (Exception e)
     {
@@ -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())
       {
diff --git a/src/jalview/ws/dbsources/PDBRestClient.java b/src/jalview/ws/dbsources/PDBRestClient.java
deleted file mode 100644 (file)
index dbdb01d..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.dbsources;
-
-import jalview.util.MessageManager;
-import jalview.ws.uimodel.PDBRestRequest;
-import jalview.ws.uimodel.PDBRestResponse;
-import jalview.ws.uimodel.PDBRestResponse.PDBResponseSummary;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.ws.rs.core.MediaType;
-
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
-
-import com.sun.jersey.api.client.Client;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.WebResource;
-import com.sun.jersey.api.client.config.ClientConfig;
-import com.sun.jersey.api.client.config.DefaultClientConfig;
-
-/**
- * A rest client for querying the Search endpoing of the PDB REST API
- * 
- * @author tcnofoegbu
- *
- */
-public class PDBRestClient
-{
-  public static final String PDB_SEARCH_ENDPOINT = "http://www.ebi.ac.uk/pdbe/search/pdb/select?";
-
-  private static int DEFAULT_RESPONSE_SIZE = 200;
-
-  /**
-   * Takes a PDBRestRequest object and returns a response upon execution
-   * 
-   * @param pdbRestRequest
-   *          the PDBRestRequest instance to be processed
-   * @return the pdbResponse object for the given request
-   * @throws Exception
-   */
-  public PDBRestResponse executeRequest(PDBRestRequest pdbRestRequest)
-          throws Exception
-  {
-    try
-    {
-      ClientConfig clientConfig = new DefaultClientConfig();
-      Client client = Client.create(clientConfig);
-
-      String wantedFields = getPDBDocFieldsAsCommaDelimitedString(pdbRestRequest
-              .getWantedFields());
-      int responseSize = (pdbRestRequest.getResponseSize() == 0) ? DEFAULT_RESPONSE_SIZE
-              : pdbRestRequest.getResponseSize();
-      String sortParam = null;
-      if (pdbRestRequest.getFieldToSortBy() == null
-              || pdbRestRequest.getFieldToSortBy().trim().isEmpty())
-      {
-        sortParam = "";
-      }
-      else
-      {
-        if (pdbRestRequest.getFieldToSortBy()
-                .equalsIgnoreCase("Resolution"))
-        {
-          sortParam = pdbRestRequest.getFieldToSortBy()
-                  + (pdbRestRequest.isAscending() ? " asc" : " desc");
-        }
-        else
-        {
-          sortParam = pdbRestRequest.getFieldToSortBy()
-                  + (pdbRestRequest.isAscending() ? " desc" : " asc");
-        }
-      }
-
-      String facetPivot = (pdbRestRequest.getFacetPivot() == null || pdbRestRequest
-              .getFacetPivot().isEmpty()) ? "" : pdbRestRequest
-              .getFacetPivot();
-      String facetPivotMinCount = String.valueOf(pdbRestRequest
-              .getFacetPivotMinCount());
-      
-      // Build request parameters for the REST Request
-      WebResource webResource = null;
-      if (pdbRestRequest.isFacet())
-      {
-        webResource = client.resource(PDB_SEARCH_ENDPOINT)
-                .queryParam("wt", "json").queryParam("fl", wantedFields)
-                .queryParam("rows", String.valueOf(responseSize))
-                .queryParam("q", pdbRestRequest.getQuery())
-                .queryParam("sort", sortParam).queryParam("facet", "true")
-                .queryParam("facet.pivot", facetPivot)
-                .queryParam("facet.pivot.mincount", facetPivotMinCount);
-      }
-      else
-      {
-        webResource = client.resource(PDB_SEARCH_ENDPOINT)
-                .queryParam("wt", "json").queryParam("fl", wantedFields)
-                .queryParam("rows", String.valueOf(responseSize))
-                .queryParam("q", pdbRestRequest.getQuery())
-                .queryParam("sort", sortParam);
-      }
-      // Execute the REST request
-      ClientResponse clientResponse = webResource.accept(
-              MediaType.APPLICATION_JSON).get(ClientResponse.class);
-
-      // Get the JSON string from the response object
-      String responseString = clientResponse.getEntity(String.class);
-      // System.out.println("query >>>>>>> " + pdbRestRequest.toString());
-
-      // Check the response status and report exception if one occurs
-      if (clientResponse.getStatus() != 200)
-      {
-        String errorMessage = "";
-        if (clientResponse.getStatus() == 400)
-        {
-          errorMessage = parseJsonExceptionString(responseString);
-          throw new Exception(errorMessage);
-        }
-        else
-        {
-          errorMessage = getMessageByHTTPStatusCode(clientResponse
-                  .getStatus());
-          throw new Exception(errorMessage);
-        }
-      }
-
-      // Make redundant objects eligible for garbage collection to conserve
-      // memory
-      clientResponse = null;
-      client = null;
-
-      // Process the response and return the result to the caller.
-      return parsePDBJsonResponse(responseString, pdbRestRequest);
-    } catch (Exception e)
-    {
-      String exceptionMsg = e.getMessage();
-      if (exceptionMsg.contains("SocketException"))
-      {
-        // No internet connection
-        throw new Exception(
-                MessageManager
-                        .getString("exception.unable_to_detect_internet_connection"));
-      }
-      else if (exceptionMsg.contains("UnknownHostException"))
-      {
-        // The server 'www.ebi.ac.uk' is unreachable
-        throw new Exception(
-                MessageManager
-                        .getString("exception.pdb_server_unreachable"));
-      }
-      else
-      {
-        throw e;
-      }
-    }
-  }
-
-  public String getMessageByHTTPStatusCode(int code)
-  {
-    String message = "";
-    switch (code)
-    {
-    case 410:
-      message = MessageManager
-              .getString("exception.pdb_rest_service_no_longer_available");
-      break;
-    case 403:
-    case 404:
-      message = MessageManager.getString("exception.resource_not_be_found");
-      break;
-    case 408:
-    case 409:
-    case 500:
-    case 501:
-    case 502:
-    case 503:
-    case 504:
-    case 505:
-      message = MessageManager.getString("exception.pdb_server_error");
-      break;
-
-    default:
-      break;
-    }
-    return message;
-  }
-
-  /**
-   * Process error response from PDB server if/when one occurs.
-   * 
-   * @param jsonResponse
-   *          the JSON string containing error message from the server
-   * @return the processed error message from the JSON string
-   */
-  public static String parseJsonExceptionString(String jsonErrorResponse)
-  {
-    StringBuilder errorMessage = new StringBuilder(
-            "\n============= PDB Rest Client RunTime error =============\n");
-
-    try
-    {
-      JSONParser jsonParser = new JSONParser();
-      JSONObject jsonObj = (JSONObject) jsonParser.parse(jsonErrorResponse);
-      JSONObject errorResponse = (JSONObject) jsonObj.get("error");
-
-      JSONObject responseHeader = (JSONObject) jsonObj
-              .get("responseHeader");
-      JSONObject paramsObj = (JSONObject) responseHeader.get("params");
-      String status = responseHeader.get("status").toString();
-      String message = errorResponse.get("msg").toString();
-      String query = paramsObj.get("q").toString();
-      String fl = paramsObj.get("fl").toString();
-
-      errorMessage.append("Status: ").append(status).append("\n");
-      errorMessage.append("Message: ").append(message).append("\n");
-      errorMessage.append("query: ").append(query).append("\n");
-      errorMessage.append("fl: ").append(fl).append("\n");
-
-    } catch (ParseException e)
-    {
-      e.printStackTrace();
-    }
-    return errorMessage.toString();
-  }
-
-  /**
-   * Parses the JSON response string from PDB REST API. The response is dynamic
-   * hence, only fields specifically requested for in the 'wantedFields'
-   * parameter is fetched/processed
-   * 
-   * @param pdbJsonResponseString
-   *          the JSON string to be parsed
-   * @param pdbRestRequest
-   *          the request object which contains parameters used to process the
-   *          JSON string
-   * @return
-   */
-  @SuppressWarnings("unchecked")
-  public static PDBRestResponse parsePDBJsonResponse(
-          String pdbJsonResponseString, PDBRestRequest pdbRestRequest)
-  {
-    PDBRestResponse searchResult = new PDBRestResponse();
-    List<PDBResponseSummary> result = null;
-    try
-    {
-      JSONParser jsonParser = new JSONParser();
-      JSONObject jsonObj = (JSONObject) jsonParser
-              .parse(pdbJsonResponseString);
-
-      JSONObject pdbResponse = (JSONObject) jsonObj.get("response");
-      String queryTime = ((JSONObject) jsonObj.get("responseHeader")).get(
-              "QTime").toString();
-      int numFound = Integer
-              .valueOf(pdbResponse.get("numFound").toString());
-      if (numFound > 0)
-      {
-        result = new ArrayList<PDBResponseSummary>();
-        JSONArray docs = (JSONArray) pdbResponse.get("docs");
-        for (Iterator<JSONObject> docIter = docs.iterator(); docIter
-                .hasNext();)
-        {
-          JSONObject doc = docIter.next();
-          result.add(searchResult.new PDBResponseSummary(doc,
-                  pdbRestRequest));
-        }
-        searchResult.setNumberOfItemsFound(numFound);
-        searchResult.setResponseTime(queryTime);
-        searchResult.setSearchSummary(result);
-      }
-    } catch (ParseException e)
-    {
-      e.printStackTrace();
-    }
-    return searchResult;
-  }
-
-  /**
-   * Takes a collection of PDBDocField and converts its 'code' Field values into
-   * a comma delimited string.
-   * 
-   * @param pdbDocfields
-   *          the collection of PDBDocField to process
-   * @return the comma delimited string from the pdbDocFields collection
-   */
-  public static String getPDBDocFieldsAsCommaDelimitedString(
-          Collection<PDBDocField> pdbDocfields)
-  {
-    String result = "";
-    if (pdbDocfields != null && !pdbDocfields.isEmpty())
-    {
-      StringBuilder returnedFields = new StringBuilder();
-      for (PDBDocField field : pdbDocfields)
-      {
-        returnedFields.append(",").append(field.getCode());
-      }
-      returnedFields.deleteCharAt(0);
-      result = returnedFields.toString();
-    }
-    return result;
-  }
-
-  /**
-   * Determines the column index for 'PDB Id' Fields in the dynamic summary
-   * table. The PDB Id serves as a unique identifier for a given row in the
-   * summary table
-   * 
-   * @param wantedFields
-   *          the available table columns in no particular order
-   * @return the pdb id field column index
-   */
-  public static int getPDBIdColumIndex(
-          Collection<PDBDocField> wantedFields, boolean hasRefSeq)
-  {
-
-    // If a reference sequence is attached then start counting from 1 else
-    // start from zero
-    int pdbFieldIndexCounter = hasRefSeq ? 1 : 0;
-
-    for (PDBDocField field : wantedFields)
-    {
-      if (field.equals(PDBDocField.PDB_ID))
-      {
-        break; // Once PDB Id index is determined exit iteration
-      }
-      ++pdbFieldIndexCounter;
-    }
-    return pdbFieldIndexCounter;
-  }
-
-  public static PDBDocField getPDBDocFieldByCode(String fieldCode)
-          throws Exception
-  {
-    for (PDBDocField curPDBDocField : PDBDocField.values())
-    {
-      if (curPDBDocField.getCode().equalsIgnoreCase(fieldCode))
-      {
-        return curPDBDocField;
-      }
-    }
-    throw new Exception("PDB doc Field not found!");
-  }
-
-  /**
-   * This enum represents the fields available in the PDB JSON response
-   *
-   */
-  public enum PDBDocField
-  {
-    PDB_ID("PDB Id", "pdb_id", Group.CROSS_REFS), TITLE(
-            "Title",
- "title", Group.MISCELLENOUS),
-    MOLECULE_NAME("Molecule",
-            "molecule_name",
-            Group.NAMES_AND_TAXONOMY), MOLECULE_TYPE(
-            "Molecule Type", "molecule_type", Group.NAMES_AND_TAXONOMY), MOLECULE_SEQUENCE(
-            "Sequence", "molecule_sequence", Group.MISCELLENOUS), PFAM_ACCESSION(
-            "PFAM Accession", "pfam_accession",
-            Group.CROSS_REFS), PFAM_NAME(
-            "PFAM Name", "pfam_name", Group.NAMES_AND_TAXONOMY), INTERPRO_NAME(
-            "InterPro Name", "interpro_name", Group.NAMES_AND_TAXONOMY), INTERPRO_ACCESSION(
-            "InterPro Accession", "interpro_accession",
-            Group.CROSS_REFS), UNIPROT_ID("UniProt Id",
-            "uniprot_id", Group.CROSS_REFS), UNIPROT_ACCESSION(
-            "UniProt Accession", "uniprot_accession",
-            Group.CROSS_REFS),
-
-    UNIPROT_COVERAGE(
-            "UniProt Coverage", "uniprot_coverage", Group.MISCELLENOUS), UNIPROT_FEATURES(
-            "Uniprot Features", "uniprot_features", Group.MISCELLENOUS), R_FACTOR(
-"R Factor",
-            "r_factor", Group.QUALITY_MEASURES), RESOLUTION("Resolution",
-            "resolution", Group.QUALITY_MEASURES), DATA_QUALITY(
-            "Data Quality", "data_quality", Group.QUALITY_MEASURES), OVERALL_QUALITY(
-            "Overall Quality", "overall_quality", Group.QUALITY_MEASURES), POLYMER_COUNT(
-            "Number of Polymers", "number_of_polymers", Group.MISCELLENOUS), PROTEIN_CHAIN_COUNT(
-            "Number of Protein Chains", "number_of_protein_chains",
-            Group.MISCELLENOUS), BOUND_MOLECULE_COUNT(
-            "Number of Bound Molecule", "number_of_bound_molecules",
-            Group.MISCELLENOUS), POLYMER_RESIDUE_COUNT(
-            "Number of Polymer Residue", "number_of_polymer_residues",
-            Group.MISCELLENOUS), GENUS("GENUS", "genus",
-            Group.NAMES_AND_TAXONOMY), GENE_NAME("Gene Name", "gene_name",
-            Group.NAMES_AND_TAXONOMY), EXPERIMENTAL_METHOD(
-            "Experimental Method", "experimental_method",
-            Group.PROCEDURE_AND_SOFTWARE), GO_ID("GO Id", "go_id",
-            Group.CROSS_REFS), ASSEMBLY_ID("Assembly Id",
-            "assembly_id", Group.CROSS_REFS), ASSEMBLY_FORM(
-            "Assembly Form", "assembly_form", Group.MISCELLENOUS), ASSEMBLY_TYPE(
-            "Assembly Type", "assembly_type", Group.MISCELLENOUS), SPACE_GROUP(
-            "Space Group", "spacegroup", Group.MISCELLENOUS), CATH_CODE(
-            "Cath Code", "cath_code", Group.CROSS_REFS), TAX_ID(
-            "Tax Id", "tax_id", Group.CROSS_REFS), TAX_QUERY(
-            "Tax Query", "tax_query", Group.CROSS_REFS), INTERACTING_ENTITY_ID(
-            "Interacting Entity Id", "interacting_entity_id",
-            Group.CROSS_REFS), INTERACTING_MOLECULES(
-            "Interacting Molecules", "interacting_molecules",
-            Group.MISCELLENOUS), PUBMED_ID("Pubmed Id", "pubmed_id",
-            Group.CROSS_REFS), STATUS("Status", "status",
-            Group.MISCELLENOUS), MODEL_QUALITY("Model Quality",
-            "model_quality", Group.QUALITY_MEASURES), PIVOT_RESOLUTION(
-            "Pivot Resolution", "pivot_resolution", Group.QUALITY_MEASURES), DATA_REDUCTION_SOFTWARE(
-            "Data reduction software", "data_reduction_software",
-            Group.PROCEDURE_AND_SOFTWARE), MAX_OBSERVED_RES(
-            "Max observed residues",
-            "max_observed_residues", Group.MISCELLENOUS), ORG_SCI_NAME(
-            "Organism scientific name", "organism_scientific_name",
-            Group.NAMES_AND_TAXONOMY), SUPER_KINGDOM("Super kingdom",
-            "superkingdom", Group.NAMES_AND_TAXONOMY), RANK("Rank", "rank",
-            Group.NAMES_AND_TAXONOMY), CRYSTALLISATION_PH(
-            "Crystallisation Ph",
-            "crystallisation_ph", Group.MISCELLENOUS), BIOLOGICAL_FUNCTION(
-            "Biological Function", "biological_function",
-            Group.MISCELLENOUS), BIOLOGICAL_PROCESS("Biological Process",
-            "biological_process", Group.MISCELLENOUS), BIOLOGICAL_CELL_COMPONENT(
-            "Biological Cell Component", "biological_cell_component",
-            Group.MISCELLENOUS), COMPOUND_NAME("Compound Name",
-            "compound_name", Group.NAMES_AND_TAXONOMY), COMPOUND_ID(
-            "Compound Id", "compound_id", Group.CROSS_REFS), COMPOUND_WEIGHT(
-            "Compound Weight", "compound_weight", Group.MISCELLENOUS), COMPOUND_SYSTEMATIC_NAME(
-            "Compound Systematic Name", "compound_systematic_name",
-            Group.NAMES_AND_TAXONOMY), INTERACTING_LIG(
-            "Interacting Ligands",
-            "interacting_ligands", Group.MISCELLENOUS), JOURNAL("Journal",
-            "journal", Group.MISCELLENOUS), ALL_AUTHORS("All Authors",
-            "all_authors", Group.MISCELLENOUS), EXPERIMENTAL_DATA_AVAILABLE(
-            "Experiment Data Available", "experiment_data_available",
-            Group.MISCELLENOUS), DIFFRACTION_PROTOCOL(
-            "Diffraction Protocol", "diffraction_protocol",
-            Group.PROCEDURE_AND_SOFTWARE), REFINEMENT_SOFTWARE(
-            "Refinement Software", "refinement_software",
-            Group.PROCEDURE_AND_SOFTWARE), STRUCTURE_DETERMINATION_METHOD(
-            "Structure Determination Method",
-            "structure_determination_method", Group.PROCEDURE_AND_SOFTWARE), SYNCHROTON_SITE(
-            "Synchrotron Site", "synchrotron_site", Group.MISCELLENOUS), SAMPLE_PREP_METHOD(
-            "Sample Preparation Method", "sample_preparation_method",
-            Group.PROCEDURE_AND_SOFTWARE), ENTRY_AUTHORS("Entry Authors",
-            "entry_authors", Group.MISCELLENOUS), CITATION_TITLE(
-            "Citation Title", "citation_title", Group.MISCELLENOUS), STRUCTURE_SOLUTION_SOFTWARE(
-            "Structure Solution Software", "structure_solution_software",
-            Group.PROCEDURE_AND_SOFTWARE), ENTRY_ENTITY("Entry Entity",
-            "entry_entity", Group.MISCELLENOUS), R_FREE("R Free", "r_free",
-            Group.QUALITY_MEASURES), NO_OF_POLYMER_ENTITIES(
-            "Number of Polymer Entities", "number_of_polymer_entities",
-            Group.MISCELLENOUS), NO_OF_BOUND_ENTITIES(
-            "Number of Bound Entities", "number_of_bound_entities",
-            Group.MISCELLENOUS), CRYSTALLISATION_RESERVOIR(
-            "Crystallisation Reservoir", "crystallisation_reservoir",
-            Group.MISCELLENOUS), DATA_SCALING_SW("Data Scalling Software",
-            "data_scaling_software", Group.PROCEDURE_AND_SOFTWARE), DETECTOR( 
-            "Detector", "detector", Group.MISCELLENOUS), DETECTOR_TYPE(
-            "Detector Type", "detector_type", Group.MISCELLENOUS), MODIFIED_RESIDUE_FLAG(
-            "Modified Residue Flag", "modified_residue_flag",
-            Group.MISCELLENOUS), NUMBER_OF_COPIES("Number of Copies",
-            "number_of_copies", Group.MISCELLENOUS), STRUCT_ASYM_ID(
-            "Struc Asym Id", "struct_asym_id",
-            Group.CROSS_REFS), HOMOLOGUS_PDB_ENTITY_ID(
-            "Homologus PDB Entity Id", "homologus_pdb_entity_id",
-            Group.CROSS_REFS), MOLECULE_SYNONYM(
-            "Molecule Synonym",
-            "molecule_synonym", Group.MISCELLENOUS), DEPOSITION_SITE(
-            "Deposition Site", "deposition_site", Group.MISCELLENOUS), SYNCHROTRON_BEAMLINE(
-            "Synchrotron Beamline", "synchrotron_beamline",
-            Group.MISCELLENOUS), ENTITY_ID("Entity Id", "entity_id",
-            Group.CROSS_REFS), BEAM_SOURCE_NAME(
-            "Beam Source Name",
- "beam_source_name",
-            Group.NAMES_AND_TAXONOMY), PROCESSING_SITE(
-            "Processing Site", "processing_site", Group.MISCELLENOUS), ENTITY_WEIGHT(
-            "Entity Weight", "entity_weight", Group.MISCELLENOUS), VERSION(
-            "Version", "_version_", Group.MISCELLENOUS), ALL("ALL", "text",
-            Group.MISCELLENOUS);
-
-    public enum Group
-    {
-      DATE_OF("Date Of", 5), NAMES_AND_TAXONOMY("Names & Taxonomy", 3),
-      MISCELLENOUS("Miscellenous", 6), QUALITY_MEASURES("Quality Measures",
-              1), CROSS_REFS("Cross References", 2),
-      PROCEDURE_AND_SOFTWARE("Procedures & Softwares", 4);
-
-      Group(String name, int sortOrder)
-      {
-        this.name = name;
-        this.sortOrder = sortOrder;
-      }
-
-      private String name;
-
-      private int sortOrder;
-
-      public String getName()
-      {
-        return this.name;
-      }
-
-      public int getSortOrder()
-      {
-        return sortOrder;
-      }
-
-      @Override
-      public String toString()
-      {
-        return this.name;
-      }
-    };
-    private String name;
-
-    private String code;
-
-    private Group group;
-
-    PDBDocField(String name, String code, Group group)
-    {
-      this.name = name;
-      this.code = code;
-      this.group = group;
-    }
-
-    public String getName()
-    {
-      return name;
-    }
-
-    public String getCode()
-    {
-      return code;
-    }
-
-    public Group getGroup()
-    {
-      return group;
-    }
-
-    @Override
-    public String toString()
-    {
-      return name;
-    }
-  }
-}
index 4a089f7..11fe95e 100644 (file)
@@ -26,15 +26,16 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.PDBEntry.Type;
 import jalview.datamodel.SequenceI;
 import jalview.io.FormatAdapter;
 import jalview.io.PDBFeatureSettings;
+import jalview.structure.StructureImportSettings;
 import jalview.util.MessageManager;
 import jalview.ws.ebi.EBIFetchClient;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Vector;
 
 import com.stevesoft.pat.Regex;
 
@@ -44,17 +45,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";
-
-  private static String currentDefaultFomart = DBRefSource.PDB;
-
   /*
    * (non-Javadoc)
    * 
@@ -63,7 +64,6 @@ public class Pdb extends EbiFileRetrievedProxy
   @Override
   public String getAccessionSeparator()
   {
-    // TODO Auto-generated method stub
     return null;
   }
 
@@ -109,35 +109,41 @@ 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 + "'");
       stopQuery();
       return null;
     }
-    String ext = getCurrentDefaultFomart().equalsIgnoreCase("mmcif") ? ".cif"
-            : ".xml";
+    String ext = StructureImportSettings.getDefaultStructureFileFormat()
+            .equalsIgnoreCase(Type.MMCIF.toString()) ? ".cif" : ".xml";
     EBIFetchClient ebi = new EBIFetchClient();
-    file = ebi.fetchDataAsFile("pdb:" + id,
-            getCurrentDefaultFomart().toLowerCase(), "raw", ext)
-            .getAbsolutePath();
+    file = ebi.fetchDataAsFile(
+            "pdb:" + id,
+            StructureImportSettings.getDefaultStructureFileFormat()
+                    .toLowerCase(), ext).getAbsolutePath();
     stopQuery();
     if (file == null)
     {
@@ -148,7 +154,7 @@ public class Pdb extends EbiFileRetrievedProxy
 
       pdbAlignment = new FormatAdapter().readFile(file,
               jalview.io.AppletFormatAdapter.FILE,
-              getCurrentDefaultFomart());
+              StructureImportSettings.getDefaultStructureFileFormat());
       if (pdbAlignment != null)
       {
         List<SequenceI> toremove = new ArrayList<SequenceI>();
@@ -163,16 +169,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
             /*
@@ -243,12 +249,12 @@ public class Pdb extends EbiFileRetrievedProxy
   }
 
   /**
-   * obtain human glyoxalase chain A sequence
+   * human glyoxalase
    */
   @Override
   public String getTestQuery()
   {
-    return "1QIPA";
+    return "1QIP";
   }
 
   @Override
@@ -263,16 +269,6 @@ public class Pdb extends EbiFileRetrievedProxy
     return 0;
   }
 
-  public static String getCurrentDefaultFomart()
-  {
-    return currentDefaultFomart;
-  }
-
-  public static void setCurrentDefaultFomart(String currentDefaultFomart)
-  {
-    Pdb.currentDefaultFomart = currentDefaultFomart;
-  }
-
   /**
    * Returns a descriptor for suitable feature display settings with
    * <ul>
index 4f081ee..9acaa96 100644 (file)
@@ -123,10 +123,9 @@ abstract public class Pfam extends Xfam
             "STH");
     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 4f5b8f5..3c5373d 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * flyweight class specifying retrieval of Full family alignments from PFAM
  * 
@@ -40,7 +39,7 @@ public class PfamFull extends Pfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://pfam.sanger.ac.uk/family/alignment/download/format?alnType=full&format=stockholm&order=t&case=l&gaps=default&entry=";
+    return "http://pfam.xfam.org/family/alignment/download/format?alnType=full&format=stockholm&order=t&case=l&gaps=default&entry=";
   }
 
   /*
index be8f044..ba9d1e0 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * flyweight class specifying retrieval of Seed alignments from PFAM
  * 
@@ -42,7 +41,7 @@ public class PfamSeed extends Pfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://pfam.sanger.ac.uk/family/alignment/download/format?alnType=seed&format=stockholm&order=t&case=l&gaps=default&entry=";
+    return "http://pfam.xfam.org/family/alignment/download/format?alnType=seed&format=stockholm&order=t&case=l&gaps=default&entry=";
   }
 
   /*
index e1e9e9a..e6fc8ff 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * Flyweight class specifying retrieval of Full family alignments from RFAM
  * 
@@ -42,7 +41,8 @@ public class RfamFull extends Rfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://rfam.sanger.ac.uk/family/alignment/download/format?alnType=full&nseLabels=0&format=stockholm&acc=";
+    return "http://rfam.xfam.org/family/alignment/download/format?alnType=full&nseLabels=0&format=stockholm&acc=";
+
   }
 
   /*
index 2850fd5..580ebe2 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.dbsources;
 
-
 /**
  * Flyweight class specifying retrieval of Seed family alignments from RFAM
  * 
@@ -42,11 +41,17 @@ public class RfamSeed extends Rfam
   @Override
   protected String getXFAMURL()
   {
-    return "http://rfam.sanger.ac.uk/family/alignment/download/format?alnType=seed&nseLabels=0&format=stockholm&acc=";
+    return "http://rfam.xfam.org/family/";
     // Janelia Farms url
     // "http://rfam.janelia.org/cgi-bin/getalignment?type=seed&fmt=stockholm&acc=";
   }
 
+  @Override
+  public String getXFAMURLSUFFIX()
+  {
+    return "/alignment";
+  }
+
   /*
    * (non-Javadoc)
    * 
index 17f1842..b6f53cd 100644 (file)
@@ -165,7 +165,7 @@ public class Uniprot extends DbSourceProxyImpl
       // uniprotxml parameter required since december 2007
       // uniprotkb dbname changed introduced december 2008
       File file = ebi.fetchDataAsFile("uniprotkb:" + queries, "uniprotxml",
-              null, ".xml");
+              ".xml");
       Vector<UniprotEntry> entries = getUniprotEntries(new FileReader(file));
 
       if (entries != null)
@@ -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 26c9997..6cc383d 100644 (file)
@@ -55,7 +55,8 @@ public abstract class Xfam extends DbSourceProxyImpl
     startQuery();
     // TODO: trap HTTP 404 exceptions and return null
     AlignmentI rcds = new FormatAdapter().readFile(getXFAMURL()
-            + queries.trim().toUpperCase(), FormatAdapter.URL, "STH");
+            + queries.trim().toUpperCase() + getXFAMURLSUFFIX(),
+            jalview.io.FormatAdapter.URL, "STH");
     for (int s = 0, sNum = rcds.getHeight(); s < sNum; s++)
     {
       rcds.getSequenceAt(s).addDBRef(new DBRefEntry(getXfamSource(),
@@ -81,4 +82,14 @@ public abstract class Xfam extends DbSourceProxyImpl
     return true;
   }
 
+  /**
+   * default suffix to append the retrieval URL for this source.
+   * 
+   * @return "" for most Xfam sources
+   */
+  public String getXFAMURLSUFFIX()
+  {
+    return "";
+  }
+
 }
index 3f6afbc..b184ff2 100644 (file)
@@ -259,8 +259,8 @@ public class DasSourceRegistry implements DasSourceRegistryI,
   }
 
   /*
- * 
- */
+  * 
+  */
 
   @Override
   public jalviewSourceI createLocalSource(String url, String name,
index 9f6bc65..f6928c4 100644 (file)
@@ -42,9 +42,6 @@ import java.util.StringTokenizer;
  */
 public class EBIFetchClient
 {
-  String format = "default";
-
-  String style = "raw";
 
   /**
    * Creates a new EBIFetchClient object.
@@ -93,14 +90,13 @@ public class EBIFetchClient
    *          the query formatted as db:query1;query2;query3
    * @param format
    *          the format wanted
-   * @param s
-   *          - unused parameter
+   * @param extension
+   *          for the temporary file to hold response
    * @return the file holding the response
    * @throws OutOfMemoryError
    */
 
-  public File fetchDataAsFile(String ids, String format, String s,
-          String ext)
+  public File fetchDataAsFile(String ids, String format, String ext)
           throws OutOfMemoryError
   {
     File outFile = null;
@@ -108,7 +104,7 @@ public class EBIFetchClient
     {
       outFile = File.createTempFile("jalview", ext);
       outFile.deleteOnExit();
-      fetchData(ids, format, s, outFile);
+      fetchData(ids, format, outFile);
       if (outFile.length() == 0)
       {
         outFile.delete();
@@ -121,92 +117,93 @@ public class EBIFetchClient
   }
 
   /**
-   * Single DB multiple record retrieval
+   * Fetches queries and either saves the response to a file or returns as
+   * string data
    * 
    * @param ids
-   *          db:query1;query2;query3
    * @param format
-   *          raw/xml
-   * @param s
-   *          not used - remove?
-   * 
-   * @return Raw string array result of query set
+   * @param outFile
+   * @return
+   * @throws OutOfMemoryError
    */
-  public String[] fetchData(String ids, String format, String s)
+  String[] fetchData(String ids, String format, File outFile)
           throws OutOfMemoryError
   {
-    return fetchData(ids, format, s, null);
+    StringBuilder querystring = new StringBuilder(ids.length());
+    String database = parseIds(ids, querystring);
+    if (database == null)
+    {
+      System.err.println("Invalid Query string : '" + ids + "'");
+      System.err.println("Should be of form 'dbname:q1;q2;q3;q4'");
+      return null;
+    }
+
+    // note: outFile is currently always specified, so return value is null
+    String[] rslt = fetchBatch(querystring.toString(), database, format,
+            outFile);
+
+    return (rslt != null && rslt.length > 0 ? rslt : null);
   }
 
-  String[] fetchData(String ids, String f, String s, File outFile)
-          throws OutOfMemoryError
+  /**
+   * Parses ids formatted as dbname:q1;q2;q3, returns the dbname and adds
+   * queries as comma-separated items to the querystring. dbname must be
+   * specified for at least one queryId. Returns null if a mixture of different
+   * dbnames is found (ignoring case).
+   * 
+   * @param ids
+   * @param queryString
+   * @return
+   */
+  static String parseIds(String ids, StringBuilder queryString)
   {
-    // Need to split
-    // ids of the form uniprot:25KD_SARPE;ADHR_DROPS;
-    String[] rslts = new String[0];
+    String database = null;
     StringTokenizer queries = new StringTokenizer(ids, ";");
-    String db = null;
-    StringBuffer querystring = null;
-    int nq = 0;
+    boolean appending = queryString.length() > 0;
     while (queries.hasMoreTokens())
     {
       String query = queries.nextToken();
-      int p;
-      if ((p = query.indexOf(':')) > -1)
+      int p = query.indexOf(':');
+      if (p > -1)
       {
-        db = query.substring(0, p);
+        String db = query.substring(0, p);
+        if (database != null && !db.equalsIgnoreCase(database))
+        {
+          /*
+           * different databases mixed in together - invalid
+           */
+          return null;
+        }
+        database = db;
         query = query.substring(p + 1);
       }
-      if (querystring == null)
-      {
-        querystring = new StringBuffer(query);
-        nq++;
-      }
-      else
-      {
-        querystring.append("," + query);
-        nq++;
-      }
-    }
-    if (db == null)
-    {
-      System.err.println("Invalid Query string : '" + ids
-              + "'\nShould be of form 'dbname:q1;q2;q3;q4'");
-      return null;
-    }
-    String[] rslt = fetchBatch(querystring.toString(), db, f, s, outFile);
-    if (rslt != null)
-    {
-      String[] nrslts = new String[rslt.length + rslts.length];
-      System.arraycopy(rslts, 0, nrslts, 0, rslts.length);
-      System.arraycopy(rslt, 0, nrslts, rslts.length, rslt.length);
-      rslts = nrslts;
+      queryString.append(appending ? "," : "");
+      queryString.append(query);
+      appending = true;
     }
-
-    return (rslts.length == 0 ? null : rslts);
+    return database;
   }
 
-  public String[] fetchBatch(String ids, String dbPath, String format, String s,
+  /**
+   * Fetches queries and either saves the response to a file or (if no file
+   * specified) returns as string data
+   * 
+   * @param ids
+   * @param database
+   * @param format
+   * @param outFile
+   * @return
+   * @throws OutOfMemoryError
+   */
+  String[] fetchBatch(String ids, String database, String format,
           File outFile) throws OutOfMemoryError
   {
     // long time = System.currentTimeMillis();
-    /*
-     * JAL-1855 dbfetch from ena_sequence, ena_coding
-     */
-    if (dbPath.equalsIgnoreCase(DBRefSource.EMBL))
-    {
-      dbPath = "ena_sequence";
-    }
-    else if (dbPath.equalsIgnoreCase(DBRefSource.EMBLCDS))
-    {
-      dbPath = "ena_coding";
-    }
+    String url = buildUrl(ids, database, format);
 
     try
     {
-      URL rcall = new URL("http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
-              + dbPath.toLowerCase() + "/" + ids.toLowerCase()
-              + (format != null ? "/" + format : ""));
+      URL rcall = new URL(url);
 
       InputStream is = new BufferedInputStream(rcall.openStream());
       if (outFile != null)
@@ -234,8 +231,7 @@ public class EBIFetchClient
       }
     } catch (OutOfMemoryError er)
     {
-
-      System.out.println("OUT OF MEMORY DOWNLOADING QUERY FROM " + dbPath
+      System.out.println("OUT OF MEMORY DOWNLOADING QUERY FROM " + database
               + ":\n" + ids);
       throw er;
     } catch (Exception ex)
@@ -246,8 +242,7 @@ public class EBIFetchClient
         return null;
       }
       System.err.println("Unexpected exception when retrieving from "
-              + dbPath
-              + "\nQuery was : '" + ids + "'");
+              + database + "\nQuery was : '" + ids + "'");
       ex.printStackTrace(System.err);
       return null;
     } finally
@@ -257,4 +252,30 @@ public class EBIFetchClient
     }
     return null;
   }
+
+  /**
+   * Constructs the URL to fetch from
+   * 
+   * @param ids
+   * @param database
+   * @param format
+   * @return
+   */
+  static String buildUrl(String ids, String database, String format)
+  {
+    String url;
+    if (database.equalsIgnoreCase(DBRefSource.EMBL)
+            || database.equalsIgnoreCase(DBRefSource.EMBLCDS))
+    {
+      url = "http://www.ebi.ac.uk/ena/data/view/" + ids.toLowerCase()
+              + (format != null ? "&" + format : "");
+    }
+    else
+    {
+      url = "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/"
+              + database.toLowerCase() + "/" + ids.toLowerCase()
+              + (format != null ? "/" + format : "");
+    }
+    return url;
+  }
 }
index 95f5527..aad72b1 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws.jws1;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -34,7 +34,6 @@ import javax.swing.JMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 
-import ext.vamsas.MuscleWS;
 import ext.vamsas.MuscleWSServiceLocator;
 import ext.vamsas.MuscleWSSoapBindingStub;
 import ext.vamsas.ServiceHandle;
@@ -72,7 +71,7 @@ public class MsaWSClient extends WS1Client
 
   public MsaWSClient(ext.vamsas.ServiceHandle sh, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
-          boolean preserveOrder, Alignment seqdataset,
+          boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
   {
     super();
@@ -109,7 +108,7 @@ public class MsaWSClient extends WS1Client
   }
 
   private void startMsaWSClient(String altitle, AlignmentView msa,
-          boolean submitGaps, boolean preserveOrder, Alignment seqdataset)
+          boolean submitGaps, boolean preserveOrder, AlignmentI seqdataset)
   {
     if (!locateWebService())
     {
@@ -159,7 +158,7 @@ public class MsaWSClient extends WS1Client
 
     try
     {
-      this.server = (MuscleWS) loc.getMuscleWS(new java.net.URL(WsURL));
+      this.server = loc.getMuscleWS(new java.net.URL(WsURL));
       ((MuscleWSSoapBindingStub) this.server).setTimeout(60000); // One minute
       // timeout
     } catch (Exception ex)
@@ -201,6 +200,7 @@ public class MsaWSClient extends WS1Client
     return (WebServiceName.indexOf("lustal") > -1); // cheat!
   }
 
+  @Override
   public void attachWSMenuEntry(JMenu msawsmenu,
           final ServiceHandle serviceHandle, final AlignFrame alignFrame)
   {
@@ -209,6 +209,7 @@ public class MsaWSClient extends WS1Client
     method.setToolTipText(WsURL);
     method.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         AlignmentView msa = alignFrame.gatherSequencesForAlignment();
@@ -228,6 +229,7 @@ public class MsaWSClient extends WS1Client
       methodR.setToolTipText(WsURL);
       methodR.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
           AlignmentView msa = alignFrame.gatherSequencesForAlignment();
index be21de7..e4247f7 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ws.jws1;
 import jalview.analysis.AlignSeq;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
@@ -147,6 +148,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
      * 
      * @return true if getAlignment will return a valid alignment result.
      */
+    @Override
     public boolean hasResults()
     {
       if (subjobComplete && result != null && result.isFinished()
@@ -273,6 +275,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
      * 
      * @return boolean true if job can be submitted.
      */
+    @Override
     public boolean hasValidInput()
     {
       if (seqs.getSeqs() != null)
@@ -285,7 +288,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
 
   String alTitle; // name which will be used to form new alignment window.
 
-  Alignment dataset; // dataset to which the new alignment will be
+  AlignmentI dataset; // dataset to which the new alignment will be
 
   // associated.
 
@@ -327,7 +330,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
   MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
           WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
           String wsname, String title, AlignmentView _msa, boolean subgaps,
-          boolean presorder, Alignment seqset)
+          boolean presorder, AlignmentI seqset)
   {
     this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
     OutputHeader = wsInfo.getProgressText();
@@ -359,11 +362,13 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     }
   }
 
+  @Override
   public boolean isCancellable()
   {
     return true;
   }
 
+  @Override
   public void cancelJob()
   {
     if (!jobComplete && jobs != null)
@@ -430,11 +435,13 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     }
   }
 
+  @Override
   public void pollJob(AWsJob job) throws Exception
   {
     ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).getJobId());
   }
 
+  @Override
   public void StartJob(AWsJob job)
   {
     if (!(job instanceof MsaWSJob))
@@ -521,6 +528,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     return msa;
   }
 
+  @Override
   public void parseResult()
   {
     int results = 0; // number of result sets received
@@ -571,6 +579,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
       wsInfo.showResultsNewFrame
               .addActionListener(new java.awt.event.ActionListener()
               {
+                @Override
                 public void actionPerformed(java.awt.event.ActionEvent evt)
                 {
                   displayResults(true);
@@ -579,6 +588,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
       wsInfo.mergeResults
               .addActionListener(new java.awt.event.ActionListener()
               {
+                @Override
                 public void actionPerformed(java.awt.event.ActionEvent evt)
                 {
                   displayResults(false);
@@ -660,8 +670,8 @@ class MsaWSThread extends JWS1Thread implements WSClientI
 
             while (j < l)
             {
-              if (((AlignmentOrder) alorders.get(i))
-                      .equals(((AlignmentOrder) alorders.get(j))))
+              if (((AlignmentOrder) alorders.get(i)).equals((alorders
+                      .get(j))))
               {
                 alorders.remove(j);
                 l--;
@@ -704,6 +714,7 @@ class MsaWSThread extends JWS1Thread implements WSClientI
     }
   }
 
+  @Override
   public boolean canMergeResults()
   {
     return false;
index d731ced..7665fec 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws.jws1;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -39,7 +39,6 @@ import javax.swing.JMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JOptionPane;
 
-import ext.vamsas.SeqSearchI;
 import ext.vamsas.SeqSearchServiceLocator;
 import ext.vamsas.SeqSearchServiceSoapBindingStub;
 import ext.vamsas.ServiceHandle;
@@ -77,7 +76,7 @@ public class SeqSearchWSClient extends WS1Client
 
   public SeqSearchWSClient(ext.vamsas.ServiceHandle sh, String altitle,
           jalview.datamodel.AlignmentView msa, String db,
-          Alignment seqdataset, AlignFrame _alignFrame)
+          AlignmentI seqdataset, AlignFrame _alignFrame)
   {
     super();
     alignFrame = _alignFrame;
@@ -128,7 +127,7 @@ public class SeqSearchWSClient extends WS1Client
   }
 
   private void startSeqSearchClient(String altitle, AlignmentView msa,
-          String db, Alignment seqdataset)
+          String db, AlignmentI seqdataset)
   {
     if (!locateWebService())
     {
@@ -173,8 +172,7 @@ public class SeqSearchWSClient extends WS1Client
 
     try
     {
-      this.server = (SeqSearchI) loc.getSeqSearchService(new java.net.URL(
-              WsURL));
+      this.server = loc.getSeqSearchService(new java.net.URL(WsURL));
       ((SeqSearchServiceSoapBindingStub) this.server).setTimeout(60000); // One
       // minute
       // timeout
@@ -241,6 +239,7 @@ public class SeqSearchWSClient extends WS1Client
     return dbs;
   }
 
+  @Override
   public void attachWSMenuEntry(JMenu wsmenu, final ServiceHandle sh,
           final AlignFrame af)
   {
@@ -281,6 +280,7 @@ public class SeqSearchWSClient extends WS1Client
     method.setToolTipText(sh.getEndpointURL());
     method.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent e)
       {
         // use same input gatherer as for secondary structure prediction
@@ -305,6 +305,7 @@ public class SeqSearchWSClient extends WS1Client
       final String searchdb = dbs[db];
       method.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
           AlignmentView msa = af.gatherSeqOrMsaForSecStrPrediction();
index b2e9b35..70056a6 100644 (file)
 package jalview.ws.jws1;
 
 import jalview.analysis.AlignSeq;
+import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
@@ -171,8 +173,8 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
      * 
      * @return null or { Alignment(+features and annotation), NewickFile)}
      */
-    public Object[] getAlignment(Alignment dataset,
-            Map<String, Object> featureColours)
+    public Object[] getAlignment(AlignmentI dataset,
+            Map<String, FeatureColourI> featureColours)
     {
 
       if (result != null && result.isFinished())
@@ -302,7 +304,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
 
   String alTitle; // name which will be used to form new alignment window.
 
-  Alignment dataset; // dataset to which the new alignment will be
+  AlignmentI dataset; // dataset to which the new alignment will be
 
   // associated.
 
@@ -344,7 +346,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
   SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
           WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
           String wsname, String title, AlignmentView _msa, String db,
-          Alignment seqset)
+          AlignmentI seqset)
   {
     this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
     OutputHeader = wsInfo.getProgressText();
@@ -622,7 +624,7 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
     // NewickFile nf[] = new NewickFile[jobs.length];
     for (int j = 0; j < jobs.length; j++)
     {
-      Map<String, Object> featureColours = new HashMap<String, Object>();
+      Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
       Alignment al = null;
       NewickFile nf = null;
       if (jobs[j].hasResults())
index f929b1e..0cf76e0 100644 (file)
 package jalview.ws.jws2;
 
 import jalview.api.AlignCalcWorkerI;
+import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.schemes.GraduatedColor;
+import jalview.schemes.FeatureColour;
 import jalview.schemes.UserColourScheme;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.WsParamSetI;
@@ -46,8 +47,7 @@ import compbio.data.sequence.Score;
 import compbio.data.sequence.ScoreManager.ScoreHolder;
 import compbio.metadata.Argument;
 
-public class AADisorderClient extends JabawsCalcWorker implements
-        AlignCalcWorkerI
+public class AADisorderClient extends JabawsCalcWorker
 {
 
   private static final String THRESHOLD = "THRESHOLD";
@@ -308,8 +308,8 @@ public class AADisorderClient extends JabawsCalcWorker implements
                 annot.description += "<br/>" + threshNote;
               }
               annot.description += "</html>";
-              Color col = new UserColourScheme(typeName)
-                      .createColourFromName(typeName + scr.getMethod());
+              Color col = UserColourScheme.createColourFromName(typeName
+                      + scr.getMethod());
               for (int p = 0, ps = annot.annotations.length; p < ps; p++)
               {
                 if (annot.annotations[p] != null)
@@ -337,13 +337,13 @@ public class AADisorderClient extends JabawsCalcWorker implements
                   .cloneFeatureRenderer();
           for (String ft : fc.keySet())
           {
-            Object gc = fr.getFeatureStyle(ft);
-            if (gc instanceof Color)
+            FeatureColourI gc = fr.getFeatureStyle(ft);
+            if (gc.isSimpleColour())
             {
               // set graduated color as fading to white for minimum, and
               // autoscaling to values on alignment
-              GraduatedColor ggc = new GraduatedColor(Color.white,
-                      (Color) gc, Float.MIN_VALUE, Float.MAX_VALUE);
+              FeatureColourI ggc = new FeatureColour(Color.white,
+                      gc.getColour(), Float.MIN_VALUE, Float.MAX_VALUE);
               ggc.setAutoScaled(true);
               fr.setColour(ft, ggc);
             }
index 897aa1e..b33df0c 100644 (file)
@@ -331,23 +331,23 @@ public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
       System.err.println("submission error with " + getServiceActionText()
               + " :");
       x.printStackTrace();
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
     } catch (ResultNotAvailableException x)
     {
       System.err.println("collection error:\nJob ID: " + rslt);
       x.printStackTrace();
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
 
     } catch (OutOfMemoryError error)
     {
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
 
       // consensus = null;
       // hconsensus = null;
       ap.raiseOOMWarning(getServiceActionText(), error);
     } catch (Exception x)
     {
-      calcMan.workerCannotRun(this);
+      calcMan.disableWorker(this);
 
       // consensus = null;
       // hconsensus = null;
index e4d6329..c15f256 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.jws2;
 
-import jalview.api.AlignCalcWorkerI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.gui.AlignFrame;
@@ -43,9 +42,7 @@ import compbio.data.sequence.JpredAlignment;
 import compbio.metadata.Argument;
 
 public class JPred301Client extends JabawsMsaInterfaceAlignCalcWorker
-        implements AlignCalcWorkerI
 {
-
   /**
    * 
    * @return default args for this service when run as dynamic web service
@@ -87,6 +84,7 @@ public class JPred301Client extends JabawsMsaInterfaceAlignCalcWorker
     return (seqs.size() > 1);
   }
 
+  @Override
   public String getServiceActionText()
   {
     return "calculating consensus secondary structure prediction using JPred service";
@@ -112,6 +110,7 @@ public class JPred301Client extends JabawsMsaInterfaceAlignCalcWorker
    * update the consensus annotation from the sequence profile data using
    * current visualization settings.
    */
+  @Override
   public void updateResultAnnotation(boolean immediate)
   {
     if (immediate || !calcMan.isWorking(this) && msascoreset != null)
index c0b701b..8855d96 100644 (file)
@@ -256,11 +256,8 @@ public abstract class Jws2Client extends jalview.ws.WSClient
       });
       wsmenu.add(aaConEnabled);
       final JMenuItem modifyParams = new JMenuItem(aaui.getAAeditSettings());
-      modifyParams
-              .setToolTipText("<html><p>"
-                      + JvSwingUtils.wrapTooltip(false,
-                              aaui.getAAeditSettingsTooltip() + "</p>")
-                      + "</html>");
+      modifyParams.setToolTipText(JvSwingUtils.wrapTooltip(true,
+              aaui.getAAeditSettingsTooltip()));
       modifyParams.addActionListener(new ActionListener()
       {
 
index 47130a3..8fa118d 100644 (file)
@@ -20,7 +20,7 @@
  */
 package jalview.ws.jws2;
 
-import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
@@ -58,7 +58,7 @@ public class MsaWSClient extends Jws2Client
 
   public MsaWSClient(Jws2Instance sh, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
-          boolean preserveOrder, Alignment seqdataset,
+          boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
   {
     this(sh, null, null, false, altitle, msa, submitGaps, preserveOrder,
@@ -68,7 +68,7 @@ public class MsaWSClient extends Jws2Client
 
   public MsaWSClient(Jws2Instance sh, WsParamSetI preset, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
-          boolean preserveOrder, Alignment seqdataset,
+          boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
   {
     this(sh, preset, null, false, altitle, msa, submitGaps, preserveOrder,
@@ -95,7 +95,7 @@ public class MsaWSClient extends Jws2Client
   public MsaWSClient(Jws2Instance sh, WsParamSetI preset,
           List<Argument> arguments, boolean editParams, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
-          boolean preserveOrder, Alignment seqdataset,
+          boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
   {
     super(_alignFrame, preset, arguments);
@@ -138,7 +138,7 @@ public class MsaWSClient extends Jws2Client
   }
 
   private void startMsaWSClient(String altitle, AlignmentView msa,
-          boolean submitGaps, boolean preserveOrder, Alignment seqdataset)
+          boolean submitGaps, boolean preserveOrder, AlignmentI seqdataset)
   {
     // if (!locateWebService())
     // {
@@ -216,6 +216,7 @@ public class MsaWSClient extends Jws2Client
     return (WebServiceName.indexOf("lustal") > -1); // cheat!
   }
 
+  @Override
   public void attachWSMenuEntry(JMenu rmsawsmenu,
           final Jws2Instance service, final AlignFrame alignFrame)
   {
@@ -263,6 +264,7 @@ public class MsaWSClient extends Jws2Client
 
       method.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
           AlignmentView msa = alignFrame.gatherSequencesForAlignment();
@@ -288,6 +290,7 @@ public class MsaWSClient extends Jws2Client
 
         method.addActionListener(new ActionListener()
         {
+          @Override
           public void actionPerformed(ActionEvent e)
           {
             AlignmentView msa = alignFrame.gatherSequencesForAlignment();
@@ -335,17 +338,20 @@ public class MsaWSClient extends Jws2Client
               }
 
             });
-            methodR.setToolTipText(JvSwingUtils.wrapTooltip(
-                    true,
-                    "<p><strong>"
-                            + (preset.isModifiable() ? MessageManager
-                                    .getString("label.user_preset")
-                                    : MessageManager
-                                            .getString("label.service_preset"))
-                            + "</strong><br/>" + preset.getDescription()
-                            + "</p>"));
+            String tooltip = JvSwingUtils
+                    .wrapTooltip(
+                            true,
+                            "<strong>"
+                                    + (preset.isModifiable() ? MessageManager
+                                            .getString("label.user_preset")
+                                            : MessageManager
+                                                    .getString("label.service_preset"))
+                                    + "</strong><br/>"
+                                    + preset.getDescription());
+            methodR.setToolTipText(tooltip);
             methodR.addActionListener(new ActionListener()
             {
+              @Override
               public void actionPerformed(ActionEvent e)
               {
                 AlignmentView msa = alignFrame
index e2f3a7c..e425624 100644 (file)
@@ -176,6 +176,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
      * 
      * @return true if getAlignment will return a valid alignment result.
      */
+    @Override
     public boolean hasResults()
     {
       if (subjobComplete
@@ -316,6 +317,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
      * 
      * @return boolean true if job can be submitted.
      */
+    @Override
     public boolean hasValidInput()
     {
       // TODO: get attributes for this MsaWS instance to check if it can do two
@@ -436,7 +438,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
 
   String alTitle; // name which will be used to form new alignment window.
 
-  Alignment dataset; // dataset to which the new alignment will be
+  AlignmentI dataset; // dataset to which the new alignment will be
 
   // associated.
 
@@ -479,7 +481,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
           String wsUrl, WebserviceInfo wsinfo,
           jalview.gui.AlignFrame alFrame, String wsname, String title,
           AlignmentView _msa, boolean subgaps, boolean presorder,
-          Alignment seqset)
+          AlignmentI seqset)
   {
     this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
     OutputHeader = wsInfo.getProgressText();
@@ -530,11 +532,13 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     return validInput;
   }
 
+  @Override
   public boolean isCancellable()
   {
     return true;
   }
 
+  @Override
   public void cancelJob()
   {
     if (!jobComplete && jobs != null)
@@ -605,6 +609,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     }
   }
 
+  @Override
   public void pollJob(AWsJob job) throws Exception
   {
     // TODO: investigate if we still need to cast here in J1.6
@@ -650,6 +655,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     return changed;
   }
 
+  @Override
   public void StartJob(AWsJob job)
   {
     Exception lex = null;
@@ -775,6 +781,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     }
   }
 
+  @Override
   public void parseResult()
   {
     long progbar = System.currentTimeMillis();
@@ -889,6 +896,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
       wsInfo.showResultsNewFrame
               .addActionListener(new java.awt.event.ActionListener()
               {
+                @Override
                 public void actionPerformed(java.awt.event.ActionEvent evt)
                 {
                   displayResults(true);
@@ -897,6 +905,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
       wsInfo.mergeResults
               .addActionListener(new java.awt.event.ActionListener()
               {
+                @Override
                 public void actionPerformed(java.awt.event.ActionEvent evt)
                 {
                   displayResults(false);
@@ -1023,6 +1032,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI
       // becomes null if the alignment window was closed before the alignment
       // job finished.
       AlignmentI copyComplement = new Alignment(complement);
+      // todo should this be done by copy constructor?
+      copyComplement.setGapCharacter(complement.getGapCharacter());
+      // share the same dataset (and the mappings it holds)
+      copyComplement.setDataset(complement.getDataset());
       copyComplement.alignAs(al);
       if (copyComplement.getHeight() > 0)
       {
@@ -1101,6 +1114,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     }
   }
 
+  @Override
   public boolean canMergeResults()
   {
     return false;
index 41aa223..9ca6d2e 100644 (file)
@@ -20,7 +20,6 @@
  */
 package jalview.ws.jws2;
 
-import jalview.api.AlignCalcWorkerI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.gui.AlignFrame;
@@ -50,8 +49,7 @@ import compbio.metadata.Argument;
  * 
  */
 
-public class RNAalifoldClient extends JabawsCalcWorker implements
-        AlignCalcWorkerI
+public class RNAalifoldClient extends JabawsCalcWorker
 {
 
   String methodName;
@@ -75,6 +73,7 @@ public class RNAalifoldClient extends JabawsCalcWorker implements
     initViewportParams();
   }
 
+  @Override
   public String getCalcId()
   {
     return CALC_ID;
index 187540c..2af31bb 100644 (file)
@@ -122,7 +122,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
         }
         // reinstate worker if it was blacklisted (might have happened due to
         // invalid parameters)
-        alignFrame.getViewport().getCalcManager().workerMayRun(worker);
+        alignFrame.getViewport().getCalcManager().enableWorker(worker);
         worker.updateParameters(this.preset, paramset);
       }
     }
index 2392476..31168b4 100644 (file)
@@ -55,7 +55,7 @@ public class ASequenceFetcher
   /**
    * Constructor
    */
-  public ASequenceFetcher()
+  protected ASequenceFetcher()
   {
     super();
 
@@ -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;
   }
 
@@ -125,20 +124,20 @@ public class ASequenceFetcher
    *          if true, only fetch from nucleotide data sources, else peptide
    * @return
    */
-  public SequenceI[] getSequences(DBRefEntry[] refs, boolean dna)
+  public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
   {
     Vector<SequenceI> rseqs = new Vector<SequenceI>();
     Hashtable<String, List<String>> queries = new Hashtable<String, List<String>>();
-    for (int r = 0; r < refs.length; r++)
+    for (DBRefEntry ref : refs)
     {
-      if (!queries.containsKey(refs[r].getSource()))
+      if (!queries.containsKey(ref.getSource()))
       {
-        queries.put(refs[r].getSource(), new ArrayList<String>());
+        queries.put(ref.getSource(), new ArrayList<String>());
       }
-      List<String> qset = queries.get(refs[r].getSource());
-      if (!qset.contains(refs[r].getAccessionId()))
+      List<String> qset = queries.get(ref.getSource());
+      if (!qset.contains(ref.getAccessionId()))
       {
-        qset.add(refs[r].getAccessionId());
+        qset.add(ref.getAccessionId());
       }
     }
     Enumeration<String> e = queries.keys();
@@ -205,15 +204,12 @@ public class ASequenceFetcher
                 for (int is = 0; is < seqs.length; is++)
                 {
                   rseqs.addElement(seqs[is]);
-                  DBRefEntry[] frefs = DBRefUtils.searchRefs(seqs[is]
+                  List<DBRefEntry> frefs = DBRefUtils.searchRefs(seqs[is]
                           .getDBRefs(), new DBRefEntry(db, null, null));
-                  if (frefs != null)
+                  for (DBRefEntry dbr : frefs)
                   {
-                    for (DBRefEntry dbr : frefs)
-                    {
-                      queriesFound.add(dbr.getAccessionId());
-                      queriesMade.remove(dbr.getAccessionId());
-                    }
+                    queriesFound.add(dbr.getAccessionId());
+                    queriesMade.remove(dbr.getAccessionId());
                   }
                   seqs[is] = null;
                 }
index c06e51f..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
@@ -20,8 +40,6 @@ public class MappingOutputPojo
 
   private String type;
 
-  private int wrapHeight;
-
   private static final int MAX_ID_LENGTH = 30;
 
   public String getSeqName()
@@ -116,14 +134,4 @@ public class MappingOutputPojo
     this.type = type;
   }
 
-  public int getWrapHeight()
-  {
-    return wrapHeight;
-  }
-
-  public void setWrapHeight(int wrapHeight)
-  {
-    this.wrapHeight = wrapHeight;
-  }
-
 }
index e04bbb7..acca50f 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.SequenceI;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.StructureMapping;
+import jalview.util.DBRefUtils;
 import jalview.util.Format;
 import jalview.xml.binding.sifts.Entry;
 import jalview.xml.binding.sifts.Entry.Entity;
@@ -37,11 +38,9 @@ import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb;
 import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.ResidueDetail;
-import jalview.xml.binding.sifts.Entry.ListDB.Db;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,20 +58,18 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.zip.GZIPInputStream;
 
 import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.FactoryConfigurationError;
 import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
 import MCview.Atom;
 import MCview.PDBChain;
-import MCview.PDBfile;
 
 public class SiftsClient implements SiftsClientI
 {
@@ -84,8 +81,6 @@ public class SiftsClient implements SiftsClientI
 
   private String structId;
 
-  private String segStartEnd;
-
   private CoordinateSys seqCoordSys = CoordinateSys.UNIPROT;
 
   private static final int BUFFER_SIZE = 4096;
@@ -96,11 +91,9 @@ public class SiftsClient implements SiftsClientI
 
   private static final int PDB_ATOM_POS = 1;
 
-  private static final String NOT_FOUND = "Not_Found";
-
   private static final String NOT_OBSERVED = "Not_Observed";
 
-  private static final String SIFTS_FTP_BASE_URL = "ftp://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
+  private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/";
 
   private final static String NEWLINE = System.lineSeparator();
 
@@ -108,7 +101,7 @@ public class SiftsClient implements SiftsClientI
 
   private HashSet<String> curDBRefAccessionIdsString;
 
-  public enum CoordinateSys
+  private enum CoordinateSys
   {
     UNIPROT("UniProt"), PDB("PDBresnum"), PDBe("PDBe");
     private String name;
@@ -124,7 +117,7 @@ public class SiftsClient implements SiftsClientI
     }
   };
 
-  public enum ResidueDetailType
+  private enum ResidueDetailType
   {
     NAME_SEC_STRUCTURE("nameSecondaryStructure"), CODE_SEC_STRUCTURE(
             "codeSecondaryStructure"), ANNOTATION("Annotation");
@@ -157,22 +150,6 @@ public class SiftsClient implements SiftsClientI
   }
 
   /**
-   * Construct an instance of SiftsClient using the supplied SIFTs file. Note:
-   * The SIFTs file should correspond to the PDB Id in PDBfile instance
-   * 
-   * @param pdbId
-   * @param siftsFile
-   * @throws SiftsException
-   * @throws Exception
-   */
-  public SiftsClient(PDBfile pdb, File siftsFile) throws SiftsException
-  {
-    this.pdb = pdb;
-    this.pdbId = pdb.getId();
-    siftsEntry = parseSIFTs(siftsFile);
-  }
-
-  /**
    * Parse the given SIFTs File and return a JAXB POJO of parsed data
    * 
    * @param siftFile
@@ -192,23 +169,7 @@ public class SiftsClient implements SiftsClientI
               .createXMLStreamReader(gzis);
       Unmarshaller um = jc.createUnmarshaller();
       return (Entry) um.unmarshal(streamReader);
-    } catch (JAXBException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (FileNotFoundException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (XMLStreamException e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (FactoryConfigurationError e)
-    {
-      e.printStackTrace();
-      throw new SiftsException(e.getMessage());
-    } catch (IOException e)
+    } catch (Exception e)
     {
       e.printStackTrace();
       throw new SiftsException(e.getMessage());
@@ -225,8 +186,9 @@ public class SiftsClient implements SiftsClientI
    */
   public static File getSiftsFile(String pdbId) throws SiftsException
   {
-    File siftsFile = new File(SiftsSettings.getSiftDownloadDirectory()
-            + pdbId.toLowerCase() + ".xml.gz");
+    String siftsFileName = SiftsSettings.getSiftDownloadDirectory()
+            + pdbId.toLowerCase() + ".xml.gz";
+    File siftsFile = new File(siftsFileName);
     if (siftsFile.exists())
     {
       // The line below is required for unit testing... don't comment it out!!!
@@ -235,12 +197,28 @@ public class SiftsClient implements SiftsClientI
       if (isFileOlderThanThreshold(siftsFile,
               SiftsSettings.getCacheThresholdInDays()))
       {
-        // System.out.println("Downloaded file is out of date, hence re-downloading...");
-        siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+        File oldSiftsFile = new File(siftsFileName + "_old");
+        siftsFile.renameTo(oldSiftsFile);
+        try
+        {
+          siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+          oldSiftsFile.delete();
+          return siftsFile;
+        } catch (IOException e)
+        {
+          e.printStackTrace();
+          oldSiftsFile.renameTo(siftsFile);
+          return new File(siftsFileName);
+        }
       }
-      return siftsFile;
     }
-    siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+    try
+    {
+      siftsFile = downloadSiftsFile(pdbId.toLowerCase());
+    } catch (IOException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
     return siftsFile;
   }
 
@@ -278,8 +256,10 @@ public class SiftsClient implements SiftsClientI
    * @param pdbId
    * @return downloaded SIFTs XML file
    * @throws SiftsException
+   * @throws IOException
    */
-  public static File downloadSiftsFile(String pdbId) throws SiftsException
+  public static File downloadSiftsFile(String pdbId) throws SiftsException,
+          IOException
   {
     if (pdbId.contains(".cif"))
     {
@@ -295,27 +275,21 @@ public class SiftsClient implements SiftsClientI
     {
       siftsDownloadDir.mkdirs();
     }
-    try
-    {
-      // 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);
-    } catch (IOException ex)
+    // 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)
     {
-      throw new SiftsException(ex.getMessage());
+      outputStream.write(buffer, 0, bytesRead);
     }
+    outputStream.close();
+    inputStream.close();
+    // System.out.println(">>> File downloaded : " + downloadedSiftsFile);
     return new File(downloadedSiftsFile);
   }
 
@@ -349,39 +323,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("Could not get source DB Ref");
+        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)))
-        {
-          return dbRef;
-        }
+        return dbRef;
       }
     }
-    if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef))
-    {
-      return sourceDBRef;
-    }
     throw new SiftsException("Could not get source DB Ref");
   }
 
@@ -393,7 +357,7 @@ public class SiftsClient implements SiftsClientI
    *          - DBRefEntry to validate
    * @return true validation is successful otherwise false is returned.
    */
-  private boolean isValidDBRefEntry(DBRefEntryI entry)
+  boolean isValidDBRefEntry(DBRefEntryI entry)
   {
     return entry != null && entry.getAccessionId() != null
             && isFoundInSiftsEntry(entry.getAccessionId());
@@ -413,7 +377,8 @@ public class SiftsClient implements SiftsClientI
                 .getMapRegion();
         for (MapRegion mapRegion : mapRegions)
         {
-          accessions.add(mapRegion.getDb().getDbAccessionId());
+          accessions
+                  .add(mapRegion.getDb().getDbAccessionId().toLowerCase());
         }
       }
     }
@@ -425,8 +390,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)
@@ -455,7 +420,7 @@ public class SiftsClient implements SiftsClientI
   public HashMap<Integer, int[]> getGreedyMapping(String entityId,
           SequenceI seq, java.io.PrintStream os) throws SiftsException
   {
-    ArrayList<Integer> omitNonObserved = new ArrayList<Integer>();
+    List<Integer> omitNonObserved = new ArrayList<Integer>();
     int nonObservedShiftIndex = 0;
     // System.out.println("Generating mappings for : " + entityId);
     Entity entity = null;
@@ -463,13 +428,10 @@ 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();
-    if (sourceDBRef == null)
-    {
-      sourceDBRef = getValidSourceDBRef(seq);
-      // TODO ensure sequence start/end is in the same coordinate system and
-      // consistent with the choosen sourceDBRef
-    }
+    DBRefEntryI sourceDBRef;
+    sourceDBRef = getValidSourceDBRef(seq);
+    // TODO ensure sequence start/end is in the same coordinate system and
+    // consistent with the choosen sourceDBRef
 
     // set sequence coordinate system - default value is UniProt
     if (sourceDBRef.getSource().equalsIgnoreCase(DBRefSource.PDB))
@@ -489,10 +451,92 @@ public class SiftsClient implements SiftsClientI
 
     TreeMap<Integer, String> resNumMap = new TreeMap<Integer, String>();
     List<Segment> segments = entity.getSegment();
+    SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap,
+            omitNonObserved, nonObservedShiftIndex);
+    processSegments(segments, shp);
+    try
+    {
+      populateAtomPositions(entityId, mapping);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    if (seqCoordSys == CoordinateSys.UNIPROT)
+    {
+      padWithGaps(resNumMap, omitNonObserved);
+    }
+    int seqStart = UNASSIGNED;
+    int seqEnd = UNASSIGNED;
+    int pdbStart = UNASSIGNED;
+    int pdbEnd = UNASSIGNED;
+
+    if (mapping.isEmpty())
+    {
+      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];
+
+    String matchedSeq = originalSeq;
+    if (seqStart != UNASSIGNED)
+    {
+      pdbStart = mapping.get(seqStart)[PDB_RES_POS];
+      pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
+      int orignalSeqStart = seq.getStart();
+      if (orignalSeqStart >= 1)
+      {
+        int subSeqStart = (seqStart >= orignalSeqStart) ? seqStart
+                - orignalSeqStart : 0;
+        int subSeqEnd = seqEnd - (orignalSeqStart - 1);
+        subSeqEnd = originalSeq.length() < subSeqEnd ? originalSeq.length()
+                : subSeqEnd;
+        matchedSeq = originalSeq.substring(subSeqStart, subSeqEnd);
+      }
+      else
+      {
+        matchedSeq = originalSeq.substring(1, originalSeq.length());
+      }
+    }
+
+    StringBuilder targetStrucSeqs = new StringBuilder();
+    for (String res : resNumMap.values())
+    {
+      targetStrucSeqs.append(res);
+    }
+
+    if (os != null)
+    {
+      MappingOutputPojo mop = new MappingOutputPojo();
+      mop.setSeqStart(pdbStart);
+      mop.setSeqEnd(pdbEnd);
+      mop.setSeqName(seq.getName());
+      mop.setSeqResidue(matchedSeq);
+
+      mop.setStrStart(seqStart);
+      mop.setStrEnd(seqEnd);
+      mop.setStrName(structId);
+      mop.setStrResidue(targetStrucSeqs.toString());
+
+      mop.setType("pep");
+      os.print(getMappingOutput(mop).toString());
+      os.println();
+    }
+    return mapping;
+  }
+
+  void processSegments(List<Segment> segments, SegmentHelperPojo shp)
+  {
+    SequenceI seq = shp.getSeq();
+    HashMap<Integer, int[]> mapping = shp.getMapping();
+    TreeMap<Integer, String> resNumMap = shp.getResNumMap();
+    List<Integer> omitNonObserved = shp.getOmitNonObserved();
+    int nonObservedShiftIndex = shp.getNonObservedShiftIndex();
     for (Segment segment : segments)
     {
-      segStartEnd = segment.getStart() + " - " + segment.getEnd();
-      // System.out.println("Mapping segments : " + segment.getSegId() + "\\"
+      // System.out.println("Mapping segments : " + segment.getSegId() + "\\"s
       // + segStartEnd);
       List<Residue> residues = segment.getListResidue().getResidue();
       for (Residue residue : residues)
@@ -566,75 +610,6 @@ public class SiftsClient implements SiftsClientI
         }
       }
     }
-    try
-    {
-      populateAtomPositions(entityId, mapping);
-    } catch (Exception e)
-    {
-      e.printStackTrace();
-    }
-    if (seqCoordSys == CoordinateSys.UNIPROT)
-    {
-      padWithGaps(resNumMap, omitNonObserved);
-    }
-    int seqStart = UNASSIGNED;
-    int seqEnd = UNASSIGNED;
-    int pdbStart = UNASSIGNED;
-    int pdbEnd = UNASSIGNED;
-
-    Integer[] keys = mapping.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
-    if (keys.length < 1)
-    {
-      throw new SiftsException(">>> Empty SIFTS mapping generated!!");
-    }
-    seqStart = keys[0];
-    seqEnd = keys[keys.length - 1];
-
-    String matchedSeq = originalSeq;
-    if (seqStart != UNASSIGNED)
-    {
-      pdbStart = mapping.get(seqStart)[PDB_RES_POS];
-      pdbEnd = mapping.get(seqEnd)[PDB_RES_POS];
-      int orignalSeqStart = seq.getStart();
-      if (orignalSeqStart >= 1)
-      {
-        int subSeqStart = (seqStart >= orignalSeqStart) ? seqStart
-                - orignalSeqStart : 0;
-        int subSeqEnd = seqEnd - (orignalSeqStart - 1);
-        subSeqEnd = originalSeq.length() < subSeqEnd ? originalSeq.length()
-                : subSeqEnd;
-        matchedSeq = originalSeq.substring(subSeqStart, subSeqEnd);
-      }
-      else
-      {
-        matchedSeq = originalSeq.substring(1, originalSeq.length());
-      }
-    }
-
-    StringBuilder targetStrucSeqs = new StringBuilder();
-    for (String res : resNumMap.values())
-    {
-      targetStrucSeqs.append(res);
-    }
-
-    if (os != null)
-    {
-      MappingOutputPojo mop = new MappingOutputPojo();
-      mop.setSeqStart(pdbStart);
-      mop.setSeqEnd(pdbEnd);
-      mop.setSeqName(seq.getName());
-      mop.setSeqResidue(matchedSeq);
-
-      mop.setStrStart(seqStart);
-      mop.setStrEnd(seqEnd);
-      mop.setStrName(structId);
-      mop.setStrResidue(targetStrucSeqs.toString());
-
-      mop.setType("pep");
-      os.print(getMappingOutput(mop).toString());
-    }
-    return mapping;
   }
 
   /**
@@ -645,9 +620,10 @@ public class SiftsClient implements SiftsClientI
    *          Two dimension array of residue index versus atom position
    * @throws IllegalArgumentException
    *           Thrown if chainId or mapping is null
+   * @throws SiftsException
    */
-  void populateAtomPositions(String chainId,
-          HashMap<Integer, int[]> mapping) throws IllegalArgumentException
+  void populateAtomPositions(String chainId, Map<Integer, int[]> mapping)
+          throws IllegalArgumentException, SiftsException
   {
     try
     {
@@ -665,9 +641,12 @@ public class SiftsClient implements SiftsClientI
           map[PDB_ATOM_POS] = getAtomIndex(map[PDB_RES_POS], chain.atoms);
         }
       }
+    } catch (NullPointerException e)
+    {
+      throw new SiftsException(e.getMessage());
     } catch (Exception e)
     {
-      e.printStackTrace();
+      throw new SiftsException(e.getMessage());
     }
   }
 
@@ -704,7 +683,7 @@ public class SiftsClient implements SiftsClientI
    */
   private boolean isResidueObserved(Residue residue)
   {
-    HashSet<String> annotations = getResidueAnnotaitons(residue,
+    Set<String> annotations = getResidueAnnotaitons(residue,
             ResidueDetailType.ANNOTATION);
     if (annotations == null || annotations.isEmpty())
     {
@@ -727,7 +706,7 @@ public class SiftsClient implements SiftsClientI
    * @param type
    * @return
    */
-  private HashSet<String> getResidueAnnotaitons(Residue residue,
+  private Set<String> getResidueAnnotaitons(Residue residue,
           ResidueDetailType type)
   {
     HashSet<String> foundAnnotations = new HashSet<String>();
@@ -752,8 +731,9 @@ public class SiftsClient implements SiftsClientI
 
   private boolean isFoundInSiftsEntry(String accessionId)
   {
+    Set<String> siftsDBRefs = getAllMappingAccession();
     return accessionId != null
-            && getAllMappingAccession().contains(accessionId);
+            && siftsDBRefs.contains(accessionId.toLowerCase());
   }
 
   /**
@@ -761,15 +741,15 @@ public class SiftsClient implements SiftsClientI
    * 
    * @param resNumMap
    */
-  void padWithGaps(TreeMap<Integer, String> resNumMap,
-          ArrayList<Integer> omitNonObserved)
+  void padWithGaps(Map<Integer, String> resNumMap,
+          List<Integer> omitNonObserved)
   {
     if (resNumMap == null || resNumMap.isEmpty())
     {
       return;
     }
     Integer[] keys = resNumMap.keySet().toArray(new Integer[0]);
-    Arrays.sort(keys);
+    // Arrays.sort(keys);
     int firstIndex = keys[0];
     int lastIndex = keys[keys.length - 1];
     // System.out.println("Min value " + firstIndex);
@@ -783,33 +763,11 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-
-
   @Override
   public Entity getEntityById(String id) throws SiftsException
   {
-    // Sometimes SIFTS mappings are wrongly swapped between different chains of
-    // a PDB entry. This results to wrong mappings being generated. The boolean
-    // flag 'isGetEntityIdDirectly, determines whether an entity to process is
-    // determined by a greedy heuristic search or by just matching the Chain Id
-    // directly against the entity Id tag. Setting the default value to 'false'
-    // utilise the heuristic search which always produces correct mappings but
-    // less optimised processing, where as changing the value to 'true'
-    // optimises performance but might result to incorrect mapping in some cases
-    // where SIFTS mappings are wrongly swapped between different chains.
-    boolean isGetEntityIdDirectly = false;
-    if (isGetEntityIdDirectly)
-    {
-      List<Entity> entities = siftsEntry.getEntity();
-      for (Entity entity : entities)
-      {
-        if (!entity.getEntityId().equalsIgnoreCase(id))
-        {
-          continue;
-        }
-        return entity;
-      }
-    }
+    // Determines an entity to process by performing a heuristic matching of all
+    // Entities with the given chainId and choosing the best matching Entity
     Entity entity = getEntityByMostOptimalMatchedId(id);
     if (entity != null)
     {
@@ -858,7 +816,8 @@ public class SiftsClient implements SiftsClientI
           }
         }
       }
-      sPojo[count].pid = 100 * (sPojo[count].chainIdFreq / sPojo[count].resCount);
+      sPojo[count].pid = (100 * sPojo[count].chainIdFreq)
+              / sPojo[count].resCount;
       ++count;
     }
     Arrays.sort(sPojo, Collections.reverseOrder());
@@ -879,7 +838,7 @@ public class SiftsClient implements SiftsClientI
     return null;
   }
 
-  public class SiftsEntitySortPojo implements
+  private class SiftsEntitySortPojo implements
           Comparable<SiftsEntitySortPojo>
   {
     public String entityId;
@@ -897,18 +856,79 @@ public class SiftsClient implements SiftsClientI
     }
   }
 
-  @Override
-  public String[] getEntryDBs()
+  private class SegmentHelperPojo
   {
-    System.out.println("\nListing DB entries...");
-    List<String> availDbs = new ArrayList<String>();
-    List<Db> dbs = siftsEntry.getListDB().getDb();
-    for (Db db : dbs)
+    private SequenceI seq;
+
+    private HashMap<Integer, int[]> mapping;
+
+    private TreeMap<Integer, String> resNumMap;
+
+    private List<Integer> omitNonObserved;
+
+    private int nonObservedShiftIndex;
+
+    public SegmentHelperPojo(SequenceI seq,
+            HashMap<Integer, int[]> mapping,
+            TreeMap<Integer, String> resNumMap,
+            List<Integer> omitNonObserved, int nonObservedShiftIndex)
+    {
+      setSeq(seq);
+      setMapping(mapping);
+      setResNumMap(resNumMap);
+      setOmitNonObserved(omitNonObserved);
+      setNonObservedShiftIndex(nonObservedShiftIndex);
+    }
+
+    public SequenceI getSeq()
+    {
+      return seq;
+    }
+
+    public void setSeq(SequenceI seq)
+    {
+      this.seq = seq;
+    }
+
+    public HashMap<Integer, int[]> getMapping()
+    {
+      return mapping;
+    }
+
+    public void setMapping(HashMap<Integer, int[]> mapping)
     {
-      availDbs.add(db.getDbSource());
-      System.out.println(db.getDbSource() + " | " + db.getDbCoordSys());
+      this.mapping = mapping;
+    }
+
+    public TreeMap<Integer, String> getResNumMap()
+    {
+      return resNumMap;
+    }
+
+    public void setResNumMap(TreeMap<Integer, String> resNumMap)
+    {
+      this.resNumMap = resNumMap;
+    }
+
+    public List<Integer> getOmitNonObserved()
+    {
+      return omitNonObserved;
+    }
+
+    public void setOmitNonObserved(List<Integer> omitNonObserved)
+    {
+      this.omitNonObserved = omitNonObserved;
+    }
+
+    public int getNonObservedShiftIndex()
+    {
+      return nonObservedShiftIndex;
+    }
+
+    public void setNonObservedShiftIndex(int nonObservedShiftIndex)
+    {
+      this.nonObservedShiftIndex = nonObservedShiftIndex;
     }
-    return availDbs.toArray(new String[0]);
   }
 
   @Override
@@ -1031,7 +1051,6 @@ public class SiftsClient implements SiftsClientI
     output.append("Length of alignment = " + seqRes.length()).append(
             NEWLINE);
     output.append(new Format("Percentage ID = %2.2f").form(pid));
-    output.append(NEWLINE);
     return output;
   }
 
@@ -1054,12 +1073,6 @@ public class SiftsClient implements SiftsClientI
   }
 
   @Override
-  public String getDbEvidence()
-  {
-    return siftsEntry.getDbEvidence();
-  }
-
-  @Override
   public String getDbSource()
   {
     return siftsEntry.getDbSource();
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;
diff --git a/src/jalview/ws/uimodel/PDBRestResponse.java b/src/jalview/ws/uimodel/PDBRestResponse.java
deleted file mode 100644 (file)
index 3dc3563..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 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.uimodel;
-
-import jalview.datamodel.SequenceI;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
-import jalview.ws.dbsources.PDBRestClient.PDBDocField.Group;
-
-import java.util.Collection;
-import java.util.Objects;
-
-import javax.swing.JTable;
-import javax.swing.table.DefaultTableModel;
-
-import org.json.simple.JSONObject;
-
-/**
- * Represents the response model produced by the PDBRestClient upon successful
- * execution of a given request
- * 
- * @author tcnofoegbu
- *
- */
-public class PDBRestResponse
-{
-  private int numberOfItemsFound;
-
-  private String responseTime;
-
-  private Collection<PDBResponseSummary> searchSummary;
-
-  public int getNumberOfItemsFound()
-  {
-    return numberOfItemsFound;
-  }
-
-  public void setNumberOfItemsFound(int itemFound)
-  {
-    this.numberOfItemsFound = itemFound;
-  }
-
-  public String getResponseTime()
-  {
-    return responseTime;
-  }
-
-  public void setResponseTime(String responseTime)
-  {
-    this.responseTime = responseTime;
-  }
-
-  public Collection<PDBResponseSummary> getSearchSummary()
-  {
-    return searchSummary;
-  }
-
-  public void setSearchSummary(Collection<PDBResponseSummary> searchSummary)
-  {
-    this.searchSummary = searchSummary;
-  }
-
-  /**
-   * Convenience method to obtain a Table model for a given summary List based
-   * on the request parameters
-   * 
-   * @param request
-   *          the PDBRestRequest object which holds useful information for
-   *          creating a table model
-   * @param summariesList
-   *          the summary list which contains the data for populating the
-   *          table's rows
-   * @return the table model which was dynamically generated
-   */
-  public static DefaultTableModel getTableModel(PDBRestRequest request,
-          Collection<PDBResponseSummary> summariesList)
-  {
-    final PDBDocField[] cols = request.getWantedFields().toArray(
-            new PDBDocField[0]);
-    final int colOffset = request.getAssociatedSequence() == null ? 0 : 1;
-    DefaultTableModel tableModel = new DefaultTableModel()
-    {
-      @Override
-      public boolean isCellEditable(int row, int column)
-      {
-        return false;
-      }
-
-      @Override
-      public Class<?> getColumnClass(int columnIndex)
-      {
-        if (colOffset == 1 && columnIndex == 0)
-        {
-          return String.class;
-        }
-        if (cols[columnIndex - colOffset].getGroup().getName()
-                .equalsIgnoreCase(Group.QUALITY_MEASURES.getName()))
-        {
-          return Double.class;
-        }
-        return String.class;
-      }
-
-    };
-    if (request.getAssociatedSequence() != null)
-    {
-      tableModel.addColumn("Ref Sequence"); // Create sequence column header if
-      // exists in the request
-    }
-    for (PDBDocField field : request.getWantedFields())
-    {
-      tableModel.addColumn(field.getName()); // Create sequence column header if
-                                             // exists in the request
-    }
-
-    for (PDBResponseSummary res : summariesList)
-    {
-      tableModel.addRow(res.getSummaryData()); // Populate table rows with
-                                               // summary list
-    }
-
-    return tableModel;
-  }
-
-  /**
-   * Model for a unique response summary
-   * 
-   */
-  public class PDBResponseSummary
-  {
-    private String pdbId;
-
-    private Object[] summaryRowData;
-
-    private SequenceI associatedSequence;
-
-    public PDBResponseSummary(JSONObject pdbJsonDoc, PDBRestRequest request)
-    {
-      Collection<PDBDocField> diplayFields = request.getWantedFields();
-      SequenceI associatedSeq = request.getAssociatedSequence();
-      int colCounter = 0;
-      summaryRowData = new Object[(associatedSeq != null) ? diplayFields
-              .size() + 1 : diplayFields.size()];
-      if (associatedSeq != null)
-      {
-        this.associatedSequence = associatedSeq;
-        summaryRowData[0] = associatedSequence;
-        colCounter = 1;
-      }
-
-      for (PDBDocField field : diplayFields)
-      {
-        String fieldData = (pdbJsonDoc.get(field.getCode()) == null) ? ""
-                : pdbJsonDoc.get(field.getCode()).toString();
-        if (field.equals(PDBDocField.PDB_ID))
-        {
-          this.pdbId = fieldData;
-          summaryRowData[colCounter++] = this.pdbId;
-        }
-        else
-        {
-          if (field.getGroup().getName()
-                  .equals(Group.QUALITY_MEASURES.getName()))
-          {
-            try
-            {
-              if (fieldData == null || fieldData.isEmpty())
-              {
-                summaryRowData[colCounter++] = null;
-              }
-              else
-              {
-              Double value = Double.valueOf(fieldData);
-              summaryRowData[colCounter++] = value;
-              }
-            } catch (Exception e)
-            {
-              e.printStackTrace();
-              System.out.println("offending value:" + fieldData);
-              summaryRowData[colCounter++] = 0.0;
-            }
-          }else{
-            summaryRowData[colCounter++] = (fieldData == null || fieldData
-                    .isEmpty()) ? null : fieldData;
-          }
-        }
-      }
-    }
-
-    public Object getPdbId()
-    {
-      return pdbId;
-    }
-
-    public void setPdbId(String pdbId)
-    {
-      this.pdbId = pdbId;
-    }
-
-    public Object[] getSummaryData()
-    {
-      return summaryRowData;
-    }
-
-    public void setSummaryData(Object[] summaryData)
-    {
-      this.summaryRowData = summaryData;
-    }
-
-    /**
-     * Returns a string representation of this object;
-     */
-    @Override
-    public String toString()
-    {
-      StringBuilder summaryFieldValues = new StringBuilder();
-      for (Object summaryField : summaryRowData)
-      {
-        summaryFieldValues.append(
-                summaryField == null ? " " : summaryField.toString())
-                .append("\t");
-      }
-      return summaryFieldValues.toString();
-    }
-
-    /**
-     * Returns hash code value for this object
-     */
-    @Override
-    public int hashCode()
-    {
-      return Objects.hash(this.pdbId, this.toString());
-    }
-
-    /**
-     * Indicates whether some object is equal to this one
-     */
-    @Override
-    public boolean equals(Object that)
-    {
-      if (!(that instanceof PDBResponseSummary))
-      {
-        return false;
-      }
-      PDBResponseSummary another = (PDBResponseSummary) that;
-      return this.toString().equals(another.toString());
-    }
-
-  }
-
-  public static void configureTableColumn(JTable tbl_summary,
-          Collection<PDBDocField> wantedFields)
-  {
-    for (PDBDocField wantedField : wantedFields)
-    {
-      try
-      {
-      if (wantedField.equals(PDBDocField.PDB_ID))
-      {
-        tbl_summary.getColumn(wantedField.getName()).setMinWidth(40);
-        tbl_summary.getColumn(wantedField.getName()).setMaxWidth(60);
-        tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(45);
-      }
-      else if (wantedField.equals(PDBDocField.TITLE))
-      {
-        tbl_summary.getColumn(wantedField.getName()).setMinWidth(300);
-        tbl_summary.getColumn(wantedField.getName()).setMaxWidth(1000);
-        tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(400);
-      }
-      else if (wantedField.getGroup() == Group.QUALITY_MEASURES)
-      {
-        tbl_summary.getColumn(wantedField.getName()).setMinWidth(50);
-        tbl_summary.getColumn(wantedField.getName()).setMaxWidth(150);
-        tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(85);
-      }
-      else
-      {
-        tbl_summary.getColumn(wantedField.getName()).setMinWidth(50);
-        tbl_summary.getColumn(wantedField.getName()).setMaxWidth(400);
-        tbl_summary.getColumn(wantedField.getName()).setPreferredWidth(95);
-      }
-      } catch (Exception e)
-      {
-        e.printStackTrace();
-      }
-    }
-  }
-}
index 33d332a..21a79fe 100644 (file)
@@ -42,7 +42,7 @@ public class AtomTest
     assertEquals("GLN", a.resName);
     assertEquals("A", a.chain);
     assertEquals(48, a.resNumber);
-    assertEquals("  48 ", a.resNumIns);
+    assertEquals("48", a.resNumIns);
     assertEquals(' ', a.insCode);
     assertEquals(22.290, a.x, 0.00001);
     assertEquals(8.595, a.y, 0.00001);
index 9255e5a..0406128 100644 (file)
@@ -32,6 +32,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.TaylorColourScheme;
+import jalview.structure.StructureImportSettings;
 
 import java.awt.Color;
 import java.util.Vector;
@@ -55,6 +56,7 @@ public class PDBChainTest
   public void setUp()
   {
     System.out.println("setup");
+    StructureImportSettings.setShowSeqFeatures(true);
     c = new PDBChain("1GAQ", "A");
   }
 
index a6a1de4..2863643 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.AppletFormatAdapter;
+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,19 @@ public class PDBfileTest
     pf.addAnnotations(al);
     return al.getAlignmentAnnotation();
   }
+
+  // @formatter:on
+
+  @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..0ddbddc 100644 (file)
@@ -23,65 +23,62 @@ 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.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()];
+    Profile[] result = new Profile[seq1.getLength()];
 
     AAFrequency.calculate(seqs, 0, seq1.getLength(), result, 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));
+    Profile col = result[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));
+    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));
+    assertEquals(25f, col.getPercentageIdentity(false));
+    assertEquals(50f, col.getPercentageIdentity(true));
+    assertEquals(1, col.getMaxCount());
+    assertEquals("CG", col.getModalResidue());
 
-    // col 3 is 75% T 25% G
+    // col 3 is all gaps
     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));
+    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[4];
+    assertEquals(75f, col.getPercentageIdentity(false));
+    assertEquals(75f, col.getPercentageIdentity(true));
+    assertEquals(3, col.getMaxCount());
+    assertEquals("T", col.getModalResidue());
   }
 
   @Test(groups = { "Functional" })
@@ -92,33 +89,33 @@ 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()];
+    Profile[] result = new Profile[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]);
+    Profile profile = result[0];
+    assertEquals(4, profile.getCounts().getCount('C'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(4, profile.getNonGapped());
+
+    profile = result[1];
+    assertEquals(3, profile.getCounts().getCount('A'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(3, profile.getNonGapped());
+
+    profile = result[2];
+    assertEquals(1, profile.getCounts().getCount('C'));
+    assertEquals(1, profile.getCounts().getCount('G'));
+    assertEquals(4, profile.getHeight());
+    assertEquals(2, profile.getNonGapped());
+
+    profile = result[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,7 +123,7 @@ 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()];
+    Profile[] result = new Profile[seq1.getLength()];
 
     // ensure class loaded and initialized
     AAFrequency.calculate(seqs, 0, seq1.getLength(), result, true);
@@ -139,14 +136,86 @@ public class AAFrequencyTest
     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 testCompleteConsensus_includeGaps_showLogo()
+  {
+    /*
+     * 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 };
+    Profile[] profiles = new Profile[seq1.getLength()];
+    AAFrequency.calculate(seqs, 0, seq1.getLength(), profiles, true);
+
+    AlignmentAnnotation consensus = new AlignmentAnnotation("Consensus",
+            "PID", new Annotation[seq1.getLength()]);
+    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 testGetPercentageFormat()
+  public void testCompleteConsensus_ignoreGaps_noLogo()
   {
-    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 };
+    Profile[] profiles = new Profile[seq1.getLength()];
+    AAFrequency.calculate(seqs, 0, seq1.getLength(), profiles, true);
+  
+    AlignmentAnnotation consensus = new AlignmentAnnotation("Consensus",
+            "PID", new Annotation[seq1.getLength()]);
+    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 810ef5f..4aed7e7 100644 (file)
@@ -22,10 +22,12 @@ package jalview.analysis;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.analysis.AlignmentUtils.DnaVariant;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -46,7 +48,6 @@ import jalview.util.MappingUtils;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -438,7 +439,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);
@@ -973,119 +975,202 @@ public class AlignmentUtilsTests
   @Test(groups = { "Functional" })
   public void testMakeCdsAlignment()
   {
+    /*
+     * scenario:
+     *     dna1 --> [4, 6] [10,12]        --> pep1 
+     *     dna2 --> [1, 3] [7, 9] [13,15] --> pep2
+     */
     SequenceI dna1 = new Sequence("dna1", "aaaGGGcccTTTaaa");
     SequenceI dna2 = new Sequence("dna2", "GGGcccTTTaaaCCC");
     SequenceI pep1 = new Sequence("pep1", "GF");
     SequenceI pep2 = new Sequence("pep2", "GFP");
+    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "pep1"));
+    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "pep2"));
     dna1.createDatasetSequence();
     dna2.createDatasetSequence();
     pep1.createDatasetSequence();
     pep2.createDatasetSequence();
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds1", 4, 6, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds2", 10, 12, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds3", 1, 3, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds4", 7, 9, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds5", 13, 15, 0f,
-            null));
     AlignmentI dna = new Alignment(new SequenceI[] { dna1, dna2 });
     dna.setDataset(null);
 
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
-    MapList map = new MapList(new int[] { 4, 6, 10, 12 },
-            new int[] { 1, 2 }, 3, 1);
+    /*
+     * 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 from the dna contig sequences
+     */
+    DBRefEntry dbref = new DBRefEntry("ENSEMBL", "0", "dna1");
+    dna1.getDatasetSequence().addDBRef(dbref);
+    org.testng.Assert.assertEquals(dbref, dna1.getPrimaryDBRefs().get(0));
+    dbref = new DBRefEntry("ENSEMBL", "0", "dna2");
+    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 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);
-    mappings.add(acf);
-    map = new MapList(new int[] { 1, 3, 7, 9, 13, 15 }, new int[] { 1, 3 },
-            3, 1);
+    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(),
+            mapfordna1);
+    dna.addCodonFrame(acf);
+    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);
-    mappings.add(acf);
+    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[] {
-        dna1, dna2 }, mappings, dna);
+        dna1, dna2 }, dna.getDataset(), null);
 
+    /*
+     * verify cds sequences
+     */
     assertEquals(2, cds.getSequences().size());
-    assertEquals("GGGTTT", cds.getSequenceAt(0)
-            .getSequenceAsString());
-    assertEquals("GGGTTTCCC", cds.getSequenceAt(1)
-            .getSequenceAsString());
+    assertEquals("GGGTTT", cds.getSequenceAt(0).getSequenceAsString());
+    assertEquals("GGGTTTCCC", cds.getSequenceAt(1).getSequenceAsString());
 
     /*
      * verify shared, extended alignment dataset
      */
     assertSame(dna.getDataset(), cds.getDataset());
-    assertTrue(dna.getDataset().getSequences()
-            .contains(cds.getSequenceAt(0).getDatasetSequence()));
-    assertTrue(dna.getDataset().getSequences()
-            .contains(cds.getSequenceAt(1).getDatasetSequence()));
+    SequenceI cds1Dss = cds.getSequenceAt(0).getDatasetSequence();
+    SequenceI cds2Dss = cds.getSequenceAt(1).getDatasetSequence();
+    assertTrue(dna.getDataset().getSequences().contains(cds1Dss));
+    assertTrue(dna.getDataset().getSequences().contains(cds2Dss));
+
+    /*
+     * verify CDS has a dbref with mapping to peptide
+     */
+    assertNotNull(cds1Dss.getDBRefs());
+    assertEquals(2, cds1Dss.getDBRefs().length);
+    dbref = cds1Dss.getDBRefs()[0];
+    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 },
+            new int[] { 1, 2 }, 3, 1);
+    assertEquals(cdsMapping, dbref.getMap().getMap());
+
+    /*
+     * 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());
+    assertEquals("0", dbref.getVersion());
+    assertEquals("CDS|dna1", dbref.getAccessionId());
+    assertNotNull(dbref.getMap());
+    assertSame(cds1Dss, dbref.getMap().getTo());
+    assertEquals(cdsMapping.getInverse(), dbref.getMap().getMap());
 
     /*
-     * Verify mappings from CDS to peptide and cDNA to CDS
+     * Verify mappings from CDS to peptide, cDNA to CDS, and cDNA to peptide
      * the mappings are on the shared alignment dataset
+     * 6 mappings, 2*(DNA->CDS), 2*(DNA->Pep), 2*(CDS->Pep) 
+     */
+    List<AlignedCodonFrame> cdsMappings = cds.getDataset().getCodonFrames();
+    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]  
      */
-    assertSame(dna.getCodonFrames(), cds.getCodonFrames());
-    List<AlignedCodonFrame> cdsMappings = cds.getCodonFrames();
-    assertEquals(2, cdsMappings.size());
-    
+    // select -> subselect type to test.
+    // Assert.assertNotSame(dna.getCodonFrames(), cds.getCodonFrames());
+    // assertEquals(4, dna.getCodonFrames().size());
+    // assertEquals(4, cds.getCodonFrames().size());
+
     /*
+     * Two mappings involve pep1 (dna to pep1, cds to pep1)
      * Mapping from pep1 to GGGTTT in first new exon sequence
      */
-    List<AlignedCodonFrame> pep1Mapping = MappingUtils
+    List<AlignedCodonFrame> pep1Mappings = MappingUtils
             .findMappingsForSequence(pep1, cdsMappings);
-    assertEquals(1, pep1Mapping.size());
+    assertEquals(2, pep1Mappings.size());
+    List<AlignedCodonFrame> mappings = MappingUtils
+            .findMappingsForSequence(cds.getSequenceAt(0), pep1Mappings);
+    assertEquals(1, mappings.size());
+
     // map G to GGG
-    SearchResults sr = MappingUtils
-            .buildSearchResults(pep1, 1, cdsMappings);
+    SearchResults sr = MappingUtils.buildSearchResults(pep1, 1, mappings);
     assertEquals(1, sr.getResults().size());
     Match m = sr.getResults().get(0);
-    assertSame(cds.getSequenceAt(0).getDatasetSequence(),
-            m.getSequence());
+    assertSame(cds1Dss, m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
     // map F to TTT
-    sr = MappingUtils.buildSearchResults(pep1, 2, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep1, 2, mappings);
     m = sr.getResults().get(0);
-    assertSame(cds.getSequenceAt(0).getDatasetSequence(),
-            m.getSequence());
+    assertSame(cds1Dss, m.getSequence());
     assertEquals(4, m.getStart());
     assertEquals(6, m.getEnd());
 
     /*
-     * Mapping from pep2 to GGGTTTCCC in second new exon sequence
+     * Two mappings involve pep2 (dna to pep2, cds to pep2)
+     * Verify mapping from pep2 to GGGTTTCCC in second new exon sequence
      */
-    List<AlignedCodonFrame> pep2Mapping = MappingUtils
+    List<AlignedCodonFrame> pep2Mappings = MappingUtils
             .findMappingsForSequence(pep2, cdsMappings);
-    assertEquals(1, pep2Mapping.size());
+    assertEquals(2, pep2Mappings.size());
+    mappings = MappingUtils.findMappingsForSequence(cds.getSequenceAt(1),
+            pep2Mappings);
+    assertEquals(1, mappings.size());
     // map G to GGG
-    sr = MappingUtils.buildSearchResults(pep2, 1, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep2, 1, mappings);
     assertEquals(1, sr.getResults().size());
     m = sr.getResults().get(0);
-    assertSame(cds.getSequenceAt(1).getDatasetSequence(),
-            m.getSequence());
+    assertSame(cds2Dss, m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
     // map F to TTT
-    sr = MappingUtils.buildSearchResults(pep2, 2, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep2, 2, mappings);
     m = sr.getResults().get(0);
-    assertSame(cds.getSequenceAt(1).getDatasetSequence(),
-            m.getSequence());
+    assertSame(cds2Dss, m.getSequence());
     assertEquals(4, m.getStart());
     assertEquals(6, m.getEnd());
     // map P to CCC
-    sr = MappingUtils.buildSearchResults(pep2, 3, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep2, 3, mappings);
     m = sr.getResults().get(0);
-    assertSame(cds.getSequenceAt(1).getDatasetSequence(),
-            m.getSequence());
+    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);
   }
 
   /**
@@ -1104,18 +1189,6 @@ public class AlignmentUtilsTests
     pep1.createDatasetSequence();
     pep2.createDatasetSequence();
     pep3.createDatasetSequence();
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds1", 4, 6, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds2", 10, 12, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds3", 1, 3, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds4", 7, 9, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds5", 1, 3, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds6", 10, 12, 0f,
-            null));
     pep1.getDatasetSequence().addDBRef(
             new DBRefEntry("EMBLCDS", "2", "A12345"));
     pep2.getDatasetSequence().addDBRef(
@@ -1124,40 +1197,38 @@ public class AlignmentUtilsTests
             new DBRefEntry("EMBLCDS", "4", "A12347"));
 
     /*
+     * Create the CDS alignment
+     */
+    AlignmentI dna = new Alignment(new SequenceI[] { dna1 });
+    dna.setDataset(null);
+
+    /*
      * Make the mappings from dna to protein
      */
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
     // map ...GGG...TTT to GF
     MapList map = 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);
-    mappings.add(acf);
+    dna.addCodonFrame(acf);
 
     // map aaa...ccc to KP
     map = new MapList(new int[] { 1, 3, 7, 9 }, new int[] { 1, 2 }, 3, 1);
     acf = new AlignedCodonFrame();
     acf.addMap(dna1.getDatasetSequence(), pep2.getDatasetSequence(), map);
-    mappings.add(acf);
+    dna.addCodonFrame(acf);
 
     // map aaa......TTT to KF
     map = new MapList(new int[] { 1, 3, 10, 12 }, new int[] { 1, 2 }, 3, 1);
     acf = new AlignedCodonFrame();
     acf.addMap(dna1.getDatasetSequence(), pep3.getDatasetSequence(), map);
-    mappings.add(acf);
-
-    /*
-     * Create the CDS alignment; also augments the dna-to-protein mappings with
-     * exon-to-protein and exon-to-dna mappings
-     */
-    AlignmentI dna = new Alignment(new SequenceI[] { dna1 });
-    dna.setDataset(null);
+    dna.addCodonFrame(acf);
 
     /*
      * execute method under test
      */
     AlignmentI cdsal = AlignmentUtils.makeCdsAlignment(
-            new SequenceI[] { dna1 }, mappings, dna);
+            new SequenceI[] { dna1 }, dna.getDataset(), null);
 
     /*
      * Verify we have 3 cds sequences, mapped to pep1/2/3 respectively
@@ -1182,7 +1253,7 @@ public class AlignmentUtilsTests
     SequenceI cdsSeq = cds.get(0);
     assertEquals("GGGTTT", cdsSeq.getSequenceAsString());
     // assertEquals("dna1|A12345", cdsSeq.getName());
-    assertEquals("dna1|pep1", cdsSeq.getName());
+    assertEquals("CDS|dna1", cdsSeq.getName());
     // assertEquals(1, cdsSeq.getDBRefs().length);
     // DBRefEntry cdsRef = cdsSeq.getDBRefs()[0];
     // assertEquals("EMBLCDS", cdsRef.getSource());
@@ -1192,7 +1263,7 @@ public class AlignmentUtilsTests
     cdsSeq = cds.get(1);
     assertEquals("aaaccc", cdsSeq.getSequenceAsString());
     // assertEquals("dna1|A12346", cdsSeq.getName());
-    assertEquals("dna1|pep2", cdsSeq.getName());
+    assertEquals("CDS|dna1", cdsSeq.getName());
     // assertEquals(1, cdsSeq.getDBRefs().length);
     // cdsRef = cdsSeq.getDBRefs()[0];
     // assertEquals("EMBLCDS", cdsRef.getSource());
@@ -1202,7 +1273,7 @@ public class AlignmentUtilsTests
     cdsSeq = cds.get(2);
     assertEquals("aaaTTT", cdsSeq.getSequenceAsString());
     // assertEquals("dna1|A12347", cdsSeq.getName());
-    assertEquals("dna1|pep3", cdsSeq.getName());
+    assertEquals("CDS|dna1", cdsSeq.getName());
     // assertEquals(1, cdsSeq.getDBRefs().length);
     // cdsRef = cdsSeq.getDBRefs()[0];
     // assertEquals("EMBLCDS", cdsRef.getSource());
@@ -1213,41 +1284,73 @@ public class AlignmentUtilsTests
      * Verify there are mappings from each cds sequence to its protein product
      * and also to its dna source
      */
-    Iterator<AlignedCodonFrame> newMappingsIterator = cdsal
-            .getCodonFrames().iterator();
-
-    // mappings for dna1 - exon1 - pep1
-    AlignedCodonFrame cdsMapping = newMappingsIterator.next();
-    List<Mapping> dnaMappings = cdsMapping.getMappingsFromSequence(dna1);
-    assertEquals(3, dnaMappings.size());
-    assertSame(cds.get(0).getDatasetSequence(), dnaMappings.get(0)
-            .getTo());
-    assertEquals("G(1) in CDS should map to G(4) in DNA", 4, dnaMappings
-            .get(0).getMap().getToPosition(1));
-    List<Mapping> peptideMappings = cdsMapping.getMappingsFromSequence(cds
-            .get(0).getDatasetSequence());
-    assertEquals(1, peptideMappings.size());
-    assertSame(pep1.getDatasetSequence(), peptideMappings.get(0).getTo());
-
-    // mappings for dna1 - cds2 - pep2
-    assertSame(cds.get(1).getDatasetSequence(), dnaMappings.get(1)
-            .getTo());
-    assertEquals("c(4) in CDS should map to c(7) in DNA", 7, dnaMappings
-            .get(1).getMap().getToPosition(4));
-    peptideMappings = cdsMapping.getMappingsFromSequence(cds.get(1)
-            .getDatasetSequence());
-    assertEquals(1, peptideMappings.size());
-    assertSame(pep2.getDatasetSequence(), peptideMappings.get(0).getTo());
-
-    // mappings for dna1 - cds3 - pep3
-    assertSame(cds.get(2).getDatasetSequence(), dnaMappings.get(2)
-            .getTo());
-    assertEquals("T(4) in CDS should map to T(10) in DNA", 10, dnaMappings
-            .get(2).getMap().getToPosition(4));
-    peptideMappings = cdsMapping.getMappingsFromSequence(cds.get(2)
-            .getDatasetSequence());
-    assertEquals(1, peptideMappings.size());
-    assertSame(pep3.getDatasetSequence(), peptideMappings.get(0).getTo());
+    List<AlignedCodonFrame> newMappings = cdsal.getCodonFrames();
+
+    /*
+     * 6 mappings involve dna1 (to pep1/2/3, cds1/2/3) 
+     */
+    List<AlignedCodonFrame> dnaMappings = MappingUtils
+            .findMappingsForSequence(dna1, newMappings);
+    assertEquals(6, dnaMappings.size());
+
+    /*
+     * dna1 to pep1
+     */
+    List<AlignedCodonFrame> mappings = MappingUtils
+            .findMappingsForSequence(pep1, dnaMappings);
+    assertEquals(1, mappings.size());
+    assertEquals(1, mappings.get(0).getMappings().size());
+    assertSame(pep1.getDatasetSequence(), mappings.get(0).getMappings()
+            .get(0).getMapping().getTo());
+
+    /*
+     * dna1 to cds1
+     */
+    List<AlignedCodonFrame> dnaToCds1Mappings = MappingUtils
+            .findMappingsForSequence(cds.get(0), dnaMappings);
+    Mapping mapping = dnaToCds1Mappings.get(0).getMappings().get(0)
+            .getMapping();
+    assertSame(cds.get(0).getDatasetSequence(), mapping.getTo());
+    assertEquals("G(1) in CDS should map to G(4) in DNA", 4, mapping
+            .getMap().getToPosition(1));
+
+    /*
+     * dna1 to pep2
+     */
+    mappings = MappingUtils.findMappingsForSequence(pep2, dnaMappings);
+    assertEquals(1, mappings.size());
+    assertEquals(1, mappings.get(0).getMappings().size());
+    assertSame(pep2.getDatasetSequence(), mappings.get(0).getMappings()
+            .get(0).getMapping().getTo());
+
+    /*
+     * dna1 to cds2
+     */
+    List<AlignedCodonFrame> dnaToCds2Mappings = MappingUtils
+            .findMappingsForSequence(cds.get(1), dnaMappings);
+    mapping = dnaToCds2Mappings.get(0).getMappings().get(0).getMapping();
+    assertSame(cds.get(1).getDatasetSequence(), mapping.getTo());
+    assertEquals("c(4) in CDS should map to c(7) in DNA", 7, mapping
+            .getMap().getToPosition(4));
+
+    /*
+     * dna1 to pep3
+     */
+    mappings = MappingUtils.findMappingsForSequence(pep3, dnaMappings);
+    assertEquals(1, mappings.size());
+    assertEquals(1, mappings.get(0).getMappings().size());
+    assertSame(pep3.getDatasetSequence(), mappings.get(0).getMappings()
+            .get(0).getMapping().getTo());
+
+    /*
+     * dna1 to cds3
+     */
+    List<AlignedCodonFrame> dnaToCds3Mappings = MappingUtils
+            .findMappingsForSequence(cds.get(2), dnaMappings);
+    mapping = dnaToCds3Mappings.get(0).getMappings().get(0).getMapping();
+    assertSame(cds.get(2).getDatasetSequence(), mapping.getTo());
+    assertEquals("T(4) in CDS should map to T(10) in DNA", 10, mapping
+            .getMap().getToPosition(4));
   }
 
   @Test(groups = { "Functional" })
@@ -1275,8 +1378,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();
@@ -1297,7 +1399,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");
@@ -1308,7 +1410,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());
@@ -1323,7 +1425,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---");
   }
@@ -1422,7 +1524,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));
@@ -1432,12 +1534,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());
@@ -1452,10 +1554,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));
@@ -1465,12 +1567,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());
@@ -1496,41 +1598,28 @@ public class AlignmentUtilsTests
     dna3.createDatasetSequence();
     pep1.createDatasetSequence();
     pep2.createDatasetSequence();
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds1", 4, 8, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds2", 9, 12, 0f,
-            null));
-    dna1.addSequenceFeature(new SequenceFeature("CDS", "cds3", 16, 18, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds", 4, 8, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds", 12, 12, 0f,
-            null));
-    dna2.addSequenceFeature(new SequenceFeature("CDS", "cds", 16, 18, 0f,
-            null));
-  
-    List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
+
+    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);
-    mappings.add(acf);
+    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);
-    mappings.add(acf);
-  
-    AlignmentI dna = new Alignment(new SequenceI[] { dna1, dna2, dna3 });
-    dna.setDataset(null);
+    dna.addCodonFrame(acf);
+
     AlignmentI cds = AlignmentUtils.makeCdsAlignment(new SequenceI[] {
-        dna1, dna2, dna3 }, mappings, dna);
+        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
      */
@@ -1541,59 +1630,67 @@ public class AlignmentUtilsTests
             .contains(cdsSeqs.get(1).getDatasetSequence()));
 
     /*
-     * Verify updated mappings
+     * Verify 6 mappings: dna1 to cds1, cds1 to pep1, dna1 to pep1
+     * and the same for dna2/cds2/pep2
      */
-    List<AlignedCodonFrame> cdsMappings = cds.getCodonFrames();
-    assertEquals(2, cdsMappings.size());
-  
+    List<AlignedCodonFrame> mappings = cds.getCodonFrames();
+    assertEquals(6, mappings.size());
+
     /*
-     * Mapping from pep1 to GGGTTT in first new CDS sequence
+     * 2 mappings involve pep1
      */
-    List<AlignedCodonFrame> pep1Mapping = MappingUtils
-            .findMappingsForSequence(pep1, cdsMappings);
-    assertEquals(1, pep1Mapping.size());
+    List<AlignedCodonFrame> pep1Mappings = MappingUtils
+            .findMappingsForSequence(pep1, mappings);
+    assertEquals(2, pep1Mappings.size());
+
     /*
+     * Get mapping of pep1 to cds1 and verify it
      * maps GPFG to 1-3,4-6,7-9,10-12
      */
-    SearchResults sr = MappingUtils
-            .buildSearchResults(pep1, 1, cdsMappings);
+    List<AlignedCodonFrame> pep1CdsMappings = MappingUtils
+            .findMappingsForSequence(cds.getSequenceAt(0), pep1Mappings);
+    assertEquals(1, pep1CdsMappings.size());
+    SearchResults sr = MappingUtils.buildSearchResults(pep1, 1,
+            pep1CdsMappings);
     assertEquals(1, sr.getResults().size());
     Match m = sr.getResults().get(0);
-    assertEquals(cds.getSequenceAt(0).getDatasetSequence(),
-            m.getSequence());
+    assertEquals(cds.getSequenceAt(0).getDatasetSequence(), m.getSequence());
     assertEquals(1, m.getStart());
     assertEquals(3, m.getEnd());
-    sr = MappingUtils.buildSearchResults(pep1, 2, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep1, 2, pep1CdsMappings);
     m = sr.getResults().get(0);
     assertEquals(4, m.getStart());
     assertEquals(6, m.getEnd());
-    sr = MappingUtils.buildSearchResults(pep1, 3, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep1, 3, pep1CdsMappings);
     m = sr.getResults().get(0);
     assertEquals(7, m.getStart());
     assertEquals(9, m.getEnd());
-    sr = MappingUtils.buildSearchResults(pep1, 4, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep1, 4, pep1CdsMappings);
     m = sr.getResults().get(0);
     assertEquals(10, m.getStart());
     assertEquals(12, m.getEnd());
-  
+
     /*
-     * GPG in pep2 map to 1-3,4-6,7-9 in second CDS sequence
+     * Get mapping of pep2 to cds2 and verify it
+     * maps GPG in pep2 to 1-3,4-6,7-9 in second CDS sequence
      */
-    List<AlignedCodonFrame> pep2Mapping = MappingUtils
-            .findMappingsForSequence(pep2, cdsMappings);
-    assertEquals(1, pep2Mapping.size());
-    sr = MappingUtils.buildSearchResults(pep2, 1, cdsMappings);
+    List<AlignedCodonFrame> pep2Mappings = MappingUtils
+            .findMappingsForSequence(pep2, mappings);
+    assertEquals(2, pep2Mappings.size());
+    List<AlignedCodonFrame> pep2CdsMappings = MappingUtils
+            .findMappingsForSequence(cds.getSequenceAt(1), pep2Mappings);
+    assertEquals(1, pep2CdsMappings.size());
+    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, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep2, 2, pep2CdsMappings);
     m = sr.getResults().get(0);
     assertEquals(4, m.getStart());
     assertEquals(6, m.getEnd());
-    sr = MappingUtils.buildSearchResults(pep2, 3, cdsMappings);
+    sr = MappingUtils.buildSearchResults(pep2, 3, pep2CdsMappings);
     m = sr.getResults().get(0);
     assertEquals(7, m.getStart());
     assertEquals(9, m.getEnd());
@@ -1613,7 +1710,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");
@@ -1621,7 +1718,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();
@@ -1660,7 +1757,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
@@ -1668,9 +1765,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
      */
@@ -1692,7 +1789,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);
@@ -1705,7 +1802,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] }
@@ -1733,56 +1830,62 @@ public class AlignmentUtilsTests
     /*
      * first with no variants on dna
      */
-    LinkedHashMap<Integer, List<String[][]>> variantsMap = AlignmentUtils
+    LinkedHashMap<Integer, List<DnaVariant>[]> variantsMap = AlignmentUtils
             .buildDnaVariantsMap(dna, map);
     assertTrue(variantsMap.isEmpty());
 
     /*
      * single allele codon 1, on base 1
      */
-    SequenceFeature sf = new SequenceFeature("sequence_variant", "", 1, 1,
+    SequenceFeature sf1 = new SequenceFeature("sequence_variant", "", 1, 1,
             0f, null);
-    sf.setValue("alleles", "T");
-    sf.setValue("ID", "sequence_variant:rs758803211");
-    dna.addSequenceFeature(sf);
+    sf1.setValue("alleles", "T");
+    sf1.setValue("ID", "sequence_variant:rs758803211");
+    dna.addSequenceFeature(sf1);
 
     /*
      * two alleles codon 2, on bases 2 and 3 (distinct variants)
      */
-    sf = new SequenceFeature("sequence_variant", "", 5, 5, 0f, null);
-    sf.setValue("alleles", "T");
-    sf.setValue("ID", "sequence_variant:rs758803212");
-    dna.addSequenceFeature(sf);
-    sf = new SequenceFeature("sequence_variant", "", 6, 6, 0f, null);
-    sf.setValue("alleles", "G");
-    sf.setValue("ID", "sequence_variant:rs758803213");
-    dna.addSequenceFeature(sf);
+    SequenceFeature sf2 = new SequenceFeature("sequence_variant", "", 5, 5,
+            0f, null);
+    sf2.setValue("alleles", "T");
+    sf2.setValue("ID", "sequence_variant:rs758803212");
+    dna.addSequenceFeature(sf2);
+    SequenceFeature sf3 = new SequenceFeature("sequence_variant", "", 6, 6,
+            0f, null);
+    sf3.setValue("alleles", "G");
+    sf3.setValue("ID", "sequence_variant:rs758803213");
+    dna.addSequenceFeature(sf3);
 
     /*
      * two alleles codon 3, both on base 2 (one variant)
      */
-    sf = new SequenceFeature("sequence_variant", "", 8, 8, 0f, null);
-    sf.setValue("alleles", "C, G");
-    sf.setValue("ID", "sequence_variant:rs758803214");
-    dna.addSequenceFeature(sf);
+    SequenceFeature sf4 = new SequenceFeature("sequence_variant", "", 8, 8,
+            0f, null);
+    sf4.setValue("alleles", "C, G");
+    sf4.setValue("ID", "sequence_variant:rs758803214");
+    dna.addSequenceFeature(sf4);
 
     // no alleles on codon 4
 
     /*
      * alleles on codon 5 on all 3 bases (distinct variants)
      */
-    sf = new SequenceFeature("sequence_variant", "", 13, 13, 0f, null);
-    sf.setValue("alleles", "C, G"); // (C duplicates given base value)
-    sf.setValue("ID", "sequence_variant:rs758803215");
-    dna.addSequenceFeature(sf);
-    sf = new SequenceFeature("sequence_variant", "", 14, 14, 0f, null);
-    sf.setValue("alleles", "g, a"); // should force to upper-case
-    sf.setValue("ID", "sequence_variant:rs758803216");
-    dna.addSequenceFeature(sf);
-    sf = new SequenceFeature("sequence_variant", "", 15, 15, 0f, null);
-    sf.setValue("alleles", "A, T");
-    sf.setValue("ID", "sequence_variant:rs758803217");
-    dna.addSequenceFeature(sf);
+    SequenceFeature sf5 = new SequenceFeature("sequence_variant", "", 13,
+            13, 0f, null);
+    sf5.setValue("alleles", "C, G"); // (C duplicates given base value)
+    sf5.setValue("ID", "sequence_variant:rs758803215");
+    dna.addSequenceFeature(sf5);
+    SequenceFeature sf6 = new SequenceFeature("sequence_variant", "", 14,
+            14, 0f, null);
+    sf6.setValue("alleles", "g, a"); // should force to upper-case
+    sf6.setValue("ID", "sequence_variant:rs758803216");
+    dna.addSequenceFeature(sf6);
+    SequenceFeature sf7 = new SequenceFeature("sequence_variant", "", 15,
+            15, 0f, null);
+    sf7.setValue("alleles", "A, T");
+    sf7.setValue("ID", "sequence_variant:rs758803217");
+    dna.addSequenceFeature(sf7);
 
     /*
      * build map - expect variants on positions 1, 2, 3, 5
@@ -1791,39 +1894,68 @@ public class AlignmentUtilsTests
     assertEquals(4, variantsMap.size());
 
     /*
-     * one variant on protein position 1
-     */
-    assertEquals(1, variantsMap.get(1).size());
-    assertTrue(Arrays.deepEquals(new String[][] { { "A", "T" }, { "T" },
-        { "G" } }, variantsMap.get(1).get(0)));
-
-    /*
-     * two variants on protein position 2
-     */
-    assertEquals(2, variantsMap.get(2).size());
-    assertTrue(Arrays.deepEquals(new String[][] { { "A" }, { "A", "T" },
-        { "A" } }, variantsMap.get(2).get(0)));
-    assertTrue(Arrays.deepEquals(new String[][] { { "A" }, { "A" },
-        { "A", "G" } }, variantsMap.get(2).get(1)));
-
-    /*
-     * one variant on protein position 3
-     */
-    assertEquals(1, variantsMap.get(3).size());
-    assertTrue(Arrays.deepEquals(new String[][] { { "T" },
-        { "T", "C", "G" }, { "T" } }, variantsMap.get(3).get(0)));
+     * protein residue 1: variant on codon (ATG) base 1, not on 2 or 3
+     */
+    List<DnaVariant>[] pep1Variants = variantsMap.get(1);
+    assertEquals(3, pep1Variants.length);
+    assertEquals(1, pep1Variants[0].size());
+    assertEquals("A", pep1Variants[0].get(0).base); // codon[1] base
+    assertSame(sf1, pep1Variants[0].get(0).variant); // codon[1] variant
+    assertEquals(1, pep1Variants[1].size());
+    assertEquals("T", pep1Variants[1].get(0).base); // codon[2] base
+    assertNull(pep1Variants[1].get(0).variant); // no variant here
+    assertEquals(1, pep1Variants[2].size());
+    assertEquals("G", pep1Variants[2].get(0).base); // codon[3] base
+    assertNull(pep1Variants[2].get(0).variant); // no variant here
+
+    /*
+     * protein residue 2: variants on codon (AAA) bases 2 and 3
+     */
+    List<DnaVariant>[] pep2Variants = variantsMap.get(2);
+    assertEquals(3, pep2Variants.length);
+    assertEquals(1, pep2Variants[0].size());
+    // codon[1] base recorded while processing variant on codon[2]
+    assertEquals("A", pep2Variants[0].get(0).base);
+    assertNull(pep2Variants[0].get(0).variant); // no variant here
+    // codon[2] base and variant:
+    assertEquals(1, pep2Variants[1].size());
+    assertEquals("A", pep2Variants[1].get(0).base);
+    assertSame(sf2, pep2Variants[1].get(0).variant);
+    // codon[3] base was recorded when processing codon[2] variant
+    // and then the variant for codon[3] added to it
+    assertEquals(1, pep2Variants[2].size());
+    assertEquals("A", pep2Variants[2].get(0).base);
+    assertSame(sf3, pep2Variants[2].get(0).variant);
+
+    /*
+     * protein residue 3: variants on codon (TTT) base 2 only
+     */
+    List<DnaVariant>[] pep3Variants = variantsMap.get(3);
+    assertEquals(3, pep3Variants.length);
+    assertEquals(1, pep3Variants[0].size());
+    assertEquals("T", pep3Variants[0].get(0).base); // codon[1] base
+    assertNull(pep3Variants[0].get(0).variant); // no variant here
+    assertEquals(1, pep3Variants[1].size());
+    assertEquals("T", pep3Variants[1].get(0).base); // codon[2] base
+    assertSame(sf4, pep3Variants[1].get(0).variant); // codon[2] variant
+    assertEquals(1, pep3Variants[2].size());
+    assertEquals("T", pep3Variants[2].get(0).base); // codon[3] base
+    assertNull(pep3Variants[2].get(0).variant); // no variant here
 
     /*
      * three variants on protein position 5
-     * duplicated bases are not removed here, handled in computePeptideVariants
-     */
-    assertEquals(3, variantsMap.get(5).size());
-    assertTrue(Arrays.deepEquals(new String[][] { { "C", "C", "G" },
-        { "C" }, { "C" } }, variantsMap.get(5).get(0)));
-    assertTrue(Arrays.deepEquals(new String[][] { { "C" },
-        { "C", "G", "A" }, { "C" } }, variantsMap.get(5).get(1)));
-    assertTrue(Arrays.deepEquals(new String[][] { { "C" }, { "C" },
-        { "C", "A", "T" } }, variantsMap.get(5).get(2)));
+     */
+    List<DnaVariant>[] pep5Variants = variantsMap.get(5);
+    assertEquals(3, pep5Variants.length);
+    assertEquals(1, pep5Variants[0].size());
+    assertEquals("C", pep5Variants[0].get(0).base); // codon[1] base
+    assertSame(sf5, pep5Variants[0].get(0).variant); // codon[1] variant
+    assertEquals(1, pep5Variants[1].size());
+    assertEquals("C", pep5Variants[1].get(0).base); // codon[2] base
+    assertSame(sf6, pep5Variants[1].get(0).variant); // codon[2] variant
+    assertEquals(1, pep5Variants[2].size());
+    assertEquals("C", pep5Variants[2].get(0).base); // codon[3] base
+    assertSame(sf7, pep5Variants[2].get(0).variant); // codon[3] variant
   }
 
   /**
@@ -1833,67 +1965,174 @@ public class AlignmentUtilsTests
   @Test(groups = "Functional")
   public void testComputePeptideVariants()
   {
-    String[][] codonVariants = new String[][] { { "A" }, { "G" }, { "T" } };
-  
-    /*
-     * AGT codes for S - this is not included in the variants returned
-     */
-    List<String> variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[]", variants.toString());
-  
-    // S is reported if it differs from the current value (A):
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "A");
-    assertEquals("[S]", variants.toString());
-  
-    /*
-     * synonymous variant is not reported
-     */
-    codonVariants = new String[][] { { "A" }, { "G" }, { "C", "T" } };
-    // AGC and AGT both code for S
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "s");
-    assertEquals("[]", variants.toString());
-  
-    /*
-     * equivalent variants are only reported once
-     */
-    codonVariants = new String[][] { { "C" }, { "T" },
-        { "A", "C", "G", "T" } };
-    // CTA CTC CTG CTT all code for L
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[L]", variants.toString());
-  
-    /*
-     * vary codons 1 and 2; variant products are sorted and non-redundant
-     */
-    codonVariants = new String[][] { { "a", "C" }, { "g", "T" }, { "A" } };
-    // aga ata cga cta code for R, I, R, L
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[I, L, R]", variants.toString());
-  
-    /*
-     * vary codons 2 and 3
-     */
-    codonVariants = new String[][] { { "a" }, { "g", "T" }, { "A", "c" } };
-    // aga agc ata atc code for R, S, I, I
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[I, R]", variants.toString());
-  
-    /*
-     * vary codons 1 and 3
-     */
-    codonVariants = new String[][] { { "a", "t" }, { "a" }, { "t", "g" } };
-    // aat aag tat tag code for N, K, Y, STOP - STOP sorted to end
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[K, N, Y, STOP]", variants.toString());
-  
-    /*
-     * vary codons 1, 2 and 3
-     */
-    codonVariants = new String[][] { { "a", "t" }, { "G", "C" },
-        { "t", "g" } };
-    // agt agg act acg tgt tgg tct tcg code for S, R, T, T, C, W, S, S
-    variants = AlignmentUtils.computePeptideVariants(codonVariants, "S");
-    assertEquals("[C, R, T, W]", variants.toString());
+    /*
+     * scenario: AAATTTCCC codes for KFP
+     * variants:
+     *           GAA -> E             source: Ensembl
+     *           CAA -> Q             source: dbSNP
+     *           AAG synonymous       source: COSMIC
+     *           AAT -> N             source: Ensembl
+     *           ...TTC synonymous    source: dbSNP
+     *           ......CAC,CGC -> H,R source: COSMIC
+     *                 (one variant with two alleles)
+     */
+    SequenceI peptide = new Sequence("pep/10-12", "KFP");
+
+    /*
+     * two distinct variants for codon 1 position 1
+     * second one has clinical significance
+     */
+    String ensembl = "Ensembl";
+    String dbSnp = "dbSNP";
+    String cosmic = "COSMIC";
+    SequenceFeature sf1 = new SequenceFeature("sequence_variant", "", 1, 1,
+            0f, ensembl);
+    sf1.setValue("alleles", "A,G"); // GAA -> E
+    sf1.setValue("ID", "var1.125A>G");
+    SequenceFeature sf2 = new SequenceFeature("sequence_variant", "", 1, 1,
+            0f, dbSnp);
+    sf2.setValue("alleles", "A,C"); // CAA -> Q
+    sf2.setValue("ID", "var2");
+    sf2.setValue("clinical_significance", "Dodgy");
+    SequenceFeature sf3 = new SequenceFeature("sequence_variant", "", 3, 3,
+            0f, cosmic);
+    sf3.setValue("alleles", "A,G"); // synonymous
+    sf3.setValue("ID", "var3");
+    sf3.setValue("clinical_significance", "None");
+    SequenceFeature sf4 = new SequenceFeature("sequence_variant", "", 3, 3,
+            0f, ensembl);
+    sf4.setValue("alleles", "A,T"); // AAT -> N
+    sf4.setValue("ID", "sequence_variant:var4"); // prefix gets stripped off
+    sf4.setValue("clinical_significance", "Benign");
+    SequenceFeature sf5 = new SequenceFeature("sequence_variant", "", 6, 6,
+            0f, dbSnp);
+    sf5.setValue("alleles", "T,C"); // synonymous
+    sf5.setValue("ID", "var5");
+    sf5.setValue("clinical_significance", "Bad");
+    SequenceFeature sf6 = new SequenceFeature("sequence_variant", "", 8, 8,
+            0f, cosmic);
+    sf6.setValue("alleles", "C,A,G"); // CAC,CGC -> H,R
+    sf6.setValue("ID", "var6");
+    sf6.setValue("clinical_significance", "Good");
+
+    List<DnaVariant> codon1Variants = new ArrayList<DnaVariant>();
+    List<DnaVariant> codon2Variants = new ArrayList<DnaVariant>();
+    List<DnaVariant> codon3Variants = new ArrayList<DnaVariant>();
+    List<DnaVariant> codonVariants[] = new ArrayList[3];
+    codonVariants[0] = codon1Variants;
+    codonVariants[1] = codon2Variants;
+    codonVariants[2] = codon3Variants;
+
+    /*
+     * compute variants for protein position 1
+     */
+    codon1Variants.add(new DnaVariant("A", sf1));
+    codon1Variants.add(new DnaVariant("A", sf2));
+    codon2Variants.add(new DnaVariant("A"));
+    codon2Variants.add(new DnaVariant("A"));
+    codon3Variants.add(new DnaVariant("A", sf3));
+    codon3Variants.add(new DnaVariant("A", sf4));
+    AlignmentUtils.computePeptideVariants(peptide, 1, codonVariants);
+
+    /*
+     * compute variants for protein position 2
+     */
+    codon1Variants.clear();
+    codon2Variants.clear();
+    codon3Variants.clear();
+    codon1Variants.add(new DnaVariant("T"));
+    codon2Variants.add(new DnaVariant("T"));
+    codon3Variants.add(new DnaVariant("T", sf5));
+    AlignmentUtils.computePeptideVariants(peptide, 2, codonVariants);
+
+    /*
+     * compute variants for protein position 3
+     */
+    codon1Variants.clear();
+    codon2Variants.clear();
+    codon3Variants.clear();
+    codon1Variants.add(new DnaVariant("C"));
+    codon2Variants.add(new DnaVariant("C", sf6));
+    codon3Variants.add(new DnaVariant("C"));
+    AlignmentUtils.computePeptideVariants(peptide, 3, codonVariants);
+
+    /*
+     * verify added sequence features for
+     * var1 K -> E Ensembl
+     * var2 K -> Q dbSNP
+     * var4 K -> N Ensembl
+     * var6 P -> H COSMIC
+     * var6 P -> R COSMIC
+     */
+    SequenceFeature[] sfs = peptide.getSequenceFeatures();
+    assertEquals(5, sfs.length);
+
+    SequenceFeature sf = sfs[0];
+    assertEquals(1, sf.getBegin());
+    assertEquals(1, sf.getEnd());
+    assertEquals("p.Lys1Glu", sf.getDescription());
+    assertEquals("var1.125A>G", sf.getValue("ID"));
+    assertNull(sf.getValue("clinical_significance"));
+    assertEquals("ID=var1.125A>G", sf.getAttributes());
+    assertEquals(1, sf.links.size());
+    // link to variation is urlencoded
+    assertEquals(
+            "p.Lys1Glu var1.125A>G|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var1.125A%3EG",
+            sf.links.get(0));
+    assertEquals(ensembl, sf.getFeatureGroup());
+
+    sf = sfs[1];
+    assertEquals(1, sf.getBegin());
+    assertEquals(1, sf.getEnd());
+    assertEquals("p.Lys1Gln", sf.getDescription());
+    assertEquals("var2", sf.getValue("ID"));
+    assertEquals("Dodgy", sf.getValue("clinical_significance"));
+    assertEquals("ID=var2;clinical_significance=Dodgy", sf.getAttributes());
+    assertEquals(1, sf.links.size());
+    assertEquals(
+            "p.Lys1Gln var2|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var2",
+            sf.links.get(0));
+    assertEquals(dbSnp, sf.getFeatureGroup());
+
+    sf = sfs[2];
+    assertEquals(1, sf.getBegin());
+    assertEquals(1, sf.getEnd());
+    assertEquals("p.Lys1Asn", sf.getDescription());
+    assertEquals("var4", sf.getValue("ID"));
+    assertEquals("Benign", sf.getValue("clinical_significance"));
+    assertEquals("ID=var4;clinical_significance=Benign", sf.getAttributes());
+    assertEquals(1, sf.links.size());
+    assertEquals(
+            "p.Lys1Asn var4|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var4",
+            sf.links.get(0));
+    assertEquals(ensembl, sf.getFeatureGroup());
+
+    // var5 generates two distinct protein variant features
+    sf = sfs[3];
+    assertEquals(3, sf.getBegin());
+    assertEquals(3, sf.getEnd());
+    assertEquals("p.Pro3His", sf.getDescription());
+    assertEquals("var6", sf.getValue("ID"));
+    assertEquals("Good", sf.getValue("clinical_significance"));
+    assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
+    assertEquals(1, sf.links.size());
+    assertEquals(
+            "p.Pro3His var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+            sf.links.get(0));
+    assertEquals(cosmic, sf.getFeatureGroup());
+
+    sf = sfs[4];
+    assertEquals(3, sf.getBegin());
+    assertEquals(3, sf.getEnd());
+    assertEquals("p.Pro3Arg", sf.getDescription());
+    assertEquals("var6", sf.getValue("ID"));
+    assertEquals("Good", sf.getValue("clinical_significance"));
+    assertEquals("ID=var6;clinical_significance=Good", sf.getAttributes());
+    assertEquals(1, sf.links.size());
+    assertEquals(
+            "p.Pro3Arg var6|http://www.ensembl.org/Homo_sapiens/Variation/Summary?v=var6",
+            sf.links.get(0));
+    assertEquals(cosmic, sf.getFeatureGroup());
   }
 
   /**
@@ -1908,7 +2147,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("-");
@@ -1920,7 +2159,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] }
@@ -1946,7 +2185,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("-");
@@ -1956,9 +2195,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]
@@ -2011,8 +2250,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);
 
@@ -2044,11 +2282,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
      */
@@ -2060,4 +2297,219 @@ public class AlignmentUtilsTests
     assertEquals('T', map.get(11).get(seq1).charValue());
     assertEquals('T', map.get(12).get(seq1).charValue());
   }
+
+  /**
+   * Test for the case where the products for which we want CDS are specified.
+   * This is to represent the case where EMBL has CDS mappings to both Uniprot
+   * and EMBLCDSPROTEIN. makeCdsAlignment() should only return the mappings for
+   * the protein sequences specified.
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeCdsAlignment_filterProducts()
+  {
+    SequenceI dna1 = new Sequence("dna1", "aaaGGGcccTTTaaa");
+    SequenceI dna2 = new Sequence("dna2", "GGGcccTTTaaaCCC");
+    SequenceI pep1 = new Sequence("Uniprot|pep1", "GF");
+    SequenceI pep2 = new Sequence("Uniprot|pep2", "GFP");
+    SequenceI pep3 = new Sequence("EMBL|pep3", "GF");
+    SequenceI pep4 = new Sequence("EMBL|pep4", "GFP");
+    dna1.createDatasetSequence();
+    dna2.createDatasetSequence();
+    pep1.createDatasetSequence();
+    pep2.createDatasetSequence();
+    pep3.createDatasetSequence();
+    pep4.createDatasetSequence();
+    AlignmentI dna = new Alignment(new SequenceI[] { dna1, dna2 });
+    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);
+    acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map);
+    acf.addMap(dna1.getDatasetSequence(), pep3.getDatasetSequence(), map);
+    dna.addCodonFrame(acf);
+
+    acf = new AlignedCodonFrame();
+    map = new MapList(new int[] { 1, 3, 7, 9, 13, 15 }, new int[] { 1, 3 },
+            3, 1);
+    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
+     */
+    assertSame(dna.getDataset(), cds.getDataset());
+    assertTrue(dna.getDataset().getSequences()
+            .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
+     */
+    List<AlignedCodonFrame> cdsMappings = cds.getDataset().getCodonFrames();
+    /*
+     * 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]  
+     */
+    // select -> subselect type to test.
+    // 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
+     */
+    List<AlignedCodonFrame> pep3Mappings = MappingUtils
+            .findMappingsForSequence(pep3, cdsMappings);
+    assertEquals(2, pep3Mappings.size());
+    List<AlignedCodonFrame> mappings = MappingUtils
+            .findMappingsForSequence(cds.getSequenceAt(0), pep3Mappings);
+    assertEquals(1, mappings.size());
+
+    // map G to GGG
+    SearchResults sr = MappingUtils.buildSearchResults(pep3, 1, mappings);
+    assertEquals(1, sr.getResults().size());
+    Match m = sr.getResults().get(0);
+    assertSame(cds.getSequenceAt(0).getDatasetSequence(), m.getSequence());
+    assertEquals(1, m.getStart());
+    assertEquals(3, m.getEnd());
+    // map F to TTT
+    sr = MappingUtils.buildSearchResults(pep3, 2, mappings);
+    m = sr.getResults().get(0);
+    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
+     */
+    List<AlignedCodonFrame> pep4Mappings = MappingUtils
+            .findMappingsForSequence(pep4, cdsMappings);
+    assertEquals(2, pep4Mappings.size());
+    mappings = MappingUtils.findMappingsForSequence(cds.getSequenceAt(1),
+            pep4Mappings);
+    assertEquals(1, mappings.size());
+    // map G to GGG
+    sr = MappingUtils.buildSearchResults(pep4, 1, mappings);
+    assertEquals(1, sr.getResults().size());
+    m = sr.getResults().get(0);
+    assertSame(cds.getSequenceAt(1).getDatasetSequence(), m.getSequence());
+    assertEquals(1, m.getStart());
+    assertEquals(3, m.getEnd());
+    // map F to TTT
+    sr = MappingUtils.buildSearchResults(pep4, 2, mappings);
+    m = sr.getResults().get(0);
+    assertSame(cds.getSequenceAt(1).getDatasetSequence(), m.getSequence());
+    assertEquals(4, m.getStart());
+    assertEquals(6, m.getEnd());
+    // map P to CCC
+    sr = MappingUtils.buildSearchResults(pep4, 3, mappings);
+    m = sr.getResults().get(0);
+    assertSame(cds.getSequenceAt(1).getDatasetSequence(), m.getSequence());
+    assertEquals(7, m.getStart());
+    assertEquals(9, m.getEnd());
+  }
+
+  /**
+   * Test the method that just copies aligned sequences, provided all sequences
+   * to be aligned share the aligned sequence's dataset
+   */
+  @Test(groups = "Functional")
+  public void testAlignAsSameSequences()
+  {
+    SequenceI dna1 = new Sequence("dna1", "cccGGGTTTaaa");
+    SequenceI dna2 = new Sequence("dna2", "CCCgggtttAAA");
+    AlignmentI al1 = new Alignment(new SequenceI[] { dna1, dna2 });
+    ((Alignment) al1).createDatasetAlignment();
+
+    SequenceI dna3 = new Sequence(dna1);
+    SequenceI dna4 = new Sequence(dna2);
+    assertSame(dna3.getDatasetSequence(), dna1.getDatasetSequence());
+    assertSame(dna4.getDatasetSequence(), dna2.getDatasetSequence());
+    String seq1 = "-cc-GG-GT-TT--aaa";
+    dna3.setSequence(seq1);
+    String seq2 = "C--C-Cgg--gtt-tAA-A-";
+    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());
+
+    /*
+     * add another sequence to 'aligned' - should still succeed, since
+     * unaligned sequences still share a dataset with aligned sequences
+     */
+    SequenceI dna5 = new Sequence("dna5", "CCCgggtttAAA");
+    dna5.createDatasetSequence();
+    al2.addSequence(dna5);
+    assertTrue(AlignmentUtils.alignAsSameSequences(al1, al2));
+    assertEquals(seq1, al1.getSequenceAt(0).getSequenceAsString());
+    assertEquals(seq2, al1.getSequenceAt(1).getSequenceAsString());
+
+    /*
+     * add another sequence to 'unaligned' - should fail, since now not
+     * all unaligned sequences share a dataset with aligned sequences
+     */
+    SequenceI dna6 = new Sequence("dna6", "CCCgggtttAAA");
+    dna6.createDatasetSequence();
+    al1.addSequence(dna6);
+    // JAL-2110 JBP Comment: what's the use case for this behaviour ?
+    assertFalse(AlignmentUtils.alignAsSameSequences(al1, al2));
+  }
+
+  @Test(groups = "Functional")
+  public void testAlignAsSameSequencesMultipleSubSeq()
+  {
+    SequenceI dna1 = new Sequence("dna1", "cccGGGTTTaaa");
+    SequenceI dna2 = new Sequence("dna2", "CCCgggtttAAA");
+    SequenceI as1 = dna1.deriveSequence();
+    SequenceI as2 = dna1.deriveSequence().getSubSequence(3, 7);
+    SequenceI as3 = dna2.deriveSequence();
+    as1.insertCharAt(6, 5, '-');
+    String s_as1 = as1.getSequenceAsString();
+    as2.insertCharAt(6, 5, '-');
+    String s_as2 = as2.getSequenceAsString();
+    as3.insertCharAt(6, 5, '-');
+    String s_as3 = as3.getSequenceAsString();
+    AlignmentI aligned = new Alignment(new SequenceI[] { as1, as2, as3 });
+
+    // why do we need to cast this still ?
+    ((Alignment) aligned).createDatasetAlignment();
+    SequenceI uas1 = dna1.deriveSequence();
+    SequenceI uas2 = dna1.deriveSequence().getSubSequence(3, 7);
+    SequenceI uas3 = dna2.deriveSequence();
+    AlignmentI tobealigned = new Alignment(new SequenceI[] { uas1, uas2,
+        uas3 });
+    ((Alignment) tobealigned).createDatasetAlignment();
+
+    assertTrue(AlignmentUtils.alignAsSameSequences(tobealigned, aligned));
+    assertEquals(s_as1, uas1.getSequenceAsString());
+    assertEquals(s_as2, uas2.getSequenceAsString());
+    assertEquals(s_as3, uas3.getSequenceAsString());
+  }
+
 }
index bbc23e5..a85dcef 100644 (file)
 package jalview.analysis;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNotSame;
+import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.util.DBRefUtils;
+import jalview.util.MapList;
+import jalview.ws.SequenceFetcher;
+import jalview.ws.SequenceFetcherFactory;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
 public class CrossRefTest
@@ -40,27 +61,678 @@ public class CrossRefTest
     DBRefEntry ref6 = new DBRefEntry("emblCDS", "1", "A123");
     DBRefEntry ref7 = new DBRefEntry("GeneDB", "1", "A123");
     DBRefEntry ref8 = new DBRefEntry("PFAM", "1", "A123");
+    // ENSEMBL is a source of either dna or protein sequence data
+    DBRefEntry ref9 = new DBRefEntry("ENSEMBL", "1", "A123");
     DBRefEntry[] refs = new DBRefEntry[] { ref1, ref2, ref3, ref4, ref5,
-        ref6, ref7, ref8 };
+        ref6, ref7, ref8, ref9 };
 
     /*
      * Just the DNA refs:
      */
-    DBRefEntry[] found = CrossRef.findXDbRefs(false, refs);
-    assertEquals(3, found.length);
+    DBRefEntry[] found = DBRefUtils.selectDbRefs(true, refs);
+    assertEquals(4, found.length);
     assertSame(ref5, found[0]);
     assertSame(ref6, found[1]);
     assertSame(ref7, found[2]);
+    assertSame(ref9, found[3]);
 
     /*
      * Just the protein refs:
      */
-    found = CrossRef.findXDbRefs(true, refs);
+    found = DBRefUtils.selectDbRefs(false, refs);
     assertEquals(4, found.length);
     assertSame(ref1, found[0]);
     assertSame(ref2, found[1]);
-    assertSame(ref3, found[2]);
-    assertSame(ref4, found[3]);
+    assertSame(ref4, found[2]);
+    assertSame(ref9, found[3]);
+  }
+
+  /**
+   * Test the method that finds a sequence's "product" xref source databases,
+   * which may be direct (dbrefs on the sequence), or indirect (dbrefs on
+   * sequences which share a dbref with the sequence
+   */
+  @Test(groups = { "Functional" }, enabled = true)
+  public void testFindXrefSourcesForSequence_proteinToDna()
+  {
+    SequenceI seq = new Sequence("Seq1", "MGKYQARLSS");
+    List<String> sources = new ArrayList<String>();
+    AlignmentI al = new Alignment(new SequenceI[] {});
+
+    /*
+     * first with no dbrefs to search
+     */
+    sources = new CrossRef(new SequenceI[] { seq }, al)
+            .findXrefSourcesForSequences(false);
+    assertTrue(sources.isEmpty());
+
+    /*
+     * add some dbrefs to sequence
+     */
+    // protein db is not a candidate for findXrefSources
+    seq.addDBRef(new DBRefEntry("UNIPROT", "0", "A1234"));
+    // dna coding databatases are
+    seq.addDBRef(new DBRefEntry("EMBL", "0", "E2345"));
+    // a second EMBL xref should not result in a duplicate
+    seq.addDBRef(new DBRefEntry("EMBL", "0", "E2346"));
+    seq.addDBRef(new DBRefEntry("EMBLCDS", "0", "E2347"));
+    seq.addDBRef(new DBRefEntry("GENEDB", "0", "E2348"));
+    seq.addDBRef(new DBRefEntry("ENSEMBL", "0", "E2349"));
+    seq.addDBRef(new DBRefEntry("ENSEMBLGENOMES", "0", "E2350"));
+    sources = new CrossRef(new SequenceI[] { seq }, al)
+            .findXrefSourcesForSequences(false);
+    // 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
+     * and others to dna coding databases
+     */
+    sources.clear();
+    seq.setDBRefs(null);
+    seq.addDBRef(new DBRefEntry("UNIPROT", "0", "A1234"));
+    seq.addDBRef(new DBRefEntry("EMBLCDS", "0", "E2347"));
+    SequenceI seq2 = new Sequence("Seq2", "MGKYQARLSS");
+    seq2.addDBRef(new DBRefEntry("UNIPROT", "0", "A1234"));
+    seq2.addDBRef(new DBRefEntry("EMBL", "0", "E2345"));
+    seq2.addDBRef(new DBRefEntry("GENEDB", "0", "E2348"));
+    // TODO include ENSEMBLGENOMES in DBRefSource.DNACODINGDBS ?
+    al.addSequence(seq2);
+    sources = new CrossRef(new SequenceI[] { seq, seq2 }, al)
+            .findXrefSourcesForSequences(false);
+    // method removed EMBL from sources to match
+    assertEquals(2, sources.size());
+    assertEquals("[EMBLCDS, GENEDB]", sources.toString());
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where only an indirect
+   * xref is found - not on the nucleotide sequence but on a peptide sequence in
+   * the alignment which which it shares a nucleotide dbref
+   */
+  @Test(groups = { "Functional" }, enabled = true)
+  public void testFindXrefSequences_indirectDbrefToProtein()
+  {
+    /*
+     * Alignment setup:
+     *   - nucleotide dbref  EMBL|AF039662
+     *   - peptide    dbrefs EMBL|AF039662, UNIPROT|Q9ZTS2
+     */
+    SequenceI emblSeq = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
+    emblSeq.addDBRef(new DBRefEntry("EMBL", "0", "AF039662"));
+    SequenceI uniprotSeq = new Sequence("Q9ZTS2", "MASVSATMISTS");
+    uniprotSeq.addDBRef(new DBRefEntry("EMBL", "0", "AF039662"));
+    uniprotSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+
+    /*
+     * Find UNIPROT xrefs for nucleotide 
+     * - it has no UNIPROT dbref of its own
+     * - but peptide with matching nucleotide dbref does, so is returned
+     */
+    AlignmentI al = new Alignment(new SequenceI[] { emblSeq, uniprotSeq });
+    Alignment xrefs = new CrossRef(new SequenceI[] { emblSeq }, al)
+            .findXrefSequences("UNIPROT", true);
+    assertEquals(1, xrefs.getHeight());
+    assertSame(uniprotSeq, xrefs.getSequenceAt(0));
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where only an indirect
+   * xref is found - not on the peptide sequence but on a nucleotide sequence in
+   * the alignment which which it shares a protein dbref
+   */
+  @Test(groups = { "Functional" }, enabled = true)
+  public void testFindXrefSequences_indirectDbrefToNucleotide()
+  {
+    /*
+     * Alignment setup:
+     *   - peptide    dbref  UNIPROT|Q9ZTS2
+     *   - nucleotide dbref  EMBL|AF039662, UNIPROT|Q9ZTS2
+     */
+    SequenceI uniprotSeq = new Sequence("Q9ZTS2", "MASVSATMISTS");
+    uniprotSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+    SequenceI emblSeq = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
+    emblSeq.addDBRef(new DBRefEntry("EMBL", "0", "AF039662"));
+    emblSeq.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+
+    /*
+     * find EMBL xrefs for peptide sequence - it has no direct
+     * dbrefs, but the 'corresponding' nucleotide sequence does, so is returned
+     */
+    /*
+     * Find EMBL xrefs for peptide 
+     * - it has no EMBL dbref of its own
+     * - but nucleotide with matching peptide dbref does, so is returned
+     */
+    AlignmentI al = new Alignment(new SequenceI[] { emblSeq, uniprotSeq });
+    Alignment xrefs = new CrossRef(new SequenceI[] { uniprotSeq }, al)
+            .findXrefSequences("EMBL", false);
+    assertEquals(1, xrefs.getHeight());
+    assertSame(emblSeq, xrefs.getSequenceAt(0));
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where the selected
+   * sequence has no dbref to the desired source, and there are no indirect
+   * references via another sequence in the alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testFindXrefSequences_noDbrefs()
+  {
+    /*
+     * two nucleotide sequences, one with UNIPROT dbref
+     */
+    SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
+    dna1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+    SequenceI dna2 = new Sequence("AJ307031", "AAACCCTTT");
+
+    /*
+     * find UNIPROT xrefs for peptide sequence - it has no direct
+     * dbrefs, and the other sequence (which has a UNIPROT dbref) is not 
+     * equatable to it, so no results found
+     */
+    AlignmentI al = new Alignment(new SequenceI[] { dna1, dna2 });
+    Alignment xrefs = new CrossRef(new SequenceI[] { dna2 }, al)
+            .findXrefSequences("UNIPROT", true);
+    assertNull(xrefs);
+  }
+
+  /**
+   * Tests for the method that searches an alignment (with one sequence
+   * excluded) for protein/nucleotide sequences with a given cross-reference
+   */
+  @Test(groups = { "Functional" }, enabled = true)
+  public void testSearchDataset()
+  {
+    /*
+     * nucleotide sequence with UNIPROT AND EMBL dbref
+     * peptide sequence with UNIPROT dbref
+     */
+    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));
+    DBRefEntry dbref = new DBRefEntry("UNIPROT", "0", "Q9ZTS2", map);
+    dna1.addDBRef(dbref);
+    dna1.addDBRef(new DBRefEntry("EMBL", "0", "AF039662"));
+    SequenceI pep1 = new Sequence("Q9ZTS2", "MLAVSRGQ");
+    dbref = new DBRefEntry("UNIPROT", "0", "Q9ZTS2");
+    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+    AlignmentI al = new Alignment(new SequenceI[] { dna1, pep1 });
+
+    List<SequenceI> result = new ArrayList<SequenceI>();
+
+    /*
+     * first search for a dbref nowhere on the alignment:
+     */
+    dbref = new DBRefEntry("UNIPROT", "0", "P30419");
+    CrossRef testee = new CrossRef(al.getSequencesArray(), al);
+    AlignedCodonFrame acf = new AlignedCodonFrame();
+    boolean found = testee.searchDataset(true, dna1, dbref, result, acf,
+            true);
+    assertFalse(found);
+    assertTrue(result.isEmpty());
+    assertTrue(acf.isEmpty());
+
+    /*
+     * search for a protein sequence with dbref UNIPROT:Q9ZTS2
+     */
+    acf = new AlignedCodonFrame();
+    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
+    assertTrue(found);
+    assertEquals(1, result.size());
+    assertSame(pep1, result.get(0));
+    assertTrue(acf.isEmpty());
+
+    /*
+     * search for a nucleotide sequence with dbref UNIPROT:Q9ZTS2
+     */
+    result.clear();
+    acf = new AlignedCodonFrame();
+    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
+    assertTrue(found);
+    assertEquals(1, result.size());
+    assertSame(dna1, result.get(0));
+    // should now have a mapping from dna to pep1
+    List<SequenceToSequenceMapping> mappings = acf.getMappings();
+    assertEquals(1, mappings.size());
+    SequenceToSequenceMapping mapping = mappings.get(0);
+    assertSame(dna1, mapping.getFromSeq());
+    assertSame(pep1, mapping.getMapping().getTo());
+    MapList mapList = mapping.getMapping().getMap();
+    assertEquals(1, mapList.getToRatio());
+    assertEquals(3, mapList.getFromRatio());
+    assertEquals(1, mapList.getFromRanges().size());
+    assertEquals(1, mapList.getFromRanges().get(0)[0]);
+    assertEquals(21, mapList.getFromRanges().get(0)[1]);
+    assertEquals(1, mapList.getToRanges().size());
+    assertEquals(1, mapList.getToRanges().get(0)[0]);
+    assertEquals(7, mapList.getToRanges().get(0)[1]);
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where the selected
+   * sequence has a dbref with a mapping to a sequence. This represents the case
+   * where either
+   * <ul>
+   * <li>a fetched sequence is already decorated with its cross-reference (e.g.
+   * EMBL + translation), or</li>
+   * <li>Get Cross-References has been done once resulting in instantiated
+   * cross-reference mappings</li>
+   * </ul>
+   */
+  @Test(groups = { "Functional" })
+  public void testFindXrefSequences_fromDbRefMap()
+  {
+    /*
+     * scenario: nucleotide sequence AF039662
+     *   with dbref + mapping to Q9ZTS2 and P30419
+     *     which themselves each have a dbref and feature
+     */
+    SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
+    SequenceI pep1 = new Sequence("Q9ZTS2", "MALFQRSV");
+    SequenceI pep2 = new Sequence("P30419", "MTRRSQIF");
+    dna1.createDatasetSequence();
+    pep1.createDatasetSequence();
+    pep2.createDatasetSequence();
+
+    pep1.getDatasetSequence().addDBRef(
+            new DBRefEntry("Pfam", "0", "PF00111"));
+    pep1.addSequenceFeature(new SequenceFeature("type", "desc", 12, 14, 1f,
+            "group"));
+    pep2.getDatasetSequence().addDBRef(new DBRefEntry("PDB", "0", "3JTK"));
+    pep2.addSequenceFeature(new SequenceFeature("type2", "desc2", 13, 15,
+            12f, "group2"));
+
+    MapList mapList = new MapList(new int[] { 1, 24 }, new int[] { 1, 3 },
+            3, 1);
+    Mapping map = new Mapping(pep1, mapList);
+    DBRefEntry dbRef1 = new DBRefEntry("UNIPROT", "0", "Q9ZTS2", map);
+    dna1.getDatasetSequence().addDBRef(dbRef1);
+    mapList = new MapList(new int[] { 1, 24 }, new int[] { 1, 3 }, 3, 1);
+    map = new Mapping(pep2, mapList);
+    DBRefEntry dbRef2 = new DBRefEntry("UNIPROT", "0", "P30419", map);
+    dna1.getDatasetSequence().addDBRef(dbRef2);
+
+    /*
+     * find UNIPROT xrefs for nucleotide sequence - it should pick up 
+     * mapped sequences
+     */
+    AlignmentI al = new Alignment(new SequenceI[] { dna1 });
+    Alignment xrefs = new CrossRef(new SequenceI[] { dna1 }, al)
+            .findXrefSequences("UNIPROT", true);
+    assertEquals(2, xrefs.getHeight());
+
+    /*
+     * cross-refs alignment holds copies of the mapped sequences
+     * including copies of their dbrefs and features
+     */
+    checkCopySequence(pep1, xrefs.getSequenceAt(0));
+    checkCopySequence(pep2, xrefs.getSequenceAt(1));
+  }
+
+  /**
+   * Helper method that verifies that 'copy' has the same name, start, end,
+   * sequence and dataset sequence object as 'original' (but is not the same
+   * object)
+   * 
+   * @param copy
+   * @param original
+   */
+  private void checkCopySequence(SequenceI copy, SequenceI original)
+  {
+    assertNotSame(copy, original);
+    assertSame(copy.getDatasetSequence(), original.getDatasetSequence());
+    assertEquals(copy.getName(), original.getName());
+    assertEquals(copy.getStart(), original.getStart());
+    assertEquals(copy.getEnd(), original.getEnd());
+    assertEquals(copy.getSequenceAsString(), original.getSequenceAsString());
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where the selected
+   * sequence has a dbref with no mapping, triggering a fetch from database
+   */
+  @Test(groups = { "Functional" })
+  public void testFindXrefSequences_withFetch()
+  {
+    SequenceI dna1 = new Sequence("AF039662", "GGGGCAGCACAAGAAC");
+    dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "Q9ZTS2"));
+    dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "P30419"));
+    dna1.addDBRef(new DBRefEntry("UNIPROT", "ENA:0", "P00314"));
+    final SequenceI pep1 = new Sequence("Q9ZTS2", "MYQLIRSSW");
+    pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2"));
+
+    final SequenceI pep2 = new Sequence("P00314", "MRKLLAASG");
+    pep2.addDBRef(new DBRefEntry("UNIPROT", "0", "P00314"));
+
+    /*
+     * argument false suppresses adding DAS sources
+     * todo: define an interface type SequenceFetcherI and mock that
+     */
+    SequenceFetcher mockFetcher = new SequenceFetcher(false)
+    {
+      @Override
+      public boolean isFetchable(String source)
+      {
+        return true;
+      }
+
+      @Override
+      public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
+      {
+        return new SequenceI[] { pep1, pep2 };
+      }
+    };
+    SequenceFetcherFactory.setSequenceFetcher(mockFetcher);
+
+    /*
+     * find UNIPROT xrefs for nucleotide sequence
+     */
+    AlignmentI al = new Alignment(new SequenceI[] { dna1 });
+    Alignment xrefs = new CrossRef(new SequenceI[] { dna1 }, al)
+            .findXrefSequences("UNIPROT", true);
+    assertEquals(2, xrefs.getHeight());
+    assertSame(pep1, xrefs.getSequenceAt(0));
+    assertSame(pep2, xrefs.getSequenceAt(1));
+  }
+
+  @AfterClass
+  public void tearDown()
+  {
+    SequenceFetcherFactory.setSequenceFetcher(null);
+  }
+
+  /**
+   * Test for finding 'product' sequences for the case where both gene and
+   * transcript sequences have dbrefs to Uniprot.
+   */
+  @Test(groups = { "Functional" })
+  public void testFindXrefSequences_forGeneAndTranscripts()
+  {
+    /*
+     * 'gene' sequence
+     */
+    SequenceI gene = new Sequence("ENSG00000157764", "CGCCTCCCTTCCCC");
+    gene.addDBRef(new DBRefEntry("UNIPROT", "0", "P15056"));
+    gene.addDBRef(new DBRefEntry("UNIPROT", "0", "H7C5K3"));
+
+    /*
+     * 'transcript' with CDS feature (supports mapping to protein)
+     */
+    SequenceI braf001 = new Sequence("ENST00000288602", "taagATGGCGGCGCTGa");
+    braf001.addDBRef(new DBRefEntry("UNIPROT", "0", "P15056"));
+    braf001.addSequenceFeature(new SequenceFeature("CDS", "", 5, 16, 0f,
+            null));
+
+    /*
+     * 'spliced transcript' with CDS ranges
+     */
+    SequenceI braf002 = new Sequence("ENST00000497784", "gCAGGCtaTCTGTTCaa");
+    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,
+            null));
+
+    /*
+     * TODO code is fragile - use of SequenceIdMatcher depends on fetched
+     * sequences having a name starting Source|Accession
+     * 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
+     */
+    SequenceFetcher mockFetcher = new SequenceFetcher(false)
+    {
+      @Override
+      public boolean isFetchable(String source)
+      {
+        return true;
+      }
+
+      @Override
+      public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
+      {
+        return new SequenceI[] { pep1, pep2 };
+      }
+    };
+    SequenceFetcherFactory.setSequenceFetcher(mockFetcher);
+
+    /*
+     * find UNIPROT xrefs for gene and transcripts
+     * verify that
+     * - the two proteins are retrieved but not duplicated
+     * - mappings are built from transcript (CDS) to proteins
+     * - no mappings from gene to proteins
+     */
+    SequenceI[] seqs = new SequenceI[] { gene, braf001, braf002 };
+    AlignmentI al = new Alignment(seqs);
+    Alignment xrefs = new CrossRef(seqs, al).findXrefSequences("UNIPROT",
+            true);
+    assertEquals(2, xrefs.getHeight());
+    assertSame(pep1, xrefs.getSequenceAt(0));
+    assertSame(pep2, xrefs.getSequenceAt(1));
+  }
+
+  /**
+   * <pre>
+   * Test that emulates this (real but simplified) case:
+   * Alignment:          DBrefs
+   *     UNIPROT|P0CE19  EMBL|J03321, EMBL|X06707, EMBL|M19487
+   *     UNIPROT|P0CE20  EMBL|J03321, EMBL|X06707, EMBL|X07547
+   * Find cross-references for EMBL. These are mocked here as
+   *     EMBL|J03321     with mappings to P0CE18, P0CE19, P0CE20
+   *     EMBL|X06707     with mappings to P0CE17, P0CE19, P0CE20
+   *     EMBL|M19487     with mappings to P0CE19, Q46432
+   *     EMBL|X07547     with mappings to P0CE20, B0BCM4
+   * EMBL sequences are first 'fetched' (mocked here) for P0CE19.
+   * The 3 EMBL sequences are added to the alignment dataset.
+   * Their dbrefs to Uniprot products P0CE19 and P0CE20 should be matched in the
+   * alignment dataset and updated to reference the original Uniprot sequences.
+   * For the second Uniprot sequence, the J03321 and X06707 xrefs should be 
+   * resolved from the dataset, and only the X07547 dbref fetched.
+   * So the end state to verify is:
+   * - 4 cross-ref sequences returned: J03321, X06707,  M19487, X07547
+   * - P0CE19/20 dbrefs to EMBL sequences now have mappings
+   * - J03321 dbrefs to P0CE19/20 mapped to original Uniprot sequences
+   * - X06707 dbrefs to P0CE19/20 mapped to original Uniprot sequences
+   * </pre>
+   */
+  @Test(groups = { "Functional" })
+  public void testFindXrefSequences_uniprotEmblManyToMany()
+  {
+    /*
+     * Uniprot sequences, both with xrefs to EMBL|J03321 
+     * and EMBL|X07547
+     */
+    SequenceI p0ce19 = new Sequence("UNIPROT|P0CE19", "KPFG");
+    p0ce19.addDBRef(new DBRefEntry("EMBL", "0", "J03321"));
+    p0ce19.addDBRef(new DBRefEntry("EMBL", "0", "X06707"));
+    p0ce19.addDBRef(new DBRefEntry("EMBL", "0", "M19487"));
+    SequenceI p0ce20 = new Sequence("UNIPROT|P0CE20", "PFGK");
+    p0ce20.addDBRef(new DBRefEntry("EMBL", "0", "J03321"));
+    p0ce20.addDBRef(new DBRefEntry("EMBL", "0", "X06707"));
+    p0ce20.addDBRef(new DBRefEntry("EMBL", "0", "X07547"));
+
+    /*
+     * EMBL sequences to be 'fetched', complete with dbrefs and mappings
+     * to their protein products (CDS location  and translations  are provided
+     * in  EMBL XML); these should be matched to, and replaced with,
+     * the corresponding uniprot sequences after fetching
+     */
+
+    /*
+     * J03321 with mappings to P0CE19 and P0CE20
+     */
+    final SequenceI j03321 = new Sequence("EMBL|J03321", "AAACCCTTTGGGAAAA");
+    DBRefEntry dbref1 = new DBRefEntry("UNIPROT", "0", "P0CE19");
+    MapList mapList = new MapList(new int[] { 1, 12 }, new int[] { 1, 4 },
+            3, 1);
+    Mapping map = new Mapping(new Sequence("UNIPROT|P0CE19", "KPFG"),
+            mapList);
+    // add a dbref to the mapped to sequence - should get copied to p0ce19
+    map.getTo().addDBRef(new DBRefEntry("PIR", "0", "S01875"));
+    dbref1.setMap(map);
+    j03321.addDBRef(dbref1);
+    DBRefEntry dbref2 = new DBRefEntry("UNIPROT", "0", "P0CE20");
+    mapList = new MapList(new int[] { 4, 15 }, new int[] { 2, 5 }, 3, 1);
+    dbref2.setMap(new Mapping(new Sequence("UNIPROT|P0CE20", "PFGK"),
+            new MapList(mapList)));
+    j03321.addDBRef(dbref2);
+
+    /*
+     * X06707 with mappings to P0CE19 and P0CE20
+     */
+    final SequenceI x06707 = new Sequence("EMBL|X06707", "atgAAACCCTTTGGG");
+    DBRefEntry dbref3 = new DBRefEntry("UNIPROT", "0", "P0CE19");
+    MapList map2 = new MapList(new int[] { 4, 15 }, new int[] { 1, 4 }, 3,
+            1);
+    dbref3.setMap(new Mapping(new Sequence("UNIPROT|P0CE19", "KPFG"), map2));
+    x06707.addDBRef(dbref3);
+    DBRefEntry dbref4 = new DBRefEntry("UNIPROT", "0", "P0CE20");
+    MapList map3 = new MapList(new int[] { 4, 15 }, new int[] { 1, 4 }, 3,
+            1);
+    dbref4.setMap(new Mapping(new Sequence("UNIPROT|P0CE20", "PFGK"), map3));
+    x06707.addDBRef(dbref4);
+
+    /*
+     * M19487 with mapping to P0CE19 and Q46432
+     */
+    final SequenceI m19487 = new Sequence("EMBL|M19487", "AAACCCTTTGGG");
+    DBRefEntry dbref5 = new DBRefEntry("UNIPROT", "0", "P0CE19");
+    dbref5.setMap(new Mapping(new Sequence("UNIPROT|P0CE19", "KPFG"),
+            new MapList(mapList)));
+    m19487.addDBRef(dbref5);
+    DBRefEntry dbref6 = new DBRefEntry("UNIPROT", "0", "Q46432");
+    dbref6.setMap(new Mapping(new Sequence("UNIPROT|Q46432", "KPFG"),
+            new MapList(mapList)));
+    m19487.addDBRef(dbref6);
+
+    /*
+     * X07547 with mapping to P0CE20 and B0BCM4
+     */
+    final SequenceI x07547 = new Sequence("EMBL|X07547", "cccAAACCCTTTGGG");
+    DBRefEntry dbref7 = new DBRefEntry("UNIPROT", "0", "P0CE20");
+    dbref7.setMap(new Mapping(new Sequence("UNIPROT|P0CE20", "PFGK"),
+            new MapList(map2)));
+    x07547.addDBRef(dbref7);
+    DBRefEntry dbref8 = new DBRefEntry("UNIPROT", "0", "B0BCM4");
+    dbref8.setMap(new Mapping(new Sequence("UNIPROT|B0BCM4", "KPFG"),
+            new MapList(map2)));
+    x07547.addDBRef(dbref8);
+
+    /*
+     * mock sequence fetcher to 'return' the EMBL sequences
+     * TODO: Mockito would allow .thenReturn().thenReturn() here, 
+     * and also capture and verification of the parameters
+     * passed in calls to getSequences() - important to verify that
+     * duplicate sequence fetches are not requested
+     */
+    SequenceFetcher mockFetcher = new SequenceFetcher(false)
+    {
+      int call = 0;
+
+      @Override
+      public boolean isFetchable(String source)
+      {
+        return true;
+      }
+
+      @Override
+      public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
+      {
+        call++;
+        if (call == 1)
+        {
+          assertEquals("Expected 3 embl seqs in first fetch", 3,
+                  refs.size());
+          return new SequenceI[] { j03321, x06707, m19487 };
+        }
+        else
+        {
+          assertEquals("Expected 1 embl seq in second fetch", 1,
+                  refs.size());
+          return new SequenceI[] { x07547 };
+        }
+      }
+    };
+    SequenceFetcherFactory.setSequenceFetcher(mockFetcher);
+
+    /*
+     * find EMBL xrefs for Uniprot seqs and verify that
+     * - the EMBL xref'd sequences are retrieved without duplicates
+     * - mappings are added to the Uniprot dbrefs
+     * - mappings in the EMBL-to-Uniprot dbrefs are updated to the 
+     *   alignment sequences
+     * - dbrefs on the EMBL sequences are added to the original dbrefs
+     */
+    SequenceI[] seqs = new SequenceI[] { p0ce19, p0ce20 };
+    AlignmentI al = new Alignment(seqs);
+    Alignment xrefs = new CrossRef(seqs, al).findXrefSequences("EMBL",
+            false);
+
+    /*
+     * verify retrieved sequences
+     */
+    assertNotNull(xrefs);
+    assertEquals(4, xrefs.getHeight());
+    assertSame(j03321, xrefs.getSequenceAt(0));
+    assertSame(x06707, xrefs.getSequenceAt(1));
+    assertSame(m19487, xrefs.getSequenceAt(2));
+    assertSame(x07547, xrefs.getSequenceAt(3));
+
+    /*
+     * verify mappings added to Uniprot-to-EMBL dbrefs
+     */
+    Mapping mapping = p0ce19.getDBRefs()[0].getMap();
+    assertSame(j03321, mapping.getTo());
+    mapping = p0ce19.getDBRefs()[1].getMap();
+    assertSame(x06707, mapping.getTo());
+    mapping = p0ce20.getDBRefs()[0].getMap();
+    assertSame(j03321, mapping.getTo());
+    mapping = p0ce20.getDBRefs()[1].getMap();
+    assertSame(x06707, mapping.getTo());
+
+    /*
+     * verify dbrefs on EMBL are mapped to alignment seqs
+     */
+    assertSame(p0ce19, j03321.getDBRefs()[0].getMap().getTo());
+    assertSame(p0ce20, j03321.getDBRefs()[1].getMap().getTo());
+    assertSame(p0ce19, x06707.getDBRefs()[0].getMap().getTo());
+    assertSame(p0ce20, x06707.getDBRefs()[1].getMap().getTo());
+
+    /*
+     * verify new dbref on EMBL dbref mapping is copied to the
+     * original Uniprot sequence
+     */
+    assertEquals(4, p0ce19.getDBRefs().length);
+    assertEquals("PIR", p0ce19.getDBRefs()[3].getSource());
+    assertEquals("S01875", p0ce19.getDBRefs()[3].getAccessionId());
   }
 
+  @Test(groups = "Functional")
+  public void testSameSequence()
+  {
+    assertTrue(CrossRef.sameSequence(null, null));
+    SequenceI seq1 = new Sequence("seq1", "ABCDEF");
+    assertFalse(CrossRef.sameSequence(seq1, null));
+    assertFalse(CrossRef.sameSequence(null, seq1));
+    assertTrue(CrossRef.sameSequence(seq1, new Sequence("seq2", "ABCDEF")));
+    assertTrue(CrossRef.sameSequence(seq1, new Sequence("seq2", "abcdef")));
+    assertFalse(CrossRef
+            .sameSequence(seq1, new Sequence("seq2", "ABCDE-F")));
+    assertFalse(CrossRef.sameSequence(seq1, new Sequence("seq2", "BCDEF")));
+  }
 }
index 9a4c357..1851517 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignViewport;
 import jalview.io.FormatAdapter;
@@ -498,17 +499,44 @@ public class DnaTest
   @Test(groups = "Functional")
   public void testReverseSequence()
   {
-    String seq = "AcGtUrYkMbVdHNX";
+    String seq = "-Ac-GtU--rYkMbVdHNX-";
+    String seqRev = new StringBuilder(seq).reverse().toString();
 
     // reverse:
     SequenceI reversed = Dna.reverseSequence("Seq1", seq, false);
-    assertEquals(new StringBuilder(seq).reverse()
-            .toString(), reversed.getSequenceAsString());
+    assertEquals(1, reversed.getStart());
+    assertEquals(15, reversed.getEnd());
+    assertEquals(20, reversed.getLength());
+    assertEquals(seqRev, reversed.getSequenceAsString());
     assertEquals("Seq1|rev", reversed.getName());
 
     // reverse complement:
     SequenceI revcomp = Dna.reverseSequence("Seq1", seq, true);
-    assertEquals("XNDhBvKmRyAaCgT", revcomp.getSequenceAsString());
+    assertEquals("-XNDhBvKmRy--AaC-gT-", revcomp.getSequenceAsString());
     assertEquals("Seq1|revcomp", revcomp.getName());
   }
+
+  @Test(groups = "Functional")
+  public void testReverseCdna()
+  {
+    String seq = "-Ac-GtU--rYkMbVdHNX-";
+    String seqRev = new StringBuilder(seq).reverse().toString();
+    String seqDs = seq.replaceAll("-", "");
+    String seqDsRev = new StringBuilder(seqDs).reverse().toString();
+
+    SequenceI dna = new Sequence("Seq1", seq);
+    Alignment al = new Alignment(new SequenceI[] { dna });
+    al.createDatasetAlignment();
+    assertEquals(seqDs, al.getSequenceAt(0).getDatasetSequence()
+            .getSequenceAsString());
+
+    ColumnSelection cs = new ColumnSelection();
+    AlignViewportI av = new AlignViewport(al, cs);
+    Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 });
+    AlignmentI reversed = testee.reverseCdna(false);
+    assertEquals(1, reversed.getHeight());
+    assertEquals(seqRev, reversed.getSequenceAt(0).getSequenceAsString());
+    assertEquals(seqDsRev, reversed.getSequenceAt(0).getDatasetSequence()
+            .getSequenceAsString());
+  }
 }
index 55823e4..cea8ae4 100644 (file)
@@ -27,7 +27,6 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 
 import org.testng.AssertJUnit;
@@ -45,21 +44,26 @@ public class GroupingTest
 
   Sequence s5 = new Sequence("s5", "AAAADDEDTTEE");
 
-  SequenceGroup sg1 = 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 sg2 = 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 });
 
-  int[] positions = new int[] { 1, 7, 9 };
+  /*
+   * test for the case where column selections are not added in
+   * left to right order
+   */
+  int[] positions = new int[] { 7, 9, 1 };
 
   @Test(groups = { "Functional" })
   public void testMakeGroupsWithBoth()
   {
-    ArrayList<String> str = new ArrayList<String>();
+    String[] str = new String[alignment.getHeight()];
+    int seq = 0;
     for (SequenceI s : alignment.getSequences())
     {
       StringBuilder sb = new StringBuilder();
@@ -67,12 +71,12 @@ public class GroupingTest
       {
         sb.append(s.getCharAt(p));
       }
-      str.add(sb.toString());
+      str[seq++] = sb.toString();
     }
     SequenceGroup[] seqgroupsString = Grouping.makeGroupsFrom(
-            alignment.getSequencesArray(),
-            str.toArray(new String[str.size()]),
-            Arrays.asList(new SequenceGroup[] { sg1, sg2 }));
+            alignment.getSequencesArray(), str,
+            Arrays.asList(new SequenceGroup[] { sg_12, sg_345 }));
+
     ColumnSelection cs = new ColumnSelection();
     for (int p : positions)
     {
@@ -80,7 +84,7 @@ public class GroupingTest
     }
     SequenceGroup[] seqgroupsColSel = Grouping.makeGroupsFromCols(
             alignment.getSequencesArray(), cs,
-            Arrays.asList(new SequenceGroup[] { sg1, sg2 }));
+            Arrays.asList(new SequenceGroup[] { sg_12, sg_345 }));
     AssertJUnit
             .assertEquals(seqgroupsString.length, seqgroupsColSel.length);
     for (int p = 0; p < seqgroupsString.length; p++)
diff --git a/test/jalview/analysis/ResidueCountTest.java b/test/jalview/analysis/ResidueCountTest.java
new file mode 100644 (file)
index 0000000..4a71f89
--- /dev/null
@@ -0,0 +1,404 @@
+package jalview.analysis;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import jalview.analysis.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');
+    
+    assertEquals(rc.getTooltip(40, 0),
+            "P 25%; W 22%; C 17%; Q 17%; K 15%; F 2%");
+
+    assertEquals(rc.getTooltip(30, 1),
+            "P 33.3%; W 30.0%; C 23.3%; Q 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 5801437..9d35a19 100644 (file)
@@ -21,6 +21,9 @@
 package jalview.analysis;
 
 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 static org.testng.AssertJUnit.fail;
 
 import jalview.analysis.SecStrConsensus.SimpleBP;
@@ -35,11 +38,12 @@ public class RnaTest
   public void testGetSimpleBPs() throws WUSSParseException
   {
     String rna = "([{})]"; // JAL-1081 example
-    Vector<SimpleBP> bps = Rna.GetSimpleBPs(rna);
+    Vector<SimpleBP> bps = Rna.getSimpleBPs(rna);
     assertEquals(3, bps.size());
 
     /*
      * the base pairs are added in the order in which the matching base is found
+     * (popping the stack of unmatched opening brackets)
      */
     assertEquals(2, bps.get(0).bp5); // {
     assertEquals(3, bps.get(0).bp3); // }
@@ -55,25 +59,248 @@ public class RnaTest
     String rna = "(([{})]";
     try
     {
-      Rna.GetSimpleBPs(rna);
+      Rna.getSimpleBPs(rna);
       fail("expected exception");
     } catch (WUSSParseException e)
     {
-      // expected
+      // error reported as after end of input string
+      assertEquals(rna.length(), e.getProblemPos());
     }
   }
 
   @Test(groups = { "Functional" })
   public void testGetSimpleBPs_unmatchedCloser()
   {
-    String rna = "([{})]]";
+    String rna = "([{})]]]";
     try
     {
-      Rna.GetSimpleBPs(rna);
+      Rna.getSimpleBPs(rna);
       fail("expected exception");
     } catch (WUSSParseException e)
     {
-      // expected
+      // error reported as at first unmatched close
+      assertEquals(6, e.getProblemPos());
+    }
+
+    /*
+     * a variant where we have no opening bracket of the same type
+     * as the unmatched closing bracket (no stack rather than empty stack)
+     */
+    rna = "((()])";
+    try
+    {
+      Rna.getSimpleBPs(rna);
+      fail("expected exception");
+    } catch (WUSSParseException e)
+    {
+      assertEquals(4, e.getProblemPos());
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetRNASecStrucState()
+  {
+    assertNull(Rna.getRNASecStrucState(null));
+    for (int i = 0; i <= 255; i++)
+    {
+      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
+       */
+      if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')
+              || "()[]{}<>".indexOf(s) > -1)
+      {
+        assertEquals("" + i, s, ss);
+      }
+      else
+      {
+        assertEquals(" ", ss);
+      }
+    }
+
+    /*
+     * a string is processed character by character
+     */
+    assertEquals("a [K ]z} {Q b(w)p><i",
+            Rna.getRNASecStrucState("a.[K-]z}?{Q b(w)p><i"));
+  }
+
+  /**
+   * Tests for isClosingParenthesis with char or String argument
+   */
+  @Test(groups = { "Functional" })
+  public void testIsClosingParenthesis()
+  {
+    assertFalse(Rna.isClosingParenthesis(null));
+
+    /*
+     * only a-z, )]}> are closing bracket symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isClosingChar = Rna.isClosingParenthesis((char) i);
+      boolean isClosingString = Rna.isClosingParenthesis(String
+              .valueOf((char) i));
+      if ((i >= 'a' && i <= 'z') || i == ')' || i == '}' || i == ']'
+              || i == '>')
+      {
+        assertTrue(String.format("close base pair %c", i), isClosingChar);
+        assertTrue(String.format("close base pair %c", i), isClosingString);
+      }
+      else
+      {
+        assertFalse(String.format("close base pair %c", i), isClosingChar);
+        assertFalse(String.format("close base pair %c", i), isClosingString);
+      }
+      assertFalse(Rna.isClosingParenthesis(String.valueOf((char) i) + " "));
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsCanonicalOrWobblePair()
+  {
+    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.isCanonicalOrWobblePair(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") || pair.equals("GT")
+                || pair.equals("TG") || pair.equals("GU")
+                || pair.equals("UG"))
+        {
+          assertTrue(pair + " should be valid", result);
+        }
+        else
+        {
+          assertFalse(pair + " should be invalid", result);
+        }
+      }
+    }
+  }
+
+  @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
+   */
+  @Test(groups = { "Functional" })
+  public void testIsOpeningParenthesis()
+  {
+    /*
+     * only A-Z, ([{< are opening bracket symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isOpeningChar = Rna.isOpeningParenthesis((char) i);
+      boolean isOpeningString = Rna.isOpeningParenthesis(String
+              .valueOf((char) i));
+      if ((i >= 'A' && i <= 'Z') || i == '(' || i == '{' || i == '['
+              || i == '<')
+      {
+        assertTrue(String.format("Open base pair %c", i), isOpeningChar);
+        assertTrue(String.format("Open base pair %c", i), isOpeningString);
+      }
+      else
+      {
+        assertFalse(String.format("Open base pair %c", i), isOpeningChar);
+        assertFalse(String.format("Open base pair %c", i), isOpeningString);
+      }
+      assertFalse(Rna.isOpeningParenthesis(String.valueOf((char) i) + " "));
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetMatchingOpeningParenthesis() throws WUSSParseException
+  {
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isClosing = Rna.isClosingParenthesis((char) i);
+      if (isClosing)
+      {
+        char opening = Rna.getMatchingOpeningParenthesis((char) i);
+        if (i >= 'a' && i <= 'z')
+        {
+          assertEquals(i + 'A' - 'a', opening);
+        }
+        else if (i == ')' && opening == '(' || i == ']' && opening == '['
+                || i == '}' && opening == '{' || i == '>' && opening == '<')
+        {
+          // ok
+        }
+        else
+        {
+          fail("Got " + opening + " as opening bracket pair for "
+                  + ((char) i));
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests for isRnaSecondaryStructureSymbol with char or String argument
+   */
+  @Test(groups = { "Functional" })
+  public void testIsRnaSecondaryStructureSymbol()
+  {
+    assertFalse(Rna.isRnaSecondaryStructureSymbol(null));
+
+    /*
+     * only A-Z,  a-z, ()[]{}<> are valid symbols
+     */
+    for (int i = 0; i <= 255; i++)
+    {
+      boolean isValidChar = Rna.isRnaSecondaryStructureSymbol((char) i);
+      boolean isValidString = Rna.isRnaSecondaryStructureSymbol(String
+              .valueOf((char) i));
+      if ((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || i == '('
+              || i == ')' || i == '{' || i == '}' || i == '[' || i == ']'
+              || i == '<' || i == '>')
+      {
+        assertTrue(String.format("close base pair %c", i), isValidChar);
+        assertTrue(String.format("close base pair %c", i), isValidString);
+      }
+      else
+      {
+        assertFalse(String.format("close base pair %c", i), isValidChar);
+        assertFalse(String.format("close base pair %c", i), isValidString);
+      }
+      assertFalse(Rna.isRnaSecondaryStructureSymbol(String
+              .valueOf((char) i) + " "));
     }
   }
 }
diff --git a/test/jalview/analysis/SeqsetUtilsTest.java b/test/jalview/analysis/SeqsetUtilsTest.java
new file mode 100644 (file)
index 0000000..b4d079a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.Hashtable;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author jprocter
+ *
+ */
+public class SeqsetUtilsTest
+{
+  /**
+   * test for JAL-2046 bug - duplication of sequence features on reconstructed
+   * alignment
+   */
+  @Test(groups = { "Functional" })
+  public void testSeqFeatureAddition()
+  {
+    SequenceI[] sqset = new SequenceI[] {
+        new Sequence("Aseq1", "AREALSEQ"),
+        new Sequence("Aseq2", "AREALSEQ") };
+
+    AlignmentI al = new Alignment(sqset);
+    al.setDataset(null);
+    AlignmentI ds = al.getDataset();
+    SequenceFeature sf1 = new SequenceFeature("f1", "foo", "bleh", 2, 3,
+            "far"), sf2 = new SequenceFeature("f2", "foo", "bleh", 2, 3,
+            "far");
+    ds.getSequenceAt(0).addSequenceFeature(sf1);
+    Hashtable unq = SeqsetUtils.uniquify(sqset, true);
+    SequenceI[] sqset2 = new SequenceI[] {
+        new Sequence(sqset[0].getName(), sqset[0].getSequenceAsString()),
+        new Sequence(sqset[1].getName(), sqset[1].getSequenceAsString()) };
+    Assert.assertTrue(sqset[0].getSequenceFeatures()[0] == sf1);
+    Assert.assertEquals(sqset2[0].getSequenceFeatures(), null);
+    ds.getSequenceAt(0).addSequenceFeature(sf2);
+    Assert.assertEquals(sqset[0].getSequenceFeatures().length, 2);
+    SeqsetUtils.deuniquify(unq, sqset2);
+    // explicitly test that original sequence features still exist because they
+    // are on the shared dataset sequence
+    Assert.assertEquals(sqset[0].getSequenceFeatures().length, 2);
+    Assert.assertEquals(sqset2[0].getSequenceFeatures().length, 2);
+    Assert.assertTrue(sqset[0].getSequenceFeatures()[0] == sqset2[0]
+            .getSequenceFeatures()[0]);
+    Assert.assertTrue(sqset[0].getSequenceFeatures()[1] == sqset2[0]
+            .getSequenceFeatures()[1]);
+  }
+}
index eb0fc47..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;
@@ -50,6 +70,10 @@ public class SequenceIdMatcherTest
     assertTrue(testee.equals("A12345,"));
     assertTrue(testee.equals("A12345?"));
     assertTrue(testee.equals("A12345_"));
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
 
     /*
      * matcher name = target name + word separator...
@@ -58,13 +82,21 @@ public class SequenceIdMatcherTest
     assertTrue(testee.equals("A12345"));
 
     /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
+
+    /*
      * miscellaneous failing cases
      */
     testee = sequenceIdMatcher.new SeqIdName("A12345");
     assertFalse(testee.equals((Object) null));
     assertFalse(testee.equals(""));
-    assertFalse(testee.equals("a12345"));
     assertFalse(testee.equals("A12346|A12345"));
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
 
     testee = sequenceIdMatcher.new SeqIdName("A12345?B23456");
     assertFalse(testee.equals("B23456"));
@@ -74,5 +106,15 @@ public class SequenceIdMatcherTest
     testee = sequenceIdMatcher.new SeqIdName("A12345<");
     assertFalse(testee.equals("A12345?"));
     assertTrue(testee.equals("A12345<")); // bug? inconsistent
+    /*
+     * case insensitive matching
+     */
+    assertTrue(testee.equals("a12345"));
+
+    testee = sequenceIdMatcher.new SeqIdName("UNIPROT|A12345");
+    assertFalse(testee.equals("A12345"));
+    assertFalse(testee.equals("UNIPROT|B98765"));
+    assertFalse(testee.equals("UNIPROT|"));
+    assertTrue(testee.equals("UNIPROT"));
   }
 }
index 2dc2ac3..309790f 100644 (file)
@@ -27,7 +27,7 @@ import jalview.gui.AlignFrame;
 import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
 
-import org.testng.AssertJUnit;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class FeatureScoreModelTest
@@ -40,14 +40,13 @@ public class FeatureScoreModelTest
 
   int[] sf3 = new int[] { -1, -1, -1, -1, -1, -1, 76, 77 };
 
-  @Test(groups = { "Functional" })
-  public void testFeatureScoreModel() throws Exception
+  public AlignFrame getTestAlignmentFrame()
   {
     AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded(
             alntestFile, FormatAdapter.PASTE);
     AlignmentI al = alf.getViewport().getAlignment();
-    AssertJUnit.assertEquals(4, al.getHeight());
-    AssertJUnit.assertEquals(5, al.getWidth());
+    Assert.assertEquals(al.getHeight(), 4);
+    Assert.assertEquals(al.getWidth(), 5);
     for (int i = 0; i < 4; i++)
     {
       SequenceI ds = al.getSequenceAt(i).getDatasetSequence();
@@ -72,21 +71,70 @@ public class FeatureScoreModelTest
     alf.getFeatureRenderer().setVisible("sf2");
     alf.getFeatureRenderer().setVisible("sf3");
     alf.getFeatureRenderer().findAllFeatures(true);
-    AssertJUnit.assertEquals("Number of feature types", 3, alf
-            .getFeatureRenderer().getDisplayedFeatureTypes().size());
-    AssertJUnit.assertTrue(alf.getCurrentView().areFeaturesDisplayed());
+    Assert.assertEquals(alf.getFeatureRenderer().getDisplayedFeatureTypes()
+            .size(), 3, "Number of feature types");
+    Assert.assertTrue(alf.getCurrentView().areFeaturesDisplayed());
+    return alf;
+  }
+
+  @Test(groups = { "Functional" })
+  public void testFeatureScoreModel() throws Exception
+  {
+    AlignFrame alf = getTestAlignmentFrame();
+    FeatureScoreModel fsm = new FeatureScoreModel();
+    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+            .getAlignPanel()));
+    alf.selectAllSequenceMenuItem_actionPerformed(null);
+    float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
+            true));
+    Assert.assertTrue(dm[0][2] == 0f,
+            "FER1_MESCR (0) should be identical with RAPSA (2)");
+    Assert.assertTrue(dm[0][1] > dm[0][2],
+            "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
+  }
+
+  @Test(groups = { "Functional" })
+  public void testFeatureScoreModel_hiddenFirstColumn() throws Exception
+  {
+    AlignFrame alf = getTestAlignmentFrame();
+    // hiding first two columns shouldn't affect the tree
+    alf.getViewport().hideColumns(0, 1);
     FeatureScoreModel fsm = new FeatureScoreModel();
-    AssertJUnit.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));
-    AssertJUnit.assertTrue("FER1_MESCR should be identical with RAPSA (2)",
-            dm[0][2] == 0f);
-    AssertJUnit
-            .assertTrue(
-                    "FER1_MESCR should be further from SPIOL (1) than it is from RAPSA (2)",
-                    dm[0][1] > dm[0][2]);
+    Assert.assertTrue(dm[0][2] == 0f,
+            "FER1_MESCR (0) should be identical with RAPSA (2)");
+    Assert.assertTrue(dm[0][1] > dm[0][2],
+            "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
+  }
 
+  @Test(groups = { "Functional" })
+  public void testFeatureScoreModel_HiddenColumns() throws Exception
+  {
+    AlignFrame alf = getTestAlignmentFrame();
+    // hide columns and check tree changes
+    alf.getViewport().hideColumns(3, 4);
+    alf.getViewport().hideColumns(0, 1);
+    FeatureScoreModel fsm = new FeatureScoreModel();
+    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+            .getAlignPanel()));
+    alf.selectAllSequenceMenuItem_actionPerformed(null);
+    float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
+            true));
+    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,
+            "After hiding last two columns FER1_MESCR (0) should now also be identical with SPIOL (1)");
+    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)");
+    }
   }
 }
diff --git a/test/jalview/bin/ArgsParserTest.java b/test/jalview/bin/ArgsParserTest.java
new file mode 100644 (file)
index 0000000..20e43b8
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import org.testng.annotations.Test;
+
+public class ArgsParserTest
+{
+  @Test(groups = "Functional")
+  public void testGetValue()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertEquals(4, ap.getSize());
+    assertNull(ap.getValue("rubbish"));
+    assertEquals("Tester", ap.getValue("job"));
+    // call to getValue removes the argument and its value
+    assertEquals(2, ap.getSize());
+    assertNull(ap.getValue("job"));
+    assertFalse(ap.contains("job"));
+    assertFalse(ap.contains("Tester"));
+
+    assertEquals("Henry", ap.getValue("name"));
+    assertEquals(0, ap.getSize());
+    assertNull(ap.getValue("name"));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetValue_decoded()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name%241", "Henry",
+        "-job", "Test%203%2a" });
+    // parameter value is decoded
+    assertEquals("Test 3*", ap.getValue("job", true));
+    // parameter name is not decoded
+    assertNull(ap.getValue("name$1", true));
+    assertEquals("Henry", ap.getValue("name%241", true));
+  }
+
+  @Test(groups = "Functional")
+  public void testNextValue()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertEquals("name", ap.nextValue());
+    assertEquals("Henry", ap.nextValue());
+    assertEquals("job", ap.nextValue());
+    assertEquals("Tester", ap.nextValue());
+  }
+
+  @Test(groups = "Functional")
+  public void testContains()
+  {
+    ArgsParser ap = new ArgsParser(new String[] { "-name", "Henry", "-job",
+        "Tester" });
+    assertFalse(ap.contains("Susan"));
+    assertFalse(ap.contains("-name"));
+    assertTrue(ap.contains("name"));
+    // testing for contains removes the argument
+    assertFalse(ap.contains("name"));
+  }
+}
diff --git a/test/jalview/bin/CacheTest.java b/test/jalview/bin/CacheTest.java
new file mode 100644 (file)
index 0000000..803139f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class CacheTest
+{
+  private Locale locale;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpBeforeClass()
+  {
+    locale = Locale.getDefault();
+  }
+
+  @AfterClass(alwaysRun = true)
+  public void tearDownAfterClass()
+  {
+    Locale.setDefault(locale);
+  }
+
+  /**
+   * Test that saved date format does not vary with current locale
+   */
+  @Test(groups = "Functional")
+  public void testSetDateProperty()
+  {
+    Date now = new Date();
+    Locale.setDefault(Locale.FRENCH);
+    String formattedDate = Cache.setDateProperty("test", now);
+    Locale.setDefault(Locale.UK);
+    String formattedDate2 = Cache.setDateProperty("test", now);
+    assertEquals(formattedDate, formattedDate2);
+
+    // currently using Locale.UK to format dates:
+    assertEquals(
+            formattedDate2,
+            SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.MEDIUM,
+                    SimpleDateFormat.MEDIUM, Locale.UK).format(now));
+  }
+}
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());
diff --git a/test/jalview/controller/AlignViewControllerTest.java b/test/jalview/controller/AlignViewControllerTest.java
new file mode 100644 (file)
index 0000000..7fd8965
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+
+import java.util.BitSet;
+
+import org.testng.annotations.Test;
+
+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");
+
+    /*
+     * features start/end are base 1
+     */
+    seq1.addSequenceFeature(new SequenceFeature("Metal", "desc", 2, 4, 0f,
+            null));
+    seq1.addSequenceFeature(new SequenceFeature("Helix", "desc", 1, 15, 0f,
+            null));
+    seq2.addSequenceFeature(new SequenceFeature("Metal", "desc", 4, 10, 0f,
+            null));
+    seq3.addSequenceFeature(new SequenceFeature("Metal", "desc", 11, 15,
+            0f, null));
+
+    /*
+     * select the first three columns --> Metal in seq1 2-3
+     */
+    SequenceGroup sg = new SequenceGroup();
+    sg.setStartRes(0); // base 0
+    sg.setEndRes(2);
+    sg.addSequence(seq1, false);
+    sg.addSequence(seq2, false);
+    sg.addSequence(seq3, false);
+    sg.addSequence(seq4, false);
+
+    BitSet bs = new BitSet();
+    int seqCount = AlignViewController.findColumnsWithFeature("Metal", sg,
+            bs);
+    assertEquals(1, seqCount);
+    assertEquals(2, bs.cardinality());
+    assertTrue(bs.get(1));
+    assertTrue(bs.get(2));
+
+    /*
+     * select the first four columns: Metal in seq1 2:4, seq2 4:4
+     */
+    sg.setEndRes(3);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+    assertEquals(2, seqCount);
+    assertEquals(3, bs.cardinality());
+    assertTrue(bs.get(1));
+    assertTrue(bs.get(2));
+    assertTrue(bs.get(3));
+
+    /*
+     * select column 11: Metal in seq3 only
+     */
+    sg.setStartRes(10);
+    sg.setEndRes(10);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+    assertEquals(1, seqCount);
+    assertEquals(1, bs.cardinality());
+    assertTrue(bs.get(10));
+
+    /*
+     * select columns 16-20: no Metal feature
+     */
+    sg.setStartRes(15);
+    sg.setEndRes(19);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Metal", sg, bs);
+    assertEquals(0, seqCount);
+    assertEquals(0, bs.cardinality());
+
+    /*
+     * look for a feature that isn't there
+     */
+    sg.setStartRes(0);
+    sg.setEndRes(19);
+    bs.clear();
+    seqCount = AlignViewController.findColumnsWithFeature("Pfam", sg, bs);
+    assertEquals(0, seqCount);
+    assertEquals(0, bs.cardinality());
+  }
+}
index cd8a1e3..2e0793e 100644 (file)
@@ -451,4 +451,30 @@ public class AlignedCodonFrameTest
     assertArrayEquals(new int[] { 2, 2 },
             acf.getMappedRegion(seq2, seq1, 6));
   }
+
+  /**
+   * Tests for addMap. See also tests for MapList.addMapList
+   */
+  @Test(groups = { "Functional" })
+  public void testAddMap()
+  {
+    final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
+    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);
+    acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+    assertEquals(1, acf.getMappingsFromSequence(seq1).size());
+    Mapping before = acf.getMappingsFromSequence(seq1).get(0);
+
+    /*
+     * add the same map again, verify it doesn't get duplicated
+     */
+    acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
+    assertEquals(1, acf.getMappingsFromSequence(seq1).size());
+    assertSame(before, acf.getMappingsFromSequence(seq1).get(0));
+  }
 }
index 271162b..1aff519 100644 (file)
@@ -219,4 +219,65 @@ public class AlignmentAnnotationTests
     assertEquals(1, ann.annotations[1].value, 0.001);
     assertEquals(2, ann.annotations[2].value, 0.001);
   }
-}
+
+  /**
+   * Test the method that defaults rna symbol to the one matching the preceding
+   * unmatched opening bracket (if any)
+   */
+  @Test(groups = { "Functional" })
+  public void testGetDefaultRnaHelixSymbol()
+  {
+    AlignmentAnnotation ann = new AlignmentAnnotation("SS",
+            "secondary structure", null);
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+    Annotation[] anns = new Annotation[20];
+    ann.annotations = anns;
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
+    assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
+    assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
+    assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
+
+    /*
+     * .(.[.{.<.}.>.).].
+     */
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    anns[3] = new Annotation("[", "S", '[', 0f);
+    anns[5] = new Annotation("{", "S", '{', 0f);
+    anns[7] = new Annotation("<", "S", '<', 0f);
+    anns[9] = new Annotation("}", "S", '}', 0f);
+    anns[11] = new Annotation(">", "S", '>', 0f);
+    anns[13] = new Annotation(")", "S", ')', 0f);
+    anns[15] = new Annotation("]", "S", ']', 0f);
+
+    String expected = "(())]]}}>>>>]]]](";
+    for (int i = 0; i < expected.length(); i++)
+    {
+      assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+              ann.getDefaultRnaHelixSymbol(i));
+    }
+
+    /*
+     * .(.[.(.).{.}.<.].D.
+     */
+    anns[1] = new Annotation("(", "S", '(', 0f);
+    anns[3] = new Annotation("[", "S", '[', 0f);
+    anns[5] = new Annotation("(", "S", '(', 0f);
+    anns[7] = new Annotation(")", "S", ')', 0f);
+    anns[9] = new Annotation("{", "S", '{', 0f);
+    anns[11] = new Annotation("}", "S", '}', 0f);
+    anns[13] = new Annotation("<", "S", '>', 0f);
+    anns[15] = new Annotation("]", "S", ']', 0f);
+    anns[17] = new Annotation("D", "S", 'D', 0f);
+
+    expected = "(())]]))]]}}]]>>>>dd";
+    for (int i = 0; i < expected.length(); i++)
+    {
+      assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+              ann.getDefaultRnaHelixSymbol(i));
+    }
+  }
+}
\ No newline at end of file
index 5a45176..7958e9b 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.AppletFormatAdapter;
 import jalview.io.FormatAdapter;
 import jalview.util.MapList;
@@ -37,6 +38,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;
 
@@ -101,6 +103,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.
@@ -217,7 +686,7 @@ public class AlignmentTest
    * 
    * @throws IOException
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Functional" }, enabled = true)
   // TODO review / update this test after redesign of alignAs method
   public void testAlignAs_cdnaAsProtein() throws IOException
   {
@@ -232,7 +701,7 @@ public class AlignmentTest
      * Realign DNA; currently keeping existing gaps in introns only
      */
     ((Alignment) al1).alignAs(al2, false, true);
-    assertEquals("ACG---GCUCCA------ACT", al1.getSequenceAt(0)
+    assertEquals("ACG---GCUCCA------ACT---", al1.getSequenceAt(0)
             .getSequenceAsString());
     assertEquals("---CGT---TAACGA---AGT---", al1.getSequenceAt(1)
             .getSequenceAsString());
@@ -243,7 +712,7 @@ public class AlignmentTest
    * 
    * @throws IOException
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Functional" }, enabled = true)
   // TODO review / update this test after redesign of alignAs method
   public void testAlignAs_cdnaAsProtein_singleSequence() throws IOException
   {
@@ -315,7 +784,12 @@ public class AlignmentTest
       acf.addMap(seqFrom, seqTo, ml);
     }
 
+    /*
+     * not sure whether mappings 'belong' or protein or nucleotide
+     * alignment, so adding to both ;~)
+     */
     alFrom.addCodonFrame(acf);
+    alTo.addCodonFrame(acf);
   }
 
   /**
@@ -398,6 +872,8 @@ public class AlignmentTest
     // TODO should the copy constructor copy the dataset?
     // or make a new one referring to the same dataset sequences??
     assertNull(copy.getDataset());
+    // TODO test metadata is copied when AlignmentI is a dataset
+
     // assertArrayEquals(copy.getDataset().getSequencesArray(), protein
     // .getDataset().getSequencesArray());
   }
@@ -436,8 +912,7 @@ public class AlignmentTest
     // TODO promote this method to AlignmentI
     ((Alignment) protein).createDatasetAlignment();
 
-    // TODO this method should return AlignmentI not Alignment !!
-    Alignment ds = protein.getDataset();
+    AlignmentI ds = protein.getDataset();
 
     // side-effect: dataset created on second sequence
     assertNotNull(protein.getSequenceAt(1).getDatasetSequence());
@@ -454,6 +929,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()
   {
@@ -477,6 +1006,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");
@@ -504,4 +1055,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 0245b15..ec528c5 100644 (file)
@@ -24,8 +24,12 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 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;
@@ -66,6 +70,9 @@ public class ColumnSelectionTest
 
     // removing an element in the list removes it
     cs.removeElement(2);
+    // ...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));
   }
@@ -93,6 +100,84 @@ public class ColumnSelectionTest
     assertEquals(2, cs.findColumnPosition(5));
   }
 
+  /**
+   * Test the code used to locate the reference sequence ruler origin
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateVisibleBoundsofSequence()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+    assertEquals(2, seq.findIndex(seq.getStart()));
+
+    // no hidden columns
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    // hidden column on gap after end of sequence - should not affect bounds
+    cs.hideColumns(13);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hidden column on gap before beginning of sequence - should vis bounds by
+    // one
+    cs.hideColumns(0);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
+                seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hide columns around most of sequence - leave one residue remaining
+    cs.hideColumns(1, 3);
+    cs.hideColumns(6, 11);
+    assertEquals("-D",
+            cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
+    assertEquals(
+            Arrays.toString(new int[] { 1, 1, 3, 3,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+    cs.revealAllHiddenColumns();
+
+    // hide whole sequence - should just get location of hidden region
+    // containing sequence
+    cs.hideColumns(1, 11);
+    assertEquals(
+            Arrays.toString(new int[] { 0, 1, 0, 0,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+  }
+
+  @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") });
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideInsertionsFor(al.getSequenceAt(0));
+    assertEquals(
+            "G",
+            ""
+                    + al.getSequenceAt(0).getCharAt(
+                            cs.adjustForHiddenColumns(9)));
+
+  }
+
   @Test(groups = { "Functional" })
   public void testHideColumns()
   {
@@ -248,10 +333,14 @@ public class ColumnSelectionTest
    * this fails, HideSelectedColumns may also fail
    */
   @Test(groups = { "Functional" })
-  public void testgetSelectedRanges()
+  public void testGetSelectedRanges()
   {
+    /*
+     * getSelectedRanges returns ordered columns regardless
+     * of the order in which they are added
+     */
     ColumnSelection cs = new ColumnSelection();
-    int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
+    int[] sel = { 4, 3, 7, 21, 9, 20, 8, 22, 2 };
     for (int col : sel)
     {
       cs.addElement(col);
@@ -401,4 +490,265 @@ public class ColumnSelectionTest
     cs.addElement(0);
     assertEquals(0, cs.getMin());
   }
+
+  @Test(groups = { "Functional" })
+  public void testEquals()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
+    cs.addElement(513);
+    cs.addElement(1);
+    cs.hideColumns(3);
+    cs.hideColumns(7);
+    cs.hideColumns(5, 9);
+
+    // same selections added in a different order
+    ColumnSelection cs2 = new ColumnSelection();
+    cs2.addElement(1);
+    cs2.addElement(513);
+    cs2.addElement(0);
+
+    // with no hidden columns
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    // with hidden columns added in a different order
+    cs2.hideColumns(6, 9);
+    cs2.hideColumns(5, 8);
+    cs2.hideColumns(3);
+
+    assertTrue(cs.equals(cs2));
+    assertTrue(cs.equals(cs));
+    assertTrue(cs2.equals(cs));
+    assertTrue(cs2.equals(cs2));
+
+    cs2.addElement(12);
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    cs2.removeElement(12);
+    assertTrue(cs.equals(cs2));
+
+    cs2.hideColumns(88);
+    assertFalse(cs.equals(cs2));
+    /*
+     * unhiding a column adds it to selection!
+     */
+    cs2.revealHiddenColumns(88);
+    assertFalse(cs.equals(cs2));
+    cs.addElement(88);
+    assertTrue(cs.equals(cs2));
+  }
+
+  /**
+   * Test the method that returns selected columns, in the order in which they
+   * were added
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSelected()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 4, 3, 7, 21 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertEquals("[4, 3, 7, 21]", selected.toString());
+
+    /*
+     * getSelected returns a read-only view of the list
+     * verify the view follows any changes in it
+     */
+    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)
+    {
+      // expected
+    }
+    try
+    {
+      selected.remove(3);
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
+    {
+      // expected
+    }
+    try
+    {
+      Collections.sort(selected);
+      fail("expected exception");
+    } catch (UnsupportedOperationException e)
+    {
+      // expected
+    }
+  }
+
+  /**
+   * 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.addElement(2);
+
+    /*
+     * 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")
+  public void testMarkColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(5); // this will be cleared
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    assertTrue(cs.markColumns(toMark, 3, 8, false, false, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(2, selected.size());
+    assertTrue(selected.contains(3));
+    assertTrue(selected.contains(6));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_extend()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(1);
+    cs.addElement(5);
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * extending selection of {3, 6} should leave {1, 3, 5, 6} selected
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, false, true, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(1));
+    assertTrue(selected.contains(3));
+    assertTrue(selected.contains(5));
+    assertTrue(selected.contains(6));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_invert()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(5); // this will be cleared
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * inverted selection of {3, 6} should select {4, 5, 7, 8}
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, true, false, false));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(4));
+    assertTrue(selected.contains(5));
+    assertTrue(selected.contains(7));
+    assertTrue(selected.contains(8));
+  }
+
+  @Test(groups = "Functional")
+  public void testMarkColumns_toggle()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(1); // outside change range
+    cs.addElement(3);
+    cs.addElement(4);
+    cs.addElement(10); // outside change range
+    BitSet toMark = new BitSet();
+    toMark.set(1);
+    toMark.set(3);
+    toMark.set(6);
+    toMark.set(9);
+
+    /*
+     * toggling state of {3, 6} should leave {1, 4, 6, 10} selected
+     */
+    assertTrue(cs.markColumns(toMark, 3, 8, false, false, true));
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    assertTrue(selected.contains(1));
+    assertTrue(selected.contains(4));
+    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 b3376a6..87e7082 100644 (file)
@@ -20,7 +20,9 @@
  */
 package jalview.datamodel;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.util.MapList;
@@ -60,4 +62,158 @@ public class DBRefEntryTest
     assertTrue(ref1.equalRef(ref2));
     assertTrue(ref2.equalRef(ref1));
   }
+
+  /**
+   * Tests for the method that may update a DBRefEntry from another with a
+   * mapping or 'real' version
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdateFrom()
+  {
+    DBRefEntry ref1 = new DBRefEntry("UNIPROT", "1", "V71633");
+
+    assertFalse(ref1.updateFrom(null));
+
+    /*
+     * equivalent other dbref
+     */
+    DBRefEntry ref2 = new DBRefEntry("uniprot", "1", "v71633");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("UNIPROT", ref1.getSource()); // unchanged
+    assertEquals("V71633", ref1.getAccessionId()); // unchanged
+
+    /*
+     * ref1 has no mapping, acquires mapping from ref2
+     */
+    Mapping map = new Mapping(new MapList(new int[] { 1, 3 }, new int[] {
+        1, 1 }, 3, 1));
+    ref2.setMap(map);
+    assertTrue(ref1.updateFrom(ref2));
+    assertSame(map, ref1.getMap()); // null mapping updated
+
+    /*
+     * ref1 has a mapping, does not acquire mapping from ref2
+     */
+    ref2.setMap(new Mapping(map));
+    assertTrue(ref1.updateFrom(ref2));
+    assertSame(map, ref1.getMap()); // non-null mapping not updated
+
+    /*
+     * ref2 has a different source, accession or version
+     */
+    ref2.setSource("pdb");
+    assertFalse(ref1.updateFrom(ref2));
+    ref2.setSource(ref1.getSource());
+    ref2.setAccessionId("P12345");
+    assertFalse(ref1.updateFrom(ref2));
+    ref2.setAccessionId(ref1.getAccessionId());
+    ref1.setVersion("2");
+    assertFalse(ref1.updateFrom(ref2));
+
+    /*
+     * a non-null version supersedes "0" or "source:0"
+     */
+    ref2.setVersion(null);
+    assertFalse(ref1.updateFrom(ref2));
+    assertEquals("2", ref1.getVersion());
+    ref2.setVersion("3");
+    ref1.setVersion("0");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("3", ref1.getVersion());
+    ref1.setVersion("UNIPROT:0");
+    assertTrue(ref1.updateFrom(ref2));
+    assertEquals("3", ref1.getVersion());
+
+    /*
+     * version "source:n" with n>0 is not superseded
+     */
+    ref1.setVersion("UNIPROT:1");
+    assertFalse(ref1.updateFrom(ref2));
+    assertEquals("UNIPROT:1", ref1.getVersion());
+
+    /*
+     * version "10" is not superseded
+     */
+    ref1.setVersion("10");
+    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());
+  }
 }
diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java
new file mode 100644 (file)
index 0000000..42fc58b
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNotSame;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import jalview.gui.AlignViewport;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class HiddenSequencesTest
+{
+  static int SEQ_COUNT = 10;
+
+  SequenceI[] seqs;
+
+  /**
+   * Set up an alignment of 10 sequences
+   */
+  @BeforeTest(alwaysRun = true)
+  public void setUp()
+  {
+    seqs = new SequenceI[SEQ_COUNT];
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      // sequence lengths are 1, 2, ... 10
+      seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+    }
+  }
+
+  /**
+   * Test the method that converts sequence alignment index to what it would be
+   * if all sequences were unhidden
+   */
+  @Test(groups = "Functional")
+  public void testAdjustForHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.adjustForHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.adjustForHiddenSeqs(0));
+    assertEquals(2, hs.adjustForHiddenSeqs(1));
+    assertEquals(3, hs.adjustForHiddenSeqs(2));
+    assertEquals(4, hs.adjustForHiddenSeqs(3));
+    assertEquals(7, hs.adjustForHiddenSeqs(4));
+    assertEquals(8, hs.adjustForHiddenSeqs(5));
+    assertEquals(9, hs.adjustForHiddenSeqs(6));
+  }
+
+  /**
+   * Test the method that increments the internal array size if a sequence is
+   * added to the alignment (ugh this should not be exposed to the light of day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceAdded()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide one sequence
+    hs.hideSequence(seqs[3]);
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * add a sequence to the alignment
+     * - the safe way to call hs.adjustHeightSequenceAdded!
+     * (implementation depends on alignment height having
+     * been already updated for the added sequence)
+     */
+    al.addSequence(new Sequence("a", "b"));
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
+    assertEquals(SEQ_COUNT + 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that decrements the internal array size if a sequence is
+   * deleted from the alignment (ugh this should not be exposed to the light of
+   * day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceDeleted()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide two sequences
+    hs.hideSequence(seqs[3]);
+    hs.hideSequence(seqs[5]);
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertTrue(hs.isHidden(seqs[5]));
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * delete a visible sequence from the alignment
+     * - the safe way to call hs.adjustHeightSequenceDeleted!
+     * (implementation depends on alignment height having
+     * been already updated for the removed sequence)
+     */
+    al.deleteSequence(seqs[2]);
+    assertEquals(2, hs.getSize());
+    // the visible alignment is unchanged:
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
+    // sequences array size has decremented:
+    assertEquals(SEQ_COUNT - 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that converts a 'full alignment' sequence index into the
+   * equivalent in the alignment with sequences hidden
+   */
+  @Test(groups = "Functional")
+  public void testFindIndexWithoutHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.findIndexWithoutHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
+    assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
+    assertEquals(2, hs.findIndexWithoutHiddenSeqs(3));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(4));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(5));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(6));
+    assertEquals(4, hs.findIndexWithoutHiddenSeqs(7));
+    assertEquals(5, hs.findIndexWithoutHiddenSeqs(8));
+    assertEquals(6, hs.findIndexWithoutHiddenSeqs(9));
+  }
+
+  /**
+   * Test the method that reconstructs (sort of) the full alignment including
+   * hidden sequences
+   */
+  @Test(groups = "Functional")
+  public void testGetFullAlignment()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertArrayEquals(seqs, al.getSequencesArray());
+    al.setProperty("a", "b");
+    al.addAnnotation(new AlignmentAnnotation("ann", "label", 12f));
+    al.setSeqrep(seqs[4]);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[8], false);
+    al.addGroup(sg);
+    ((Alignment) al).hasRNAStructure = true;
+
+    HiddenSequences hs = al.getHiddenSequences();
+    AlignmentI al2 = hs.getFullAlignment();
+    // new alignment but with original sequences
+    assertNotSame(al, al2);
+    assertArrayEquals(al.getSequencesArray(), al2.getSequencesArray());
+
+    hs.hideSequence(seqs[4]);
+    hs.hideSequence(seqs[9]);
+    al2 = hs.getFullAlignment();
+    assertNotSame(al, al2);
+    assertArrayEquals(seqs, al2.getSequencesArray());
+    assertNotNull(al2.getProperties());
+    assertSame(al.getProperties(), al2.getProperties());
+    assertNotNull(al2.getAlignmentAnnotation());
+    assertSame(al.getAlignmentAnnotation(), al2.getAlignmentAnnotation());
+    assertSame(seqs[4], al2.getSeqrep());
+    assertNotNull(al2.getGroups());
+    assertSame(al.getGroups(), al2.getGroups());
+    assertTrue(al2.hasRNAStructure());
+  }
+
+  /**
+   * Test the method that returns the hidden sequence at a given index in the
+   * full alignment
+   * 
+   * @return either the sequence (if hidden) or null (if not hidden)
+   */
+  @Test(groups = "Functional")
+  public void testGetHiddenSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertNull(hs.getHiddenSequence(0));
+    hs.hideSequence(seqs[3]);
+    assertSame(seqs[3], hs.getHiddenSequence(3));
+    assertNull(hs.getHiddenSequence(2));
+    assertNull(hs.getHiddenSequence(4));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSize()
+  {
+  }
+
+  @Test(groups = "Functional")
+  public void testGetWidth()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getWidth());
+    hs.hideSequence(seqs[6]);
+    hs.hideSequence(seqs[8]);
+    assertEquals(9, hs.getWidth());
+  }
+
+  /**
+   * Test the method that adds a sequence to the hidden sequences and deletes it
+   * from the alignment, and its converse
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertTrue(al.getSequences().contains(seqs[1]));
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+
+    /*
+     * hide the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[1]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertEquals(1, hs.getSize());
+    assertEquals(9, al.getHeight());
+    assertSame(seqs[2], al.getSequenceAt(1));
+
+    /*
+     * hide what is now the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[2]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertTrue(hs.isHidden(seqs[2]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[2]));
+    assertEquals(2, hs.getSize());
+    assertEquals(8, al.getHeight());
+
+    /*
+     * perform 'reveal' on what is now the second sequence in the alignment
+     * this should unhide the two sequences that precede it
+     */
+    List<SequenceI> revealed = hs.showSequence(1, null);
+    assertEquals(2, revealed.size());
+    assertTrue(revealed.contains(seqs[1]));
+    assertTrue(revealed.contains(seqs[2]));
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+  }
+
+  @Test(groups = "Functional")
+  public void testIsHidden()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    hs.hideSequence(seqs[7]);
+    hs.hideSequence(seqs[4]);
+    assertTrue(hs.isHidden(seqs[4]));
+    assertFalse(hs.isHidden(seqs[5]));
+    assertFalse(hs.isHidden(seqs[6]));
+    assertTrue(hs.isHidden(seqs[7]));
+    assertFalse(hs.isHidden(null));
+    assertFalse(hs.isHidden(new Sequence("", "")));
+  }
+
+  /**
+   * Test hiding and unhiding a group with a representative sequence. The
+   * representative should be left visible when the group is hidden, and
+   * included in the selected group when it is unhidden.
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence_withHiddenRepSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+
+    /*
+     * represent seqs 2-4 with seq3
+     * this hides seq2 and seq4 but not seq3
+     */
+    AlignViewport av = new AlignViewport(al);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[1], false);
+    sg.addSequence(seqs[2], false);
+    sg.addSequence(seqs[3], false);
+    av.setSelectionGroup(sg);
+
+    /*
+     * hiding group with reference sequence is done via AlignViewport
+     */
+    av.hideSequences(seqs[2], true);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(hs.isHidden(seqs[2]));
+    assertTrue(hs.isHidden(seqs[3]));
+
+    /*
+     * should now be no sequences selected in the alignment
+     */
+    assertNull(av.getSelectionGroup());
+
+    /*
+     * visible alignment is now seq0/2/4/5/6/7/8/9
+     * 'reveal sequences' at the representative sequence (index = 1)
+     * this should unhide the one above i.e. seq1
+     * and return a selection list including seq2
+     * 
+     * note have to call via AlignViewport to get the expected
+     * resulting sequence selection
+     */
+    av.showSequence(1);
+
+    /*
+     * only seq3 is now hidden
+     */
+    assertEquals(1, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    sg = av.getSelectionGroup();
+
+    /*
+     * unhidden and representative sequence selected
+     * (this behaviour may change! JAL-2133)
+     */
+    assertEquals(2, sg.getSize());
+    assertTrue(sg.getSequences().contains(seqs[1]));
+    assertTrue(sg.getSequences().contains(seqs[2]));
+    assertFalse(sg.getSequences().contains(seqs[3]));
+  }
+}
index 3131ad7..b326d90 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertSame;
 
 import jalview.util.MapList;
 
@@ -75,4 +76,18 @@ public class MappingTest
     m = new Mapping(seq, fk);
     assertEquals("[ [1, 6] [8, 13] ] 3:1 to [ [4, 7] ] Seq1", m.toString());
   }
+
+  @Test(groups = { "Functional" })
+  public void testCopyConstructor()
+  {
+    MapList ml = new MapList(new int[] { 1, 6, 8, 13 }, new int[] { 4, 7 },
+            3, 1);
+    SequenceI seq = new Sequence("seq1", "agtacg");
+    Mapping m = new Mapping(seq, ml);
+    m.setMappedFromId("abc");
+    Mapping copy = new Mapping(m);
+    assertEquals("abc", copy.getMappedFromId());
+    assertEquals(ml, copy.getMap());
+    assertSame(seq, copy.getTo());
+  }
 }
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 8a3b925..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;
@@ -34,58 +45,257 @@ public class PDBEntryTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
 
   @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;
     }
-
   }
 
 }
index ffcaa26..f9a0a4f 100644 (file)
@@ -169,7 +169,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
index 705c773..bb6581f 100644 (file)
@@ -23,6 +23,8 @@ package jalview.datamodel;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 
+import jalview.util.Comparison;
+
 import org.testng.annotations.Test;
 
 /**
@@ -30,6 +32,30 @@ import org.testng.annotations.Test;
  */
 public class SeqCigarTest
 {
+  @Test(groups = { "Functional" })
+  public void testFindPosition()
+  {
+    SequenceI oseq = new Sequence("MySeq", "ASD---ASD---ASD", 37, 45);
+    oseq.createDatasetSequence();
+    SeqCigar cs = new SeqCigar(oseq);
+    assertEquals(oseq.getSequenceAsString(), cs.getSequenceString('-'));
+    for (int c = 0, cLen = oseq.getLength(); c < cLen; c++)
+    {
+      int os_p = oseq.findPosition(c);
+      int cigar_p = cs.findPosition(c);
+      if (Comparison.isGap(oseq.getCharAt(c)))
+      {
+        assertEquals("Expected gap at position " + os_p + " column " + c,
+                -1, cigar_p);
+      }
+      else
+      {
+        assertEquals("Positions don't match for at column " + c, os_p,
+                cigar_p);
+      }
+    }
+  }
+
   /*
    * refactored 'as is' from main method
    * 
index 82b260e..2ec824d 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 95755ee..065bed7 100644 (file)
@@ -29,11 +29,15 @@ import static org.testng.AssertJUnit.assertTrue;
 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;
 import java.util.Vector;
 
+import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -62,6 +66,30 @@ public class SequenceTest
     assertEquals("Gap interval 2 end wrong", 8, gapInt.get(1)[1]);
   }
 
+  @Test(groups = ("Functional"))
+  public void testIsProtein()
+  {
+    // test Protein
+    assertTrue(new Sequence("prot", "ASDFASDFASDF").isProtein());
+    // test DNA
+    assertFalse(new Sequence("prot", "ACGTACGTACGT").isProtein());
+    // test RNA
+    SequenceI sq = new Sequence("prot", "ACGUACGUACGU");
+    assertFalse(sq.isProtein());
+    // change sequence, should trigger an update of cached result
+    sq.setSequence("ASDFASDFADSF");
+    assertTrue(sq.isProtein());
+    /*
+     * in situ change of sequence doesn't change hashcode :-O
+     * (sequence should not expose internal implementation)
+     */
+    for (int i = 0; i < sq.getSequence().length; i++)
+    {
+      sq.getSequence()[i] = "acgtu".charAt(i % 5);
+    }
+    assertTrue(sq.isProtein()); // but it isn't
+  }
+
   @Test(groups = { "Functional" })
   public void testGetAnnotation()
   {
@@ -83,8 +111,7 @@ public class SequenceTest
   {
     AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
             1f);
-    AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
-            1f);
+    addAnnotation("label2", "desc2", "calcId2", 1f);
     AlignmentAnnotation ann3 = addAnnotation("label1", "desc3", "calcId3",
             1f);
     AlignmentAnnotation[] anns = seq.getAnnotation("label1");
@@ -106,16 +133,15 @@ public class SequenceTest
   @Test(groups = { "Functional" })
   public void testGetAlignmentAnnotations_forCalcIdAndLabel()
   {
-    AlignmentAnnotation ann1 = addAnnotation("label1", "desc1", "calcId1",
-            1f);
+    addAnnotation("label1", "desc1", "calcId1", 1f);
     AlignmentAnnotation ann2 = addAnnotation("label2", "desc2", "calcId2",
             1f);
-    AlignmentAnnotation ann3 = addAnnotation("label2", "desc3", "calcId3",
-            1f);
+    addAnnotation("label2", "desc3", "calcId3", 1f);
     AlignmentAnnotation ann4 = addAnnotation("label2", "desc3", "calcId2",
             1f);
-    AlignmentAnnotation ann5 = addAnnotation("label5", "desc3", null, 1f);
-    AlignmentAnnotation ann6 = addAnnotation(null, "desc3", "calcId3", 1f);
+    addAnnotation("label5", "desc3", null, 1f);
+    addAnnotation(null, "desc3", "calcId3", 1f);
+
     List<AlignmentAnnotation> anns = seq.getAlignmentAnnotations("calcId2",
             "label2");
     assertEquals(2, anns.size());
@@ -313,6 +339,9 @@ public class SequenceTest
     /*
      * SequenceFeature on sequence and dataset sequence; returns that on
      * sequence
+     * 
+     * Note JAL-2046: spurious: we have no use case for this at the moment.
+     * This test also buggy - as sf2.equals(sf), no new feature is added
      */
     SequenceFeature sf2 = new SequenceFeature();
     sq.getDatasetSequence().addSequenceFeature(sf2);
@@ -322,18 +351,30 @@ public class SequenceTest
 
     /*
      * SequenceFeature on dataset sequence only
+     * Note JAL-2046: spurious: we have no use case for setting a non-dataset sequence's feature array to null at the moment.
      */
     sq.setSequenceFeatures(null);
-    sfs = sq.getSequenceFeatures();
-    assertEquals(1, sfs.length);
-    assertSame(sf2, sfs[0]);
+    assertNull(sq.getDatasetSequence().getSequenceFeatures());
 
     /*
      * Corrupt case - no SequenceFeature, dataset's dataset is the original
      * sequence. Test shows no infinite loop results.
      */
     sq.getDatasetSequence().setSequenceFeatures(null);
-    sq.getDatasetSequence().setDatasetSequence(sq); // loop!
+    /**
+     * is there a usecase for this ? setDatasetSequence should throw an error if
+     * this actually occurs.
+     */
+    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());
   }
 
@@ -378,6 +419,20 @@ public class SequenceTest
   }
 
   /**
+   * test createDatasetSequence behaves to doc
+   */
+  @Test(groups = { "Functional" })
+  public void testCreateDatasetSequence()
+  {
+    SequenceI sq = new Sequence("my", "ASDASD");
+    assertNull(sq.getDatasetSequence());
+    SequenceI rds = sq.createDatasetSequence();
+    assertNotNull(rds);
+    assertNull(rds.getDatasetSequence());
+    assertEquals(sq.getDatasetSequence(), rds);
+  }
+
+  /**
    * Test for deriveSequence applied to a sequence with a dataset
    */
   @Test(groups = { "Functional" })
@@ -390,16 +445,114 @@ public class SequenceTest
     sq.setStart(3);
     sq.setEnd(4);
 
+    sq.setDescription("Test sequence description..");
+    sq.setVamsasId("TestVamsasId");
+    sq.addDBRef(new DBRefEntry("PDB", "version0", "1TST"));
+
+    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", "version3", "3PDB")); // should do nothing
+    sq.getDatasetSequence().addDBRef(
+            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);
+
+    /*
+     * 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));
+    annotsList.add(new Annotation("A", "A", 'X', 0.1f));
+    Annotation[] annots = annotsList.toArray(new Annotation[0]);
+    sq.addAlignmentAnnotation(new AlignmentAnnotation("Test annot",
+            "Test annot description", annots));
+    sq.getDatasetSequence().addAlignmentAnnotation(
+            new AlignmentAnnotation("Test annot", "Test annot description",
+                    annots));
+    Assert.assertEquals(sq.getDescription(), "Test sequence description..");
+    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, 5); // same
+                                                                        // as
+                                                                        // sq.getDBRefs()
+    Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries().size(),
+            4);
+    Assert.assertNotNull(sq.getDatasetSequence().getAnnotation());
+
     Sequence derived = (Sequence) sq.deriveSequence();
+
+    Assert.assertEquals(derived.getDescription(),
+            "Test sequence description..");
+    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, 5);
+    Assert.assertEquals(derived.getDatasetSequence().getAllPDBEntries()
+            .size(), 4);
+    Assert.assertNotNull(derived.getDatasetSequence().getAnnotation());
+
     assertEquals("CD", derived.getSequenceAsString());
     assertSame(sq.getDatasetSequence(), derived.getDatasetSequence());
 
     assertNull(sq.sequenceFeatures);
-    // assertNull(derived.sequenceFeatures);
+    assertNull(derived.sequenceFeatures);
+    // derived sequence should access dataset sequence features
     assertNotNull(sq.getSequenceFeatures());
-    // derived sequence has a copy of the sequence features (is this right?)
     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());
+
   }
 
   /**
@@ -444,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());
@@ -471,6 +624,8 @@ public class SequenceTest
     seq1.setDescription("description");
     seq1.addAlignmentAnnotation(new AlignmentAnnotation("label", "desc",
             1.3d));
+    // JAL-2046 - what is the contract for using a derived sequence's
+    // addSequenceFeature ?
     seq1.addSequenceFeature(new SequenceFeature("type", "desc", 22, 33,
             12.4f, "group"));
     seq1.addPDBId(new PDBEntry("1A70", "B", Type.PDB, "File"));
@@ -518,7 +673,15 @@ public class SequenceTest
     // copy has a copy of the sequence feature:
     SequenceFeature[] sfs = copy.getSequenceFeatures();
     assertEquals(1, sfs.length);
-    assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
+    if (seq1.getDatasetSequence() != null
+            && copy.getDatasetSequence() == seq1.getDatasetSequence())
+    {
+      assertTrue(sfs[0] == seq1.getSequenceFeatures()[0]);
+    }
+    else
+    {
+      assertFalse(sfs[0] == seq1.getSequenceFeatures()[0]);
+    }
     assertTrue(sfs[0].equals(seq1.getSequenceFeatures()[0]));
 
     // copy has a copy of the PDB entry
@@ -537,4 +700,304 @@ public class SequenceTest
     assertEquals(' ', sq.getCharAt(5));
     assertEquals(' ', sq.getCharAt(-1));
   }
+
+  /**
+   * Tests for adding (or updating) dbrefs
+   * 
+   * @see DBRefEntry#updateFrom(DBRefEntry)
+   */
+  @Test(groups = { "Functional" })
+  public void testAddDBRef()
+  {
+    SequenceI sq = new Sequence("", "abcde");
+    assertNull(sq.getDBRefs());
+    DBRefEntry dbref = new DBRefEntry("Uniprot", "1", "P00340");
+    sq.addDBRef(dbref);
+    assertEquals(1, sq.getDBRefs().length);
+    assertSame(dbref, sq.getDBRefs()[0]);
+
+    /*
+     * change of version - new entry
+     */
+    DBRefEntry dbref2 = new DBRefEntry("Uniprot", "2", "P00340");
+    sq.addDBRef(dbref2);
+    assertEquals(2, sq.getDBRefs().length);
+    assertSame(dbref, sq.getDBRefs()[0]);
+    assertSame(dbref2, sq.getDBRefs()[1]);
+
+    /*
+     * matches existing entry - not added
+     */
+    sq.addDBRef(new DBRefEntry("UNIPROT", "1", "p00340"));
+    assertEquals(2, sq.getDBRefs().length);
+
+    /*
+     * different source = new entry
+     */
+    DBRefEntry dbref3 = new DBRefEntry("UniRef", "1", "p00340");
+    sq.addDBRef(dbref3);
+    assertEquals(3, sq.getDBRefs().length);
+    assertSame(dbref3, sq.getDBRefs()[2]);
+
+    /*
+     * different ref = new entry
+     */
+    DBRefEntry dbref4 = new DBRefEntry("UniRef", "1", "p00341");
+    sq.addDBRef(dbref4);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref4, sq.getDBRefs()[3]);
+
+    /*
+     * matching ref with a mapping - map updated
+     */
+    DBRefEntry dbref5 = new DBRefEntry("UniRef", "1", "p00341");
+    Mapping map = new Mapping(new MapList(new int[] { 1, 3 }, new int[] {
+        1, 1 }, 3, 1));
+    dbref5.setMap(map);
+    sq.addDBRef(dbref5);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref4, sq.getDBRefs()[3]);
+    assertSame(map, dbref4.getMap());
+
+    /*
+     * 'real' version replaces "0" version
+     */
+    dbref2.setVersion("0");
+    DBRefEntry dbref6 = new DBRefEntry(dbref2.getSource(), "3",
+            dbref2.getAccessionId());
+    sq.addDBRef(dbref6);
+    assertEquals(4, sq.getDBRefs().length);
+    assertSame(dbref2, sq.getDBRefs()[1]);
+    assertEquals("3", dbref2.getVersion());
+
+    /*
+     * 'real' version replaces "source:0" version
+     */
+    dbref3.setVersion("Uniprot:0");
+    DBRefEntry dbref7 = new DBRefEntry(dbref3.getSource(), "3",
+            dbref3.getAccessionId());
+    sq.addDBRef(dbref7);
+    assertEquals(4, sq.getDBRefs().length);
+    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 9fffc45..8ed5cc4 100644 (file)
@@ -1,12 +1,38 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertSame;
 
-import jalview.util.MappingUtils;
+import jalview.analysis.SequenceIdMatcher;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
 
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Vector;
+import java.util.List;
 
 import org.testng.annotations.Test;
 
@@ -18,291 +44,211 @@ public class EmblEntryTest
     EmblEntry testee = new EmblEntry();
 
     /*
-     * Make a (CDS) Feature with 4 locations
+     * Make a (CDS) Feature with 5 locations
      */
     EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
-
-    /*
-     * single range [10-20]
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * complement range [30-40]
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    b2 = new BasePosition();
-    b2.setPos("40");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * join range [50-60], [70-80]
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("70");
-    b2 = new BasePosition();
-    b2.setPos("80");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-
-    /*
-     * complement range [90-100], [110-120]
-     * this should be the same as complement(join(90..100,110.120))
-     * which is "join 90-100 and 110-120, then complement"
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("90");
-    b2 = new BasePosition();
-    b2.setPos("100");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("110");
-    b2 = new BasePosition();
-    b2.setPos("120");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    cds.setLocation("join(10..20,complement(30..40),50..60,70..80,complement(110..120))");
 
     int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 40, 30, 50, 60, 70, 80, 120, 110, 100, 90]",
+    assertEquals("[10, 20, 40, 30, 50, 60, 70, 80, 120, 110]",
             Arrays.toString(exons));
   }
 
   @Test(groups = "Functional")
-  public void testGetCdsRanges_badData()
+  public void testParseCodingFeature()
   {
-    EmblEntry testee = new EmblEntry();
+    // not the whole sequence but enough for this test...
+    List<SequenceI> peptides = new ArrayList<SequenceI>();
+    SequenceIdMatcher matcher = new SequenceIdMatcher(peptides);
+    EmblFile ef = EmblTestHelper.getEmblFile();
+    assertEquals(1, ef.getEntries().size());
+    EmblEntry testee = ef.getEntries().get(0);
+    String sourceDb = "EMBL";
+    SequenceI dna = testee.makeSequence(sourceDb);
+
+    /*
+     * parse three CDS features, with two/one/no Uniprot cross-refs
+     */
+    for (EmblFeature feature : ef.getEntries().get(0).getFeatures())
+    {
+      if ("CDS".equals(feature.getName()))
+      {
+        testee.parseCodingFeature(feature, sourceDb, dna, peptides, matcher);
+      }
+    }
+
+    /*
+     * peptides should now have five entries:
+     * EMBL product and two Uniprot accessions for the first CDS / translation
+     * EMBL product and one Uniprot accession for the second CDS / "
+     * EMBL product only for the third
+     */
+    assertEquals(6, peptides.size());
+    assertEquals("CAA30420.1", peptides.get(0).getName());
+    assertEquals("MLCF", peptides.get(0).getSequenceAsString());
+    assertEquals("UNIPROT|B0BCM4", peptides.get(1).getName());
+    assertEquals("MLCF", peptides.get(1).getSequenceAsString());
+    assertEquals("UNIPROT|P0CE20", peptides.get(2).getName());
+    assertEquals("MLCF", peptides.get(2).getSequenceAsString());
+    assertEquals("CAA30421.1", peptides.get(3).getName());
+    assertEquals("MSSS", peptides.get(3).getSequenceAsString());
+    assertEquals("UNIPROT|B0BCM3", peptides.get(4).getName());
+    assertEquals("MSSS", peptides.get(4).getSequenceAsString());
+    assertEquals("CAA12345.6", peptides.get(5).getName());
+    assertEquals("MSS", peptides.get(5).getSequenceAsString());
+
+    /*
+     * verify dna sequence has dbrefs with CDS mappings to the peptide 'products'
+     */
+    MapList cds1Map = new MapList(new int[] { 57, 46 }, new int[] { 1, 4 },
+            3, 1);
+    MapList cds2Map = new MapList(new int[] { 4, 15 }, new int[] { 1, 4 },
+            3, 1);
+    MapList cds3Map = new MapList(new int[] { 4, 6, 10, 15 }, new int[] {
+        1, 3 }, 3, 1);
+    DBRefEntry[] dbrefs = dna.getDBRefs();
+    assertEquals(4, dbrefs.length);
+    DBRefEntry dbRefEntry = dbrefs[0];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("B0BCM4", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(1), dbRefEntry.getMap().getTo());
+    assertEquals(cds1Map, dbRefEntry.getMap().getMap());
+
+    dbRefEntry = dbrefs[1];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("P0CE20", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(2), dbRefEntry.getMap().getTo());
+    assertEquals(cds1Map, dbRefEntry.getMap().getMap());
+
+    dbRefEntry = dbrefs[2];
+    assertEquals("UNIPROT", dbRefEntry.getSource());
+    assertEquals("B0BCM3", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(4), dbRefEntry.getMap().getTo());
+    assertEquals(cds2Map, dbRefEntry.getMap().getMap());
+
+    dbRefEntry = dbrefs[3];
+    assertEquals("EMBLCDSPROTEIN", dbRefEntry.getSource());
+    assertEquals("CAA12345.6", dbRefEntry.getAccessionId());
+    assertSame(peptides.get(5), dbRefEntry.getMap().getTo());
+    assertEquals(cds3Map, dbRefEntry.getMap().getMap());
+
+    /*
+     * verify peptides have dbrefs
+     * - to EMBL sequence (with inverse 1:3 cds mapping)
+     * - to EMBLCDS (with 1:3 mapping)
+     * - direct (no mapping) to other protein accessions
+     */
+    MapList proteinToCdsMap1 = new MapList(new int[] { 1, 4 }, new int[] {
+        1, 12 }, 1, 3);
+    MapList proteinToCdsMap2 = new MapList(new int[] { 1, 3 }, new int[] {
+        1, 9 }, 1, 3);
+
+    // dbrefs for first CDS EMBL product CAA30420.1
+    dbrefs = peptides.get(0).getDBRefs();
+    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());
+    assertEquals(proteinToCdsMap1, dbrefs[1].getMap().getMap());
+    assertEquals(DBRefSource.EMBLCDSProduct, dbrefs[2].getSource());
+    assertEquals("CAA30420.1", dbrefs[2].getAccessionId());
+    assertNull(dbrefs[2].getMap());
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "2.1", "B0BCM4"),
+            dbrefs[3]);
+    assertNull(dbrefs[3].getMap());
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "0", "P0CE20"),
+            dbrefs[4]);
+    assertNull(dbrefs[4].getMap());
+
+    // dbrefs for first CDS first Uniprot xref
+    dbrefs = peptides.get(1).getDBRefs();
+    assertEquals(2, dbrefs.length);
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "2.1", "B0BCM4"),
+            dbrefs[0]);
+    assertNull(dbrefs[0].getMap());
+    assertEquals(DBRefSource.EMBL, dbrefs[1].getSource());
+    assertEquals("X07547", dbrefs[1].getAccessionId());
+    assertEquals(cds1Map.getInverse(), dbrefs[1].getMap().getMap());
+
+    // dbrefs for first CDS second Uniprot xref
+    dbrefs = peptides.get(2).getDBRefs();
+    assertEquals(2, dbrefs.length);
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "0", "P0CE20"),
+            dbrefs[0]);
+    assertNull(dbrefs[0].getMap());
+    assertEquals(DBRefSource.EMBL, dbrefs[1].getSource());
+    assertEquals("X07547", dbrefs[1].getAccessionId());
+    assertEquals(cds1Map.getInverse(), dbrefs[1].getMap().getMap());
+
+    // dbrefs for second CDS EMBL product CAA30421.1
+    dbrefs = peptides.get(3).getDBRefs();
+    assertEquals(4, dbrefs.length);
+    assertEquals(DBRefSource.EMBL, dbrefs[0].getSource());
+    assertEquals("CAA30421.1", dbrefs[0].getAccessionId());
+    assertEquals(cds2Map.getInverse(), dbrefs[0].getMap().getMap());
+    assertEquals(DBRefSource.EMBLCDS, dbrefs[1].getSource());
+    assertEquals("CAA30421.1", dbrefs[1].getAccessionId());
+    assertEquals(proteinToCdsMap1, dbrefs[1].getMap().getMap());
+    assertEquals(DBRefSource.EMBLCDSProduct, dbrefs[2].getSource());
+    assertEquals("CAA30421.1", dbrefs[2].getAccessionId());
+    assertNull(dbrefs[2].getMap());
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "0", "B0BCM3"),
+            dbrefs[3]);
+    assertNull(dbrefs[3].getMap());
+
+    // dbrefs for second CDS second Uniprot xref
+    dbrefs = peptides.get(4).getDBRefs();
+    assertEquals(2, dbrefs.length);
+    assertEquals(new DBRefEntry(DBRefSource.UNIPROT, "0", "B0BCM3"),
+            dbrefs[0]);
+    assertNull(dbrefs[0].getMap());
+    assertEquals(DBRefSource.EMBL, dbrefs[1].getSource());
+    assertEquals("X07547", dbrefs[1].getAccessionId());
+    assertEquals(cds2Map.getInverse(), dbrefs[1].getMap().getMap());
+
+    // dbrefs for third CDS inferred EMBL product CAA12345.6
+    dbrefs = peptides.get(5).getDBRefs();
+    assertEquals(3, dbrefs.length);
+    assertEquals(DBRefSource.EMBL, dbrefs[0].getSource());
+    assertEquals("CAA12345.6", dbrefs[0].getAccessionId());
+    assertEquals(cds3Map.getInverse(), dbrefs[0].getMap().getMap());
+    assertEquals(DBRefSource.EMBLCDS, dbrefs[1].getSource());
+    assertEquals("CAA12345.6", dbrefs[1].getAccessionId());
+    assertEquals(proteinToCdsMap2, dbrefs[1].getMap().getMap());
+    assertEquals(DBRefSource.EMBLCDSProduct, dbrefs[2].getSource());
+    assertEquals("CAA12345.6", dbrefs[2].getAccessionId());
+    assertNull(dbrefs[2].getMap());
+  }
 
-    /*
-     * Make a (CDS) Feature with 4 locations
-     */
-    EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
+  @Test(groups = "Functional")
+  public void testAdjustForProteinLength()
+  {
+    int[] exons = new int[] { 11, 15, 21, 25, 31, 38 }; // 18 bp
 
-    /*
-     * single range [10-20]
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    // exact length match:
+    assertSame(exons, EmblEntry.adjustForProteinLength(6, exons));
 
-    /*
-     * single range with missing end position - should be skipped
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    locElement.setBasePositions(new BasePosition[] { b1 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    // match if we assume exons include stop codon not in protein:
+    assertSame(exons, EmblEntry.adjustForProteinLength(5, exons));
 
-    /*
-     * single range with extra base position - should be skipped
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    locElement.setBasePositions(new BasePosition[] { b1, b1, b1 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    // truncate last exon by 6bp
+    int[] truncated = EmblEntry.adjustForProteinLength(4, exons);
+    assertEquals("[11, 15, 21, 25, 31, 32]", Arrays.toString(truncated));
 
-    /*
-     * single valid range [50-60] to finish
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
+    // remove last exon and truncate preceding by 1bp
+    truncated = EmblEntry.adjustForProteinLength(3, exons);
+    assertEquals("[11, 15, 21, 24]", Arrays.toString(truncated));
 
-    int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 50, 60]", Arrays.toString(exons));
-  }
+    // exact removal of exon case:
+    exons = new int[] { 11, 15, 21, 27, 33, 38 }; // 18 bp
+    truncated = EmblEntry.adjustForProteinLength(4, exons);
+    assertEquals("[11, 15, 21, 27]", Arrays.toString(truncated));
 
-  /**
-   * Test retrieval of exon locations matching an accession id
-   */
-  @Test(groups = "Functional")
-  public void testGetCdsRanges_forAccession()
-  {
-    EmblEntry testee = new EmblEntry();
-    String accession = "A1234";
-    testee.setAccession(accession);
-    /*
-     * Make a (CDS) Feature with 4 locations
-     */
-    EmblFeature cds = new EmblFeature();
-    Vector<EmblFeatureLocations> locs = new Vector<EmblFeatureLocations>();
-    cds.setLocations(locs);
-  
-    /*
-     * single range [10-20] for 'this' accession
-     */
-    EmblFeatureLocations loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(false);
-    Vector<EmblFeatureLocElement> elements = new Vector<EmblFeatureLocElement>();
-    EmblFeatureLocElement locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    BasePosition b1 = new BasePosition();
-    b1.setPos("10");
-    BasePosition b2 = new BasePosition();
-    b2.setPos("20");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * complement range [30-40] - no accession
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("single");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    b1 = new BasePosition();
-    b1.setPos("30");
-    b2 = new BasePosition();
-    b2.setPos("40");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * join range [50-60] this accession, [70-80] another
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(false);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    b1 = new BasePosition();
-    b1.setPos("50");
-    b2 = new BasePosition();
-    b2.setPos("60");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession("notme");
-    b1 = new BasePosition();
-    b1.setPos("70");
-    b2 = new BasePosition();
-    b2.setPos("80");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * complement range [90-100] wrong accession, [110-120] good 
-     * this should be the same as complement(join(90..100,110.120))
-     * which is "join 90-100 and 110-120, then complement"
-     */
-    loc = new EmblFeatureLocations();
-    loc.setLocationType("join");
-    loc.setLocationComplement(true);
-    elements = new Vector<EmblFeatureLocElement>();
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession("wrong");
-    b1 = new BasePosition();
-    b1.setPos("90");
-    b2 = new BasePosition();
-    b2.setPos("100");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    locElement = new EmblFeatureLocElement();
-    locElement.setAccession(accession);
-    b1 = new BasePosition();
-    b1.setPos("110");
-    b2 = new BasePosition();
-    b2.setPos("120");
-    locElement.setBasePositions(new BasePosition[] { b1, b2 });
-    elements.add(locElement);
-    loc.setLocElements(elements);
-    locs.add(loc);
-  
-    /*
-     * verify we pick out only ranges for A1234
-     */
-    int[] exons = testee.getCdsRanges(cds);
-    assertEquals("[10, 20, 50, 60, 120, 110]",
-            Arrays.toString(exons));
+    // what if exons are too short for protein?
+    truncated = EmblEntry.adjustForProteinLength(7, exons);
+    assertSame(exons, truncated);
   }
 }
index c6a94d7..906436f 100644 (file)
 package jalview.datamodel.xdb.embl;
 
 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 java.io.StringReader;
 import java.util.Vector;
 
 import org.testng.annotations.Test;
 
 public class EmblFileTest
 {
-  // adapted from http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/embl/x53828/emblxml
-  private static final String TESTDATA = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
-          + "<EMBL_Services>"
-          + "<entry accession=\"X53828\" version=\"3\" lastUpdated=\"2005-04-18\" releaseCreated=\"25\" releaseLastUpdated=\"83\">"
-          + "<description>Chicken LDH-A mRNA for lactate dehydrogenase A chain (EC 1.1.1.27)</description>"
-          + "<keyword>L-lactate dehydrogenase</keyword><keyword>chutney</keyword>"
-          + "<dbreference db=\"EuropePMC\" primary=\"PMC1460223\" secondary=\"9649548\" />"
-          + "<dbreference db=\"MD5\" primary=\"d3b68\" />"
-          + "<feature name=\"CDS\"><dbreference db=\"GOA\" primary=\"P00340\" secondary=\"2.1\" /><dbreference db=\"InterPro\" primary=\"IPR001236\" />"
-          + "<qualifier name=\"note\"><value>L-lactate dehydrogenase A-chain</value><value>pickle</value></qualifier>"
-          + "<qualifier name=\"translation\"><value>MSLKDHLIHN</value><evidence>Keith</evidence></qualifier>"
-          + "<location type=\"single\" complement=\"true\">"
-          + "<locationElement type=\"range\" accession=\"X53828\" version=\"1\" complement=\"false\">"
-          + "<basePosition type=\"simple\">60</basePosition><basePosition type=\"join\">1058</basePosition>"
-          + "</locationElement></location></feature>"
-          + "<sequence type=\"mRNA\" version=\"2\">GTGACG</sequence></entry></EMBL_Services>";
 
   @Test(groups = { "Functional" })
   public void testGetEmblFile()
   {
-    Vector<EmblEntry> entries = EmblFile.getEmblFile(
-            new StringReader(TESTDATA)).getEntries();
+    Vector<EmblEntry> entries = EmblTestHelper.getEmblFile().getEntries();
     assertEquals(1, entries.size());
     EmblEntry entry = entries.get(0);
 
-    assertEquals("X53828", entry.getAccession());
-    assertEquals(
-            "Chicken LDH-A mRNA for lactate dehydrogenase A chain (EC 1.1.1.27)",
-            entry.getDesc());
-    assertEquals("2005-04-18", entry.getLastUpdated());
+    assertEquals("X07547", entry.getAccession());
+    assertEquals("C. trachomatis plasmid", entry.getDescription());
+    assertEquals("STD", entry.getDataClass());
+    assertEquals("PRO", entry.getTaxonomicDivision());
+    assertEquals("1999-02-10", entry.getLastUpdatedDate());
+    assertEquals("58", entry.getLastUpdatedRelease());
+    assertEquals("1988-11-10", entry.getFirstPublicDate());
+    assertEquals("18", entry.getFirstPublicRelease());
+    assertEquals("genomic DNA", entry.getMoleculeType());
+    assertEquals("1", entry.getSequenceVersion());
+    assertEquals("8", entry.getEntryVersion());
+    assertEquals("linear", entry.getTopology());
+    assertEquals("7499", entry.getSequenceLength());
 
     /*
      * FIXME these assertions fail - values are null - why?? Adding or removing
      * attributes in the test XML modifies behaviour. eg. inserting an attribute
      * _before_ lastUpdated results in a null value in this field.
      */
-    // assertEquals("25", entry.getRCreated());
-    // assertEquals("83", entry.getRLastUpdated());
+    assertEquals("1988-11-10", entry.getFirstPublicDate());
+    assertEquals("18", entry.getFirstPublicRelease());
 
     assertEquals(2, entry.getKeywords().size());
-    assertEquals("L-lactate dehydrogenase", entry.getKeywords().get(0));
-    assertEquals("chutney", entry.getKeywords().get(1));
+    assertEquals("plasmid", entry.getKeywords().get(0));
+    assertEquals("unidentified reading frame", entry.getKeywords().get(1));
 
     /*
      * dbrefs
@@ -83,72 +71,98 @@ public class EmblFileTest
     assertEquals(2, entry.getDbRefs().size());
     DBRefEntry dbref = entry.getDbRefs().get(0);
     assertEquals("EuropePMC", dbref.getSource());
-    assertEquals("PMC1460223", dbref.getAccessionId());
-    assertEquals("9649548", dbref.getVersion());
+    assertEquals("PMC107176", dbref.getAccessionId());
+    assertEquals("9573186", dbref.getVersion());
     dbref = entry.getDbRefs().get(1);
     assertEquals("MD5", dbref.getSource());
-    assertEquals("d3b68", dbref.getAccessionId());
+    assertEquals("ac73317", dbref.getAccessionId());
     // blank version has been converted to "0"
     assertEquals("0", dbref.getVersion());
 
     /*
-     * sequence features
+     * three sequence features for CDS
+     */
+    assertEquals(3, entry.getFeatures().size());
+    /*
+     * first CDS
      */
-    assertEquals(1, entry.getFeatures().size());
     EmblFeature ef = entry.getFeatures().get(0);
     assertEquals("CDS", ef.getName());
+    assertEquals("complement(46..57)", ef.getLocation());
     assertEquals(2, ef.getDbRefs().size());
     dbref = ef.getDbRefs().get(0);
-    assertEquals("GOA", dbref.getSource());
-    assertEquals("P00340", dbref.getAccessionId());
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("B0BCM4", dbref.getAccessionId());
     assertEquals("2.1", dbref.getVersion());
     dbref = ef.getDbRefs().get(1);
-    assertEquals("InterPro", dbref.getSource());
-    assertEquals("IPR001236", dbref.getAccessionId());
-    // blank version converted to "0":
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("P0CE20", dbref.getAccessionId());
+    // blank version gets converted to "0":
     assertEquals("0", dbref.getVersion());
-    assertEquals(2, ef.getQualifiers().size());
-
-    // feature qualifiers
+    // CDS feature qualifiers
+    assertEquals(3, ef.getQualifiers().size());
     Qualifier q = ef.getQualifiers().get(0);
     assertEquals("note", q.getName());
     assertEquals(2, q.getValues().length);
-    assertEquals("L-lactate dehydrogenase A-chain", q.getValues()[0]);
+    assertEquals("ORF 8 (AA 1-330)", q.getValues()[0]);
     assertEquals("pickle", q.getValues()[1]);
     assertNull(q.getEvidence());
     q = ef.getQualifiers().get(1);
+    assertEquals("protein_id", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("CAA30420.1", q.getValues()[0]);
+    q = ef.getQualifiers().get(2);
     assertEquals("translation", q.getName());
     assertEquals(1, q.getValues().length);
-    assertEquals("MSLKDHLIHN", q.getValues()[0]);
+    assertEquals("MLCF", q.getValues()[0]);
     assertEquals(1, q.getEvidence().length);
     assertEquals("Keith", q.getEvidence()[0]);
 
-    // feature locations
-    assertEquals(1, ef.getLocations().size());
-    EmblFeatureLocations fl = ef.getLocations().get(0);
-    assertEquals("single", fl.getLocationType());
-    assertTrue(fl.isLocationComplement());
-    assertEquals(1, fl.getLocElements().size());
-    EmblFeatureLocElement le = fl.getLocElements().get(0);
-    assertEquals("range", le.getType());
-    assertEquals("X53828", le.getAccession());
-    assertEquals("1", le.getVersion());
-    assertFalse(le.isComplement());
-    assertEquals(2, le.getBasePositions().length);
-    BasePosition bp = le.getBasePositions()[0];
-    assertEquals("simple", bp.getType());
-    assertEquals("60", bp.getPos());
-    bp = le.getBasePositions()[1];
-    assertEquals("join", bp.getType());
-    assertEquals("1058", bp.getPos());
+    /*
+     * second CDS
+     */
+    ef = entry.getFeatures().get(1);
+    assertEquals("CDS", ef.getName());
+    assertEquals("4..15", ef.getLocation());
+    assertEquals(1, ef.getDbRefs().size());
+    dbref = ef.getDbRefs().get(0);
+    assertEquals("UniProtKB/Swiss-Prot", dbref.getSource());
+    assertEquals("B0BCM3", dbref.getAccessionId());
+    assertEquals("0", dbref.getVersion());
+    assertEquals(2, ef.getQualifiers().size());
+    q = ef.getQualifiers().get(0);
+    assertEquals("protein_id", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("CAA30421.1", q.getValues()[0]);
+    q = ef.getQualifiers().get(1);
+    assertEquals("translation", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("MSSS", q.getValues()[0]);
+
+    /*
+     * third CDS
+     */
+    ef = entry.getFeatures().get(2);
+    assertEquals("CDS", ef.getName());
+    assertEquals("join(4..6,10..15)", ef.getLocation());
+    assertNull(ef.getDbRefs());
+    assertEquals(2, ef.getQualifiers().size());
+    q = ef.getQualifiers().get(0);
+    assertEquals("protein_id", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("CAA12345.6", q.getValues()[0]);
+    q = ef.getQualifiers().get(1);
+    assertEquals("translation", q.getName());
+    assertEquals(1, q.getValues().length);
+    assertEquals("MSS", q.getValues()[0]);
 
     /*
-     * Sequence
+     * Sequence - verify newline not converted to space (JAL-2029)
      */
     EmblSequence seq = entry.getSequence();
-    assertEquals("mRNA", seq.getType());
-    assertEquals("2", seq.getVersion());
-    assertEquals("GTGACG", seq.getSequence());
+    assertEquals(
+            "GGTATGTCCTCTAGTACAAACACCCCCAATATTGTGATATAATTAAAAACATAGCAT",
+            seq.getSequence());
 
     /*
      * getSequence() converts empty DBRefEntry.version to "0"
diff --git a/test/jalview/datamodel/xdb/embl/EmblTestHelper.java b/test/jalview/datamodel/xdb/embl/EmblTestHelper.java
new file mode 100644 (file)
index 0000000..0c7624f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+public class EmblTestHelper
+{
+  // adapted from http://www.ebi.ac.uk/ena/data/view/X07547&display=xml
+  // dna and translations truncated for convenience
+  private static final String TESTDATA = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+          + "<ROOT>"
+          + "<entry accession=\"X07547\" version=\"1\" entryVersion=\"8\""
+          + " dataClass=\"STD\" taxonomicDivision=\"PRO\""
+          + " moleculeType=\"genomic DNA\" sequenceLength=\"7499\" topology=\"linear\""
+          + " firstPublic=\"1988-11-10\" firstPublicRelease=\"18\""
+          + " lastUpdated=\"1999-02-10\" lastUpdatedRelease=\"58\">"
+          + "<secondaryAccession>X07574</secondaryAccession>"
+          + "<description>C. trachomatis plasmid</description>"
+          + "<keyword>plasmid</keyword><keyword>unidentified reading frame</keyword>"
+          + "<xref db=\"EuropePMC\" id=\"PMC107176\" secondaryId=\"9573186\" />"
+          + "<xref db=\"MD5\" id=\"ac73317\" />"
+          /*
+           * first CDS (range and translation changed to keep test data manageable)
+           */
+          + "<feature name=\"CDS\" location=\"complement(46..57)\">"
+          // test the case of >1 cross-ref to the same database (JAL-2029)
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"B0BCM4\" secondaryId=\"2.1\" />"
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"P0CE20\" />"
+          + "<qualifier name=\"note\"><value>ORF 8 (AA 1-330)</value><value>pickle</value></qualifier>"
+          + "<qualifier name=\"protein_id\"><value>CAA30420.1</value></qualifier>"
+          + "<qualifier name=\"translation\"><value>MLCF</value><evidence>Keith</evidence></qualifier>"
+          + "</feature>"
+          /*
+           * second CDS (range and translation changed to keep test data manageable)
+           */
+          + "<feature name=\"CDS\" location=\"4..15\">"
+          + "<xref db=\"UniProtKB/Swiss-Prot\" id=\"B0BCM3\" />"
+          + "<qualifier name=\"protein_id\"><value>CAA30421.1</value></qualifier>"
+          + "<qualifier name=\"translation\"><value>MSSS</value></qualifier>"
+          + "</feature>"
+          /*
+           * third CDS is made up - has no xref - code should synthesize 
+           * one to an assumed EMBLCDSPROTEIN accession
+           */
+          + "<feature name=\"CDS\" location=\"join(4..6,10..15)\">"
+          + "<qualifier name=\"protein_id\"><value>CAA12345.6</value></qualifier>"
+          + "<qualifier name=\"translation\"><value>MSS</value></qualifier>"
+          + "</feature>"
+          /*
+           * sequence (modified for test purposes)
+           * emulates EMBL XML 1.2 which splits sequence data every 60 characters
+           * see EmblSequence.setSequence
+           */
+          + "<sequence>GGTATGTCCTCTAGTACAAAC\n"
+          + "ACCCCCAATATTGTGATATAATTAAAAACATAGCAT"
+          + "</sequence></entry></ROOT>";
+
+  static EmblFile getEmblFile()
+  {
+    return EmblFile.getEmblFile(new StringReader(TESTDATA));
+  }
+}
diff --git a/test/jalview/ext/android/SparseIntArrayTest.java b/test/jalview/ext/android/SparseIntArrayTest.java
new file mode 100644 (file)
index 0000000..0ce0467
--- /dev/null
@@ -0,0 +1,124 @@
+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..351f640
--- /dev/null
@@ -0,0 +1,94 @@
+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 90c38d4..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;
@@ -21,17 +41,18 @@ import org.testng.annotations.Test;
 
 public class EnsemblCdnaTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     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 183f933..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;
@@ -20,13 +40,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblCdsTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
@@ -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 5cf296c..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;
@@ -22,13 +42,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblGeneTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
@@ -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 daad8b1..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;
@@ -19,13 +39,13 @@ import org.testng.annotations.Test;
 
 public class EnsemblGenomeTest
 {
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
@@ -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 6f7c1ad..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;
@@ -12,47 +32,47 @@ public class EnsemblRestClientTest
 {
 
   @Test(suiteName = "live")
-  public void testLiveCheckEnsembl()
+  public void testIsEnsemblAvailable()
   {
     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 6df479c..d3a6e32 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;
@@ -6,7 +26,6 @@ import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
 import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.AppletFormatAdapter;
@@ -16,10 +35,7 @@ import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyLite;
 
 import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.Arrays;
-import java.util.List;
 
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
@@ -27,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[][] {
@@ -109,13 +124,13 @@ public class EnsemblSeqProxyTest
                   + "NRDQIIFMVGRGYLSPDLSKVRSNCPKAMKRLMAECLKKKRDERPLFPQILASIELLARS\n"
                   + "LPKIHRSASEPSLNRAGFQTEDFSLYACASPKTPIQAGGYGAFPVH" } };
 
-  @BeforeClass
+  @BeforeClass(alwaysRun = true)
   public void setUp()
   {
     SequenceOntologyFactory.setInstance(new SequenceOntologyLite());
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public void tearDown()
   {
     SequenceOntologyFactory.setInstance(null);
@@ -129,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, AppletFormatAdapter.PASTE);
     SequenceI[] trueSqs = trueRes.getSeqsAsArray();
@@ -156,63 +170,8 @@ public class EnsemblSeqProxyTest
               "Sequences differ for " + tr.getName() + "\n" + "Exp:"
                       + tr.getSequenceAsString() + "\n" + "Got:"
                       + rseq[0].getSequenceAsString());
-  
-    }
-  }
-
-  @Test(suiteName = "live")
-  public void testLiveCheckEnsembl()
-  {
-    EnsemblRestClient sf = new EnsemblRestClient()
-    {
-
-      @Override
-      public String getDbName()
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      public AlignmentI getSequenceRecords(String queries) throws Exception
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
 
-      @Override
-      protected URL getUrl(List<String> ids) throws MalformedURLException
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      protected boolean useGetRequest()
-      {
-        // TODO Auto-generated method stub
-        return false;
-      }
-
-      @Override
-      protected String getRequestMimeType(boolean b)
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-      @Override
-      protected String getResponseMimeType()
-      {
-        // TODO Auto-generated method stub
-        return null;
-      }
-
-    };
-    boolean isAvailable = sf.isEnsemblAvailable();
-    System.out.println("Ensembl is "
-            + (isAvailable ? "UP!"
-                    : "DOWN or unreachable ******************* BAD!"));
+    }
   }
 
   @Test(groups = "Functional")
@@ -267,7 +226,8 @@ public class EnsemblSeqProxyTest
     sb = new StringBuilder();
     EnsemblSeqProxy.reverseComplementAllele(sb, "-GATt"); // revcomp=aATC-
     EnsemblSeqProxy.reverseComplementAllele(sb, "hgmd_mutation");
-    assertEquals("aATC-,hgmd_mutation", sb.toString());
+    EnsemblSeqProxy.reverseComplementAllele(sb, "PhenCode_variation");
+    assertEquals("aATC-,hgmd_mutation,PhenCode_variation", sb.toString());
   }
 
   /**
@@ -311,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 cde4afe..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;
 
@@ -21,11 +42,14 @@ public class EnsemblXrefTest
            "{\"primary_id\":\"GO:0000165\",\"dbname\":\"GO\"}]";
   //@formatter:on
 
-  @Test(groups = "functional")
+  @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..f8c53b0 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;
 
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 a68f7c8..b2d3253 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;
@@ -30,6 +31,8 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FileLoader;
+import jalview.structure.StructureImportSettings;
+import jalview.structure.StructureImportSettings.StructureParser;
 
 import java.util.Vector;
 
@@ -50,11 +53,12 @@ public class JmolParserTest
    * 1QCF is the full PDB file including headers, HETATM etc
    */
   String[] testFile = new String[] { "./examples/1GAQ.txt",
-      "./test/jalview/ext/jmol/1xyz.pdb" };
+      "./test/jalview/ext/jmol/1xyz.pdb",
+      "./test/jalview/ext/jmol/1qcf.pdb" };
 
   //@formatter:off
   // a modified and very cut-down extract of 4UJ4
-  String pdbWithChainBreak =
+  String pastePDBDataWithChainBreak =
      "HEADER    TRANSPORT PROTEIN                       08-APR-15   4UJ4\n" +
      // chain B has missing residues; these should all go in the same sequence:
      "ATOM   1909  CA  VAL B 358      21.329 -19.739 -67.740  1.00201.05           C\n" +
@@ -83,10 +87,16 @@ 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");
+    StructureImportSettings
+            .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
   }
 
   @Test(groups = { "Functional" })
@@ -108,8 +118,7 @@ public class JmolParserTest
     {
       PDBfile mctest = new PDBfile(false, false, false, pdbStr,
               AppletFormatAdapter.FILE);
-      JmolParser jtest = new JmolParser(false, false, false, pdbStr,
-              jalview.io.AppletFormatAdapter.FILE);
+      JmolParser jtest = new JmolParser(pdbStr, AppletFormatAdapter.FILE);
       Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
 
       assertTrue(
@@ -127,6 +136,7 @@ public class JmolParserTest
         validateSecStrRows(al);
       }
     }
+
   }
 
   private void validateSecStrRows(AlignmentI al)
@@ -156,7 +166,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(
@@ -172,15 +183,10 @@ public class JmolParserTest
   @Test(groups = { "Functional" })
   public void testParse_missingResidues() throws Exception
   {
-    PDBfile mctest = new PDBfile(false, false, false, pdbWithChainBreak,
+    PDBfile mctest = new PDBfile(false, false, false,
+            pastePDBDataWithChainBreak, AppletFormatAdapter.PASTE);
+    JmolParser jtest = new JmolParser(pastePDBDataWithChainBreak,
             AppletFormatAdapter.PASTE);
-    boolean annotFromStructure = false;
-    boolean localSecondaryStruct = false;
-    boolean serviceSecondaryStruct = false;
-    JmolParser jtest = new JmolParser(annotFromStructure,
-            localSecondaryStruct, serviceSecondaryStruct,
-            pdbWithChainBreak,
-            jalview.io.AppletFormatAdapter.PASTE);
     Vector<SequenceI> seqs = jtest.getSeqs();
     Vector<SequenceI> mcseqs = mctest.getSeqs();
 
@@ -202,15 +208,11 @@ public class JmolParserTest
   {
     PDBfile mctest = new PDBfile(false, false, false, pdbWithAltLoc,
             AppletFormatAdapter.PASTE);
-    boolean annotFromStructure = false;
-    boolean localSecondaryStruct = false;
-    boolean serviceSecondaryStruct = false;
-    JmolParser jtest = new JmolParser(annotFromStructure,
-            localSecondaryStruct, serviceSecondaryStruct, pdbWithAltLoc,
-            jalview.io.AppletFormatAdapter.PASTE);
+    JmolParser jtest = new JmolParser(pdbWithAltLoc,
+            AppletFormatAdapter.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());
@@ -247,4 +249,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",
+            AppletFormatAdapter.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 c9b2980..10224fa 100644 (file)
@@ -53,7 +53,7 @@ public class JmolViewerTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
diff --git a/test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java b/test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java
new file mode 100644 (file)
index 0000000..254e082
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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;
+import jalview.io.AppletFormatAdapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import MCview.PDBfile;
+
+/**
+ * This is not a unit test, rather it is a bulk End-to-End scan for sequences
+ * consistency for PDB files parsed with JmolParser vs. Jalview's PDBfile
+ * parser. The directory of PDB files to test must be provided in the launch
+ * args.
+ * 
+ * @author tcnofoegbu
+ *
+ */
+public class JmolVsJalviewPDBParserEndToEndTest
+{
+
+  public static void main(String[] args)
+  {
+    if (args == null || args[0] == null)
+    {
+      System.err
+              .println("You must provide a PDB directory in the launch argument");
+      return;
+    }
+
+    // args[0] must provide the directory of PDB files to run the test with
+    String testDir = args[0];
+    System.out.println("PDB directory : " + testDir);
+    File pdbDir = new File(testDir);
+    String testFiles[] = pdbDir.list();
+    testFileParser(testDir, testFiles);
+  }
+
+  public static void testFileParser(String testDir, String[] testFiles)
+  {
+    Set<String> failedFiles = new HashSet<String>();
+    int totalSeqScanned = 0, totalFail = 0;
+    for (String pdbStr : testFiles)
+    {
+      String testFile = testDir + "/" + pdbStr;
+      PDBfile mctest = null;
+      JmolParser jtest = null;
+      try
+      {
+        mctest = new PDBfile(false, false, false, testFile,
+                AppletFormatAdapter.FILE);
+        jtest = new JmolParser(testFile, AppletFormatAdapter.FILE);
+      } catch (IOException e)
+      {
+        System.err.println("Exception thrown while parsing : " + pdbStr);
+      }
+      Vector<SequenceI> seqs = jtest.getSeqs();
+      Vector<SequenceI> mcseqs = mctest.getSeqs();
+
+      for (SequenceI sq : seqs)
+      {
+        try
+        {
+          String testSeq = mcseqs.remove(0).getSequenceAsString();
+          if (!sq.getSequenceAsString().equals(testSeq))
+          {
+            ++totalFail;
+            System.err.println("Test Failed for " + pdbStr + ". Diff:");
+            System.err.println(sq.getSequenceAsString());
+            System.err.println(testSeq);
+            failedFiles.add(pdbStr);
+          }
+          ++totalSeqScanned;
+        } catch (Exception e)
+        {
+          e.printStackTrace();
+        }
+      }
+    }
+    int count = 0;
+
+    System.out.println("\n\nTotal sequence Scanned : " + totalSeqScanned);
+    System.out.println("Total sequence passed : "
+            + (totalSeqScanned - totalFail));
+    System.out.println("Total sequence failed : " + totalFail);
+    System.out
+            .println("Success rate: "
+                    + ((totalSeqScanned - totalFail) * 100)
+                    / totalSeqScanned + "%");
+    System.out.println("\nList of " + failedFiles.size()
+            + " file(s) with sequence diffs:");
+    for (String problemFile : failedFiles)
+    {
+      System.out.println(++count + ". " + problemFile);
+    }
+  }
+}
index 679385a..4110863 100644 (file)
@@ -43,7 +43,7 @@ import compbio.util.FileUtil;
 public class TestAnnotate3D
 {
 
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void test1GIDbyId() throws Exception
   {
     // use same ID as standard tests given at
@@ -53,7 +53,7 @@ public class TestAnnotate3D
     testRNAMLcontent(ids, null);
   }
 
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void testIdVsContent2GIS() throws Exception
   {
     Iterator<Reader> ids = Annotate3D.getRNAMLForPDBId("2GIS");
@@ -97,7 +97,7 @@ public class TestAnnotate3D
    * 
    * @throws Exception
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Network" }, enabled = true)
   public void testPDBfileVsRNAML() throws Exception
   {
     PDBfile pdbf = new PDBfile(true, false, true, "examples/2GIS.pdb",
@@ -111,7 +111,6 @@ public class TestAnnotate3D
     testRNAMLcontent(readers, pdbf);
   }
 
-  @Test(groups = { "Functional" }, enabled = false)
   private void testRNAMLcontent(Iterator<Reader> readers, PDBfile pdbf)
           throws Exception
   {
index cd28a2b..93a98b8 100644 (file)
@@ -54,7 +54,7 @@ public class JalviewChimeraView
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
index be07485..1bc802e 100644 (file)
@@ -1,13 +1,30 @@
+/*
+ * 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;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.ext.so.SequenceOntology;
-import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
 
-import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -15,20 +32,21 @@ public class SequenceOntologyTest
 {
   private SequenceOntologyI so;
 
-  @BeforeClass
-  public void setUp() {
+  @BeforeClass(alwaysRun = true)
+  public void setUp()
+  {
     long now = System.currentTimeMillis();
-    SequenceOntologyFactory.setInstance(new SequenceOntology());
+    try
+    {
+      so = new SequenceOntology();
+    } catch (Throwable t)
+    {
+      System.out.println("SOTest error ");
+      t.printStackTrace(System.err);
+    }
     long elapsed = System.currentTimeMillis() - now;
     System.out.println("Load and cache of Sequence Ontology took "
             + elapsed + "ms");
-    so = SequenceOntologyFactory.getInstance();
-  }
-
-  @AfterClass
-  public void tearDown()
-  {
-    SequenceOntologyFactory.setInstance(null);
   }
 
   @Test(groups = "Functional")
diff --git a/test/jalview/fts/core/FTSRestClientTest.java b/test/jalview/fts/core/FTSRestClientTest.java
new file mode 100644 (file)
index 0000000..b751b77
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * 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;
+import jalview.fts.api.FTSDataColumnI.FTSDataColumnGroupI;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class FTSRestClientTest
+{
+  private FTSRestClient ftsRestClient;
+
+  @BeforeMethod(alwaysRun = true)
+  public void setup()
+  {
+    ftsRestClient = new FTSRestClient()
+    {
+
+      @Override
+      public String getColumnDataConfigFileName()
+      {
+        return "/fts/uniprot_data_columns.txt";
+      }
+
+      @Override
+      public FTSRestResponse executeRequest(FTSRestRequest ftsRequest)
+              throws Exception
+      {
+        return null;
+      }
+    };
+  }
+
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumIndexTest()
+  {
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    int foundIndex = -1;
+    try
+    {
+      Assert.assertEquals(foundIndex, -1);
+      foundIndex = ftsRestClient.getPrimaryKeyColumIndex(wantedFields,
+              false);
+      Assert.assertEquals(foundIndex, 0);
+      foundIndex = ftsRestClient
+              .getPrimaryKeyColumIndex(wantedFields, true);
+      Assert.assertEquals(foundIndex, 1);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getAllDefaulDisplayedDataColumns()
+  {
+    Assert.assertNotNull(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns());
+    Assert.assertTrue(!ftsRestClient.getAllDefaultDisplayedFTSDataColumns()
+            .isEmpty());
+    Assert.assertEquals(ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns().size(), 7);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnsFieldsAsCommaDelimitedString()
+  {
+    Collection<FTSDataColumnI> wantedFields = ftsRestClient
+            .getAllDefaultDisplayedFTSDataColumns();
+    String actual = ftsRestClient
+            .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
+    Assert.assertEquals(actual,
+            "id,entry name,protein names,genes,organism,reviewed,length");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getAllFTSDataColumns()
+  {
+    Collection<FTSDataColumnI> allFields = ftsRestClient
+            .getAllFTSDataColumns();
+    Assert.assertNotNull(allFields);
+    Assert.assertEquals(allFields.size(), 117);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getSearchableDataColumns()
+  {
+    Collection<FTSDataColumnI> searchalbeFields = ftsRestClient
+            .getSearchableDataColumns();
+    Assert.assertNotNull(searchalbeFields);
+    Assert.assertEquals(searchalbeFields.size(), 22);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getPrimaryKeyColumn()
+  {
+    FTSDataColumnI expectedPKColumn;
+    try
+    {
+      expectedPKColumn = ftsRestClient
+              .getDataColumnByNameOrCode("Uniprot Id");
+      Assert.assertNotNull(ftsRestClient.getPrimaryKeyColumn());
+      Assert.assertEquals(ftsRestClient.getPrimaryKeyColumn(),
+              expectedPKColumn);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnByNameOrCode()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("genes");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getName(), "Gene Names");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDataColumnGroupById()
+  {
+    FTSDataColumnGroupI foundDataColGroup;
+    try
+    {
+      foundDataColGroup = ftsRestClient.getDataColumnGroupById("g3");
+      Assert.assertNotNull(foundDataColGroup);
+      Assert.assertEquals(foundDataColGroup.getName(), "Names & Taxonomy");
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDefaultResponsePageSize()
+  {
+    int defaultResSize = ftsRestClient.getDefaultResponsePageSize();
+    Assert.assertEquals(defaultResSize, 500);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getColumnMinWidthTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("Protein names");
+      Assert.assertNotNull(foundDataCol);
+      int actualColMinWidth = foundDataCol.getMinWidth();
+      Assert.assertEquals(actualColMinWidth, 300);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getColumnMaxWidthTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("Protein names");
+      Assert.assertNotNull(foundDataCol);
+      int actualColMinWidth = foundDataCol.getMaxWidth();
+      Assert.assertEquals(actualColMinWidth, 1500);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getColumnPreferredWidthTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("Protein names");
+      Assert.assertNotNull(foundDataCol);
+      int actualColMinWidth = foundDataCol.getPreferredWidth();
+      Assert.assertEquals(actualColMinWidth, 500);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getColumnClassTest()
+  {
+    try
+    {
+      FTSDataColumnI foundDataCol = ftsRestClient
+              .getDataColumnByNameOrCode("Protein names");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              String.class);
+      foundDataCol = ftsRestClient.getDataColumnByNameOrCode("length");
+      Assert.assertNotNull(foundDataCol);
+      Assert.assertEquals(foundDataCol.getDataType().getDataTypeClass(),
+              Integer.class);
+      // foundDataCol = ftsRestClient.getDataColumnByNameOrCode("length");
+      // Assert.assertNotNull(foundDataCol);
+      // Assert.assertEquals(foundDataCol.getDataColumnClass(), Double.class);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      Assert.fail("Exception thrown while testing...");
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void coverageForEqualsAndHashFunction()
+  {
+    Set<FTSDataColumnI> uniqueSet = new HashSet<FTSDataColumnI>();
+    Collection<FTSDataColumnI> searchableCols = ftsRestClient
+            .getSearchableDataColumns();
+    for (FTSDataColumnI foundCol : searchableCols)
+    {
+      System.out.println(foundCol.toString());
+      uniqueSet.add(foundCol);
+      uniqueSet.add(foundCol);
+    }
+    Assert.assertTrue(!uniqueSet.isEmpty());
+    Assert.assertEquals(uniqueSet.size(), 22);
+  }
+
+  @Test(groups = { "Functional" })
+  public void coverageForMiscellaneousBranches()
+  {
+    String actual = ftsRestClient.getPrimaryKeyColumn().toString();
+    Assert.assertEquals(actual, "Uniprot Id");
+
+    String actualGroupStr;
+    try
+    {
+      actualGroupStr = ftsRestClient.getDataColumnGroupById("g4")
+              .toString();
+      Assert.assertEquals(actualGroupStr, "Procedures & Softwares");
+      actualGroupStr = ftsRestClient.getDataColumnGroupById(
+              "unavailable group").toString();
+    } catch (Exception e)
+    {
+      Assert.assertTrue(true);
+    }
+
+    String actualResourseFile = ftsRestClient
+            .getResourceFile("/fts/uniprot_data_columns.txt");
+    Assert.assertNotNull(actualResourseFile);
+    Assert.assertTrue(actualResourseFile.length() > 31);
+  }
+
+  @Test(groups = { "Functional" }, expectedExceptions = Exception.class)
+  public void coverageForExceptionBranches() throws Exception
+  {
+    try
+    {
+      ftsRestClient.getDataColumnByNameOrCode("unavailable column");
+    } catch (Exception e)
+    {
+      System.out.println(e.getMessage());
+      String expectedMessage = "Couldn't find data column with name : unavailable column";
+      Assert.assertEquals(e.getMessage(), expectedMessage);
+    }
+    try
+    {
+      ftsRestClient.getDataColumnGroupById("unavailable column group Id");
+    } catch (Exception e)
+    {
+      System.out.println(e.getMessage());
+      String expectedMessage = "Couldn't find data column group with id : unavailable column group Id";
+      Assert.assertEquals(e.getMessage(), expectedMessage);
+    }
+
+    ftsRestClient.getDataColumnByNameOrCode("unavailable column");
+
+    ftsRestClient.getResourceFile("unavailable resource file");
+
+  }
+
+}
similarity index 79%
rename from test/jalview/gui/PDBSearchPanelTest.java
rename to test/jalview/fts/service/pdb/PDBFTSPanelTest.java
index 5e31bef..69792bb 100644 (file)
@@ -18,7 +18,7 @@
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.gui;
+package jalview.fts.service.pdb;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
@@ -30,7 +30,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-public class PDBSearchPanelTest
+public class PDBFTSPanelTest
 {
 
   @BeforeMethod(alwaysRun = true)
@@ -38,7 +38,7 @@ public class PDBSearchPanelTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
@@ -46,7 +46,7 @@ public class PDBSearchPanelTest
   @Test(groups = { "Functional" })
   public void populateCmbSearchTargetOptionsTest()
   {
-    PDBSearchPanel searchPanel = new PDBSearchPanel(null);
+    PDBFTSPanel searchPanel = new PDBFTSPanel(null);
     assertTrue(searchPanel.getCmbSearchTarget().getItemCount() > 0);
     searchPanel.populateCmbSearchTargetOptions();
   }
@@ -55,13 +55,13 @@ public class PDBSearchPanelTest
   public void testDecodeSearchTerm()
   {
     String expectedString = "1xyz OR text:2xyz OR text:3xyz";
-    String outcome = PDBSearchPanel.decodeSearchTerm("1xyz:A;2xyz;3xyz",
+    String outcome = PDBFTSPanel.decodeSearchTerm("1xyz:A;2xyz;3xyz",
             "text");
     // System.out.println("1 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
 
     expectedString = "1xyz";
-    outcome = PDBSearchPanel.decodeSearchTerm("1xyz", "text");
+    outcome = PDBFTSPanel.decodeSearchTerm("1xyz", "text");
     // System.out.println("2 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
   }
@@ -71,36 +71,42 @@ public class PDBSearchPanelTest
   {
 
     String expectedString = "1xyz:A";
-    String outcome = PDBSearchPanel.getPDBIdwithSpecifiedChain("1xyz",
+    String outcome = PDBFTSPanel.getPDBIdwithSpecifiedChain("1xyz",
             "2xyz;3xyz;1xyz:A");
     System.out.println("1 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
 
     expectedString = "2xyz";
-    outcome = PDBSearchPanel.getPDBIdwithSpecifiedChain("2xyz",
+    outcome = PDBFTSPanel.getPDBIdwithSpecifiedChain("2xyz",
             "1xyz:A;2xyz;3xyz");
     System.out.println("2 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
 
     expectedString = "2xyz:A";
-    outcome = PDBSearchPanel.getPDBIdwithSpecifiedChain("2xyz", "2xyz:A");
+    outcome = PDBFTSPanel.getPDBIdwithSpecifiedChain("2xyz", "2xyz:A");
     System.out.println("3 >>>>>>>>>>> " + outcome);
     assertEquals(expectedString, outcome);
   }
 
-  @Test(groups = { "Network", "External" }, timeOut = 5000)
+  @Test(groups = { "External" }, timeOut = 7000)
   public void txt_search_ActionPerformedTest()
   {
-    PDBSearchPanel searchPanel = new PDBSearchPanel(null);
+    PDBFTSPanel searchPanel = new PDBFTSPanel(null);
     JInternalFrame mainFrame = searchPanel.getMainFrame();
     JTextField txt_search = searchPanel.getTxtSearch();
 
     assertTrue(mainFrame.getTitle().length() == 20);
     assertTrue(mainFrame.getTitle()
             .equalsIgnoreCase("PDB Sequence Fetcher"));
-
     txt_search.setText("ABC");
-
+    try
+    {
+      // wait for web-service to handle response
+      Thread.sleep(3000);
+    } catch (InterruptedException e)
+    {
+      e.printStackTrace();
+    }
     assertTrue(mainFrame.getTitle().length() > 20);
     assertTrue(!mainFrame.getTitle().equalsIgnoreCase(
             "PDB Sequence Fetcher"));
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.ws.dbsources;
+package jalview.fts.service.pdb;
 
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
-import jalview.ws.dbsources.PDBRestClient.PDBDocField;
-import jalview.ws.uimodel.PDBRestRequest;
-import jalview.ws.uimodel.PDBRestResponse;
+import jalview.fts.api.FTSDataColumnI;
+import jalview.fts.core.FTSRestRequest;
+import jalview.fts.core.FTSRestResponse;
 
 import java.io.BufferedReader;
 import java.io.FileReader;
@@ -51,7 +51,7 @@ import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.api.client.config.ClientConfig;
 import com.sun.jersey.api.client.config.DefaultClientConfig;
 
-public class PDBRestClientTest
+public class PDBFTSRestClientTest
 {
 
   @BeforeMethod(alwaysRun = true)
@@ -59,7 +59,7 @@ public class PDBRestClientTest
   {
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
   }
@@ -67,24 +67,35 @@ public class PDBRestClientTest
   @Test(groups = { "External", "Network" })
   public void executeRequestTest()
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.MOLECULE_TYPE);
-    wantedFields.add(PDBDocField.PDB_ID);
-    wantedFields.add(PDBDocField.GENUS);
-    wantedFields.add(PDBDocField.GENE_NAME);
-    wantedFields.add(PDBDocField.TITLE);
-
-    PDBRestRequest request = new PDBRestRequest();
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("molecule_type"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("pdb_id"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("genus"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("gene_name"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("title"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+
+    FTSRestRequest request = new FTSRestRequest();
     request.setAllowEmptySeq(false);
     request.setResponseSize(100);
     request.setFieldToSearchBy("text:");
     request.setSearchTerm("abc");
     request.setWantedFields(wantedFields);
 
-    PDBRestResponse response;
+    FTSRestResponse response;
     try
     {
-      response = new PDBRestClient().executeRequest(request);
+      response = PDBFTSRestClient.getInstance().executeRequest(request);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -99,16 +110,27 @@ public class PDBRestClientTest
   @Test(groups = { "Functional" })
   public void getPDBDocFieldsAsCommaDelimitedStringTest()
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.MOLECULE_TYPE);
-    wantedFields.add(PDBDocField.PDB_ID);
-    wantedFields.add(PDBDocField.GENUS);
-    wantedFields.add(PDBDocField.GENE_NAME);
-    wantedFields.add(PDBDocField.TITLE);
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("molecule_type"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("pdb_id"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("genus"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("gene_name"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("title"));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
 
     String expectedResult = "molecule_type,pdb_id,genus,gene_name,title";
-    String actualResult = PDBRestClient
-            .getPDBDocFieldsAsCommaDelimitedString(wantedFields);
+    String actualResult = PDBFTSRestClient.getInstance()
+            .getDataColumnsFieldsAsCommaDelimitedString(wantedFields);
 
     assertEquals("", expectedResult, actualResult);
   }
@@ -116,14 +138,25 @@ public class PDBRestClientTest
   @Test(groups = { "External, Network" })
   public void parsePDBJsonExceptionStringTest()
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.MOLECULE_TYPE);
-    wantedFields.add(PDBDocField.PDB_ID);
-    wantedFields.add(PDBDocField.GENUS);
-    wantedFields.add(PDBDocField.GENE_NAME);
-    wantedFields.add(PDBDocField.TITLE);
-
-    PDBRestRequest request = new PDBRestRequest();
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("molecule_type"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("pdb_id"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("genus"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("gene_name"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("title"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+
+    FTSRestRequest request = new FTSRestRequest();
     request.setAllowEmptySeq(false);
     request.setResponseSize(100);
     request.setFieldToSearchBy("text:");
@@ -139,7 +172,7 @@ public class PDBRestClientTest
       e.printStackTrace();
     }
 
-    String parsedErrorResponse = PDBRestClient
+    String parsedErrorResponse = PDBFTSRestClient
             .parseJsonExceptionString(jsonErrorResponse);
 
     String expectedErrorMsg = "\n============= PDB Rest Client RunTime error =============\n"
@@ -151,32 +184,43 @@ public class PDBRestClientTest
     assertEquals(expectedErrorMsg, parsedErrorResponse);
   }
 
-  @Test(
-    groups = { "External", "Network" },
-    expectedExceptions = Exception.class)
+  @Test(groups = { "External" }, expectedExceptions = Exception.class)
   public void testForExpectedRuntimeException() throws Exception
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.PDB_ID);
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    wantedFields.add(PDBFTSRestClient.getInstance()
+            .getDataColumnByNameOrCode("pdb_id"));
 
-    PDBRestRequest request = new PDBRestRequest();
+    FTSRestRequest request = new FTSRestRequest();
     request.setFieldToSearchBy("text:");
     request.setSearchTerm("abc OR text:go:abc");
     request.setWantedFields(wantedFields);
-    new PDBRestClient().executeRequest(request);
+    PDBFTSRestClient.getInstance().executeRequest(request);
   }
 
+  // JBP: Is this actually external ? Looks like it is mocked
   @Test(groups = { "External" })
   public void parsePDBJsonResponseTest()
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.MOLECULE_TYPE);
-    wantedFields.add(PDBDocField.PDB_ID);
-    wantedFields.add(PDBDocField.GENUS);
-    wantedFields.add(PDBDocField.GENE_NAME);
-    wantedFields.add(PDBDocField.TITLE);
-
-    PDBRestRequest request = new PDBRestRequest();
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("molecule_type"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("pdb_id"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("genus"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("gene_name"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("title"));
+    } catch (Exception e1)
+    {
+      e1.printStackTrace();
+    }
+
+    FTSRestRequest request = new FTSRestRequest();
     request.setAllowEmptySeq(false);
     request.setWantedFields(wantedFields);
 
@@ -188,7 +232,7 @@ public class PDBRestClientTest
     {
       e.printStackTrace();
     }
-    PDBRestResponse response = PDBRestClient.parsePDBJsonResponse(
+    FTSRestResponse response = PDBFTSRestClient.parsePDBJsonResponse(
             jsonString, request);
     assertTrue(response.getSearchSummary() != null);
     assertTrue(response.getNumberOfItemsFound() == 931);
@@ -198,14 +242,34 @@ public class PDBRestClientTest
   @Test(groups = { "Functional" })
   public void getPDBIdColumIndexTest()
   {
-    List<PDBDocField> wantedFields = new ArrayList<PDBDocField>();
-    wantedFields.add(PDBDocField.MOLECULE_TYPE);
-    wantedFields.add(PDBDocField.GENUS);
-    wantedFields.add(PDBDocField.GENE_NAME);
-    wantedFields.add(PDBDocField.TITLE);
-    wantedFields.add(PDBDocField.PDB_ID);
-    assertEquals(5, PDBRestClient.getPDBIdColumIndex(wantedFields, true));
-    assertEquals(4, PDBRestClient.getPDBIdColumIndex(wantedFields, false));
+    List<FTSDataColumnI> wantedFields = new ArrayList<FTSDataColumnI>();
+    try
+    {
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("molecule_type"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("genus"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("gene_name"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("title"));
+      wantedFields.add(PDBFTSRestClient.getInstance()
+              .getDataColumnByNameOrCode("pdb_id"));
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    try
+    {
+      assertEquals(5, PDBFTSRestClient.getInstance()
+              .getPrimaryKeyColumIndex(wantedFields, true));
+      assertEquals(4, PDBFTSRestClient.getInstance()
+              .getPrimaryKeyColumIndex(wantedFields, false));
+    } catch (Exception e)
+    {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
   }
 
   @Test(groups = { "External" })
@@ -216,7 +280,7 @@ public class PDBRestClientTest
 
     // Build request parameters for the REST Request
     WebResource webResource = client
-            .resource(PDBRestClient.PDB_SEARCH_ENDPOINT)
+            .resource(PDBFTSRestClient.PDB_SEARCH_ENDPOINT)
             .queryParam("wt", "json").queryParam("rows", String.valueOf(1))
             .queryParam("q", "text:abc AND molecule_sequence:['' TO *]");
 
@@ -255,9 +319,10 @@ public class PDBRestClientTest
 
         JSONObject pdbJsonDoc = docIter.next();
 
-        for (PDBDocField field : PDBDocField.values())
+        for (FTSDataColumnI field : PDBFTSRestClient.getInstance()
+                .getAllFTSDataColumns())
         {
-          if (field == PDBDocField.ALL)
+          if (field.getName().equalsIgnoreCase("ALL"))
           {
             continue;
           }
diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java
new file mode 100644 (file)
index 0000000..316d9af
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class AlignFrameTest
+{
+
+  @Test
+  public void testHideFeatureColumns()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "ABCDEFGHIJ");
+    SequenceI seq2 = new Sequence("Seq2", "ABCDEFGHIJ");
+    seq1.addSequenceFeature(new SequenceFeature("Metal", "", 1, 5,
+            Float.NaN, null));
+    seq2.addSequenceFeature(new SequenceFeature("Metal", "", 6, 10,
+            Float.NaN, null));
+    seq1.addSequenceFeature(new SequenceFeature("Turn", "", 2, 4,
+            Float.NaN, null));
+    seq2.addSequenceFeature(new SequenceFeature("Turn", "", 7, 9,
+            Float.NaN, null));
+    AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+    AlignFrame af = new AlignFrame(al, al.getWidth(), al.getHeight());
+
+    /*
+     * hiding a feature not present does nothing
+     */
+    assertFalse(af.hideFeatureColumns("exon", true));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    assertTrue(af.getViewport().getColumnSelection().getHiddenColumns()
+            .isEmpty());
+    assertFalse(af.hideFeatureColumns("exon", false));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    assertTrue(af.getViewport().getColumnSelection().getHiddenColumns()
+            .isEmpty());
+
+    /*
+     * hiding a feature in all columns does nothing
+     */
+    assertFalse(af.hideFeatureColumns("Metal", true));
+    assertTrue(af.getViewport().getColumnSelection().isEmpty());
+    List<int[]> hidden = af.getViewport().getColumnSelection()
+            .getHiddenColumns();
+    assertTrue(hidden.isEmpty());
+
+    /*
+     * hide a feature present in some columns
+     * sequence positions [2-4], [7-9] are column positions
+     * [1-3], [6-8] base zero
+     */
+    assertTrue(af.hideFeatureColumns("Turn", true));
+    hidden = af.getViewport().getColumnSelection().getHiddenColumns();
+    assertEquals(2, hidden.size());
+    assertEquals(1, hidden.get(0)[0]);
+    assertEquals(3, hidden.get(0)[1]);
+    assertEquals(6, hidden.get(1)[0]);
+    assertEquals(8, hidden.get(1)[1]);
+  }
+}
index b39b2bd..00c52ed 100644 (file)
@@ -26,16 +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.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.PIDColourScheme;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.MapList;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -54,8 +61,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)
@@ -73,15 +79,16 @@ public class AlignViewportTest
   @Test(groups = { "Functional" })
   public void testCollateForPdb()
   {
+    // JBP: What behaviour is this supposed to test ?
     /*
      * Set up sequence pdb ids
      */
-    PDBEntry pdb1 = new PDBEntry("1ABC", "A", Type.PDB, "1ABC.pdb");
-    PDBEntry pdb2 = new PDBEntry("2ABC", "A", Type.PDB, "2ABC.pdb");
-    PDBEntry pdb3 = new PDBEntry("3ABC", "A", Type.PDB, "3ABC.pdb");
+    PDBEntry pdb1 = new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb");
+    PDBEntry pdb2 = new PDBEntry("2ABC", "C", Type.PDB, "2ABC.pdb");
+    PDBEntry pdb3 = new PDBEntry("3ABC", "D", Type.PDB, "3ABC.pdb");
 
     /*
-     * seq1 and seq3 refer to 1ABC, seq2 to 2ABC, none to 3ABC
+     * seq1 and seq3 refer to 1abcB, seq2 to 2abcC, none to 3abcD
      */
     al.getSequenceAt(0).getDatasetSequence()
             .addPDBId(new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb"));
@@ -133,8 +140,13 @@ public class AlignViewportTest
     AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
             ">Seq1\nCAGT\n", FormatAdapter.PASTE);
 
+    SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
+    acf1.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 1, 4 },
+            1, 1));
     AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
+            1, 1));
 
     List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
     mappings.add(acf1);
@@ -178,10 +190,20 @@ public class AlignViewportTest
             ">Seq1\nRSVQ\n", FormatAdapter.PASTE);
     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
             ">Seq2\nDGEL\n", FormatAdapter.PASTE);
-
+    SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
+    SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
+    SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
+    SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
+    // need to be distinct
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
+    acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
+            new int[] { 1, 12 }, 1, 3));
     AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
+            new int[] { 1, 12 }, 1, 3));
     AlignedCodonFrame acf3 = new AlignedCodonFrame();
+    acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
+        12 }, 1, 1));
 
     List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
     mappings1.add(acf1);
@@ -231,10 +253,20 @@ public class AlignViewportTest
             ">Seq1\nRSVQ\n", FormatAdapter.PASTE);
     AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
             ">Seq2\nDGEL\n", FormatAdapter.PASTE);
-
+    SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
+    SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
+    SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
+    SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
+    // need to be distinct
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
+    acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
+            new int[] { 1, 12 }, 1, 3));
     AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
+            new int[] { 1, 12 }, 1, 3));
     AlignedCodonFrame acf3 = new AlignedCodonFrame();
+    acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
+        12 }, 1, 1));
 
     List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
     mappings1.add(acf1);
@@ -270,4 +302,49 @@ 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", FormatAdapter.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", FormatAdapter.FILE);
+    ColourSchemeI cs = new PIDColourScheme();
+    af.getViewport().setGlobalColourScheme(cs);
+    assertFalse(cs.conservationApplied());
+  }
 }
index f08fa8d..6621a94 100644 (file)
@@ -75,6 +75,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 ff8c179..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;
@@ -47,7 +43,7 @@ public class JAL1353bugdemo
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
@@ -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 52eadcb..212bcce 100644 (file)
@@ -48,7 +48,7 @@ public class PaintRefresherTest
     PaintRefresher.components.clear();
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown()
   {
     PaintRefresher.components.clear();
index edf3202..b4e8629 100644 (file)
@@ -27,6 +27,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.AppletFormatAdapter;
 import jalview.io.FormatAdapter;
@@ -440,4 +443,91 @@ 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_NAME$");
+    links.add("UNIPROT | http://www.uniprot.org/uniprot/$SEQUENCE_ID$");
+    links.add("INTERPRO | http://www.ebi.ac.uk/interpro/entry/$SEQUENCE_ID$");
+    // Gene3D entry tests for case (in)sensitivity
+    links.add("Gene3D | http://gene3d.biochem.ucl.ac.uk/Gene3D/search?sterm=$SEQUENCE_ID$&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]);
+    }
+
+
+  }
 }
index 28b9b83..446d32d 100644 (file)
@@ -24,9 +24,11 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.jbgui.GStructureChooser.FilterOption;
 
 import java.util.Vector;
 
@@ -43,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();
@@ -60,7 +62,7 @@ public class StructureChooserTest
     seq.setPDBId(pdbIds);
   }
 
-  @AfterMethod
+  @AfterMethod(alwaysRun = true)
   public void tearDown() throws Exception
   {
     seq = null;
@@ -80,23 +82,49 @@ public class StructureChooserTest
     seq.setDBRefs(null);
     query = StructureChooser.buildQuery(seq);
     assertEquals("text:4kqy", query);
+
+    DBRefEntry uniprotDBRef = new DBRefEntry();
+    uniprotDBRef.setAccessionId("P12345");
+    uniprotDBRef.setSource(DBRefSource.UNIPROT);
+    seq.addDBRef(uniprotDBRef);
+
+    DBRefEntry pdbDBRef = new DBRefEntry();
+    pdbDBRef.setAccessionId("1XYZ");
+    pdbDBRef.setSource(DBRefSource.PDB);
+    seq.addDBRef(pdbDBRef);
+
+    for (int x = 1; x < 5; x++)
+    {
+      DBRefEntry dbRef = new DBRefEntry();
+      dbRef.setAccessionId("XYZ_" + x);
+      seq.addDBRef(dbRef);
+    }
+    query = StructureChooser.buildQuery(seq);
+    assertEquals(
+            "uniprot_accession:P12345 OR uniprot_id:P12345 OR pdb_id:1xyz",
+            query);
   }
 
   @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();
+    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" })
@@ -109,4 +137,22 @@ public class StructureChooserTest
     assertTrue(sc.getDiscoveredStructuresSet().size() > 0);
 
   }
+
+  @Test(groups = { "Functional" })
+  public void sanitizeSeqNameTest()
+  {
+    String name = "ab_cdEF|fwxyz012349";
+    assertEquals(name, StructureChooser.sanitizeSeqName(name));
+
+    // remove a [nn] substring
+    name = "abcde12[345]fg";
+    assertEquals("abcde12fg", StructureChooser.sanitizeSeqName(name));
+
+    // remove characters other than a-zA-Z0-9 | or _
+    name = "ab[cd],.\t£$*!- \\\"@:e";
+    assertEquals("abcde", StructureChooser.sanitizeSeqName(name));
+
+    name = "abcde12[345a]fg";
+    assertEquals("abcde12345afg", StructureChooser.sanitizeSeqName(name));
+  }
 }
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/1a70.pdb b/test/jalview/io/1a70.pdb
new file mode 100644 (file)
index 0000000..1c69a73
--- /dev/null
@@ -0,0 +1,1146 @@
+HEADER    IRON-SULFUR PROTEIN                     19-MAR-98   1A70              
+TITLE     SPINACH FERREDOXIN                                                    
+COMPND    MOL_ID: 1;                                                            
+COMPND   2 MOLECULE: FERREDOXIN;                                                
+COMPND   3 CHAIN: A;                                                            
+COMPND   4 ENGINEERED: YES;                                                     
+COMPND   5 MUTATION: YES                                                        
+SOURCE    MOL_ID: 1;                                                            
+SOURCE   2 ORGANISM_SCIENTIFIC: SPINACIA OLERACEA;                              
+SOURCE   3 ORGANISM_COMMON: SPINACH;                                            
+SOURCE   4 ORGANISM_TAXID: 3562;                                                
+SOURCE   5 EXPRESSION_SYSTEM: ESCHERICHIA COLI;                                 
+SOURCE   6 EXPRESSION_SYSTEM_TAXID: 562                                         
+KEYWDS    IRON-SULFUR PROTEIN, PHOTOSYNTHESIS, ELECTRON TRANSPORT               
+EXPDTA    X-RAY DIFFRACTION                                                     
+AUTHOR    C.BINDA,A.CODA,A.MATTEVI,A.ALIVERTI,G.ZANETTI                         
+REVDAT   3   24-FEB-09 1A70    1       VERSN                                    
+REVDAT   2   13-JAN-99 1A70    3       ATOM   SOURCE COMPND REMARK              
+REVDAT   2 2                   3       HETATM JRNL   KEYWDS TER                 
+REVDAT   2 3                   3       CONECT                                   
+REVDAT   1   25-NOV-98 1A70    0                                                
+JRNL        AUTH   C.BINDA,A.CODA,A.ALIVERTI,G.ZANETTI,A.MATTEVI                
+JRNL        TITL   STRUCTURE OF THE MUTANT E92K OF [2FE-2S]                     
+JRNL        TITL 2 FERREDOXIN I FROM SPINACIA OLERACEA AT 1.7 A                 
+JRNL        TITL 3 RESOLUTION.                                                  
+JRNL        REF    ACTA CRYSTALLOGR.,SECT.D      V.  54  1353 1998              
+JRNL        REFN                   ISSN 0907-4449                               
+JRNL        PMID   10089511                                                     
+JRNL        DOI    10.1107/S0907444998005137                                    
+REMARK   1                                                                      
+REMARK   2                                                                      
+REMARK   2 RESOLUTION.    1.70 ANGSTROMS.                                       
+REMARK   3                                                                      
+REMARK   3 REFINEMENT.                                                          
+REMARK   3   PROGRAM     : TNT V. 5-D                                           
+REMARK   3   AUTHORS     : TRONRUD,TEN EYCK,MATTHEWS                            
+REMARK   3                                                                      
+REMARK   3  DATA USED IN REFINEMENT.                                            
+REMARK   3   RESOLUTION RANGE HIGH (ANGSTROMS) : 1.70                           
+REMARK   3   RESOLUTION RANGE LOW  (ANGSTROMS) : 100.00                         
+REMARK   3   DATA CUTOFF            (SIGMA(F)) : 0.000                          
+REMARK   3   COMPLETENESS FOR RANGE        (%) : 97.6                           
+REMARK   3   NUMBER OF REFLECTIONS             : 11755                          
+REMARK   3                                                                      
+REMARK   3  USING DATA ABOVE SIGMA CUTOFF.                                      
+REMARK   3   CROSS-VALIDATION METHOD          : A POSTERIORI                    
+REMARK   3   FREE R VALUE TEST SET SELECTION  : EVERY 10TH REFLECTION           
+REMARK   3   R VALUE     (WORKING + TEST SET) : 0.190                           
+REMARK   3   R VALUE            (WORKING SET) : 0.182                           
+REMARK   3   FREE R VALUE                     : 0.200                           
+REMARK   3   FREE R VALUE TEST SET SIZE   (%) : 10.000                          
+REMARK   3   FREE R VALUE TEST SET COUNT      : 1090                            
+REMARK   3                                                                      
+REMARK   3  USING ALL DATA, NO SIGMA CUTOFF.                                    
+REMARK   3   R VALUE   (WORKING + TEST SET, NO CUTOFF) : 0.2010                 
+REMARK   3   R VALUE          (WORKING SET, NO CUTOFF) : 0.1960                 
+REMARK   3   FREE R VALUE                  (NO CUTOFF) : 0.259                  
+REMARK   3   FREE R VALUE TEST SET SIZE (%, NO CUTOFF) : 10.00                  
+REMARK   3   FREE R VALUE TEST SET COUNT   (NO CUTOFF) : 1176                   
+REMARK   3   TOTAL NUMBER OF REFLECTIONS   (NO CUTOFF) : 11755                  
+REMARK   3                                                                      
+REMARK   3  NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.                    
+REMARK   3   PROTEIN ATOMS            : 732                                     
+REMARK   3   NUCLEIC ACID ATOMS       : 0                                       
+REMARK   3   HETEROGEN ATOMS          : 4                                       
+REMARK   3   SOLVENT ATOMS            : 81                                      
+REMARK   3                                                                      
+REMARK   3  WILSON B VALUE (FROM FCALC, A**2) : 5.100                           
+REMARK   3                                                                      
+REMARK   3  RMS DEVIATIONS FROM IDEAL VALUES.    RMS    WEIGHT  COUNT           
+REMARK   3   BOND LENGTHS                 (A) : 0.019 ; 70.000; 620             
+REMARK   3   BOND ANGLES            (DEGREES) : 2.994 ; 90.000; 855             
+REMARK   3   TORSION ANGLES         (DEGREES) : 18.500; 0.000 ; 300             
+REMARK   3   PSEUDOROTATION ANGLES  (DEGREES) : NULL  ; NULL  ; NULL            
+REMARK   3   TRIGONAL CARBON PLANES       (A) : 0.021 ; 70.000; 13              
+REMARK   3   GENERAL PLANES               (A) : 0.021 ; 240.000; 94             
+REMARK   3   ISOTROPIC THERMAL FACTORS (A**2) : 4.300 ; 2.100 ; 620             
+REMARK   3   NON-BONDED CONTACTS          (A) : 0.039 ; 125.000; 9              
+REMARK   3                                                                      
+REMARK   3  INCORRECT CHIRAL-CENTERS (COUNT) : NULL                             
+REMARK   3                                                                      
+REMARK   3  BULK SOLVENT MODELING.                                              
+REMARK   3   METHOD USED : BABINET SCALING                                      
+REMARK   3   KSOL        : 0.80                                                 
+REMARK   3   BSOL        : 150.00                                               
+REMARK   3                                                                      
+REMARK   3  RESTRAINT LIBRARIES.                                                
+REMARK   3   STEREOCHEMISTRY : TNT PROTGEO                                      
+REMARK   3   ISOTROPIC THERMAL FACTOR RESTRAINTS : TNT BCORREL V1.0             
+REMARK   3                                                                      
+REMARK   3  OTHER REFINEMENT REMARKS: NULL                                      
+REMARK   4                                                                      
+REMARK   4 1A70 COMPLIES WITH FORMAT V. 3.15, 01-DEC-08                         
+REMARK 100                                                                      
+REMARK 100 THIS ENTRY HAS BEEN PROCESSED BY BNL.                                
+REMARK 200                                                                      
+REMARK 200 EXPERIMENTAL DETAILS                                                 
+REMARK 200  EXPERIMENT TYPE                : X-RAY DIFFRACTION                  
+REMARK 200  DATE OF DATA COLLECTION        : JUN-96                             
+REMARK 200  TEMPERATURE           (KELVIN) : 293                                
+REMARK 200  PH                             : 7.5                                
+REMARK 200  NUMBER OF CRYSTALS USED        : 1                                  
+REMARK 200                                                                      
+REMARK 200  SYNCHROTRON              (Y/N) : N                                  
+REMARK 200  RADIATION SOURCE               : ROTATING ANODE                     
+REMARK 200  BEAMLINE                       : NULL                               
+REMARK 200  X-RAY GENERATOR MODEL          : RIGAKU RUH2R                       
+REMARK 200  MONOCHROMATIC OR LAUE    (M/L) : M                                  
+REMARK 200  WAVELENGTH OR RANGE        (A) : 1.5418                             
+REMARK 200  MONOCHROMATOR                  : GRAPHITE(002)                      
+REMARK 200  OPTICS                         : MIRRORS                            
+REMARK 200                                                                      
+REMARK 200  DETECTOR TYPE                  : IMAGE PLATE                        
+REMARK 200  DETECTOR MANUFACTURER          : MARRESEARCH                        
+REMARK 200  INTENSITY-INTEGRATION SOFTWARE : MOSFLM                             
+REMARK 200  DATA SCALING SOFTWARE          : AGROVATA                           
+REMARK 200                                                                      
+REMARK 200  NUMBER OF UNIQUE REFLECTIONS   : 11755                              
+REMARK 200  RESOLUTION RANGE HIGH      (A) : 1.700                              
+REMARK 200  RESOLUTION RANGE LOW       (A) : NULL                               
+REMARK 200  REJECTION CRITERIA  (SIGMA(I)) : 2.000                              
+REMARK 200                                                                      
+REMARK 200 OVERALL.                                                             
+REMARK 200  COMPLETENESS FOR RANGE     (%) : 97.6                               
+REMARK 200  DATA REDUNDANCY                : 2.500                              
+REMARK 200  R MERGE                    (I) : 0.07800                            
+REMARK 200  R SYM                      (I) : 0.11200                            
+REMARK 200  <I/SIGMA(I)> FOR THE DATA SET  : 10.0000                            
+REMARK 200                                                                      
+REMARK 200 IN THE HIGHEST RESOLUTION SHELL.                                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : 1.70                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE LOW  (A) : 1.80                     
+REMARK 200  COMPLETENESS FOR SHELL     (%) : 68.0                               
+REMARK 200  DATA REDUNDANCY IN SHELL       : 2.50                               
+REMARK 200  R MERGE FOR SHELL          (I) : 0.20200                            
+REMARK 200  R SYM FOR SHELL            (I) : 0.30500                            
+REMARK 200  <I/SIGMA(I)> FOR SHELL         : 2.000                              
+REMARK 200                                                                      
+REMARK 200 DIFFRACTION PROTOCOL: NULL                                           
+REMARK 200 METHOD USED TO DETERMINE THE STRUCTURE: MOLECULAR REPLACEMENT        
+REMARK 200 SOFTWARE USED: AMORE                                                 
+REMARK 200 STARTING MODEL: PDB ENTRY 1FRR                                       
+REMARK 200                                                                      
+REMARK 200 REMARK: NULL                                                         
+REMARK 280                                                                      
+REMARK 280 CRYSTAL                                                              
+REMARK 280 SOLVENT CONTENT, VS   (%): 50.00                                     
+REMARK 280 MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): 1.50                     
+REMARK 280                                                                      
+REMARK 280 CRYSTALLIZATION CONDITIONS: PROTEIN WAS CRYSTALLIZED FROM 2.6M       
+REMARK 280  AMMONIUM SULPHATE IN 50MM PHOSPHATE BUFFER, PH 7.5                  
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY                                            
+REMARK 290 SYMMETRY OPERATORS FOR SPACE GROUP: P 21 21 21                       
+REMARK 290                                                                      
+REMARK 290      SYMOP   SYMMETRY                                                
+REMARK 290     NNNMMM   OPERATOR                                                
+REMARK 290       1555   X,Y,Z                                                   
+REMARK 290       2555   -X+1/2,-Y,Z+1/2                                         
+REMARK 290       3555   -X,Y+1/2,-Z+1/2                                         
+REMARK 290       4555   X+1/2,-Y+1/2,-Z                                         
+REMARK 290                                                                      
+REMARK 290     WHERE NNN -> OPERATOR NUMBER                                     
+REMARK 290           MMM -> TRANSLATION VECTOR                                  
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY TRANSFORMATIONS                            
+REMARK 290 THE FOLLOWING TRANSFORMATIONS OPERATE ON THE ATOM/HETATM             
+REMARK 290 RECORDS IN THIS ENTRY TO PRODUCE CRYSTALLOGRAPHICALLY                
+REMARK 290 RELATED MOLECULES.                                                   
+REMARK 290   SMTRY1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 290   SMTRY1   2 -1.000000  0.000000  0.000000       15.50000            
+REMARK 290   SMTRY2   2  0.000000 -1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   2  0.000000  0.000000  1.000000       41.76000            
+REMARK 290   SMTRY1   3 -1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   3  0.000000  1.000000  0.000000       19.59000            
+REMARK 290   SMTRY3   3  0.000000  0.000000 -1.000000       41.76000            
+REMARK 290   SMTRY1   4  1.000000  0.000000  0.000000       15.50000            
+REMARK 290   SMTRY2   4  0.000000 -1.000000  0.000000       19.59000            
+REMARK 290   SMTRY3   4  0.000000  0.000000 -1.000000        0.00000            
+REMARK 290                                                                      
+REMARK 290 REMARK: NULL                                                         
+REMARK 300                                                                      
+REMARK 300 BIOMOLECULE: 1                                                       
+REMARK 300 SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM                
+REMARK 300 GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN                  
+REMARK 300 THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON               
+REMARK 300 BURIED SURFACE AREA.                                                 
+REMARK 350                                                                      
+REMARK 350 COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN           
+REMARK 350 BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE                
+REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS          
+REMARK 350 GIVEN BELOW.  BOTH NON-CRYSTALLOGRAPHIC AND                          
+REMARK 350 CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.                               
+REMARK 350                                                                      
+REMARK 350 BIOMOLECULE: 1                                                       
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: MONOMERIC                         
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: A                                     
+REMARK 350   BIOMT1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 350   BIOMT2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 350   BIOMT3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: COVALENT BOND ANGLES                                       
+REMARK 500                                                                      
+REMARK 500 THE STEREOCHEMICAL PARAMETERS OF THE FOLLOWING RESIDUES              
+REMARK 500 HAVE VALUES WHICH DEVIATE FROM EXPECTED VALUES BY MORE               
+REMARK 500 THAN 6*RMSD (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN               
+REMARK 500 IDENTIFIER; SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).                 
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT: (10X,I3,1X,A3,1X,A1,I4,A1,3(1X,A4,2X),12X,F5.1)              
+REMARK 500                                                                      
+REMARK 500 EXPECTED VALUES PROTEIN: ENGH AND HUBER, 1999                        
+REMARK 500 EXPECTED VALUES NUCLEIC ACID: CLOWNEY ET AL 1996                     
+REMARK 500                                                                      
+REMARK 500  M RES CSSEQI ATM1   ATM2   ATM3                                     
+REMARK 500    ASP A  20   CB  -  CG  -  OD2 ANGL. DEV. =  -6.8 DEGREES          
+REMARK 500    ASP A  34   CB  -  CG  -  OD1 ANGL. DEV. =   6.1 DEGREES          
+REMARK 500    ASP A  34   CB  -  CG  -  OD2 ANGL. DEV. =  -5.9 DEGREES          
+REMARK 500    ARG A  40   NE  -  CZ  -  NH2 ANGL. DEV. =  -4.7 DEGREES          
+REMARK 500    ASP A  59   CB  -  CG  -  OD2 ANGL. DEV. =  -5.6 DEGREES          
+REMARK 500    ASP A  65   CB  -  CG  -  OD1 ANGL. DEV. =   5.7 DEGREES          
+REMARK 500    ASP A  84   CB  -  CG  -  OD1 ANGL. DEV. =  12.2 DEGREES          
+REMARK 500    ASP A  84   CB  -  CG  -  OD2 ANGL. DEV. = -14.6 DEGREES          
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: TORSION ANGLES                                             
+REMARK 500                                                                      
+REMARK 500 TORSION ANGLES OUTSIDE THE EXPECTED RAMACHANDRAN REGIONS:            
+REMARK 500 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;               
+REMARK 500 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).                             
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT:(10X,I3,1X,A3,1X,A1,I4,A1,4X,F7.2,3X,F7.2)                    
+REMARK 500                                                                      
+REMARK 500 EXPECTED VALUES: GJ KLEYWEGT AND TA JONES (1996). PHI/PSI-           
+REMARK 500 CHOLOGY: RAMACHANDRAN REVISITED. STRUCTURE 4, 1395 - 1400            
+REMARK 500                                                                      
+REMARK 500  M RES CSSEQI        PSI       PHI                                   
+REMARK 500    SER A  38      -77.42   -141.70                                   
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: CHIRAL CENTERS                                             
+REMARK 500                                                                      
+REMARK 500 UNEXPECTED CONFIGURATION OF THE FOLLOWING CHIRAL                     
+REMARK 500 CENTER(S) USING IMPROPER CA--C--CB--N CHIRALITY                      
+REMARK 500 M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN                            
+REMARK 500 IDENTIFIER; SSEQ=SEQUENCE NUMBER; I=INSERTION CODE                   
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT: (11X,I3,1X,A3,1X,A1,I4,A1,6X,F5.1,6X,A1,10X,A1,3X,A16)       
+REMARK 500                                                                      
+REMARK 500   M RES CSSEQI    IMPROPER   EXPECTED   FOUND DETAILS                
+REMARK 500     ALA A   1       115.2                     ALPHA-CARBON           
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 525                                                                      
+REMARK 525 SOLVENT                                                              
+REMARK 525                                                                      
+REMARK 525 THE SOLVENT MOLECULES HAVE CHAIN IDENTIFIERS THAT                    
+REMARK 525 INDICATE THE POLYMER CHAIN WITH WHICH THEY ARE MOST                  
+REMARK 525 CLOSELY ASSOCIATED. THE REMARK LISTS ALL THE SOLVENT                 
+REMARK 525 MOLECULES WHICH ARE MORE THAN 5A AWAY FROM THE                       
+REMARK 525 NEAREST POLYMER CHAIN (M = MODEL NUMBER;                             
+REMARK 525 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE                  
+REMARK 525 NUMBER; I=INSERTION CODE):                                           
+REMARK 525                                                                      
+REMARK 525  M RES CSSEQI                                                        
+REMARK 525    HOH A1653        DISTANCE =  5.18 ANGSTROMS                       
+REMARK 525    HOH A1666        DISTANCE =  5.57 ANGSTROMS                       
+REMARK 525    HOH A1680        DISTANCE =  8.72 ANGSTROMS                       
+REMARK 800                                                                      
+REMARK 800 SITE                                                                 
+REMARK 800 SITE_IDENTIFIER: AC1                                                 
+REMARK 800 EVIDENCE_CODE: SOFTWARE                                              
+REMARK 800 SITE_DESCRIPTION: BINDING SITE FOR RESIDUE FES A 1602                
+DBREF  1A70 A    1    97  UNP    P00221   FER1_SPIOL      51    147             
+SEQADV 1A70 LYS A   92  UNP  P00221    GLU   142 ENGINEERED                     
+SEQRES   1 A   97  ALA ALA TYR LYS VAL THR LEU VAL THR PRO THR GLY ASN          
+SEQRES   2 A   97  VAL GLU PHE GLN CYS PRO ASP ASP VAL TYR ILE LEU ASP          
+SEQRES   3 A   97  ALA ALA GLU GLU GLU GLY ILE ASP LEU PRO TYR SER CYS          
+SEQRES   4 A   97  ARG ALA GLY SER CYS SER SER CYS ALA GLY LYS LEU LYS          
+SEQRES   5 A   97  THR GLY SER LEU ASN GLN ASP ASP GLN SER PHE LEU ASP          
+SEQRES   6 A   97  ASP ASP GLN ILE ASP GLU GLY TRP VAL LEU THR CYS ALA          
+SEQRES   7 A   97  ALA TYR PRO VAL SER ASP VAL THR ILE GLU THR HIS LYS          
+SEQRES   8 A   97  LYS GLU GLU LEU THR ALA                                      
+HET    FES  A1602       4                                                       
+HETNAM     FES FE2/S2 (INORGANIC) CLUSTER                                       
+FORMUL   2  FES    FE2 S2                                                       
+FORMUL   3  HOH   *81(H2 O)                                                     
+HELIX    1   1 ILE A   24  GLU A   30  1                                   7    
+HELIX    2   2 ASP A   66  GLU A   71  1                                   6    
+HELIX    3   3 THR A   76  ALA A   78  5                                   3    
+HELIX    4   4 LYS A   92  GLU A   94  5                                   3    
+SHEET    1   A 5 GLY A  12  PRO A  19  0                                        
+SHEET    2   A 5 ALA A   2  THR A   9 -1  N  THR A   9   O  GLY A  12           
+SHEET    3   A 5 VAL A  85  GLU A  88  1  N  VAL A  85   O  THR A   6           
+SHEET    4   A 5 ALA A  48  THR A  53 -1  N  THR A  53   O  THR A  86           
+SHEET    5   A 5 TRP A  73  LEU A  75 -1  N  VAL A  74   O  GLY A  49           
+LINK        FE1  FES A1602                 SG  CYS A  39     1555   1555  2.32  
+LINK        FE1  FES A1602                 SG  CYS A  44     1555   1555  2.28  
+LINK        FE2  FES A1602                 SG  CYS A  47     1555   1555  2.36  
+LINK        FE2  FES A1602                 SG  CYS A  77     1555   1555  2.27  
+SITE     1 AC1  8 SER A  38  CYS A  39  ARG A  40  GLY A  42                    
+SITE     2 AC1  8 SER A  43  CYS A  44  CYS A  47  CYS A  77                    
+CRYST1   31.000   39.180   83.520  90.00  90.00  90.00 P 21 21 21    4          
+ORIGX1      1.000000  0.000000  0.000000        0.00000                         
+ORIGX2      0.000000  1.000000  0.000000        0.00000                         
+ORIGX3      0.000000  0.000000  1.000000        0.00000                         
+SCALE1      0.032258  0.000000  0.000000        0.00000                         
+SCALE2      0.000000  0.025523  0.000000        0.00000                         
+SCALE3      0.000000  0.000000  0.011973        0.00000                         
+ATOM      1  N   ALA A   1       1.578  -4.284   5.235  1.00 64.26           N  
+ATOM      2  CA  ALA A   1       2.384  -5.448   5.549  1.00 56.75           C  
+ATOM      3  C   ALA A   1       3.756  -4.955   5.925  1.00 52.65           C  
+ATOM      4  O   ALA A   1       3.885  -4.610   7.073  1.00 48.15           O  
+ATOM      5  CB  ALA A   1       1.801  -6.118   6.780  1.00 57.60           C  
+ATOM      6  N   ALA A   2       4.702  -4.829   4.989  1.00 44.72           N  
+ATOM      7  CA  ALA A   2       6.033  -4.319   5.297  1.00 39.74           C  
+ATOM      8  C   ALA A   2       6.471  -3.432   4.151  1.00 38.97           C  
+ATOM      9  O   ALA A   2       6.000  -3.558   3.005  1.00 35.65           O  
+ATOM     10  CB  ALA A   2       6.977  -5.471   5.509  1.00 39.07           C  
+ATOM     11  N   TYR A   3       7.381  -2.517   4.408  1.00 35.77           N  
+ATOM     12  CA  TYR A   3       7.706  -1.626   3.320  1.00 34.41           C  
+ATOM     13  C   TYR A   3       9.186  -1.384   3.280  1.00 33.59           C  
+ATOM     14  O   TYR A   3       9.923  -1.779   4.188  1.00 31.95           O  
+ATOM     15  CB  TYR A   3       6.953  -0.249   3.319  1.00 39.83           C  
+ATOM     16  CG  TYR A   3       5.433  -0.309   3.472  1.00 45.38           C  
+ATOM     17  CD1 TYR A   3       4.627  -0.464   2.343  1.00 44.25           C  
+ATOM     18  CD2 TYR A   3       4.849  -0.181   4.741  1.00 42.82           C  
+ATOM     19  CE1 TYR A   3       3.235  -0.498   2.478  1.00 44.87           C  
+ATOM     20  CE2 TYR A   3       3.455  -0.215   4.877  1.00 31.11           C  
+ATOM     21  CZ  TYR A   3       2.650  -0.374   3.744  1.00 36.82           C  
+ATOM     22  OH  TYR A   3       1.297  -0.407   3.867  1.00 45.94           O  
+ATOM     23  N   LYS A   4       9.588  -0.749   2.216  1.00 25.97           N  
+ATOM     24  CA  LYS A   4      10.996  -0.492   1.999  1.00 26.02           C  
+ATOM     25  C   LYS A   4      11.389   0.887   2.512  1.00 27.15           C  
+ATOM     26  O   LYS A   4      10.856   1.920   2.077  1.00 29.78           O  
+ATOM     27  CB  LYS A   4      11.330  -0.599   0.521  1.00 28.74           C  
+ATOM     28  CG  LYS A   4      12.767  -0.182   0.231  1.00 41.18           C  
+ATOM     29  CD  LYS A   4      13.579  -1.258  -0.483  1.00 65.99           C  
+ATOM     30  CE  LYS A   4      13.898  -2.462   0.403  1.00 71.21           C  
+ATOM     31  NZ  LYS A   4      15.116  -3.169  -0.011  1.00100.00           N  
+ATOM     32  N   VAL A   5      12.331   0.863   3.439  1.00 25.81           N  
+ATOM     33  CA  VAL A   5      12.856   2.091   4.022  1.00 21.97           C  
+ATOM     34  C   VAL A   5      14.205   2.397   3.480  1.00 24.32           C  
+ATOM     35  O   VAL A   5      15.049   1.515   3.638  1.00 28.20           O  
+ATOM     36  CB  VAL A   5      12.952   2.019   5.546  1.00 26.13           C  
+ATOM     37  CG1 VAL A   5      13.589   3.279   6.154  1.00 24.03           C  
+ATOM     38  CG2 VAL A   5      11.587   1.886   6.220  1.00 28.00           C  
+ATOM     39  N   THR A   6      14.446   3.585   2.881  1.00 23.42           N  
+ATOM     40  CA  THR A   6      15.819   3.958   2.510  1.00 22.77           C  
+ATOM     41  C   THR A   6      16.295   5.055   3.506  1.00 27.61           C  
+ATOM     42  O   THR A   6      15.661   6.102   3.654  1.00 28.00           O  
+ATOM     43  CB  THR A   6      15.821   4.529   1.094  1.00 26.23           C  
+ATOM     44  OG1 THR A   6      15.370   3.515   0.217  1.00 27.15           O  
+ATOM     45  CG2 THR A   6      17.230   4.964   0.813  1.00 27.17           C  
+ATOM     46  N   LEU A   7      17.379   4.897   4.238  1.00 20.82           N  
+ATOM     47  CA  LEU A   7      17.815   5.979   5.096  1.00 18.17           C  
+ATOM     48  C   LEU A   7      19.102   6.537   4.478  1.00 26.80           C  
+ATOM     49  O   LEU A   7      20.054   5.815   4.166  1.00 31.28           O  
+ATOM     50  CB  LEU A   7      18.204   5.474   6.533  1.00 24.27           C  
+ATOM     51  CG  LEU A   7      17.064   4.808   7.373  1.00 25.99           C  
+ATOM     52  CD1 LEU A   7      17.597   4.132   8.670  1.00 28.24           C  
+ATOM     53  CD2 LEU A   7      15.847   5.760   7.582  1.00 23.18           C  
+ATOM     54  N   VAL A   8      19.178   7.825   4.390  1.00 24.64           N  
+ATOM     55  CA  VAL A   8      20.351   8.582   3.937  1.00 24.53           C  
+ATOM     56  C   VAL A   8      21.067   9.037   5.189  1.00 25.60           C  
+ATOM     57  O   VAL A   8      20.609  10.034   5.788  1.00 24.85           O  
+ATOM     58  CB  VAL A   8      19.949   9.817   3.074  1.00 26.13           C  
+ATOM     59  CG1 VAL A   8      21.154  10.667   2.669  1.00 26.51           C  
+ATOM     60  CG2 VAL A   8      19.153   9.301   1.862  1.00 23.87           C  
+ATOM     61  N   THR A   9      22.132   8.282   5.580  1.00 23.15           N  
+ATOM     62  CA  THR A   9      22.863   8.664   6.790  1.00 23.40           C  
+ATOM     63  C   THR A   9      24.173   9.314   6.438  1.00 33.13           C  
+ATOM     64  O   THR A   9      24.654   9.241   5.303  1.00 31.04           O  
+ATOM     65  CB  THR A   9      23.218   7.469   7.641  1.00 29.07           C  
+ATOM     66  OG1 THR A   9      24.437   6.916   7.123  1.00 34.25           O  
+ATOM     67  CG2 THR A   9      22.097   6.424   7.576  1.00 23.85           C  
+ATOM     68  N   PRO A  10      24.773   9.907   7.443  1.00 32.74           N  
+ATOM     69  CA  PRO A  10      26.012  10.626   7.192  1.00 40.21           C  
+ATOM     70  C   PRO A  10      27.145   9.843   6.552  1.00 39.02           C  
+ATOM     71  O   PRO A  10      27.994  10.367   5.811  1.00 40.41           O  
+ATOM     72  CB  PRO A  10      26.365  11.354   8.512  1.00 40.85           C  
+ATOM     73  CG  PRO A  10      25.100  11.360   9.383  1.00 38.81           C  
+ATOM     74  CD  PRO A  10      24.169  10.310   8.772  1.00 29.25           C  
+ATOM     75  N   THR A  11      27.149   8.583   6.860  1.00 29.69           N  
+ATOM     76  CA  THR A  11      28.191   7.741   6.370  1.00 31.68           C  
+ATOM     77  C   THR A  11      27.680   6.836   5.253  1.00 40.26           C  
+ATOM     78  O   THR A  11      28.315   5.815   4.937  1.00 32.78           O  
+ATOM     79  CB  THR A  11      28.745   6.892   7.546  1.00 35.16           C  
+ATOM     80  OG1 THR A  11      27.737   6.011   8.077  1.00 41.86           O  
+ATOM     81  CG2 THR A  11      29.280   7.785   8.637  1.00 34.63           C  
+ATOM     82  N   GLY A  12      26.479   7.095   4.715  1.00 29.29           N  
+ATOM     83  CA  GLY A  12      26.019   6.151   3.680  1.00 27.67           C  
+ATOM     84  C   GLY A  12      24.548   5.765   3.657  1.00 31.61           C  
+ATOM     85  O   GLY A  12      23.861   5.746   4.657  1.00 27.16           O  
+ATOM     86  N   ASN A  13      24.028   5.411   2.492  1.00 27.49           N  
+ATOM     87  CA  ASN A  13      22.641   4.967   2.352  1.00 28.15           C  
+ATOM     88  C   ASN A  13      22.472   3.508   2.820  1.00 34.35           C  
+ATOM     89  O   ASN A  13      23.261   2.592   2.523  1.00 34.29           O  
+ATOM     90  CB  ASN A  13      22.229   5.041   0.859  1.00 22.27           C  
+ATOM     91  CG  ASN A  13      22.215   6.448   0.279  1.00 28.56           C  
+ATOM     92  OD1 ASN A  13      22.151   7.484   0.966  1.00 29.38           O  
+ATOM     93  ND2 ASN A  13      22.260   6.532  -1.054  1.00 29.02           N  
+ATOM     94  N   VAL A  14      21.376   3.154   3.448  1.00 24.93           N  
+ATOM     95  CA  VAL A  14      21.199   1.768   3.845  1.00 24.17           C  
+ATOM     96  C   VAL A  14      19.689   1.494   3.624  1.00 35.26           C  
+ATOM     97  O   VAL A  14      18.847   2.366   3.880  1.00 34.14           O  
+ATOM     98  CB  VAL A  14      21.457   1.553   5.350  1.00 35.72           C  
+ATOM     99  CG1 VAL A  14      22.781   2.158   5.819  1.00 45.19           C  
+ATOM    100  CG2 VAL A  14      20.379   2.191   6.228  1.00 37.45           C  
+ATOM    101  N   GLU A  15      19.318   0.319   3.133  1.00 25.56           N  
+ATOM    102  CA  GLU A  15      17.873  -0.022   2.949  1.00 24.81           C  
+ATOM    103  C   GLU A  15      17.513  -1.257   3.780  1.00 28.51           C  
+ATOM    104  O   GLU A  15      18.367  -2.054   4.152  1.00 39.92           O  
+ATOM    105  CB  GLU A  15      17.528  -0.396   1.499  1.00 26.55           C  
+ATOM    106  CG  GLU A  15      18.058   0.554   0.428  1.00 76.87           C  
+ATOM    107  CD  GLU A  15      17.768   0.033  -0.987  1.00100.00           C  
+ATOM    108  OE1 GLU A  15      17.197  -1.116  -1.149  1.00 68.35           O  
+ATOM    109  OE2 GLU A  15      18.097   0.737  -2.014  1.00100.00           O  
+ATOM    110  N   PHE A  16      16.247  -1.431   4.065  1.00 26.52           N  
+ATOM    111  CA  PHE A  16      15.777  -2.608   4.823  1.00 28.30           C  
+ATOM    112  C   PHE A  16      14.244  -2.584   4.803  1.00 33.00           C  
+ATOM    113  O   PHE A  16      13.635  -1.520   4.649  1.00 30.39           O  
+ATOM    114  CB  PHE A  16      16.306  -2.569   6.266  1.00 32.53           C  
+ATOM    115  CG  PHE A  16      15.886  -1.332   7.078  1.00 25.02           C  
+ATOM    116  CD1 PHE A  16      14.640  -1.297   7.723  1.00 32.70           C  
+ATOM    117  CD2 PHE A  16      16.753  -0.235   7.192  1.00 28.27           C  
+ATOM    118  CE1 PHE A  16      14.269  -0.176   8.481  1.00 33.73           C  
+ATOM    119  CE2 PHE A  16      16.383   0.883   7.952  1.00 30.83           C  
+ATOM    120  CZ  PHE A  16      15.142   0.913   8.597  1.00 28.38           C  
+ATOM    121  N   GLN A  17      13.645  -3.759   4.941  1.00 35.55           N  
+ATOM    122  CA  GLN A  17      12.164  -3.892   4.941  1.00 33.09           C  
+ATOM    123  C   GLN A  17      11.622  -3.664   6.368  1.00 36.52           C  
+ATOM    124  O   GLN A  17      12.161  -4.187   7.348  1.00 34.16           O  
+ATOM    125  CB  GLN A  17      11.745  -5.297   4.473  1.00 40.84           C  
+ATOM    126  CG  GLN A  17      12.118  -5.610   3.015  1.00 75.19           C  
+ATOM    127  CD  GLN A  17      11.176  -5.056   1.937  1.00100.00           C  
+ATOM    128  OE1 GLN A  17      10.033  -5.500   1.819  1.00 91.53           O  
+ATOM    129  NE2 GLN A  17      11.600  -4.099   1.131  1.00 56.40           N  
+ATOM    130  N   CYS A  18      10.541  -2.882   6.483  1.00 32.45           N  
+ATOM    131  CA  CYS A  18       9.949  -2.554   7.813  1.00 34.72           C  
+ATOM    132  C   CYS A  18       8.464  -2.778   7.839  1.00 34.29           C  
+ATOM    133  O   CYS A  18       7.700  -2.208   7.075  1.00 31.05           O  
+ATOM    134  CB  CYS A  18      10.249  -1.090   8.161  1.00 29.02           C  
+ATOM    135  SG  CYS A  18       9.658  -0.587   9.853  1.00 28.94           S  
+ATOM    136  N   PRO A  19       8.085  -3.629   8.787  1.00 33.32           N  
+ATOM    137  CA  PRO A  19       6.690  -3.963   9.026  1.00 32.10           C  
+ATOM    138  C   PRO A  19       6.006  -2.702   9.499  1.00 40.78           C  
+ATOM    139  O   PRO A  19       6.592  -1.893  10.222  1.00 36.47           O  
+ATOM    140  CB  PRO A  19       6.661  -5.023  10.134  1.00 34.58           C  
+ATOM    141  CG  PRO A  19       8.108  -5.439  10.360  1.00 38.47           C  
+ATOM    142  CD  PRO A  19       9.005  -4.461   9.587  1.00 36.38           C  
+ATOM    143  N   ASP A  20       4.761  -2.545   9.044  1.00 34.47           N  
+ATOM    144  CA  ASP A  20       3.939  -1.390   9.316  1.00 33.10           C  
+ATOM    145  C   ASP A  20       3.594  -1.249  10.782  1.00 37.33           C  
+ATOM    146  O   ASP A  20       3.007  -0.234  11.167  1.00 33.51           O  
+ATOM    147  CB  ASP A  20       2.776  -1.182   8.329  1.00 44.18           C  
+ATOM    148  CG  ASP A  20       1.663  -2.172   8.473  1.00 58.88           C  
+ATOM    149  OD1 ASP A  20       1.737  -3.155   9.206  1.00 56.81           O  
+ATOM    150  OD2 ASP A  20       0.598  -1.806   7.784  1.00 79.64           O  
+ATOM    151  N   ASP A  21       3.977  -2.293  11.543  1.00 35.64           N  
+ATOM    152  CA  ASP A  21       3.728  -2.237  12.962  1.00 40.82           C  
+ATOM    153  C   ASP A  21       4.983  -2.105  13.764  1.00 45.13           C  
+ATOM    154  O   ASP A  21       4.965  -2.495  14.923  1.00 45.86           O  
+ATOM    155  CB  ASP A  21       2.706  -3.233  13.568  1.00 39.20           C  
+ATOM    156  CG  ASP A  21       3.075  -4.710  13.573  1.00 64.17           C  
+ATOM    157  OD1 ASP A  21       4.036  -5.157  12.965  1.00 61.46           O  
+ATOM    158  OD2 ASP A  21       2.230  -5.476  14.256  1.00 79.00           O  
+ATOM    159  N   VAL A  22       6.067  -1.601  13.191  1.00 30.02           N  
+ATOM    160  CA  VAL A  22       7.303  -1.467  13.989  1.00 23.17           C  
+ATOM    161  C   VAL A  22       7.875  -0.083  13.703  1.00 37.42           C  
+ATOM    162  O   VAL A  22       7.841   0.425  12.545  1.00 29.14           O  
+ATOM    163  CB  VAL A  22       8.279  -2.554  13.524  1.00 35.95           C  
+ATOM    164  CG1 VAL A  22       9.671  -2.333  14.072  1.00 33.42           C  
+ATOM    165  CG2 VAL A  22       7.790  -3.977  13.845  1.00 40.60           C  
+ATOM    166  N   TYR A  23       8.319   0.603  14.747  1.00 31.07           N  
+ATOM    167  CA  TYR A  23       8.868   1.922  14.526  1.00 23.20           C  
+ATOM    168  C   TYR A  23      10.146   1.813  13.697  1.00 20.53           C  
+ATOM    169  O   TYR A  23      10.967   0.886  13.815  1.00 22.64           O  
+ATOM    170  CB  TYR A  23       9.207   2.601  15.864  1.00 24.89           C  
+ATOM    171  CG  TYR A  23       8.048   2.917  16.813  1.00 29.11           C  
+ATOM    172  CD1 TYR A  23       6.967   3.710  16.422  1.00 25.37           C  
+ATOM    173  CD2 TYR A  23       8.087   2.419  18.126  1.00 29.47           C  
+ATOM    174  CE1 TYR A  23       5.959   3.981  17.342  1.00 33.05           C  
+ATOM    175  CE2 TYR A  23       7.167   2.794  19.097  1.00 27.42           C  
+ATOM    176  CZ  TYR A  23       6.100   3.579  18.677  1.00 29.98           C  
+ATOM    177  OH  TYR A  23       5.135   3.895  19.566  1.00 32.49           O  
+ATOM    178  N   ILE A  24      10.358   2.857  12.891  1.00 26.63           N  
+ATOM    179  CA  ILE A  24      11.544   3.002  12.045  1.00 23.62           C  
+ATOM    180  C   ILE A  24      12.848   2.723  12.839  1.00 27.47           C  
+ATOM    181  O   ILE A  24      13.721   1.942  12.446  1.00 25.11           O  
+ATOM    182  CB  ILE A  24      11.530   4.355  11.265  1.00 27.34           C  
+ATOM    183  CG1 ILE A  24      10.308   4.326  10.338  1.00 27.39           C  
+ATOM    184  CG2 ILE A  24      12.839   4.618  10.484  1.00 25.71           C  
+ATOM    185  CD1 ILE A  24      10.409   5.326   9.248  1.00 35.33           C  
+ATOM    186  N   LEU A  25      13.016   3.398  13.982  1.00 21.68           N  
+ATOM    187  CA  LEU A  25      14.226   3.232  14.751  1.00 23.19           C  
+ATOM    188  C   LEU A  25      14.494   1.805  15.152  1.00 19.67           C  
+ATOM    189  O   LEU A  25      15.622   1.287  15.036  1.00 21.97           O  
+ATOM    190  CB  LEU A  25      14.214   4.251  15.971  1.00 25.03           C  
+ATOM    191  CG  LEU A  25      15.399   4.134  16.985  1.00 33.85           C  
+ATOM    192  CD1 LEU A  25      16.767   4.626  16.432  1.00 28.22           C  
+ATOM    193  CD2 LEU A  25      15.003   4.794  18.321  1.00 23.35           C  
+ATOM    194  N   ASP A  26      13.445   1.170  15.740  1.00 21.80           N  
+ATOM    195  CA  ASP A  26      13.567  -0.238  16.197  1.00 24.22           C  
+ATOM    196  C   ASP A  26      13.968  -1.184  15.076  1.00 28.12           C  
+ATOM    197  O   ASP A  26      14.887  -2.035  15.191  1.00 26.29           O  
+ATOM    198  CB  ASP A  26      12.229  -0.815  16.715  1.00 26.64           C  
+ATOM    199  CG  ASP A  26      11.713  -0.170  18.009  1.00 37.98           C  
+ATOM    200  OD1 ASP A  26      12.168   0.845  18.458  1.00 46.55           O  
+ATOM    201  OD2 ASP A  26      10.581  -0.638  18.464  1.00 44.33           O  
+ATOM    202  N   ALA A  27      13.266  -0.995  13.938  1.00 28.45           N  
+ATOM    203  CA  ALA A  27      13.559  -1.804  12.709  1.00 30.31           C  
+ATOM    204  C   ALA A  27      15.013  -1.637  12.266  1.00 24.55           C  
+ATOM    205  O   ALA A  27      15.704  -2.620  11.990  1.00 26.78           O  
+ATOM    206  CB  ALA A  27      12.584  -1.510  11.550  1.00 27.80           C  
+ATOM    207  N   ALA A  28      15.467  -0.370  12.227  1.00 21.71           N  
+ATOM    208  CA  ALA A  28      16.844  -0.113  11.872  1.00 22.96           C  
+ATOM    209  C   ALA A  28      17.837  -0.801  12.830  1.00 31.14           C  
+ATOM    210  O   ALA A  28      18.866  -1.394  12.440  1.00 29.37           O  
+ATOM    211  CB  ALA A  28      17.190   1.365  11.769  1.00 30.64           C  
+ATOM    212  N   GLU A  29      17.519  -0.733  14.138  1.00 32.57           N  
+ATOM    213  CA  GLU A  29      18.383  -1.339  15.157  1.00 33.34           C  
+ATOM    214  C   GLU A  29      18.598  -2.824  14.926  1.00 23.91           C  
+ATOM    215  O   GLU A  29      19.748  -3.285  14.959  1.00 29.83           O  
+ATOM    216  CB  GLU A  29      17.921  -0.963  16.602  1.00 25.60           C  
+ATOM    217  CG  GLU A  29      18.305   0.502  16.913  1.00 24.44           C  
+ATOM    218  CD  GLU A  29      17.457   1.018  18.046  1.00 25.19           C  
+ATOM    219  OE1 GLU A  29      16.460   0.426  18.438  1.00 24.78           O  
+ATOM    220  OE2 GLU A  29      17.923   2.098  18.586  1.00 23.81           O  
+ATOM    221  N   GLU A  30      17.448  -3.455  14.709  1.00 27.47           N  
+ATOM    222  CA  GLU A  30      17.286  -4.882  14.380  1.00 37.83           C  
+ATOM    223  C   GLU A  30      18.140  -5.359  13.188  1.00 40.11           C  
+ATOM    224  O   GLU A  30      18.573  -6.495  13.120  1.00 39.63           O  
+ATOM    225  CB  GLU A  30      15.794  -5.252  14.170  1.00 40.07           C  
+ATOM    226  CG  GLU A  30      14.957  -5.155  15.458  1.00 42.44           C  
+ATOM    227  CD  GLU A  30      13.539  -5.612  15.275  1.00 56.36           C  
+ATOM    228  OE1 GLU A  30      13.164  -6.260  14.314  1.00 50.54           O  
+ATOM    229  OE2 GLU A  30      12.725  -5.114  16.174  1.00 36.99           O  
+ATOM    230  N   GLU A  31      18.344  -4.473  12.222  1.00 38.32           N  
+ATOM    231  CA  GLU A  31      19.177  -4.703  11.071  1.00 35.60           C  
+ATOM    232  C   GLU A  31      20.646  -4.398  11.378  1.00 52.16           C  
+ATOM    233  O   GLU A  31      21.518  -4.562  10.510  1.00 49.05           O  
+ATOM    234  CB  GLU A  31      18.620  -3.894   9.866  1.00 32.36           C  
+ATOM    235  CG  GLU A  31      17.343  -4.552   9.270  1.00 42.97           C  
+ATOM    236  CD  GLU A  31      17.511  -6.010   8.860  1.00 67.41           C  
+ATOM    237  OE1 GLU A  31      18.482  -6.441   8.262  1.00 80.04           O  
+ATOM    238  OE2 GLU A  31      16.571  -6.805   9.318  1.00 80.93           O  
+ATOM    239  N   GLY A  32      20.934  -3.911  12.608  1.00 36.45           N  
+ATOM    240  CA  GLY A  32      22.297  -3.587  13.006  1.00 31.78           C  
+ATOM    241  C   GLY A  32      22.778  -2.203  12.703  1.00 31.69           C  
+ATOM    242  O   GLY A  32      23.972  -1.976  12.642  1.00 34.57           O  
+ATOM    243  N   ILE A  33      21.850  -1.251  12.501  1.00 35.35           N  
+ATOM    244  CA  ILE A  33      22.177   0.144  12.177  1.00 28.42           C  
+ATOM    245  C   ILE A  33      22.256   1.009  13.444  1.00 33.98           C  
+ATOM    246  O   ILE A  33      21.378   0.942  14.287  1.00 32.45           O  
+ATOM    247  CB  ILE A  33      21.135   0.765  11.251  1.00 31.00           C  
+ATOM    248  CG1 ILE A  33      20.902  -0.025   9.950  1.00 47.25           C  
+ATOM    249  CG2 ILE A  33      21.426   2.216  10.846  1.00 27.16           C  
+ATOM    250  CD1 ILE A  33      19.920   0.766   9.061  1.00 51.98           C  
+ATOM    251  N   ASP A  34      23.258   1.860  13.579  1.00 31.29           N  
+ATOM    252  CA  ASP A  34      23.303   2.712  14.757  1.00 34.35           C  
+ATOM    253  C   ASP A  34      22.744   4.100  14.464  1.00 43.06           C  
+ATOM    254  O   ASP A  34      23.349   4.874  13.724  1.00 33.14           O  
+ATOM    255  CB  ASP A  34      24.761   2.854  15.196  1.00 38.16           C  
+ATOM    256  CG  ASP A  34      24.920   3.628  16.465  1.00 60.77           C  
+ATOM    257  OD1 ASP A  34      24.013   4.180  17.048  1.00 67.71           O  
+ATOM    258  OD2 ASP A  34      26.160   3.670  16.870  1.00100.00           O  
+ATOM    259  N   LEU A  35      21.606   4.432  15.063  1.00 25.84           N  
+ATOM    260  CA  LEU A  35      20.982   5.725  14.886  1.00 25.49           C  
+ATOM    261  C   LEU A  35      20.972   6.503  16.230  1.00 30.02           C  
+ATOM    262  O   LEU A  35      20.894   5.970  17.324  1.00 30.20           O  
+ATOM    263  CB  LEU A  35      19.524   5.626  14.330  1.00 29.86           C  
+ATOM    264  CG  LEU A  35      19.326   4.995  12.913  1.00 34.99           C  
+ATOM    265  CD1 LEU A  35      17.826   5.101  12.508  1.00 25.92           C  
+ATOM    266  CD2 LEU A  35      20.204   5.766  11.885  1.00 28.46           C  
+ATOM    267  N   PRO A  36      20.991   7.774  16.189  1.00 24.98           N  
+ATOM    268  CA  PRO A  36      20.915   8.450  17.496  1.00 27.92           C  
+ATOM    269  C   PRO A  36      19.519   8.369  18.150  1.00 34.05           C  
+ATOM    270  O   PRO A  36      18.406   8.438  17.518  1.00 24.43           O  
+ATOM    271  CB  PRO A  36      21.187   9.939  17.172  1.00 25.14           C  
+ATOM    272  CG  PRO A  36      21.223  10.101  15.644  1.00 33.38           C  
+ATOM    273  CD  PRO A  36      21.123   8.723  15.027  1.00 27.27           C  
+ATOM    274  N   TYR A  37      19.578   8.381  19.481  1.00 24.54           N  
+ATOM    275  CA  TYR A  37      18.347   8.494  20.237  1.00 24.90           C  
+ATOM    276  C   TYR A  37      18.650   8.899  21.687  1.00 44.09           C  
+ATOM    277  O   TYR A  37      19.790   8.838  22.140  1.00 28.24           O  
+ATOM    278  CB  TYR A  37      17.491   7.256  20.362  1.00 18.81           C  
+ATOM    279  CG  TYR A  37      18.233   6.159  21.122  1.00 24.63           C  
+ATOM    280  CD1 TYR A  37      19.137   5.311  20.464  1.00 26.04           C  
+ATOM    281  CD2 TYR A  37      18.018   5.944  22.486  1.00 29.97           C  
+ATOM    282  CE1 TYR A  37      19.817   4.294  21.132  1.00 30.23           C  
+ATOM    283  CE2 TYR A  37      18.673   4.912  23.167  1.00 24.88           C  
+ATOM    284  CZ  TYR A  37      19.581   4.091  22.501  1.00 30.95           C  
+ATOM    285  OH  TYR A  37      20.213   3.062  23.175  1.00 38.22           O  
+ATOM    286  N   SER A  38      17.595   9.277  22.418  1.00 29.18           N  
+ATOM    287  CA  SER A  38      17.725   9.558  23.845  1.00 32.26           C  
+ATOM    288  C   SER A  38      16.490   9.055  24.659  1.00 25.30           C  
+ATOM    289  O   SER A  38      16.606   7.975  25.282  1.00 25.32           O  
+ATOM    290  CB  SER A  38      18.302  10.927  24.200  1.00 22.00           C  
+ATOM    291  OG  SER A  38      17.293  11.869  24.016  1.00 33.52           O  
+ATOM    292  N   CYS A  39      15.380   9.816  24.591  1.00 23.71           N  
+ATOM    293  CA  CYS A  39      14.183   9.490  25.362  1.00 26.55           C  
+ATOM    294  C   CYS A  39      13.438   8.285  24.842  1.00 34.48           C  
+ATOM    295  O   CYS A  39      12.786   7.587  25.618  1.00 26.18           O  
+ATOM    296  CB  CYS A  39      13.199  10.697  25.491  1.00 29.83           C  
+ATOM    297  SG  CYS A  39      12.242  11.025  23.939  1.00 29.79           S  
+ATOM    298  N   ARG A  40      13.487   8.054  23.495  1.00 24.58           N  
+ATOM    299  CA  ARG A  40      12.723   6.913  22.913  1.00 28.18           C  
+ATOM    300  C   ARG A  40      11.205   7.064  23.170  1.00 30.09           C  
+ATOM    301  O   ARG A  40      10.487   6.085  23.025  1.00 31.35           O  
+ATOM    302  CB  ARG A  40      13.215   5.463  23.156  1.00 26.06           C  
+ATOM    303  CG  ARG A  40      14.725   5.291  22.954  1.00 26.48           C  
+ATOM    304  CD  ARG A  40      15.197   3.855  23.177  1.00 29.25           C  
+ATOM    305  NE  ARG A  40      14.665   2.882  22.173  1.00 29.50           N  
+ATOM    306  CZ  ARG A  40      15.384   2.358  21.164  1.00 24.32           C  
+ATOM    307  NH1 ARG A  40      16.675   2.663  20.962  1.00 22.08           N  
+ATOM    308  NH2 ARG A  40      14.730   1.522  20.369  1.00 24.44           N  
+ATOM    309  N   ALA A  41      10.703   8.251  23.551  1.00 30.98           N  
+ATOM    310  CA  ALA A  41       9.258   8.340  23.833  1.00 35.10           C  
+ATOM    311  C   ALA A  41       8.586   9.429  23.005  1.00 32.60           C  
+ATOM    312  O   ALA A  41       7.617   9.978  23.480  1.00 33.61           O  
+ATOM    313  CB  ALA A  41       9.061   8.685  25.305  1.00 32.00           C  
+ATOM    314  N   GLY A  42       9.184   9.924  21.887  1.00 37.71           N  
+ATOM    315  CA  GLY A  42       8.569  11.038  21.100  1.00 32.94           C  
+ATOM    316  C   GLY A  42       8.463  12.452  21.726  1.00 33.79           C  
+ATOM    317  O   GLY A  42       7.614  13.321  21.347  1.00 27.19           O  
+ATOM    318  N   SER A  43       9.383  12.734  22.670  1.00 29.21           N  
+ATOM    319  CA  SER A  43       9.217  14.009  23.222  1.00 27.72           C  
+ATOM    320  C   SER A  43      10.468  14.838  23.104  1.00 36.35           C  
+ATOM    321  O   SER A  43      10.575  15.886  23.772  1.00 37.69           O  
+ATOM    322  CB  SER A  43       8.702  13.848  24.657  1.00 41.18           C  
+ATOM    323  OG  SER A  43       9.762  13.391  25.438  1.00 37.35           O  
+ATOM    324  N   CYS A  44      11.424  14.383  22.281  1.00 24.01           N  
+ATOM    325  CA  CYS A  44      12.645  15.163  22.186  1.00 26.72           C  
+ATOM    326  C   CYS A  44      13.177  15.352  20.744  1.00 34.67           C  
+ATOM    327  O   CYS A  44      12.489  14.868  19.850  1.00 30.25           O  
+ATOM    328  CB  CYS A  44      13.745  14.604  23.122  1.00 22.69           C  
+ATOM    329  SG  CYS A  44      14.770  13.299  22.485  1.00 24.81           S  
+ATOM    330  N   SER A  45      14.308  16.078  20.499  1.00 24.73           N  
+ATOM    331  CA  SER A  45      14.777  16.268  19.112  1.00 26.39           C  
+ATOM    332  C   SER A  45      15.868  15.266  18.722  1.00 30.37           C  
+ATOM    333  O   SER A  45      16.412  15.218  17.615  1.00 28.25           O  
+ATOM    334  CB  SER A  45      15.275  17.674  18.949  1.00 27.38           C  
+ATOM    335  OG  SER A  45      16.431  17.813  19.806  1.00 29.38           O  
+ATOM    336  N   SER A  46      16.301  14.457  19.674  1.00 21.91           N  
+ATOM    337  CA  SER A  46      17.426  13.616  19.381  1.00 21.12           C  
+ATOM    338  C   SER A  46      17.353  12.724  18.144  1.00 25.42           C  
+ATOM    339  O   SER A  46      18.410  12.471  17.586  1.00 26.31           O  
+ATOM    340  CB  SER A  46      17.834  12.702  20.561  1.00 28.46           C  
+ATOM    341  OG  SER A  46      18.253  13.537  21.616  1.00 36.10           O  
+ATOM    342  N   CYS A  47      16.247  12.026  17.904  1.00 21.93           N  
+ATOM    343  CA  CYS A  47      16.202  11.056  16.827  1.00 21.80           C  
+ATOM    344  C   CYS A  47      15.649  11.698  15.536  1.00 21.02           C  
+ATOM    345  O   CYS A  47      15.149  10.997  14.648  1.00 23.37           O  
+ATOM    346  CB  CYS A  47      15.227   9.940  17.245  1.00 20.46           C  
+ATOM    347  SG  CYS A  47      13.560  10.572  17.479  1.00 24.27           S  
+ATOM    348  N   ALA A  48      15.664  12.998  15.481  1.00 23.57           N  
+ATOM    349  CA  ALA A  48      15.062  13.721  14.300  1.00 27.12           C  
+ATOM    350  C   ALA A  48      15.728  13.356  12.956  1.00 23.33           C  
+ATOM    351  O   ALA A  48      16.985  13.288  12.810  1.00 22.29           O  
+ATOM    352  CB  ALA A  48      15.001  15.246  14.459  1.00 23.21           C  
+ATOM    353  N   GLY A  49      14.841  13.313  11.994  1.00 26.74           N  
+ATOM    354  CA  GLY A  49      15.186  13.132  10.580  1.00 29.02           C  
+ATOM    355  C   GLY A  49      14.265  14.081   9.719  1.00 28.23           C  
+ATOM    356  O   GLY A  49      13.303  14.752  10.210  1.00 20.19           O  
+ATOM    357  N   LYS A  50      14.518  14.061   8.367  1.00 22.94           N  
+ATOM    358  CA  LYS A  50      13.710  14.863   7.373  1.00 21.93           C  
+ATOM    359  C   LYS A  50      13.181  13.817   6.316  1.00 27.46           C  
+ATOM    360  O   LYS A  50      13.986  13.010   5.743  1.00 22.40           O  
+ATOM    361  CB  LYS A  50      14.564  15.966   6.685  1.00 22.08           C  
+ATOM    362  CG  LYS A  50      14.605  17.254   7.500  1.00 70.03           C  
+ATOM    363  CD  LYS A  50      13.535  18.294   7.153  1.00 70.65           C  
+ATOM    364  CE  LYS A  50      14.198  19.537   6.556  1.00 95.81           C  
+ATOM    365  NZ  LYS A  50      13.315  20.498   5.873  1.00100.00           N  
+ATOM    366  N   LEU A  51      11.843  13.756   6.190  1.00 23.93           N  
+ATOM    367  CA  LEU A  51      11.182  12.820   5.242  1.00 22.04           C  
+ATOM    368  C   LEU A  51      11.343  13.464   3.811  1.00 26.89           C  
+ATOM    369  O   LEU A  51      11.019  14.617   3.489  1.00 26.02           O  
+ATOM    370  CB  LEU A  51       9.711  12.786   5.619  1.00 23.42           C  
+ATOM    371  CG  LEU A  51       8.853  12.151   4.557  1.00 26.07           C  
+ATOM    372  CD1 LEU A  51       9.040  10.663   4.609  1.00 32.32           C  
+ATOM    373  CD2 LEU A  51       7.389  12.360   4.843  1.00 35.33           C  
+ATOM    374  N   LYS A  52      11.980  12.719   2.963  1.00 24.44           N  
+ATOM    375  CA  LYS A  52      12.215  13.149   1.602  1.00 23.16           C  
+ATOM    376  C   LYS A  52      11.098  12.677   0.642  1.00 30.50           C  
+ATOM    377  O   LYS A  52      10.510  13.473  -0.152  1.00 32.15           O  
+ATOM    378  CB  LYS A  52      13.547  12.573   1.200  1.00 24.68           C  
+ATOM    379  CG  LYS A  52      14.590  13.069   2.203  1.00 61.41           C  
+ATOM    380  CD  LYS A  52      14.704  14.575   2.120  1.00 88.91           C  
+ATOM    381  CE  LYS A  52      15.163  15.276   3.378  1.00 99.36           C  
+ATOM    382  NZ  LYS A  52      15.668  16.630   3.069  1.00100.00           N  
+ATOM    383  N   THR A  53      10.723  11.429   0.796  1.00 22.25           N  
+ATOM    384  CA  THR A  53       9.693  10.822  -0.062  1.00 24.34           C  
+ATOM    385  C   THR A  53       8.818   9.802   0.661  1.00 27.89           C  
+ATOM    386  O   THR A  53       9.369   8.972   1.390  1.00 28.95           O  
+ATOM    387  CB  THR A  53      10.434   9.920  -1.104  1.00 31.58           C  
+ATOM    388  OG1 THR A  53      11.485  10.615  -1.745  1.00 36.65           O  
+ATOM    389  CG2 THR A  53       9.392   9.465  -2.097  1.00 28.92           C  
+ATOM    390  N   GLY A  54       7.520   9.785   0.437  1.00 23.82           N  
+ATOM    391  CA  GLY A  54       6.697   8.779   1.103  1.00 22.96           C  
+ATOM    392  C   GLY A  54       5.747   9.381   2.211  1.00 21.97           C  
+ATOM    393  O   GLY A  54       5.664  10.588   2.423  1.00 25.52           O  
+ATOM    394  N   SER A  55       5.072   8.494   2.960  1.00 25.22           N  
+ATOM    395  CA  SER A  55       4.154   8.875   4.011  1.00 28.49           C  
+ATOM    396  C   SER A  55       4.486   8.103   5.302  1.00 24.34           C  
+ATOM    397  O   SER A  55       4.973   6.965   5.258  1.00 27.68           O  
+ATOM    398  CB  SER A  55       2.761   8.352   3.609  1.00 29.79           C  
+ATOM    399  OG  SER A  55       2.398   8.865   2.336  1.00 41.45           O  
+ATOM    400  N   LEU A  56       4.183   8.723   6.426  1.00 26.66           N  
+ATOM    401  CA  LEU A  56       4.424   8.134   7.760  1.00 25.62           C  
+ATOM    402  C   LEU A  56       3.240   8.370   8.687  1.00 30.33           C  
+ATOM    403  O   LEU A  56       2.434   9.273   8.469  1.00 29.36           O  
+ATOM    404  CB  LEU A  56       5.559   8.867   8.490  1.00 26.75           C  
+ATOM    405  CG  LEU A  56       6.906   8.861   7.782  1.00 34.83           C  
+ATOM    406  CD1 LEU A  56       7.858   9.937   8.326  1.00 29.42           C  
+ATOM    407  CD2 LEU A  56       7.639   7.531   7.941  1.00 28.43           C  
+ATOM    408  N   ASN A  57       3.150   7.556   9.719  1.00 28.09           N  
+ATOM    409  CA  ASN A  57       2.162   7.782  10.791  1.00 24.87           C  
+ATOM    410  C   ASN A  57       2.970   8.183  12.032  1.00 23.91           C  
+ATOM    411  O   ASN A  57       3.748   7.365  12.556  1.00 25.64           O  
+ATOM    412  CB  ASN A  57       1.327   6.524  11.056  1.00 26.11           C  
+ATOM    413  CG  ASN A  57       0.408   6.647  12.288  1.00 35.12           C  
+ATOM    414  OD1 ASN A  57       0.559   7.569  13.092  1.00 40.95           O  
+ATOM    415  ND2 ASN A  57      -0.544   5.753  12.492  1.00 41.01           N  
+ATOM    416  N   GLN A  58       2.776   9.444  12.447  1.00 27.37           N  
+ATOM    417  CA  GLN A  58       3.511  10.052  13.595  1.00 31.76           C  
+ATOM    418  C   GLN A  58       2.582  10.362  14.800  1.00 34.04           C  
+ATOM    419  O   GLN A  58       2.879  11.183  15.671  1.00 29.19           O  
+ATOM    420  CB  GLN A  58       4.233  11.333  13.150  1.00 25.80           C  
+ATOM    421  CG  GLN A  58       5.444  11.050  12.242  1.00 28.40           C  
+ATOM    422  CD  GLN A  58       6.459  12.201  12.190  1.00 47.72           C  
+ATOM    423  OE1 GLN A  58       6.420  13.019  11.268  1.00 34.30           O  
+ATOM    424  NE2 GLN A  58       7.377  12.316  13.133  1.00 26.13           N  
+ATOM    425  N   ASP A  59       1.433   9.693  14.869  1.00 36.72           N  
+ATOM    426  CA  ASP A  59       0.490   9.937  15.971  1.00 38.66           C  
+ATOM    427  C   ASP A  59       1.091   9.815  17.356  1.00 35.94           C  
+ATOM    428  O   ASP A  59       0.654  10.514  18.266  1.00 39.04           O  
+ATOM    429  CB  ASP A  59      -0.584   8.841  15.935  1.00 42.70           C  
+ATOM    430  CG  ASP A  59      -1.530   8.991  14.788  1.00 46.32           C  
+ATOM    431  OD1 ASP A  59      -1.658  10.028  14.186  1.00 38.83           O  
+ATOM    432  OD2 ASP A  59      -2.364   7.994  14.691  1.00 59.49           O  
+ATOM    433  N   ASP A  60       1.995   8.847  17.545  1.00 24.98           N  
+ATOM    434  CA  ASP A  60       2.571   8.658  18.857  1.00 24.28           C  
+ATOM    435  C   ASP A  60       3.580   9.740  19.204  1.00 40.65           C  
+ATOM    436  O   ASP A  60       4.138   9.656  20.278  1.00 43.03           O  
+ATOM    437  CB  ASP A  60       3.322   7.326  18.890  1.00 27.18           C  
+ATOM    438  CG  ASP A  60       2.315   6.216  18.808  1.00 57.16           C  
+ATOM    439  OD1 ASP A  60       1.117   6.432  18.881  1.00 51.58           O  
+ATOM    440  OD2 ASP A  60       2.833   5.017  18.626  1.00 41.88           O  
+ATOM    441  N   GLN A  61       3.968  10.668  18.334  1.00 27.55           N  
+ATOM    442  CA  GLN A  61       4.973  11.625  18.768  1.00 30.08           C  
+ATOM    443  C   GLN A  61       4.316  12.872  19.438  1.00 40.72           C  
+ATOM    444  O   GLN A  61       3.179  13.216  19.124  1.00 34.19           O  
+ATOM    445  CB  GLN A  61       5.776  12.028  17.544  1.00 33.63           C  
+ATOM    446  CG  GLN A  61       5.117  13.131  16.681  1.00 25.93           C  
+ATOM    447  CD  GLN A  61       5.331  14.519  17.217  1.00 28.73           C  
+ATOM    448  OE1 GLN A  61       6.402  14.827  17.721  1.00 30.35           O  
+ATOM    449  NE2 GLN A  61       4.427  15.450  16.881  1.00 35.06           N  
+ATOM    450  N   SER A  62       4.967  13.636  20.333  1.00 27.75           N  
+ATOM    451  CA  SER A  62       4.283  14.824  20.910  1.00 30.90           C  
+ATOM    452  C   SER A  62       5.077  16.100  20.909  1.00 36.75           C  
+ATOM    453  O   SER A  62       4.690  17.110  21.441  1.00 52.66           O  
+ATOM    454  CB  SER A  62       3.864  14.633  22.379  1.00 35.95           C  
+ATOM    455  OG  SER A  62       4.952  14.105  23.125  1.00 46.21           O  
+ATOM    456  N   PHE A  63       6.252  16.067  20.384  1.00 29.60           N  
+ATOM    457  CA  PHE A  63       7.102  17.228  20.417  1.00 27.99           C  
+ATOM    458  C   PHE A  63       6.946  18.183  19.229  1.00 31.11           C  
+ATOM    459  O   PHE A  63       7.002  19.359  19.419  1.00 27.26           O  
+ATOM    460  CB  PHE A  63       8.530  16.630  20.559  1.00 25.49           C  
+ATOM    461  CG  PHE A  63       9.618  17.648  20.427  1.00 30.88           C  
+ATOM    462  CD1 PHE A  63       9.947  18.463  21.509  1.00 26.86           C  
+ATOM    463  CD2 PHE A  63      10.321  17.816  19.230  1.00 29.02           C  
+ATOM    464  CE1 PHE A  63      11.013  19.366  21.435  1.00 29.07           C  
+ATOM    465  CE2 PHE A  63      11.373  18.727  19.142  1.00 29.76           C  
+ATOM    466  CZ  PHE A  63      11.726  19.519  20.243  1.00 33.72           C  
+ATOM    467  N   LEU A  64       6.865  17.724  17.971  1.00 25.68           N  
+ATOM    468  CA  LEU A  64       6.831  18.662  16.842  1.00 24.82           C  
+ATOM    469  C   LEU A  64       5.450  19.287  16.739  1.00 26.70           C  
+ATOM    470  O   LEU A  64       4.460  18.591  16.986  1.00 31.40           O  
+ATOM    471  CB  LEU A  64       7.034  17.871  15.491  1.00 22.47           C  
+ATOM    472  CG  LEU A  64       8.369  17.086  15.396  1.00 29.46           C  
+ATOM    473  CD1 LEU A  64       8.417  16.185  14.142  1.00 30.53           C  
+ATOM    474  CD2 LEU A  64       9.647  17.977  15.456  1.00 24.48           C  
+ATOM    475  N   ASP A  65       5.405  20.538  16.305  1.00 28.62           N  
+ATOM    476  CA  ASP A  65       4.152  21.243  16.006  1.00 34.60           C  
+ATOM    477  C   ASP A  65       3.666  20.894  14.548  1.00 41.36           C  
+ATOM    478  O   ASP A  65       4.444  20.342  13.747  1.00 26.86           O  
+ATOM    479  CB  ASP A  65       4.279  22.755  16.344  1.00 31.77           C  
+ATOM    480  CG  ASP A  65       5.013  23.596  15.359  1.00 47.04           C  
+ATOM    481  OD1 ASP A  65       5.134  23.317  14.193  1.00 48.63           O  
+ATOM    482  OD2 ASP A  65       5.539  24.667  15.877  1.00 71.08           O  
+ATOM    483  N   ASP A  66       2.394  21.176  14.206  1.00 31.65           N  
+ATOM    484  CA  ASP A  66       1.862  20.859  12.888  1.00 33.85           C  
+ATOM    485  C   ASP A  66       2.718  21.427  11.772  1.00 38.51           C  
+ATOM    486  O   ASP A  66       2.894  20.807  10.719  1.00 38.50           O  
+ATOM    487  CB  ASP A  66       0.336  21.139  12.705  1.00 35.51           C  
+ATOM    488  CG  ASP A  66      -0.498  20.102  13.425  1.00 95.83           C  
+ATOM    489  OD1 ASP A  66      -0.319  18.893  13.287  1.00100.00           O  
+ATOM    490  OD2 ASP A  66      -1.318  20.615  14.323  1.00 84.76           O  
+ATOM    491  N   ASP A  67       3.271  22.611  12.040  1.00 33.26           N  
+ATOM    492  CA  ASP A  67       4.128  23.303  11.083  1.00 33.10           C  
+ATOM    493  C   ASP A  67       5.410  22.560  10.803  1.00 45.29           C  
+ATOM    494  O   ASP A  67       5.837  22.433   9.647  1.00 34.92           O  
+ATOM    495  CB  ASP A  67       4.521  24.678  11.546  1.00 31.04           C  
+ATOM    496  CG  ASP A  67       3.513  25.724  11.117  1.00 90.55           C  
+ATOM    497  OD1 ASP A  67       2.330  25.355  10.766  1.00 92.64           O  
+ATOM    498  OD2 ASP A  67       3.854  26.959  11.106  1.00100.00           O  
+ATOM    499  N   GLN A  68       6.015  22.094  11.853  1.00 38.59           N  
+ATOM    500  CA  GLN A  68       7.260  21.369  11.718  1.00 32.76           C  
+ATOM    501  C   GLN A  68       7.016  20.090  10.901  1.00 26.08           C  
+ATOM    502  O   GLN A  68       7.814  19.732  10.023  1.00 30.32           O  
+ATOM    503  CB  GLN A  68       7.820  21.057  13.091  1.00 22.57           C  
+ATOM    504  CG  GLN A  68       8.535  22.262  13.705  1.00 26.78           C  
+ATOM    505  CD  GLN A  68       8.904  22.067  15.173  1.00 35.57           C  
+ATOM    506  OE1 GLN A  68       8.118  21.511  15.936  1.00 29.91           O  
+ATOM    507  NE2 GLN A  68      10.069  22.499  15.619  1.00 29.90           N  
+ATOM    508  N   ILE A  69       5.903  19.435  11.205  1.00 25.11           N  
+ATOM    509  CA  ILE A  69       5.499  18.196  10.509  1.00 27.87           C  
+ATOM    510  C   ILE A  69       5.327  18.483   9.019  1.00 34.66           C  
+ATOM    511  O   ILE A  69       5.811  17.729   8.162  1.00 29.47           O  
+ATOM    512  CB  ILE A  69       4.171  17.674  11.063  1.00 32.70           C  
+ATOM    513  CG1 ILE A  69       4.302  17.089  12.470  1.00 40.33           C  
+ATOM    514  CG2 ILE A  69       3.565  16.559  10.207  1.00 29.13           C  
+ATOM    515  CD1 ILE A  69       5.045  15.752  12.495  1.00 32.83           C  
+ATOM    516  N   ASP A  70       4.637  19.573   8.776  1.00 31.86           N  
+ATOM    517  CA  ASP A  70       4.370  20.072   7.426  1.00 38.31           C  
+ATOM    518  C   ASP A  70       5.714  20.306   6.684  1.00 40.55           C  
+ATOM    519  O   ASP A  70       5.839  20.039   5.474  1.00 48.39           O  
+ATOM    520  CB  ASP A  70       3.604  21.400   7.532  1.00 52.17           C  
+ATOM    521  CG  ASP A  70       2.078  21.257   7.683  1.00 55.19           C  
+ATOM    522  OD1 ASP A  70       1.545  20.107   7.915  1.00 80.92           O  
+ATOM    523  OD2 ASP A  70       1.323  22.303   7.572  1.00 63.35           O  
+ATOM    524  N   GLU A  71       6.703  20.810   7.446  1.00 34.13           N  
+ATOM    525  CA  GLU A  71       8.074  21.120   6.933  1.00 34.15           C  
+ATOM    526  C   GLU A  71       8.794  19.823   6.526  1.00 30.41           C  
+ATOM    527  O   GLU A  71       9.763  19.846   5.748  1.00 35.23           O  
+ATOM    528  CB  GLU A  71       8.924  21.851   8.000  1.00 41.29           C  
+ATOM    529  CG  GLU A  71       8.882  23.387   7.868  1.00 64.85           C  
+ATOM    530  CD  GLU A  71      10.268  24.068   7.864  1.00100.00           C  
+ATOM    531  OE1 GLU A  71      11.290  23.479   8.387  1.00 55.31           O  
+ATOM    532  OE2 GLU A  71      10.413  25.243   7.337  1.00100.00           O  
+ATOM    533  N   GLY A  72       8.295  18.726   7.081  1.00 27.79           N  
+ATOM    534  CA  GLY A  72       8.784  17.369   6.766  1.00 32.80           C  
+ATOM    535  C   GLY A  72       9.646  16.761   7.895  1.00 32.09           C  
+ATOM    536  O   GLY A  72      10.348  15.757   7.699  1.00 25.25           O  
+ATOM    537  N   TRP A  73       9.595  17.356   9.076  1.00 22.23           N  
+ATOM    538  CA  TRP A  73      10.383  16.849  10.220  1.00 21.49           C  
+ATOM    539  C   TRP A  73       9.765  15.543  10.734  1.00 26.19           C  
+ATOM    540  O   TRP A  73       8.548  15.414  10.743  1.00 26.06           O  
+ATOM    541  CB  TRP A  73      10.454  17.886  11.341  1.00 23.52           C  
+ATOM    542  CG  TRP A  73      11.396  19.048  11.007  1.00 26.22           C  
+ATOM    543  CD1 TRP A  73      11.039  20.269  10.605  1.00 28.20           C  
+ATOM    544  CD2 TRP A  73      12.823  19.008  11.067  1.00 24.95           C  
+ATOM    545  NE1 TRP A  73      12.238  21.017  10.401  1.00 28.21           N  
+ATOM    546  CE2 TRP A  73      13.272  20.262  10.674  1.00 34.89           C  
+ATOM    547  CE3 TRP A  73      13.768  18.030  11.414  1.00 24.84           C  
+ATOM    548  CZ2 TRP A  73      14.626  20.610  10.598  1.00 32.01           C  
+ATOM    549  CZ3 TRP A  73      15.133  18.390  11.338  1.00 28.18           C  
+ATOM    550  CH2 TRP A  73      15.540  19.620  10.948  1.00 32.61           C  
+ATOM    551  N   VAL A  74      10.593  14.559  11.200  1.00 23.35           N  
+ATOM    552  CA  VAL A  74      10.113  13.267  11.705  1.00 26.91           C  
+ATOM    553  C   VAL A  74      10.908  12.880  12.956  1.00 21.84           C  
+ATOM    554  O   VAL A  74      12.136  13.080  12.973  1.00 22.56           O  
+ATOM    555  CB  VAL A  74      10.512  12.092  10.734  1.00 34.43           C  
+ATOM    556  CG1 VAL A  74       9.845  10.767  11.131  1.00 31.94           C  
+ATOM    557  CG2 VAL A  74      10.272  12.404   9.276  1.00 34.41           C  
+ATOM    558  N   LEU A  75      10.212  12.238  13.882  1.00 23.50           N  
+ATOM    559  CA  LEU A  75      10.892  11.635  15.066  1.00 25.89           C  
+ATOM    560  C   LEU A  75      10.923  10.134  14.847  1.00 21.88           C  
+ATOM    561  O   LEU A  75       9.878   9.418  14.894  1.00 24.28           O  
+ATOM    562  CB  LEU A  75      10.252  12.047  16.425  1.00 24.52           C  
+ATOM    563  CG  LEU A  75      10.262  13.564  16.716  1.00 29.19           C  
+ATOM    564  CD1 LEU A  75       9.589  13.895  18.095  1.00 27.15           C  
+ATOM    565  CD2 LEU A  75      11.679  14.128  16.642  1.00 24.99           C  
+ATOM    566  N   THR A  76      12.124   9.633  14.510  1.00 20.95           N  
+ATOM    567  CA  THR A  76      12.251   8.258  14.122  1.00 22.14           C  
+ATOM    568  C   THR A  76      11.899   7.212  15.221  1.00 25.69           C  
+ATOM    569  O   THR A  76      11.533   6.102  14.878  1.00 20.55           O  
+ATOM    570  CB  THR A  76      13.595   7.943  13.417  1.00 29.14           C  
+ATOM    571  OG1 THR A  76      14.619   8.070  14.358  1.00 22.12           O  
+ATOM    572  CG2 THR A  76      13.851   8.815  12.151  1.00 21.65           C  
+ATOM    573  N   CYS A  77      11.936   7.604  16.523  1.00 19.42           N  
+ATOM    574  CA  CYS A  77      11.573   6.588  17.500  1.00 23.31           C  
+ATOM    575  C   CYS A  77      10.080   6.382  17.585  1.00 23.91           C  
+ATOM    576  O   CYS A  77       9.604   5.521  18.330  1.00 27.19           O  
+ATOM    577  CB  CYS A  77      12.096   7.056  18.896  1.00 26.08           C  
+ATOM    578  SG  CYS A  77      11.280   8.530  19.603  1.00 24.96           S  
+ATOM    579  N   ALA A  78       9.316   7.248  16.935  1.00 20.23           N  
+ATOM    580  CA  ALA A  78       7.844   7.176  17.084  1.00 26.31           C  
+ATOM    581  C   ALA A  78       7.033   7.191  15.789  1.00 36.64           C  
+ATOM    582  O   ALA A  78       5.853   7.565  15.774  1.00 30.28           O  
+ATOM    583  CB  ALA A  78       7.355   8.353  17.931  1.00 24.52           C  
+ATOM    584  N   ALA A  79       7.710   6.814  14.700  1.00 29.72           N  
+ATOM    585  CA  ALA A  79       7.111   6.869  13.368  1.00 32.19           C  
+ATOM    586  C   ALA A  79       6.958   5.506  12.733  1.00 25.32           C  
+ATOM    587  O   ALA A  79       7.919   4.711  12.753  1.00 24.70           O  
+ATOM    588  CB  ALA A  79       7.896   7.902  12.468  1.00 25.97           C  
+ATOM    589  N   TYR A  80       5.749   5.231  12.211  1.00 25.90           N  
+ATOM    590  CA  TYR A  80       5.484   4.014  11.425  1.00 24.76           C  
+ATOM    591  C   TYR A  80       5.417   4.400   9.929  1.00 24.61           C  
+ATOM    592  O   TYR A  80       4.854   5.446   9.553  1.00 25.82           O  
+ATOM    593  CB  TYR A  80       4.219   3.175  11.706  1.00 26.45           C  
+ATOM    594  CG  TYR A  80       4.106   2.676  13.134  1.00 31.84           C  
+ATOM    595  CD1 TYR A  80       4.830   1.580  13.624  1.00 34.25           C  
+ATOM    596  CD2 TYR A  80       3.242   3.365  13.990  1.00 34.72           C  
+ATOM    597  CE1 TYR A  80       4.714   1.193  14.964  1.00 30.56           C  
+ATOM    598  CE2 TYR A  80       3.065   2.963  15.314  1.00 30.24           C  
+ATOM    599  CZ  TYR A  80       3.790   1.866  15.770  1.00 35.29           C  
+ATOM    600  OH  TYR A  80       3.624   1.546  17.078  1.00 51.62           O  
+ATOM    601  N   PRO A  81       6.018   3.558   9.080  1.00 27.26           N  
+ATOM    602  CA  PRO A  81       5.949   3.836   7.625  1.00 29.66           C  
+ATOM    603  C   PRO A  81       4.575   3.430   7.093  1.00 31.14           C  
+ATOM    604  O   PRO A  81       4.053   2.403   7.575  1.00 29.26           O  
+ATOM    605  CB  PRO A  81       6.936   2.848   6.980  1.00 28.79           C  
+ATOM    606  CG  PRO A  81       7.194   1.736   8.003  1.00 31.75           C  
+ATOM    607  CD  PRO A  81       6.736   2.280   9.352  1.00 26.94           C  
+ATOM    608  N   VAL A  82       3.960   4.235   6.214  1.00 27.18           N  
+ATOM    609  CA  VAL A  82       2.685   3.782   5.638  1.00 35.74           C  
+ATOM    610  C   VAL A  82       2.831   3.398   4.139  1.00 42.39           C  
+ATOM    611  O   VAL A  82       1.907   3.001   3.426  1.00 34.16           O  
+ATOM    612  CB  VAL A  82       1.424   4.610   5.984  1.00 36.83           C  
+ATOM    613  CG1 VAL A  82       1.091   4.669   7.474  1.00 37.46           C  
+ATOM    614  CG2 VAL A  82       1.473   6.001   5.423  1.00 34.29           C  
+ATOM    615  N   SER A  83       4.039   3.560   3.645  1.00 36.29           N  
+ATOM    616  CA  SER A  83       4.438   3.307   2.273  1.00 34.79           C  
+ATOM    617  C   SER A  83       5.941   3.232   2.282  1.00 35.38           C  
+ATOM    618  O   SER A  83       6.586   3.383   3.330  1.00 27.25           O  
+ATOM    619  CB  SER A  83       4.139   4.497   1.347  1.00 30.61           C  
+ATOM    620  OG  SER A  83       5.019   5.647   1.485  1.00 28.06           O  
+ATOM    621  N   ASP A  84       6.494   3.021   1.094  1.00 26.06           N  
+ATOM    622  CA  ASP A  84       7.922   3.058   1.040  1.00 30.29           C  
+ATOM    623  C   ASP A  84       8.379   4.468   1.376  1.00 30.65           C  
+ATOM    624  O   ASP A  84       7.718   5.431   0.999  1.00 31.40           O  
+ATOM    625  CB  ASP A  84       8.418   2.707  -0.338  1.00 29.55           C  
+ATOM    626  CG  ASP A  84       8.195   1.254  -0.617  1.00 40.79           C  
+ATOM    627  OD1 ASP A  84       7.890   0.313   0.155  1.00 34.20           O  
+ATOM    628  OD2 ASP A  84       8.405   1.151  -1.879  1.00 47.36           O  
+ATOM    629  N   VAL A  85       9.526   4.644   2.031  1.00 22.99           N  
+ATOM    630  CA  VAL A  85       9.939   6.010   2.333  1.00 20.82           C  
+ATOM    631  C   VAL A  85      11.478   6.190   2.308  1.00 24.03           C  
+ATOM    632  O   VAL A  85      12.262   5.206   2.513  1.00 27.17           O  
+ATOM    633  CB  VAL A  85       9.478   6.435   3.755  1.00 28.89           C  
+ATOM    634  CG1 VAL A  85       7.965   6.527   3.938  1.00 26.65           C  
+ATOM    635  CG2 VAL A  85      10.152   5.504   4.814  1.00 29.90           C  
+ATOM    636  N   THR A  86      11.848   7.460   1.993  1.00 20.22           N  
+ATOM    637  CA  THR A  86      13.198   7.883   2.071  1.00 21.23           C  
+ATOM    638  C   THR A  86      13.330   8.952   3.174  1.00 25.70           C  
+ATOM    639  O   THR A  86      12.605   9.949   3.191  1.00 22.59           O  
+ATOM    640  CB  THR A  86      13.718   8.431   0.769  1.00 23.30           C  
+ATOM    641  OG1 THR A  86      13.519   7.475  -0.260  1.00 26.36           O  
+ATOM    642  CG2 THR A  86      15.210   8.768   0.824  1.00 22.87           C  
+ATOM    643  N   ILE A  87      14.262   8.733   4.102  1.00 22.97           N  
+ATOM    644  CA  ILE A  87      14.463   9.665   5.240  1.00 23.87           C  
+ATOM    645  C   ILE A  87      15.949  10.014   5.452  1.00 19.36           C  
+ATOM    646  O   ILE A  87      16.814   9.140   5.475  1.00 24.47           O  
+ATOM    647  CB  ILE A  87      13.972   9.014   6.543  1.00 21.55           C  
+ATOM    648  CG1 ILE A  87      12.454   8.826   6.572  1.00 27.50           C  
+ATOM    649  CG2 ILE A  87      14.331   9.833   7.785  1.00 20.65           C  
+ATOM    650  CD1 ILE A  87      11.969   7.924   7.710  1.00 31.38           C  
+ATOM    651  N   GLU A  88      16.242  11.311   5.598  1.00 21.01           N  
+ATOM    652  CA  GLU A  88      17.622  11.757   5.934  1.00 22.22           C  
+ATOM    653  C   GLU A  88      17.735  11.750   7.465  1.00 27.78           C  
+ATOM    654  O   GLU A  88      16.941  12.400   8.152  1.00 24.12           O  
+ATOM    655  CB  GLU A  88      17.905  13.188   5.441  1.00 28.56           C  
+ATOM    656  CG  GLU A  88      17.653  13.397   3.950  1.00 41.70           C  
+ATOM    657  CD  GLU A  88      18.260  14.697   3.405  1.00 48.78           C  
+ATOM    658  OE1 GLU A  88      18.764  15.569   4.210  1.00 55.59           O  
+ATOM    659  OE2 GLU A  88      18.265  14.913   2.133  1.00 95.14           O  
+ATOM    660  N   THR A  89      18.708  11.014   7.991  1.00 21.38           N  
+ATOM    661  CA  THR A  89      18.881  10.871   9.468  1.00 25.41           C  
+ATOM    662  C   THR A  89      19.936  11.870  10.028  1.00 30.23           C  
+ATOM    663  O   THR A  89      20.541  12.649   9.288  1.00 22.22           O  
+ATOM    664  CB  THR A  89      19.313   9.435   9.803  1.00 24.95           C  
+ATOM    665  OG1 THR A  89      20.566   9.146   9.196  1.00 26.36           O  
+ATOM    666  CG2 THR A  89      18.316   8.369   9.323  1.00 23.11           C  
+ATOM    667  N   HIS A  90      20.129  11.829  11.361  1.00 29.25           N  
+ATOM    668  CA  HIS A  90      21.114  12.699  12.096  1.00 30.89           C  
+ATOM    669  C   HIS A  90      20.896  14.194  11.746  1.00 19.65           C  
+ATOM    670  O   HIS A  90      21.807  14.876  11.254  1.00 24.29           O  
+ATOM    671  CB  HIS A  90      22.552  12.359  11.680  1.00 23.67           C  
+ATOM    672  CG  HIS A  90      22.966  10.925  12.015  1.00 28.74           C  
+ATOM    673  ND1 HIS A  90      22.367   9.824  11.412  1.00 25.05           N  
+ATOM    674  CD2 HIS A  90      23.901  10.429  12.868  1.00 25.95           C  
+ATOM    675  CE1 HIS A  90      22.932   8.732  11.896  1.00 26.62           C  
+ATOM    676  NE2 HIS A  90      23.848   9.075  12.766  1.00 27.96           N  
+ATOM    677  N   LYS A  91      19.692  14.702  12.017  1.00 21.85           N  
+ATOM    678  CA  LYS A  91      19.328  16.104  11.671  1.00 24.48           C  
+ATOM    679  C   LYS A  91      18.969  16.961  12.899  1.00 22.53           C  
+ATOM    680  O   LYS A  91      18.507  18.105  12.767  1.00 24.20           O  
+ATOM    681  CB  LYS A  91      18.092  16.125  10.769  1.00 24.74           C  
+ATOM    682  CG  LYS A  91      18.394  15.720   9.329  1.00 33.72           C  
+ATOM    683  CD  LYS A  91      19.267  16.737   8.594  1.00 33.40           C  
+ATOM    684  CE  LYS A  91      19.650  16.284   7.184  1.00 56.58           C  
+ATOM    685  NZ  LYS A  91      20.051  17.398   6.313  1.00 70.22           N  
+ATOM    686  N   LYS A  92      19.193  16.402  14.066  1.00 29.41           N  
+ATOM    687  CA  LYS A  92      18.862  17.064  15.343  1.00 29.57           C  
+ATOM    688  C   LYS A  92      19.404  18.499  15.416  1.00 31.36           C  
+ATOM    689  O   LYS A  92      18.727  19.418  15.897  1.00 30.72           O  
+ATOM    690  CB  LYS A  92      19.478  16.299  16.516  1.00 28.26           C  
+ATOM    691  CG  LYS A  92      19.717  17.184  17.743  1.00 42.15           C  
+ATOM    692  CD  LYS A  92      19.736  16.395  19.054  1.00 58.10           C  
+ATOM    693  CE  LYS A  92      21.130  16.311  19.680  1.00 74.57           C  
+ATOM    694  NZ  LYS A  92      21.096  16.204  21.146  1.00 73.77           N  
+ATOM    695  N   GLU A  93      20.609  18.655  14.934  1.00 25.37           N  
+ATOM    696  CA  GLU A  93      21.334  19.926  15.008  1.00 33.41           C  
+ATOM    697  C   GLU A  93      20.816  20.964  13.971  1.00 34.04           C  
+ATOM    698  O   GLU A  93      21.217  22.136  13.972  1.00 37.10           O  
+ATOM    699  CB  GLU A  93      22.827  19.630  14.806  1.00 36.08           C  
+ATOM    700  CG  GLU A  93      23.635  19.664  16.121  1.00100.00           C  
+ATOM    701  CD  GLU A  93      23.858  18.339  16.907  1.00100.00           C  
+ATOM    702  OE1 GLU A  93      22.862  17.695  17.423  1.00100.00           O  
+ATOM    703  OE2 GLU A  93      25.060  17.880  17.081  1.00100.00           O  
+ATOM    704  N   GLU A  94      19.911  20.554  13.095  1.00 33.03           N  
+ATOM    705  CA  GLU A  94      19.390  21.462  12.044  1.00 33.87           C  
+ATOM    706  C   GLU A  94      17.957  21.905  12.326  1.00 30.08           C  
+ATOM    707  O   GLU A  94      17.403  22.771  11.634  1.00 29.33           O  
+ATOM    708  CB  GLU A  94      19.373  20.759  10.693  1.00 36.71           C  
+ATOM    709  CG  GLU A  94      20.771  20.470  10.160  1.00 52.81           C  
+ATOM    710  CD  GLU A  94      20.788  20.210   8.656  1.00100.00           C  
+ATOM    711  OE1 GLU A  94      19.722  20.405   7.957  1.00 57.89           O  
+ATOM    712  OE2 GLU A  94      21.868  19.796   8.088  1.00 85.85           O  
+ATOM    713  N   LEU A  95      17.393  21.306  13.332  1.00 26.01           N  
+ATOM    714  CA  LEU A  95      16.011  21.563  13.709  1.00 26.71           C  
+ATOM    715  C   LEU A  95      15.801  23.027  14.206  1.00 33.16           C  
+ATOM    716  O   LEU A  95      16.584  23.603  15.002  1.00 28.74           O  
+ATOM    717  CB  LEU A  95      15.601  20.616  14.840  1.00 24.05           C  
+ATOM    718  CG  LEU A  95      14.137  20.768  15.253  1.00 37.37           C  
+ATOM    719  CD1 LEU A  95      13.161  20.208  14.216  1.00 39.22           C  
+ATOM    720  CD2 LEU A  95      13.808  20.048  16.563  1.00 48.43           C  
+ATOM    721  N   THR A  96      14.690  23.657  13.803  1.00 24.29           N  
+ATOM    722  CA  THR A  96      14.357  24.971  14.259  1.00 20.50           C  
+ATOM    723  C   THR A  96      12.842  25.027  14.364  1.00 29.60           C  
+ATOM    724  O   THR A  96      12.150  24.097  13.856  1.00 27.87           O  
+ATOM    725  CB  THR A  96      14.675  26.113  13.293  1.00 29.55           C  
+ATOM    726  OG1 THR A  96      13.917  25.851  12.128  1.00 30.05           O  
+ATOM    727  CG2 THR A  96      16.120  26.211  13.007  1.00 23.85           C  
+ATOM    728  N   ALA A  97      12.313  26.090  15.052  1.00 27.16           N  
+ATOM    729  CA  ALA A  97      10.851  26.183  15.191  1.00 37.74           C  
+ATOM    730  C   ALA A  97      10.166  26.814  14.004  1.00 64.29           C  
+ATOM    731  O   ALA A  97       9.815  27.983  14.121  1.00100.00           O  
+ATOM    732  CB  ALA A  97      10.299  26.681  16.508  1.00 35.84           C  
+TER     733      ALA A  97                                                      
+HETATM  734 FE1  FES A1602      13.398  11.548  21.999  1.00 26.97          FE  
+HETATM  735 FE2  FES A1602      12.925  10.090  19.701  1.00 26.54          FE  
+HETATM  736  S1  FES A1602      14.657   9.885  21.071  1.00 26.27           S  
+HETATM  737  S2  FES A1602      11.681  11.837  20.546  1.00 27.47           S  
+HETATM  738  O   HOH A1603      20.314   3.189  17.662  1.00 28.40           O  
+HETATM  739  O   HOH A1604      19.136  13.499  14.797  1.00 27.63           O  
+HETATM  740  O   HOH A1605      15.839  17.655  22.569  1.00 31.32           O  
+HETATM  741  O   HOH A1606      13.340  -3.911  18.366  1.00 31.87           O  
+HETATM  742  O   HOH A1607      17.589   8.577  14.886  1.00 25.57           O  
+HETATM  743  O   HOH A1608       3.158   6.964  15.663  1.00 32.70           O  
+HETATM  744  O   HOH A1609      12.607   3.196   0.028  1.00 35.81           O  
+HETATM  745  O   HOH A1610      17.941  10.294  12.971  1.00 28.21           O  
+HETATM  746  O   HOH A1611       1.926   1.370   9.724  1.00 37.77           O  
+HETATM  747  O   HOH A1612      11.412   3.410  19.732  1.00 37.42           O  
+HETATM  748  O   HOH A1613       8.807  17.793  25.373  1.00 41.85           O  
+HETATM  749  O   HOH A1614       3.590  11.528   5.863  1.00 39.49           O  
+HETATM  750  O   HOH A1615      25.052   1.593  11.348  1.00 43.97           O  
+HETATM  751  O   HOH A1616      -6.196   7.375  14.972  1.00 75.86           O  
+HETATM  752  O   HOH A1617       8.534  -0.956  17.306  1.00 37.45           O  
+HETATM  753  O   HOH A1618       6.639  15.107   8.525  1.00 36.12           O  
+HETATM  754  O   HOH A1619      22.246   2.005  21.737  1.00 36.05           O  
+HETATM  755  O   HOH A1620      14.535  -4.507  10.197  1.00 55.68           O  
+HETATM  756  O   HOH A1621       4.876   2.526  -1.355  1.00 41.58           O  
+HETATM  757  O   HOH A1622      11.330   5.913  -0.990  1.00 42.42           O  
+HETATM  758  O   HOH A1623       8.224   5.865  20.826  1.00 41.41           O  
+HETATM  759  O   HOH A1624      22.831   5.923  19.420  1.00 45.06           O  
+HETATM  760  O   HOH A1625      14.917  23.836  10.267  1.00 40.43           O  
+HETATM  761  O   HOH A1626      11.139  24.357  10.914  1.00 63.90           O  
+HETATM  762  O   HOH A1627      11.625  17.756   3.797  1.00 64.36           O  
+HETATM  763  O   HOH A1628       0.872  11.720  21.228  1.00 66.38           O  
+HETATM  764  O   HOH A1629      -0.211   4.813  15.867  1.00 63.96           O  
+HETATM  765  O   HOH A1630      20.658  -7.095   8.049  1.00 67.10           O  
+HETATM  766  O   HOH A1631      24.043   4.181  -2.687  1.00 53.06           O  
+HETATM  767  O   HOH A1632      21.936   6.378  21.945  1.00 55.43           O  
+HETATM  768  O   HOH A1633      19.025  24.652  14.863  1.00 51.35           O  
+HETATM  769  O   HOH A1634      11.308   8.680  28.143  1.00 44.39           O  
+HETATM  770  O   HOH A1635      -0.428   0.927   5.386  1.00 85.08           O  
+HETATM  771  O   HOH A1636      21.798  10.879  23.320  1.00 52.42           O  
+HETATM  772  O   HOH A1637       3.239   6.955  -0.065  1.00 55.66           O  
+HETATM  773  O   HOH A1638      22.779   2.365  18.908  1.00 43.93           O  
+HETATM  774  O   HOH A1639      24.188   5.146  11.189  1.00 45.31           O  
+HETATM  775  O   HOH A1640      -1.683  -0.913   1.878  1.00 69.36           O  
+HETATM  776  O   HOH A1641       8.696   6.563  -1.677  1.00 58.88           O  
+HETATM  777  O   HOH A1642       7.367  26.197  14.480  1.00 49.47           O  
+HETATM  778  O   HOH A1643       6.591  -1.657  -1.410  1.00 85.37           O  
+HETATM  779  O   HOH A1644       7.606  18.977   3.435  1.00 63.19           O  
+HETATM  780  O   HOH A1645      -3.822  10.414  11.859  1.00 57.70           O  
+HETATM  781  O   HOH A1646      21.749  12.594   6.625  1.00 51.80           O  
+HETATM  782  O   HOH A1647      23.131   4.812  23.785  1.00 50.20           O  
+HETATM  783  O   HOH A1648      16.610   3.001  -2.612  1.00 56.90           O  
+HETATM  784  O   HOH A1649      22.528  16.502  13.897  1.00 55.79           O  
+HETATM  785  O   HOH A1650      26.500   7.848  10.348  1.00 68.43           O  
+HETATM  786  O   HOH A1651       3.851  12.983   3.178  1.00 49.71           O  
+HETATM  787  O   HOH A1652      19.786  18.726  20.646  1.00 45.90           O  
+HETATM  788  O   HOH A1653      18.145  27.680   9.755  1.00 64.26           O  
+HETATM  789  O   HOH A1654      17.574  -8.112   7.017  1.00 76.51           O  
+HETATM  790  O   HOH A1655      22.282  13.839  15.539  1.00 60.51           O  
+HETATM  791  O   HOH A1656      21.110  -7.809  14.066  1.00 66.51           O  
+HETATM  792  O   HOH A1657      25.732  22.369  16.313  1.00 59.47           O  
+HETATM  793  O   HOH A1658      13.415   9.318  -2.947  1.00 59.85           O  
+HETATM  794  O   HOH A1659      13.899  22.771   7.168  1.00 63.98           O  
+HETATM  795  O   HOH A1660      27.481   5.665  17.885  1.00 79.40           O  
+HETATM  796  O   HOH A1661       8.580  -4.372  17.408  1.00 60.41           O  
+HETATM  797  O   HOH A1662      24.876   4.074   8.926  1.00 71.07           O  
+HETATM  798  O   HOH A1663      10.525  -6.340  15.708  1.00 53.48           O  
+HETATM  799  O   HOH A1664      -1.284   5.529  19.201  1.00 68.40           O  
+HETATM  800  O   HOH A1665      15.014  11.978  -2.461  1.00 64.00           O  
+HETATM  801  O   HOH A1666      14.106  -9.236   2.519  1.00 67.28           O  
+HETATM  802  O   HOH A1667      14.062  29.978  13.852  1.00 84.39           O  
+HETATM  803  O   HOH A1668       6.500   2.082  -3.927  1.00 73.15           O  
+HETATM  804  O   HOH A1669      -3.999  12.915  12.023  1.00 70.07           O  
+HETATM  805  O   HOH A1670      22.522  10.655  20.491  1.00 62.92           O  
+HETATM  806  O   HOH A1671       5.802  -4.428  16.828  1.00 64.57           O  
+HETATM  807  O   HOH A1672      -0.285  -5.312   2.050  1.00 83.51           O  
+HETATM  808  O   HOH A1673      -0.266   3.144  11.216  1.00 68.25           O  
+HETATM  809  O   HOH A1674      25.407  13.378  14.852  1.00 80.99           O  
+HETATM  810  O   HOH A1675      15.568   7.564  -2.586  1.00 71.16           O  
+HETATM  811  O   HOH A1676       4.787  10.976  22.962  1.00 65.51           O  
+HETATM  812  O   HOH A1677      25.854  23.790  19.080  1.00 69.96           O  
+HETATM  813  O   HOH A1678       6.047  15.849  24.673  1.00 76.93           O  
+HETATM  814  O   HOH A1679       3.270  10.385  25.458  1.00 68.03           O  
+HETATM  815  O   HOH A1680      17.147 -11.645  -0.378  1.00 76.39           O  
+HETATM  816  O   HOH A1681       3.889  11.272  28.440  1.00 57.34           O  
+HETATM  817  O   HOH A1682       0.829  10.575   6.206  1.00 61.71           O  
+HETATM  818  O   HOH A1683      -2.192  14.658  14.063  1.00 83.95           O  
+CONECT  297  734                                                                
+CONECT  329  734                                                                
+CONECT  347  735                                                                
+CONECT  578  735                                                                
+CONECT  734  297  329  736  737                                                 
+CONECT  735  347  578  736  737                                                 
+CONECT  736  734  735                                                           
+CONECT  737  734  735                                                           
+MASTER      253    0    1    4    5    0    2    6  817    1    8    8          
+END                                                                             
diff --git a/test/jalview/io/2nq2.pdb b/test/jalview/io/2nq2.pdb
new file mode 100644 (file)
index 0000000..a43217a
--- /dev/null
@@ -0,0 +1,10096 @@
+HEADER    METAL TRANSPORT                         30-OCT-06   2NQ2              
+TITLE     AN INWARD-FACING CONFORMATION OF A PUTATIVE METAL-CHELATE             
+TITLE    2 TYPE ABC TRANSPORTER.                                                
+COMPND    MOL_ID: 1;                                                            
+COMPND   2 MOLECULE: HYPOTHETICAL ABC TRANSPORTER PERMEASE PROTEIN              
+COMPND   3 HI1471;                                                              
+COMPND   4 CHAIN: A, B;                                                         
+COMPND   5 ENGINEERED: YES;                                                     
+COMPND   6 MOL_ID: 2;                                                           
+COMPND   7 MOLECULE: HYPOTHETICAL ABC TRANSPORTER ATP-BINDING PROTEIN           
+COMPND   8 HI1470;                                                              
+COMPND   9 CHAIN: C, D;                                                         
+COMPND  10 ENGINEERED: YES                                                      
+SOURCE    MOL_ID: 1;                                                            
+SOURCE   2 ORGANISM_SCIENTIFIC: HAEMOPHILUS INFLUENZAE;                         
+SOURCE   3 ORGANISM_TAXID: 727;                                                 
+SOURCE   4 STRAIN: KW20 RD;                                                     
+SOURCE   5 GENE: HI_1471;                                                       
+SOURCE   6 EXPRESSION_SYSTEM: ESCHERICHIA COLI;                                 
+SOURCE   7 EXPRESSION_SYSTEM_TAXID: 562;                                        
+SOURCE   8 EXPRESSION_SYSTEM_STRAIN: BL21(DE3)/B834(DE3);                       
+SOURCE   9 EXPRESSION_SYSTEM_VECTOR_TYPE: PLASMID;                              
+SOURCE  10 EXPRESSION_SYSTEM_PLASMID: PET19B/PET21B(+);                         
+SOURCE  11 MOL_ID: 2;                                                           
+SOURCE  12 ORGANISM_SCIENTIFIC: HAEMOPHILUS INFLUENZAE;                         
+SOURCE  13 ORGANISM_TAXID: 727;                                                 
+SOURCE  14 STRAIN: KW20 RD;                                                     
+SOURCE  15 GENE: HI_1470;                                                       
+SOURCE  16 EXPRESSION_SYSTEM: ESCHERICHIA COLI;                                 
+SOURCE  17 EXPRESSION_SYSTEM_TAXID: 562;                                        
+SOURCE  18 EXPRESSION_SYSTEM_STRAIN: BL21(DE3)/B834(DE3);                       
+SOURCE  19 EXPRESSION_SYSTEM_VECTOR_TYPE: PLASMID;                              
+SOURCE  20 EXPRESSION_SYSTEM_PLASMID: PET19B/PET21B(+)                          
+KEYWDS    PUTATIVE IRON CHELATIN ABC TRANSPORTER, ATP-BINDING PROTEIN,          
+KEYWDS   2 NUCLEOTIDE BINDING DOMAIN, TRANSMEMBRANE DOMAIN, METAL               
+KEYWDS   3 TRANSPORT                                                            
+EXPDTA    X-RAY DIFFRACTION                                                     
+AUTHOR    H.P.PINKETT,A.T.LEE,P.LUM,K.P.LOCHER,D.C.REES                         
+REVDAT   3   24-FEB-09 2NQ2    1       VERSN                                    
+REVDAT   2   30-JAN-07 2NQ2    1       JRNL                                     
+REVDAT   1   02-JAN-07 2NQ2    0                                                
+JRNL        AUTH   H.W.PINKETT,A.T.LEE,P.LUM,K.P.LOCHER,D.C.REES                
+JRNL        TITL   AN INWARD-FACING CONFORMATION OF A PUTATIVE                  
+JRNL        TITL 2 METAL-CHELATE-TYPE ABC TRANSPORTER.                          
+JRNL        REF    SCIENCE                       V. 315   373 2007              
+JRNL        REFN                   ISSN 0036-8075                               
+JRNL        PMID   17158291                                                     
+JRNL        DOI    10.1126/SCIENCE.1133488                                      
+REMARK   1                                                                      
+REMARK   2                                                                      
+REMARK   2 RESOLUTION.    2.40 ANGSTROMS.                                       
+REMARK   3                                                                      
+REMARK   3 REFINEMENT.                                                          
+REMARK   3   PROGRAM     : CNS                                                  
+REMARK   3   AUTHORS     : BRUNGER,ADAMS,CLORE,DELANO,GROS,GROSSE-              
+REMARK   3               : KUNSTLEVE,JIANG,KUSZEWSKI,NILGES, PANNU,             
+REMARK   3               : READ,RICE,SIMONSON,WARREN                            
+REMARK   3                                                                      
+REMARK   3  REFINEMENT TARGET : ENGH & HUBER                                    
+REMARK   3                                                                      
+REMARK   3  DATA USED IN REFINEMENT.                                            
+REMARK   3   RESOLUTION RANGE HIGH (ANGSTROMS) : 2.40                           
+REMARK   3   RESOLUTION RANGE LOW  (ANGSTROMS) : 28.00                          
+REMARK   3   DATA CUTOFF            (SIGMA(F)) : 0.000                          
+REMARK   3   DATA CUTOFF HIGH         (ABS(F)) : NULL                           
+REMARK   3   DATA CUTOFF LOW          (ABS(F)) : NULL                           
+REMARK   3   COMPLETENESS (WORKING+TEST)   (%) : 98.9                           
+REMARK   3   NUMBER OF REFLECTIONS             : 81106                          
+REMARK   3                                                                      
+REMARK   3  FIT TO DATA USED IN REFINEMENT.                                     
+REMARK   3   CROSS-VALIDATION METHOD          : THROUGHOUT                      
+REMARK   3   FREE R VALUE TEST SET SELECTION  : RANDOM                          
+REMARK   3   R VALUE            (WORKING SET) : 0.222                           
+REMARK   3   FREE R VALUE                     : 0.260                           
+REMARK   3   FREE R VALUE TEST SET SIZE   (%) : 9.800                           
+REMARK   3   FREE R VALUE TEST SET COUNT      : 8214                            
+REMARK   3   ESTIMATED ERROR OF FREE R VALUE  : NULL                            
+REMARK   3                                                                      
+REMARK   3  FIT IN THE HIGHEST RESOLUTION BIN.                                  
+REMARK   3   TOTAL NUMBER OF BINS USED           : NULL                         
+REMARK   3   BIN RESOLUTION RANGE HIGH       (A) : 2.40                         
+REMARK   3   BIN RESOLUTION RANGE LOW        (A) : 2.55                         
+REMARK   3   BIN COMPLETENESS (WORKING+TEST) (%) : NULL                         
+REMARK   3   REFLECTIONS IN BIN    (WORKING SET) : NULL                         
+REMARK   3   BIN R VALUE           (WORKING SET) : 0.2490                       
+REMARK   3   BIN FREE R VALUE                    : 0.3020                       
+REMARK   3   BIN FREE R VALUE TEST SET SIZE  (%) : NULL                         
+REMARK   3   BIN FREE R VALUE TEST SET COUNT     : 1297                         
+REMARK   3   ESTIMATED ERROR OF BIN FREE R VALUE : 0.008                        
+REMARK   3                                                                      
+REMARK   3  NUMBER OF NON-HYDROGEN ATOMS USED IN REFINEMENT.                    
+REMARK   3   PROTEIN ATOMS            : 8569                                    
+REMARK   3   NUCLEIC ACID ATOMS       : 0                                       
+REMARK   3   HETEROGEN ATOMS          : 0                                       
+REMARK   3   SOLVENT ATOMS            : 682                                     
+REMARK   3                                                                      
+REMARK   3  B VALUES.                                                           
+REMARK   3   FROM WILSON PLOT           (A**2) : 31.40                          
+REMARK   3   MEAN B VALUE      (OVERALL, A**2) : 51.09                          
+REMARK   3   OVERALL ANISOTROPIC B VALUE.                                       
+REMARK   3    B11 (A**2) : 5.30400                                              
+REMARK   3    B22 (A**2) : -4.44900                                             
+REMARK   3    B33 (A**2) : -0.84000                                             
+REMARK   3    B12 (A**2) : 0.00000                                              
+REMARK   3    B13 (A**2) : 0.00000                                              
+REMARK   3    B23 (A**2) : 0.00000                                              
+REMARK   3                                                                      
+REMARK   3  ESTIMATED COORDINATE ERROR.                                         
+REMARK   3   ESD FROM LUZZATI PLOT        (A) : 0.29                            
+REMARK   3   ESD FROM SIGMAA              (A) : 0.23                            
+REMARK   3   LOW RESOLUTION CUTOFF        (A) : 5.00                            
+REMARK   3                                                                      
+REMARK   3  CROSS-VALIDATED ESTIMATED COORDINATE ERROR.                         
+REMARK   3   ESD FROM C-V LUZZATI PLOT    (A) : 0.36                            
+REMARK   3   ESD FROM C-V SIGMAA          (A) : 0.31                            
+REMARK   3                                                                      
+REMARK   3  RMS DEVIATIONS FROM IDEAL VALUES.                                   
+REMARK   3   BOND LENGTHS                 (A) : 0.006                           
+REMARK   3   BOND ANGLES            (DEGREES) : NULL                            
+REMARK   3   DIHEDRAL ANGLES        (DEGREES) : NULL                            
+REMARK   3   IMPROPER ANGLES        (DEGREES) : NULL                            
+REMARK   3                                                                      
+REMARK   3  ISOTROPIC THERMAL MODEL : NULL                                      
+REMARK   3                                                                      
+REMARK   3  ISOTROPIC THERMAL FACTOR RESTRAINTS.    RMS    SIGMA                
+REMARK   3   MAIN-CHAIN BOND              (A**2) : NULL  ; NULL                 
+REMARK   3   MAIN-CHAIN ANGLE             (A**2) : NULL  ; NULL                 
+REMARK   3   SIDE-CHAIN BOND              (A**2) : NULL  ; NULL                 
+REMARK   3   SIDE-CHAIN ANGLE             (A**2) : NULL  ; NULL                 
+REMARK   3                                                                      
+REMARK   3  BULK SOLVENT MODELING.                                              
+REMARK   3   METHOD USED : NULL                                                 
+REMARK   3   KSOL        : NULL                                                 
+REMARK   3   BSOL        : 50.07                                                
+REMARK   3                                                                      
+REMARK   3  NCS MODEL : NULL                                                    
+REMARK   3                                                                      
+REMARK   3  NCS RESTRAINTS.                         RMS   SIGMA/WEIGHT          
+REMARK   3   GROUP  1  POSITIONAL            (A) : NULL  ; NULL                 
+REMARK   3   GROUP  1  B-FACTOR           (A**2) : NULL  ; NULL                 
+REMARK   3                                                                      
+REMARK   3  PARAMETER FILE  1  : PROTEIN_REP.PARAM                              
+REMARK   3  PARAMETER FILE  2  : WATER_REP.PARAM                                
+REMARK   3  PARAMETER FILE  3  : NULL                                           
+REMARK   3  TOPOLOGY FILE  1   : NULL                                           
+REMARK   3  TOPOLOGY FILE  2   : NULL                                           
+REMARK   3  TOPOLOGY FILE  3   : NULL                                           
+REMARK   3                                                                      
+REMARK   3  OTHER REFINEMENT REMARKS: WATER MOLECULES POSITIONED IN THE         
+REMARK   3  MEMBRANE SPANNING REGION LIKELY CORRESPOND TO DENSITY FROM          
+REMARK   3  DISORDERED DETERGENTS AND POSSIBLY ASSOCIATED PHOSPHOLIPIDS.        
+REMARK   4                                                                      
+REMARK   4 2NQ2 COMPLIES WITH FORMAT V. 3.15, 01-DEC-08                         
+REMARK 100                                                                      
+REMARK 100 THIS ENTRY HAS BEEN PROCESSED BY RCSB ON 28-NOV-06.                  
+REMARK 100 THE RCSB ID CODE IS RCSB040163.                                      
+REMARK 200                                                                      
+REMARK 200 EXPERIMENTAL DETAILS                                                 
+REMARK 200  EXPERIMENT TYPE                : X-RAY DIFFRACTION                  
+REMARK 200  DATE OF DATA COLLECTION        : 16-FEB-05; NULL                    
+REMARK 200  TEMPERATURE           (KELVIN) : 100; NULL                          
+REMARK 200  PH                             : 5.5                                
+REMARK 200  NUMBER OF CRYSTALS USED        : 2                                  
+REMARK 200                                                                      
+REMARK 200  SYNCHROTRON              (Y/N) : Y; Y                               
+REMARK 200  RADIATION SOURCE               : SSRL; SSRL                         
+REMARK 200  BEAMLINE                       : BL9-2; BL9-2                       
+REMARK 200  X-RAY GENERATOR MODEL          : NULL; NULL                         
+REMARK 200  MONOCHROMATIC OR LAUE    (M/L) : M; M                               
+REMARK 200  WAVELENGTH OR RANGE        (A) : 0.97925, 0.89194, 0.97927;         
+REMARK 200                                   0.97927                            
+REMARK 200  MONOCHROMATOR                  : DOUBLE CRYSTAL MONOCHROMATOR;      
+REMARK 200                                   DOUBLE CRYSTAL MONOCHROMATOR       
+REMARK 200  OPTICS                         : MIRRORS; NULL                      
+REMARK 200                                                                      
+REMARK 200  DETECTOR TYPE                  : IMAGE PLATE; NULL                  
+REMARK 200  DETECTOR MANUFACTURER          : MAR SCANNER 345 MM PLATE; NULL     
+REMARK 200  INTENSITY-INTEGRATION SOFTWARE : DENZO                              
+REMARK 200  DATA SCALING SOFTWARE          : SCALEPACK                          
+REMARK 200                                                                      
+REMARK 200  NUMBER OF UNIQUE REFLECTIONS   : 82020                              
+REMARK 200  RESOLUTION RANGE HIGH      (A) : 2.400                              
+REMARK 200  RESOLUTION RANGE LOW       (A) : 30.000                             
+REMARK 200  REJECTION CRITERIA  (SIGMA(I)) : NULL                               
+REMARK 200                                                                      
+REMARK 200 OVERALL.                                                             
+REMARK 200  COMPLETENESS FOR RANGE     (%) : 99.5                               
+REMARK 200  DATA REDUNDANCY                : 14.500                             
+REMARK 200  R MERGE                    (I) : NULL                               
+REMARK 200  R SYM                      (I) : 0.06100                            
+REMARK 200  <I/SIGMA(I)> FOR THE DATA SET  : 16.1000                            
+REMARK 200                                                                      
+REMARK 200 IN THE HIGHEST RESOLUTION SHELL.                                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE HIGH (A) : 2.40                     
+REMARK 200  HIGHEST RESOLUTION SHELL, RANGE LOW  (A) : 2.49                     
+REMARK 200  COMPLETENESS FOR SHELL     (%) : 99.2                               
+REMARK 200  DATA REDUNDANCY IN SHELL       : 14.10                              
+REMARK 200  R MERGE FOR SHELL          (I) : NULL                               
+REMARK 200  R SYM FOR SHELL            (I) : 0.27000                            
+REMARK 200  <I/SIGMA(I)> FOR SHELL         : NULL                               
+REMARK 200                                                                      
+REMARK 200 DIFFRACTION PROTOCOL: MAD; SINGLE WAVELENGTH                         
+REMARK 200 METHOD USED TO DETERMINE THE STRUCTURE: MAD                          
+REMARK 200 SOFTWARE USED: SHARP                                                 
+REMARK 200 STARTING MODEL: NULL                                                 
+REMARK 200                                                                      
+REMARK 200 REMARK: NULL                                                         
+REMARK 280                                                                      
+REMARK 280 CRYSTAL                                                              
+REMARK 280 SOLVENT CONTENT, VS   (%): 69.77                                     
+REMARK 280 MATTHEWS COEFFICIENT, VM (ANGSTROMS**3/DA): 4.07                     
+REMARK 280                                                                      
+REMARK 280 CRYSTALLIZATION CONDITIONS: 34% PENTAERYTHRITOL PROPOXYLATE,         
+REMARK 280  0.1M SODIUM CITRATE, PH 5.5, 0.2M POTASSIUM CHLORIDE, VAPOR         
+REMARK 280  DIFFUSION, SITTING DROP, TEMPERATURE 277K                           
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY                                            
+REMARK 290 SYMMETRY OPERATORS FOR SPACE GROUP: P 21 21 21                       
+REMARK 290                                                                      
+REMARK 290      SYMOP   SYMMETRY                                                
+REMARK 290     NNNMMM   OPERATOR                                                
+REMARK 290       1555   X,Y,Z                                                   
+REMARK 290       2555   -X+1/2,-Y,Z+1/2                                         
+REMARK 290       3555   -X,Y+1/2,-Z+1/2                                         
+REMARK 290       4555   X+1/2,-Y+1/2,-Z                                         
+REMARK 290                                                                      
+REMARK 290     WHERE NNN -> OPERATOR NUMBER                                     
+REMARK 290           MMM -> TRANSLATION VECTOR                                  
+REMARK 290                                                                      
+REMARK 290 CRYSTALLOGRAPHIC SYMMETRY TRANSFORMATIONS                            
+REMARK 290 THE FOLLOWING TRANSFORMATIONS OPERATE ON THE ATOM/HETATM             
+REMARK 290 RECORDS IN THIS ENTRY TO PRODUCE CRYSTALLOGRAPHICALLY                
+REMARK 290 RELATED MOLECULES.                                                   
+REMARK 290   SMTRY1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 290   SMTRY1   2 -1.000000  0.000000  0.000000       48.92300            
+REMARK 290   SMTRY2   2  0.000000 -1.000000  0.000000        0.00000            
+REMARK 290   SMTRY3   2  0.000000  0.000000  1.000000       75.13400            
+REMARK 290   SMTRY1   3 -1.000000  0.000000  0.000000        0.00000            
+REMARK 290   SMTRY2   3  0.000000  1.000000  0.000000       71.23250            
+REMARK 290   SMTRY3   3  0.000000  0.000000 -1.000000       75.13400            
+REMARK 290   SMTRY1   4  1.000000  0.000000  0.000000       48.92300            
+REMARK 290   SMTRY2   4  0.000000 -1.000000  0.000000       71.23250            
+REMARK 290   SMTRY3   4  0.000000  0.000000 -1.000000        0.00000            
+REMARK 290                                                                      
+REMARK 290 REMARK: NULL                                                         
+REMARK 300                                                                      
+REMARK 300 BIOMOLECULE: 1                                                       
+REMARK 300 SEE REMARK 350 FOR THE AUTHOR PROVIDED AND/OR PROGRAM                
+REMARK 300 GENERATED ASSEMBLY INFORMATION FOR THE STRUCTURE IN                  
+REMARK 300 THIS ENTRY. THE REMARK MAY ALSO PROVIDE INFORMATION ON               
+REMARK 300 BURIED SURFACE AREA.                                                 
+REMARK 300 REMARK: THE BIOLOGICAL ASSEMBLY IS A DIMER                           
+REMARK 350                                                                      
+REMARK 350 COORDINATES FOR A COMPLETE MULTIMER REPRESENTING THE KNOWN           
+REMARK 350 BIOLOGICALLY SIGNIFICANT OLIGOMERIZATION STATE OF THE                
+REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS          
+REMARK 350 GIVEN BELOW.  BOTH NON-CRYSTALLOGRAPHIC AND                          
+REMARK 350 CRYSTALLOGRAPHIC OPERATIONS ARE GIVEN.                               
+REMARK 350                                                                      
+REMARK 350 BIOMOLECULE: 1                                                       
+REMARK 350 AUTHOR DETERMINED BIOLOGICAL UNIT: TETRAMERIC                        
+REMARK 350 SOFTWARE DETERMINED QUATERNARY STRUCTURE: TETRAMERIC                 
+REMARK 350 SOFTWARE USED: PISA                                                  
+REMARK 350 TOTAL BURIED SURFACE AREA: 10970 ANGSTROM**2                         
+REMARK 350 SURFACE AREA OF THE COMPLEX: 44500 ANGSTROM**2                       
+REMARK 350 CHANGE IN SOLVENT FREE ENERGY: -102.0 KCAL/MOL                       
+REMARK 350 APPLY THE FOLLOWING TO CHAINS: A, C, B, D                            
+REMARK 350   BIOMT1   1  1.000000  0.000000  0.000000        0.00000            
+REMARK 350   BIOMT2   1  0.000000  1.000000  0.000000        0.00000            
+REMARK 350   BIOMT3   1  0.000000  0.000000  1.000000        0.00000            
+REMARK 465                                                                      
+REMARK 465 MISSING RESIDUES                                                     
+REMARK 465 THE FOLLOWING RESIDUES WERE NOT LOCATED IN THE                       
+REMARK 465 EXPERIMENT. (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN               
+REMARK 465 IDENTIFIER; SSSEQ=SEQUENCE NUMBER; I=INSERTION CODE.)                
+REMARK 465                                                                      
+REMARK 465   M RES C SSSEQI                                                     
+REMARK 465     MET A     1                                                      
+REMARK 465     GLN A     2                                                      
+REMARK 465     PRO A     3                                                      
+REMARK 465     ASP A     4                                                      
+REMARK 465     SER A     5                                                      
+REMARK 465     GLY A    38                                                      
+REMARK 465     GLN A    39                                                      
+REMARK 465     ILE A    40                                                      
+REMARK 465     LEU A    41                                                      
+REMARK 465     TRP A    42                                                      
+REMARK 465     ALA A    43                                                      
+REMARK 465     LYS A    44                                                      
+REMARK 465     ALA A    45                                                      
+REMARK 465     THR A    46                                                      
+REMARK 465     ALA A    47                                                      
+REMARK 465     LEU A    48                                                      
+REMARK 465     GLU A    49                                                      
+REMARK 465     ILE A    50                                                      
+REMARK 465     PHE A   142                                                      
+REMARK 465     ASN A   143                                                      
+REMARK 465     GLN A   144                                                      
+REMARK 465     ARG A   145                                                      
+REMARK 465     LYS A   331                                                      
+REMARK 465     ARG A   332                                                      
+REMARK 465     GLY A   333                                                      
+REMARK 465     GLY A   334                                                      
+REMARK 465     MET A   335                                                      
+REMARK 465     ASN A   336                                                      
+REMARK 465     GLU A   337                                                      
+REMARK 465     MET C     1                                                      
+REMARK 465     LYS C   253                                                      
+REMARK 465     MET B     1                                                      
+REMARK 465     GLN B     2                                                      
+REMARK 465     PRO B     3                                                      
+REMARK 465     ASP B     4                                                      
+REMARK 465     PRO B    35                                                      
+REMARK 465     GLN B    36                                                      
+REMARK 465     ILE B    37                                                      
+REMARK 465     GLY B    38                                                      
+REMARK 465     GLN B    39                                                      
+REMARK 465     ILE B    40                                                      
+REMARK 465     LEU B    41                                                      
+REMARK 465     TRP B    42                                                      
+REMARK 465     ALA B    43                                                      
+REMARK 465     LYS B    44                                                      
+REMARK 465     ALA B    45                                                      
+REMARK 465     THR B    46                                                      
+REMARK 465     ALA B    47                                                      
+REMARK 465     LEU B    48                                                      
+REMARK 465     GLU B    49                                                      
+REMARK 465     ILE B    50                                                      
+REMARK 465     ASP B    51                                                      
+REMARK 465     PRO B    52                                                      
+REMARK 465     VAL B    53                                                      
+REMARK 465     PHE B   140                                                      
+REMARK 465     LYS B   141                                                      
+REMARK 465     PHE B   142                                                      
+REMARK 465     ASN B   143                                                      
+REMARK 465     GLN B   144                                                      
+REMARK 465     ARG B   145                                                      
+REMARK 465     SER B   146                                                      
+REMARK 465     LYS B   331                                                      
+REMARK 465     ARG B   332                                                      
+REMARK 465     GLY B   333                                                      
+REMARK 465     GLY B   334                                                      
+REMARK 465     MET B   335                                                      
+REMARK 465     ASN B   336                                                      
+REMARK 465     GLU B   337                                                      
+REMARK 465     GLU D    17                                                      
+REMARK 465     ASN D    18                                                      
+REMARK 465     PHE D    19                                                      
+REMARK 465     LEU D    20                                                      
+REMARK 465     LYS D   253                                                      
+REMARK 470                                                                      
+REMARK 470 MISSING ATOM                                                         
+REMARK 470 THE FOLLOWING RESIDUES HAVE MISSING ATOMS(M=MODEL NUMBER;            
+REMARK 470 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE NUMBER;          
+REMARK 470 I=INSERTION CODE):                                                   
+REMARK 470   M RES CSSEQI  ATOMS                                                
+REMARK 470     GLN B  54    CG   CD   OE1  NE2                                  
+REMARK 470     GLN B  55    CG   CD   OE1  NE2                                  
+REMARK 470     GLN B  56    CG   CD   OE1  NE2                                  
+REMARK 470     VAL B  57    CG1  CG2                                            
+REMARK 470     ILE B  58    CG1  CG2  CD1                                       
+REMARK 470     PHE B  59    CG   CD1  CD2  CE1  CE2  CZ                         
+REMARK 480                                                                      
+REMARK 480 ZERO OCCUPANCY ATOM                                                  
+REMARK 480 THE FOLLOWING RESIDUES HAVE ATOMS MODELED WITH ZERO                  
+REMARK 480 OCCUPANCY. THE LOCATION AND PROPERTIES OF THESE ATOMS                
+REMARK 480 MAY NOT BE RELIABLE. (M=MODEL NUMBER; RES=RESIDUE NAME;              
+REMARK 480 C=CHAIN IDENTIFIER; SSEQ=SEQUENCE NUMBER; I=INSERTION CODE):         
+REMARK 480   M RES C SSEQI ATOMS                                                
+REMARK 480     ILE A    9   CD1                                                 
+REMARK 480     ILE A   19   CD1                                                 
+REMARK 480     ILE A   23   CD1                                                 
+REMARK 480     ILE A   27   CD1                                                 
+REMARK 480     ILE A   37   CD1                                                 
+REMARK 480     ILE A   58   CD1                                                 
+REMARK 480     ILE A   66   CD1                                                 
+REMARK 480     ILE A   86   CD1                                                 
+REMARK 480     ILE A   96   CD1                                                 
+REMARK 480     ILE A   97   CD1                                                 
+REMARK 480     ILE A  111   CD1                                                 
+REMARK 480     ILE A  125   CD1                                                 
+REMARK 480     ILE A  151   CD1                                                 
+REMARK 480     ILE A  153   CD1                                                 
+REMARK 480     ILE A  156   CD1                                                 
+REMARK 480     ILE A  171   CD1                                                 
+REMARK 480     ILE A  181   CD1                                                 
+REMARK 480     ILE A  210   CD1                                                 
+REMARK 480     ILE A  243   CD1                                                 
+REMARK 480     ILE A  256   CD1                                                 
+REMARK 480     ILE A  260   CD1                                                 
+REMARK 480     ILE A  266   CD1                                                 
+REMARK 480     ILE A  267   CD1                                                 
+REMARK 480     LEU A  304   CB    CG    CD1   CD2                               
+REMARK 480     ASP A  306   OD1   OD2                                           
+REMARK 480     ILE A  309   CD1                                                 
+REMARK 480     ILE A  311   CD1                                                 
+REMARK 480     ILE A  313   CD1                                                 
+REMARK 480     ILE A  318   CD1                                                 
+REMARK 480     LEU A  330   O                                                   
+REMARK 480     PHE C   19   CB    CG    CD1   CD2   CE1   CE2   CZ              
+REMARK 480     ILE C   33   CD1                                                 
+REMARK 480     ILE C   54   CD1                                                 
+REMARK 480     ILE C   58   CD1                                                 
+REMARK 480     ILE C   62   CD1                                                 
+REMARK 480     ILE C   68   CD1                                                 
+REMARK 480     ILE C   86   CD1                                                 
+REMARK 480     ILE C   95   CD1                                                 
+REMARK 480     ILE C  137   CD1                                                 
+REMARK 480     ILE C  139   CD1                                                 
+REMARK 480     ILE C  143   CD1                                                 
+REMARK 480     ILE C  150   CD1                                                 
+REMARK 480     ILE C  166   CD1                                                 
+REMARK 480     ILE C  172   CD1                                                 
+REMARK 480     ILE C  195   CD1                                                 
+REMARK 480     ILE C  215   CD1                                                 
+REMARK 480     LEU C  252   O                                                   
+REMARK 480     ILE B    9   CD1                                                 
+REMARK 480     ILE B   19   CD1                                                 
+REMARK 480     ILE B   23   CD1                                                 
+REMARK 480     ILE B   27   CD1                                                 
+REMARK 480     ARG B   29   CG    CD    NE    CZ    NH1   NH2                   
+REMARK 480     ILE B   66   CD1                                                 
+REMARK 480     ILE B   86   CD1                                                 
+REMARK 480     ILE B   96   CD1                                                 
+REMARK 480     ILE B   97   CD1                                                 
+REMARK 480     ILE B  111   CD1                                                 
+REMARK 480     ILE B  125   CD1                                                 
+REMARK 480     ILE B  151   CD1                                                 
+REMARK 480     ILE B  153   CD1                                                 
+REMARK 480     ILE B  156   CD1                                                 
+REMARK 480     ILE B  171   CD1                                                 
+REMARK 480     THR B  174   O                                                   
+REMARK 480     LYS B  177   NZ                                                  
+REMARK 480     ILE B  181   CD1                                                 
+REMARK 480     ILE B  210   CD1                                                 
+REMARK 480     ILE B  243   CD1                                                 
+REMARK 480     ILE B  256   CD1                                                 
+REMARK 480     ILE B  260   CD1                                                 
+REMARK 480     ILE B  266   CD1                                                 
+REMARK 480     ILE B  267   CD1                                                 
+REMARK 480     ILE B  309   CD1                                                 
+REMARK 480     ILE B  311   CD1                                                 
+REMARK 480     ILE B  313   CD1                                                 
+REMARK 480     ILE B  318   CD1                                                 
+REMARK 480     LEU B  330   O                                                   
+REMARK 480     ILE D   33   CD1                                                 
+REMARK 480     ILE D   54   CD1                                                 
+REMARK 480     ILE D   58   CD1                                                 
+REMARK 480     ILE D   62   CD1                                                 
+REMARK 480     ILE D   68   CD1                                                 
+REMARK 480     ILE D   86   CD1                                                 
+REMARK 480     ILE D   95   CD1                                                 
+REMARK 480     ILE D  137   CD1                                                 
+REMARK 480     ILE D  139   CD1                                                 
+REMARK 480     ILE D  143   CD1                                                 
+REMARK 480     ILE D  150   CD1                                                 
+REMARK 480     ILE D  166   CD1                                                 
+REMARK 480     ILE D  172   CD1                                                 
+REMARK 480     ILE D  195   CD1                                                 
+REMARK 480     ILE D  215   CD1                                                 
+REMARK 480     LEU D  252   O                                                   
+REMARK 500                                                                      
+REMARK 500 GEOMETRY AND STEREOCHEMISTRY                                         
+REMARK 500 SUBTOPIC: TORSION ANGLES                                             
+REMARK 500                                                                      
+REMARK 500 TORSION ANGLES OUTSIDE THE EXPECTED RAMACHANDRAN REGIONS:            
+REMARK 500 (M=MODEL NUMBER; RES=RESIDUE NAME; C=CHAIN IDENTIFIER;               
+REMARK 500 SSEQ=SEQUENCE NUMBER; I=INSERTION CODE).                             
+REMARK 500                                                                      
+REMARK 500 STANDARD TABLE:                                                      
+REMARK 500 FORMAT:(10X,I3,1X,A3,1X,A1,I4,A1,4X,F7.2,3X,F7.2)                    
+REMARK 500                                                                      
+REMARK 500 EXPECTED VALUES: GJ KLEYWEGT AND TA JONES (1996). PHI/PSI-           
+REMARK 500 CHOLOGY: RAMACHANDRAN REVISITED. STRUCTURE 4, 1395 - 1400            
+REMARK 500                                                                      
+REMARK 500  M RES CSSEQI        PSI       PHI                                   
+REMARK 500    SER A  31     -157.99    -95.04                                   
+REMARK 500    SER A  33      -40.69   -147.53                                   
+REMARK 500    VAL A  61      -73.75   -114.78                                   
+REMARK 500    PRO A  94       22.95    -65.56                                   
+REMARK 500    PHE A 140       55.43   -110.38                                   
+REMARK 500    LEU A 304      -53.15    -28.77                                   
+REMARK 500    PHE C  26      149.83    170.61                                   
+REMARK 500    ASN C  40      123.78    -15.19                                   
+REMARK 500    HIS C 120       20.36    -70.73                                   
+REMARK 500    LYS C 204       89.47     32.38                                   
+REMARK 500    GLN C 205       -7.71     53.58                                   
+REMARK 500    GLU C 238       -8.37     74.98                                   
+REMARK 500    ARG B  29      -72.42    -37.67                                   
+REMARK 500    TYR B  30       72.57   -104.58                                   
+REMARK 500    SER B  31     -163.46    -63.99                                   
+REMARK 500    ILE B  58       -4.14    -58.80                                   
+REMARK 500    PHE B  59        9.36    -62.84                                   
+REMARK 500    PRO B  94        0.53    -60.54                                   
+REMARK 500    PHE B 138       -1.56    -57.76                                   
+REMARK 500    ILE B 171       43.18   -106.33                                   
+REMARK 500    GLU B 176      -60.94   -125.57                                   
+REMARK 500    THR B 191       55.30    -98.01                                   
+REMARK 500    SER B 257        8.95   -155.12                                   
+REMARK 500    LYS B 329      173.01     68.28                                   
+REMARK 500    ASN D   9       39.11     37.06                                   
+REMARK 500    GLN D  15      -46.04   -133.90                                   
+REMARK 500    GLN D 205      -70.80   -103.76                                   
+REMARK 500    LYS D 237       74.21     45.00                                   
+REMARK 500    GLU D 238      -10.13     74.41                                   
+REMARK 500                                                                      
+REMARK 500 REMARK: NULL                                                         
+REMARK 525                                                                      
+REMARK 525 SOLVENT                                                              
+REMARK 525                                                                      
+REMARK 525 THE SOLVENT MOLECULES HAVE CHAIN IDENTIFIERS THAT                    
+REMARK 525 INDICATE THE POLYMER CHAIN WITH WHICH THEY ARE MOST                  
+REMARK 525 CLOSELY ASSOCIATED. THE REMARK LISTS ALL THE SOLVENT                 
+REMARK 525 MOLECULES WHICH ARE MORE THAN 5A AWAY FROM THE                       
+REMARK 525 NEAREST POLYMER CHAIN (M = MODEL NUMBER;                             
+REMARK 525 RES=RESIDUE NAME; C=CHAIN IDENTIFIER; SSEQ=SEQUENCE                  
+REMARK 525 NUMBER; I=INSERTION CODE):                                           
+REMARK 525                                                                      
+REMARK 525  M RES CSSEQI                                                        
+REMARK 525    HOH A 338        DISTANCE =  5.37 ANGSTROMS                       
+REMARK 525    HOH B 338        DISTANCE =  6.06 ANGSTROMS                       
+REMARK 525    HOH A 342        DISTANCE =  6.30 ANGSTROMS                       
+REMARK 525    HOH A 345        DISTANCE =  5.81 ANGSTROMS                       
+REMARK 525    HOH A 346        DISTANCE =  7.29 ANGSTROMS                       
+REMARK 525    HOH A 349        DISTANCE =  6.66 ANGSTROMS                       
+REMARK 525    HOH B 351        DISTANCE =  7.58 ANGSTROMS                       
+REMARK 525    HOH A 358        DISTANCE =  5.71 ANGSTROMS                       
+REMARK 525    HOH B 358        DISTANCE =  7.75 ANGSTROMS                       
+REMARK 525    HOH B 362        DISTANCE =  5.02 ANGSTROMS                       
+REMARK 525    HOH A 363        DISTANCE =  5.13 ANGSTROMS                       
+REMARK 525    HOH B 364        DISTANCE =  5.16 ANGSTROMS                       
+REMARK 525    HOH A 370        DISTANCE =  6.40 ANGSTROMS                       
+REMARK 525    HOH B 376        DISTANCE =  5.09 ANGSTROMS                       
+REMARK 525    HOH C 294        DISTANCE =  5.07 ANGSTROMS                       
+REMARK 525    HOH C 296        DISTANCE =  6.91 ANGSTROMS                       
+REMARK 525    HOH A 382        DISTANCE =  5.29 ANGSTROMS                       
+REMARK 525    HOH A 384        DISTANCE =  5.51 ANGSTROMS                       
+REMARK 525    HOH C 302        DISTANCE =  7.27 ANGSTROMS                       
+REMARK 525    HOH A 389        DISTANCE =  5.06 ANGSTROMS                       
+REMARK 525    HOH A 392        DISTANCE =  9.75 ANGSTROMS                       
+REMARK 525    HOH A 395        DISTANCE =  6.38 ANGSTROMS                       
+REMARK 525    HOH A 396        DISTANCE =  5.75 ANGSTROMS                       
+REMARK 525    HOH A 397        DISTANCE =  6.46 ANGSTROMS                       
+REMARK 525    HOH B 397        DISTANCE =  6.74 ANGSTROMS                       
+REMARK 525    HOH A 398        DISTANCE =  7.71 ANGSTROMS                       
+REMARK 525    HOH A 399        DISTANCE =  7.70 ANGSTROMS                       
+REMARK 525    HOH B 399        DISTANCE =  5.77 ANGSTROMS                       
+REMARK 525    HOH A 400        DISTANCE =  5.78 ANGSTROMS                       
+REMARK 525    HOH A 401        DISTANCE =  7.95 ANGSTROMS                       
+REMARK 525    HOH A 402        DISTANCE =  5.92 ANGSTROMS                       
+REMARK 525    HOH A 405        DISTANCE =  7.57 ANGSTROMS                       
+REMARK 525    HOH A 406        DISTANCE =  5.49 ANGSTROMS                       
+REMARK 525    HOH A 408        DISTANCE =  5.55 ANGSTROMS                       
+REMARK 525    HOH B 409        DISTANCE =  9.52 ANGSTROMS                       
+REMARK 525    HOH B 410        DISTANCE =  6.44 ANGSTROMS                       
+REMARK 525    HOH A 411        DISTANCE =  5.20 ANGSTROMS                       
+REMARK 525    HOH B 411        DISTANCE =  7.86 ANGSTROMS                       
+REMARK 525    HOH A 412        DISTANCE =  5.16 ANGSTROMS                       
+REMARK 525    HOH A 413        DISTANCE =  5.00 ANGSTROMS                       
+REMARK 525    HOH B 413        DISTANCE =  8.08 ANGSTROMS                       
+REMARK 525    HOH D 330        DISTANCE =  6.06 ANGSTROMS                       
+REMARK 525    HOH A 415        DISTANCE =  7.14 ANGSTROMS                       
+REMARK 525    HOH B 415        DISTANCE =  5.04 ANGSTROMS                       
+REMARK 525    HOH A 416        DISTANCE =  6.80 ANGSTROMS                       
+REMARK 525    HOH B 416        DISTANCE = 10.06 ANGSTROMS                       
+REMARK 525    HOH A 417        DISTANCE =  6.57 ANGSTROMS                       
+REMARK 525    HOH A 421        DISTANCE =  8.13 ANGSTROMS                       
+REMARK 525    HOH A 422        DISTANCE =  8.23 ANGSTROMS                       
+REMARK 525    HOH D 338        DISTANCE =  5.22 ANGSTROMS                       
+REMARK 525    HOH A 423        DISTANCE =  9.06 ANGSTROMS                       
+REMARK 525    HOH D 339        DISTANCE =  5.28 ANGSTROMS                       
+REMARK 525    HOH A 424        DISTANCE =  7.85 ANGSTROMS                       
+REMARK 525    HOH A 426        DISTANCE =  6.09 ANGSTROMS                       
+REMARK 525    HOH A 429        DISTANCE =  5.42 ANGSTROMS                       
+REMARK 525    HOH A 430        DISTANCE =  5.84 ANGSTROMS                       
+REMARK 525    HOH B 430        DISTANCE =  7.73 ANGSTROMS                       
+REMARK 525    HOH A 431        DISTANCE = 10.42 ANGSTROMS                       
+REMARK 525    HOH C 347        DISTANCE =  7.06 ANGSTROMS                       
+REMARK 525    HOH A 433        DISTANCE =  6.10 ANGSTROMS                       
+REMARK 525    HOH B 434        DISTANCE =  5.06 ANGSTROMS                       
+REMARK 525    HOH C 354        DISTANCE =  6.04 ANGSTROMS                       
+REMARK 525    HOH C 356        DISTANCE =  6.29 ANGSTROMS                       
+REMARK 525    HOH A 441        DISTANCE =  6.55 ANGSTROMS                       
+REMARK 525    HOH B 441        DISTANCE =  7.64 ANGSTROMS                       
+REMARK 525    HOH A 442        DISTANCE =  8.53 ANGSTROMS                       
+REMARK 525    HOH C 359        DISTANCE =  7.30 ANGSTROMS                       
+REMARK 525    HOH A 444        DISTANCE = 10.19 ANGSTROMS                       
+REMARK 525    HOH A 445        DISTANCE =  5.36 ANGSTROMS                       
+REMARK 525    HOH B 445        DISTANCE =  5.82 ANGSTROMS                       
+REMARK 525    HOH B 446        DISTANCE =  6.30 ANGSTROMS                       
+REMARK 525    HOH A 448        DISTANCE =  8.26 ANGSTROMS                       
+REMARK 525    HOH A 449        DISTANCE =  7.30 ANGSTROMS                       
+REMARK 525    HOH B 449        DISTANCE =  6.83 ANGSTROMS                       
+REMARK 525    HOH A 450        DISTANCE =  9.81 ANGSTROMS                       
+REMARK 525    HOH A 452        DISTANCE =  5.48 ANGSTROMS                       
+REMARK 525    HOH A 453        DISTANCE =  7.51 ANGSTROMS                       
+REMARK 525    HOH B 453        DISTANCE =  8.35 ANGSTROMS                       
+REMARK 525    HOH C 369        DISTANCE =  6.71 ANGSTROMS                       
+REMARK 525    HOH A 454        DISTANCE =  5.21 ANGSTROMS                       
+REMARK 525    HOH A 455        DISTANCE =  8.98 ANGSTROMS                       
+REMARK 525    HOH A 456        DISTANCE =  9.32 ANGSTROMS                       
+REMARK 525    HOH D 372        DISTANCE =  6.89 ANGSTROMS                       
+REMARK 525    HOH B 457        DISTANCE =  6.31 ANGSTROMS                       
+REMARK 525    HOH D 373        DISTANCE =  5.26 ANGSTROMS                       
+REMARK 525    HOH C 374        DISTANCE =  5.29 ANGSTROMS                       
+REMARK 525    HOH A 459        DISTANCE =  7.97 ANGSTROMS                       
+REMARK 525    HOH C 375        DISTANCE =  5.53 ANGSTROMS                       
+REMARK 525    HOH B 460        DISTANCE =  5.34 ANGSTROMS                       
+REMARK 525    HOH D 376        DISTANCE =  6.46 ANGSTROMS                       
+REMARK 525    HOH A 463        DISTANCE =  6.52 ANGSTROMS                       
+REMARK 525    HOH A 464        DISTANCE =  6.23 ANGSTROMS                       
+REMARK 525    HOH B 464        DISTANCE =  7.58 ANGSTROMS                       
+REMARK 525    HOH A 466        DISTANCE =  8.61 ANGSTROMS                       
+REMARK 525    HOH B 466        DISTANCE =  6.22 ANGSTROMS                       
+REMARK 525    HOH C 383        DISTANCE =  8.79 ANGSTROMS                       
+REMARK 525    HOH B 468        DISTANCE =  5.07 ANGSTROMS                       
+REMARK 525    HOH B 469        DISTANCE =  7.64 ANGSTROMS                       
+REMARK 525    HOH C 385        DISTANCE =  6.10 ANGSTROMS                       
+REMARK 525    HOH B 470        DISTANCE =  9.68 ANGSTROMS                       
+REMARK 525    HOH A 471        DISTANCE =  5.61 ANGSTROMS                       
+REMARK 525    HOH C 388        DISTANCE =  5.55 ANGSTROMS                       
+REMARK 525    HOH A 474        DISTANCE =  5.57 ANGSTROMS                       
+REMARK 525    HOH B 476        DISTANCE = 10.97 ANGSTROMS                       
+REMARK 525    HOH A 478        DISTANCE =  8.95 ANGSTROMS                       
+REMARK 525    HOH B 478        DISTANCE =  8.30 ANGSTROMS                       
+REMARK 525    HOH B 479        DISTANCE =  6.15 ANGSTROMS                       
+REMARK 525    HOH B 482        DISTANCE =  9.07 ANGSTROMS                       
+REMARK 525    HOH C 398        DISTANCE =  6.09 ANGSTROMS                       
+REMARK 525    HOH B 483        DISTANCE =  8.06 ANGSTROMS                       
+REMARK 525    HOH B 484        DISTANCE =  8.48 ANGSTROMS                       
+REMARK 525    HOH B 485        DISTANCE =  5.32 ANGSTROMS                       
+REMARK 525    HOH C 401        DISTANCE =  9.94 ANGSTROMS                       
+REMARK 525    HOH D 401        DISTANCE =  6.72 ANGSTROMS                       
+REMARK 525    HOH B 490        DISTANCE =  5.59 ANGSTROMS                       
+REMARK 525    HOH C 406        DISTANCE =  5.52 ANGSTROMS                       
+REMARK 525    HOH C 407        DISTANCE =  7.25 ANGSTROMS                       
+REMARK 525    HOH D 407        DISTANCE =  7.08 ANGSTROMS                       
+REMARK 525    HOH B 492        DISTANCE =  7.25 ANGSTROMS                       
+REMARK 525    HOH C 408        DISTANCE =  9.39 ANGSTROMS                       
+REMARK 525    HOH D 408        DISTANCE =  9.27 ANGSTROMS                       
+REMARK 525    HOH B 493        DISTANCE =  6.63 ANGSTROMS                       
+REMARK 525    HOH C 409        DISTANCE =  6.14 ANGSTROMS                       
+REMARK 525    HOH C 410        DISTANCE =  5.56 ANGSTROMS                       
+REMARK 525    HOH B 495        DISTANCE =  7.33 ANGSTROMS                       
+REMARK 525    HOH B 496        DISTANCE =  6.23 ANGSTROMS                       
+REMARK 525    HOH D 412        DISTANCE =  6.50 ANGSTROMS                       
+REMARK 525    HOH C 413        DISTANCE =  6.54 ANGSTROMS                       
+REMARK 525    HOH B 499        DISTANCE =  5.36 ANGSTROMS                       
+REMARK 525    HOH C 415        DISTANCE =  5.97 ANGSTROMS                       
+REMARK 525    HOH C 417        DISTANCE =  6.59 ANGSTROMS                       
+REMARK 525    HOH C 421        DISTANCE =  5.28 ANGSTROMS                       
+REMARK 525    HOH D 421        DISTANCE =  6.24 ANGSTROMS                       
+REMARK 525    HOH C 422        DISTANCE =  7.91 ANGSTROMS                       
+REMARK 525    HOH D 422        DISTANCE =  7.25 ANGSTROMS                       
+REMARK 525    HOH D 423        DISTANCE =  8.83 ANGSTROMS                       
+REMARK 525    HOH D 432        DISTANCE =  5.76 ANGSTROMS                       
+REMARK 525    HOH D 435        DISTANCE =  7.07 ANGSTROMS                       
+REMARK 525    HOH D 438        DISTANCE =  8.14 ANGSTROMS                       
+REMARK 525    HOH D 445        DISTANCE =  6.07 ANGSTROMS                       
+REMARK 525    HOH D 459        DISTANCE =  6.28 ANGSTROMS                       
+REMARK 525    HOH D 461        DISTANCE =  7.26 ANGSTROMS                       
+DBREF  2NQ2 A    1   337  UNP    Q57130   Y1471_HAEIN      1    337             
+DBREF  2NQ2 B    1   337  UNP    Q57130   Y1471_HAEIN      1    337             
+DBREF  2NQ2 C    1   253  UNP    Q57399   Y1470_HAEIN      1    253             
+DBREF  2NQ2 D    1   253  UNP    Q57399   Y1470_HAEIN      1    253             
+SEQRES   1 A  337  MET GLN PRO ASP SER TYR PRO LYS ILE LEU PHE GLY LEU          
+SEQRES   2 A  337  THR LEU LEU LEU VAL ILE THR ALA VAL ILE SER LEU GLY          
+SEQRES   3 A  337  ILE GLY ARG TYR SER LEU SER VAL PRO GLN ILE GLY GLN          
+SEQRES   4 A  337  ILE LEU TRP ALA LYS ALA THR ALA LEU GLU ILE ASP PRO          
+SEQRES   5 A  337  VAL GLN GLN GLN VAL ILE PHE GLN VAL ARG LEU PRO ARG          
+SEQRES   6 A  337  ILE LEU THR ALA LEU CYS VAL GLY ALA GLY LEU ALA LEU          
+SEQRES   7 A  337  SER GLY VAL VAL LEU GLN GLY ILE PHE ARG ASN PRO LEU          
+SEQRES   8 A  337  VAL ASN PRO HIS ILE ILE GLY VAL THR SER GLY SER ALA          
+SEQRES   9 A  337  PHE GLY GLY THR LEU ALA ILE PHE PHE GLY PHE SER LEU          
+SEQRES  10 A  337  TYR GLY LEU PHE THR SER THR ILE LEU PHE GLY PHE GLY          
+SEQRES  11 A  337  THR LEU ALA LEU VAL PHE LEU PHE SER PHE LYS PHE ASN          
+SEQRES  12 A  337  GLN ARG SER LEU LEU MET LEU ILE LEU ILE GLY MET ILE          
+SEQRES  13 A  337  LEU SER GLY LEU PHE SER ALA LEU VAL SER LEU LEU GLN          
+SEQRES  14 A  337  TYR ILE SER ASP THR GLU GLU LYS LEU PRO SER ILE VAL          
+SEQRES  15 A  337  PHE TRP LEU MET GLY SER PHE ALA THR SER ASN TRP GLU          
+SEQRES  16 A  337  LYS LEU LEU PHE PHE PHE VAL PRO PHE LEU LEU CYS SER          
+SEQRES  17 A  337  SER ILE LEU LEU SER LEU SER TRP ARG LEU ASN LEU LEU          
+SEQRES  18 A  337  SER LEU ASP GLU LYS GLU ALA LYS ALA LEU GLY VAL LYS          
+SEQRES  19 A  337  MET ALA PRO LEU ARG TRP LEU VAL ILE PHE LEU SER GLY          
+SEQRES  20 A  337  SER LEU VAL ALA CYS GLN VAL ALA ILE SER GLY SER ILE          
+SEQRES  21 A  337  GLY TRP VAL GLY LEU ILE ILE PRO HIS LEU SER ARG MET          
+SEQRES  22 A  337  LEU VAL GLY ALA ASN HIS GLN SER LEU LEU PRO CYS THR          
+SEQRES  23 A  337  MET LEU VAL GLY ALA THR TYR MET LEU LEU VAL ASP ASN          
+SEQRES  24 A  337  VAL ALA ARG SER LEU SER ASP ALA GLU ILE PRO ILE SER          
+SEQRES  25 A  337  ILE LEU THR ALA LEU ILE GLY ALA PRO LEU PHE GLY VAL          
+SEQRES  26 A  337  LEU VAL TYR LYS LEU LYS ARG GLY GLY MET ASN GLU              
+SEQRES   1 C  253  MET ASN LYS ALA LEU SER VAL GLU ASN LEU GLY PHE TYR          
+SEQRES   2 C  253  TYR GLN ALA GLU ASN PHE LEU PHE GLN GLN LEU ASN PHE          
+SEQRES   3 C  253  ASP LEU ASN LYS GLY ASP ILE LEU ALA VAL LEU GLY GLN          
+SEQRES   4 C  253  ASN GLY CYS GLY LYS SER THR LEU LEU ASP LEU LEU LEU          
+SEQRES   5 C  253  GLY ILE HIS ARG PRO ILE GLN GLY LYS ILE GLU VAL TYR          
+SEQRES   6 C  253  GLN SER ILE GLY PHE VAL PRO GLN PHE PHE SER SER PRO          
+SEQRES   7 C  253  PHE ALA TYR SER VAL LEU ASP ILE VAL LEU MET GLY ARG          
+SEQRES   8 C  253  SER THR HIS ILE ASN THR PHE ALA LYS PRO LYS SER HIS          
+SEQRES   9 C  253  ASP TYR GLN VAL ALA MET GLN ALA LEU ASP TYR LEU ASN          
+SEQRES  10 C  253  LEU THR HIS LEU ALA LYS ARG GLU PHE THR SER LEU SER          
+SEQRES  11 C  253  GLY GLY GLN ARG GLN LEU ILE LEU ILE ALA ARG ALA ILE          
+SEQRES  12 C  253  ALA SER GLU CYS LYS LEU ILE LEU LEU ASP GLU PRO THR          
+SEQRES  13 C  253  SER ALA LEU ASP LEU ALA ASN GLN ASP ILE VAL LEU SER          
+SEQRES  14 C  253  LEU LEU ILE ASP LEU ALA GLN SER GLN ASN MET THR VAL          
+SEQRES  15 C  253  VAL PHE THR THR HIS GLN PRO ASN GLN VAL VAL ALA ILE          
+SEQRES  16 C  253  ALA ASN LYS THR LEU LEU LEU ASN LYS GLN ASN PHE LYS          
+SEQRES  17 C  253  PHE GLY GLU THR ARG ASN ILE LEU THR SER GLU ASN LEU          
+SEQRES  18 C  253  THR ALA LEU PHE HIS LEU PRO MET PHE GLU GLN GLN ALA          
+SEQRES  19 C  253  GLN TYR LYS GLU SER PHE PHE THR HIS PHE VAL PRO LEU          
+SEQRES  20 C  253  TYR LYS THR LEU LEU LYS                                      
+SEQRES   1 B  337  MET GLN PRO ASP SER TYR PRO LYS ILE LEU PHE GLY LEU          
+SEQRES   2 B  337  THR LEU LEU LEU VAL ILE THR ALA VAL ILE SER LEU GLY          
+SEQRES   3 B  337  ILE GLY ARG TYR SER LEU SER VAL PRO GLN ILE GLY GLN          
+SEQRES   4 B  337  ILE LEU TRP ALA LYS ALA THR ALA LEU GLU ILE ASP PRO          
+SEQRES   5 B  337  VAL GLN GLN GLN VAL ILE PHE GLN VAL ARG LEU PRO ARG          
+SEQRES   6 B  337  ILE LEU THR ALA LEU CYS VAL GLY ALA GLY LEU ALA LEU          
+SEQRES   7 B  337  SER GLY VAL VAL LEU GLN GLY ILE PHE ARG ASN PRO LEU          
+SEQRES   8 B  337  VAL ASN PRO HIS ILE ILE GLY VAL THR SER GLY SER ALA          
+SEQRES   9 B  337  PHE GLY GLY THR LEU ALA ILE PHE PHE GLY PHE SER LEU          
+SEQRES  10 B  337  TYR GLY LEU PHE THR SER THR ILE LEU PHE GLY PHE GLY          
+SEQRES  11 B  337  THR LEU ALA LEU VAL PHE LEU PHE SER PHE LYS PHE ASN          
+SEQRES  12 B  337  GLN ARG SER LEU LEU MET LEU ILE LEU ILE GLY MET ILE          
+SEQRES  13 B  337  LEU SER GLY LEU PHE SER ALA LEU VAL SER LEU LEU GLN          
+SEQRES  14 B  337  TYR ILE SER ASP THR GLU GLU LYS LEU PRO SER ILE VAL          
+SEQRES  15 B  337  PHE TRP LEU MET GLY SER PHE ALA THR SER ASN TRP GLU          
+SEQRES  16 B  337  LYS LEU LEU PHE PHE PHE VAL PRO PHE LEU LEU CYS SER          
+SEQRES  17 B  337  SER ILE LEU LEU SER LEU SER TRP ARG LEU ASN LEU LEU          
+SEQRES  18 B  337  SER LEU ASP GLU LYS GLU ALA LYS ALA LEU GLY VAL LYS          
+SEQRES  19 B  337  MET ALA PRO LEU ARG TRP LEU VAL ILE PHE LEU SER GLY          
+SEQRES  20 B  337  SER LEU VAL ALA CYS GLN VAL ALA ILE SER GLY SER ILE          
+SEQRES  21 B  337  GLY TRP VAL GLY LEU ILE ILE PRO HIS LEU SER ARG MET          
+SEQRES  22 B  337  LEU VAL GLY ALA ASN HIS GLN SER LEU LEU PRO CYS THR          
+SEQRES  23 B  337  MET LEU VAL GLY ALA THR TYR MET LEU LEU VAL ASP ASN          
+SEQRES  24 B  337  VAL ALA ARG SER LEU SER ASP ALA GLU ILE PRO ILE SER          
+SEQRES  25 B  337  ILE LEU THR ALA LEU ILE GLY ALA PRO LEU PHE GLY VAL          
+SEQRES  26 B  337  LEU VAL TYR LYS LEU LYS ARG GLY GLY MET ASN GLU              
+SEQRES   1 D  253  MET ASN LYS ALA LEU SER VAL GLU ASN LEU GLY PHE TYR          
+SEQRES   2 D  253  TYR GLN ALA GLU ASN PHE LEU PHE GLN GLN LEU ASN PHE          
+SEQRES   3 D  253  ASP LEU ASN LYS GLY ASP ILE LEU ALA VAL LEU GLY GLN          
+SEQRES   4 D  253  ASN GLY CYS GLY LYS SER THR LEU LEU ASP LEU LEU LEU          
+SEQRES   5 D  253  GLY ILE HIS ARG PRO ILE GLN GLY LYS ILE GLU VAL TYR          
+SEQRES   6 D  253  GLN SER ILE GLY PHE VAL PRO GLN PHE PHE SER SER PRO          
+SEQRES   7 D  253  PHE ALA TYR SER VAL LEU ASP ILE VAL LEU MET GLY ARG          
+SEQRES   8 D  253  SER THR HIS ILE ASN THR PHE ALA LYS PRO LYS SER HIS          
+SEQRES   9 D  253  ASP TYR GLN VAL ALA MET GLN ALA LEU ASP TYR LEU ASN          
+SEQRES  10 D  253  LEU THR HIS LEU ALA LYS ARG GLU PHE THR SER LEU SER          
+SEQRES  11 D  253  GLY GLY GLN ARG GLN LEU ILE LEU ILE ALA ARG ALA ILE          
+SEQRES  12 D  253  ALA SER GLU CYS LYS LEU ILE LEU LEU ASP GLU PRO THR          
+SEQRES  13 D  253  SER ALA LEU ASP LEU ALA ASN GLN ASP ILE VAL LEU SER          
+SEQRES  14 D  253  LEU LEU ILE ASP LEU ALA GLN SER GLN ASN MET THR VAL          
+SEQRES  15 D  253  VAL PHE THR THR HIS GLN PRO ASN GLN VAL VAL ALA ILE          
+SEQRES  16 D  253  ALA ASN LYS THR LEU LEU LEU ASN LYS GLN ASN PHE LYS          
+SEQRES  17 D  253  PHE GLY GLU THR ARG ASN ILE LEU THR SER GLU ASN LEU          
+SEQRES  18 D  253  THR ALA LEU PHE HIS LEU PRO MET PHE GLU GLN GLN ALA          
+SEQRES  19 D  253  GLN TYR LYS GLU SER PHE PHE THR HIS PHE VAL PRO LEU          
+SEQRES  20 D  253  TYR LYS THR LEU LEU LYS                                      
+FORMUL   5  HOH   *682(H2 O)                                                    
+HELIX    1   1 TYR A    6  LEU A   25  1                                  20    
+HELIX    2   2 PRO A   52  VAL A   61  1                                  10    
+HELIX    3   3 VAL A   61  PHE A   87  1                                  27    
+HELIX    4   4 GLY A   98  PHE A  113  1                                  16    
+HELIX    5   5 SER A  116  PHE A  140  1                                  25    
+HELIX    6   6 SER A  146  ILE A  171  1                                  26    
+HELIX    7   7 GLU A  176  LEU A  185  1                                  10    
+HELIX    8   8 ASN A  193  LEU A  214  1                                  22    
+HELIX    9   9 TRP A  216  LEU A  223  5                                   8    
+HELIX   10  10 ASP A  224  LEU A  231  1                                   8    
+HELIX   11  11 LYS A  234  GLY A  258  1                                  25    
+HELIX   12  12 LEU A  265  GLY A  276  1                                  12    
+HELIX   13  13 ASN A  278  LEU A  304  1                                  27    
+HELIX   14  14 PRO A  310  LYS A  329  1                                  20    
+HELIX   15  15 GLY C   43  LEU C   52  1                                  10    
+HELIX   16  16 SER C   82  MET C   89  1                                   8    
+HELIX   17  17 GLY C   90  ILE C   95  5                                   6    
+HELIX   18  18 LYS C  102  LEU C  116  1                                  15    
+HELIX   19  19 LEU C  118  ALA C  122  5                                   5    
+HELIX   20  20 GLU C  125  LEU C  129  5                                   5    
+HELIX   21  21 SER C  130  SER C  145  1                                  16    
+HELIX   22  22 ASP C  160  SER C  177  1                                  18    
+HELIX   23  23 GLN C  188  ALA C  196  1                                   9    
+HELIX   24  24 THR C  212  LEU C  216  1                                   5    
+HELIX   25  25 THR C  217  HIS C  226  1                                  10    
+HELIX   26  26 TYR C  248  LEU C  252  5                                   5    
+HELIX   27  27 SER B    5  GLY B   26  1                                  22    
+HELIX   28  28 VAL B   57  VAL B   61  5                                   5    
+HELIX   29  29 ARG B   62  PHE B   87  1                                  26    
+HELIX   30  30 GLY B   98  PHE B  113  1                                  16    
+HELIX   31  31 SER B  116  PHE B  138  1                                  23    
+HELIX   32  32 LEU B  147  ILE B  171  1                                  25    
+HELIX   33  33 GLU B  176  MET B  186  1                                  11    
+HELIX   34  34 ASN B  193  LEU B  214  1                                  22    
+HELIX   35  35 SER B  215  LEU B  223  5                                   9    
+HELIX   36  36 ASP B  224  LEU B  231  1                                   8    
+HELIX   37  37 LYS B  234  GLY B  258  1                                  25    
+HELIX   38  38 ILE B  266  GLY B  276  1                                  11    
+HELIX   39  39 ASN B  278  SER B  305  1                                  28    
+HELIX   40  40 PRO B  310  TYR B  328  1                                  19    
+HELIX   41  41 GLY D   43  GLY D   53  1                                  11    
+HELIX   42  42 SER D   82  MET D   89  1                                   8    
+HELIX   43  43 GLY D   90  ILE D   95  5                                   6    
+HELIX   44  44 LYS D  102  LEU D  116  1                                  15    
+HELIX   45  45 LEU D  118  ALA D  122  5                                   5    
+HELIX   46  46 GLU D  125  LEU D  129  5                                   5    
+HELIX   47  47 SER D  130  SER D  145  1                                  16    
+HELIX   48  48 ASP D  160  GLN D  178  1                                  19    
+HELIX   49  49 GLN D  188  ALA D  196  1                                   9    
+HELIX   50  50 THR D  212  LEU D  216  1                                   5    
+HELIX   51  51 THR D  217  HIS D  226  1                                  10    
+SHEET    1   A 3 PHE C  19  ASN C  29  0                                        
+SHEET    2   A 3 LYS C   3  TYR C  14 -1  N  ALA C   4   O  LEU C  28           
+SHEET    3   A 3 GLN C  59  VAL C  64 -1  O  GLU C  63   N  SER C   6           
+SHEET    1   B 6 ILE C  68  VAL C  71  0                                        
+SHEET    2   B 6 LEU C 149  LEU C 152  1  O  LEU C 149   N  GLY C  69           
+SHEET    3   B 6 THR C 181  THR C 186  1  O  VAL C 183   N  LEU C 152           
+SHEET    4   B 6 ILE C  33  LEU C  37  1  N  LEU C  34   O  VAL C 182           
+SHEET    5   B 6 LYS C 198  ASN C 203  1  O  LEU C 200   N  ALA C  35           
+SHEET    6   B 6 ASN C 206  GLU C 211 -1  O  LYS C 208   N  LEU C 201           
+SHEET    1   C 2 MET C 229  TYR C 236  0                                        
+SHEET    2   C 2 SER C 239  PRO C 246 -1  O  HIS C 243   N  GLN C 232           
+SHEET    1   D 3 LEU D  24  ASN D  29  0                                        
+SHEET    2   D 3 LYS D   3  GLY D  11 -1  N  ALA D   4   O  LEU D  28           
+SHEET    3   D 3 GLN D  59  VAL D  64 -1  O  GLU D  63   N  SER D   6           
+SHEET    1   E 6 ILE D  68  VAL D  71  0                                        
+SHEET    2   E 6 LEU D 149  LEU D 152  1  O  LEU D 151   N  VAL D  71           
+SHEET    3   E 6 THR D 181  THR D 186  1  O  VAL D 183   N  LEU D 152           
+SHEET    4   E 6 ILE D  33  GLY D  38  1  N  LEU D  34   O  VAL D 182           
+SHEET    5   E 6 LYS D 198  LEU D 202  1  O  LEU D 202   N  LEU D  37           
+SHEET    6   E 6 PHE D 207  GLU D 211 -1  O  GLY D 210   N  THR D 199           
+SHEET    1   F 2 MET D 229  TYR D 236  0                                        
+SHEET    2   F 2 SER D 239  PRO D 246 -1  O  SER D 239   N  TYR D 236           
+CISPEP   1 ASP A   51    PRO A   52          0        -0.21                     
+CRYST1   97.846  142.465  150.268  90.00  90.00  90.00 P 21 21 21    8          
+ORIGX1      1.000000  0.000000  0.000000        0.00000                         
+ORIGX2      0.000000  1.000000  0.000000        0.00000                         
+ORIGX3      0.000000  0.000000  1.000000        0.00000                         
+SCALE1      0.010220  0.000000  0.000000        0.00000                         
+SCALE2      0.000000  0.007019  0.000000        0.00000                         
+SCALE3      0.000000  0.000000  0.006655        0.00000                         
+ATOM      1  N   TYR A   6     -23.166  -7.488  19.780  1.00 84.99           N  
+ATOM      2  CA  TYR A   6     -22.296  -7.260  20.972  1.00 85.30           C  
+ATOM      3  C   TYR A   6     -22.638  -8.213  22.115  1.00 84.73           C  
+ATOM      4  O   TYR A   6     -21.792  -8.985  22.564  1.00 84.22           O  
+ATOM      5  CB  TYR A   6     -22.429  -5.813  21.465  1.00 86.56           C  
+ATOM      6  CG  TYR A   6     -21.671  -5.527  22.749  1.00 87.86           C  
+ATOM      7  CD1 TYR A   6     -22.221  -4.708  23.737  1.00 88.50           C  
+ATOM      8  CD2 TYR A   6     -20.407  -6.076  22.979  1.00 88.78           C  
+ATOM      9  CE1 TYR A   6     -21.533  -4.444  24.924  1.00 89.16           C  
+ATOM     10  CE2 TYR A   6     -19.709  -5.817  24.161  1.00 89.23           C  
+ATOM     11  CZ  TYR A   6     -20.278  -5.002  25.129  1.00 89.37           C  
+ATOM     12  OH  TYR A   6     -19.598  -4.750  26.300  1.00 88.74           O  
+ATOM     13  N   PRO A   7     -23.888  -8.171  22.605  1.00 84.54           N  
+ATOM     14  CA  PRO A   7     -24.268  -9.065  23.704  1.00 83.86           C  
+ATOM     15  C   PRO A   7     -24.041 -10.527  23.336  1.00 82.66           C  
+ATOM     16  O   PRO A   7     -23.681 -11.346  24.181  1.00 82.89           O  
+ATOM     17  CB  PRO A   7     -25.743  -8.736  23.916  1.00 84.57           C  
+ATOM     18  CG  PRO A   7     -26.199  -8.374  22.530  1.00 84.68           C  
+ATOM     19  CD  PRO A   7     -25.074  -7.489  22.054  1.00 84.49           C  
+ATOM     20  N   LYS A   8     -24.251 -10.841  22.062  1.00 80.85           N  
+ATOM     21  CA  LYS A   8     -24.068 -12.198  21.569  1.00 79.35           C  
+ATOM     22  C   LYS A   8     -22.614 -12.629  21.731  1.00 77.29           C  
+ATOM     23  O   LYS A   8     -22.332 -13.803  21.964  1.00 77.76           O  
+ATOM     24  CB  LYS A   8     -24.480 -12.280  20.097  1.00 80.63           C  
+ATOM     25  CG  LYS A   8     -24.407 -13.674  19.500  1.00 82.54           C  
+ATOM     26  CD  LYS A   8     -24.903 -13.685  18.061  1.00 84.24           C  
+ATOM     27  CE  LYS A   8     -24.880 -15.092  17.474  1.00 85.26           C  
+ATOM     28  NZ  LYS A   8     -25.389 -15.121  16.070  1.00 86.27           N  
+ATOM     29  N   ILE A   9     -21.692 -11.678  21.609  1.00 74.96           N  
+ATOM     30  CA  ILE A   9     -20.269 -11.977  21.751  1.00 72.61           C  
+ATOM     31  C   ILE A   9     -19.894 -12.143  23.221  1.00 70.90           C  
+ATOM     32  O   ILE A   9     -19.156 -13.059  23.577  1.00 69.85           O  
+ATOM     33  CB  ILE A   9     -19.387 -10.864  21.128  1.00 72.53           C  
+ATOM     34  CG1 ILE A   9     -19.612 -10.806  19.614  1.00 71.79           C  
+ATOM     35  CG2 ILE A   9     -17.917 -11.128  21.434  1.00 71.18           C  
+ATOM     36  CD1 ILE A   9     -18.834  -9.710  18.916  0.00 71.98           C  
+ATOM     37  N   LEU A  10     -20.405 -11.258  24.073  1.00 69.96           N  
+ATOM     38  CA  LEU A  10     -20.114 -11.330  25.499  1.00 70.21           C  
+ATOM     39  C   LEU A  10     -20.664 -12.614  26.097  1.00 71.29           C  
+ATOM     40  O   LEU A  10     -19.992 -13.284  26.883  1.00 71.58           O  
+ATOM     41  CB  LEU A  10     -20.717 -10.135  26.238  1.00 69.18           C  
+ATOM     42  CG  LEU A  10     -20.137  -8.750  25.951  1.00 69.62           C  
+ATOM     43  CD1 LEU A  10     -20.744  -7.756  26.929  1.00 68.82           C  
+ATOM     44  CD2 LEU A  10     -18.617  -8.769  26.091  1.00 68.57           C  
+ATOM     45  N   PHE A  11     -21.894 -12.952  25.724  1.00 71.90           N  
+ATOM     46  CA  PHE A  11     -22.532 -14.157  26.227  1.00 72.34           C  
+ATOM     47  C   PHE A  11     -21.742 -15.383  25.790  1.00 71.61           C  
+ATOM     48  O   PHE A  11     -21.643 -16.364  26.528  1.00 71.42           O  
+ATOM     49  CB  PHE A  11     -23.975 -14.237  25.721  1.00 73.81           C  
+ATOM     50  CG  PHE A  11     -24.717 -15.454  26.192  1.00 75.45           C  
+ATOM     51  CD1 PHE A  11     -24.703 -16.628  25.443  1.00 75.74           C  
+ATOM     52  CD2 PHE A  11     -25.417 -15.435  27.395  1.00 76.66           C  
+ATOM     53  CE1 PHE A  11     -25.377 -17.767  25.886  1.00 76.30           C  
+ATOM     54  CE2 PHE A  11     -26.094 -16.567  27.847  1.00 76.97           C  
+ATOM     55  CZ  PHE A  11     -26.073 -17.735  27.090  1.00 76.59           C  
+ATOM     56  N   GLY A  12     -21.170 -15.315  24.592  1.00 70.91           N  
+ATOM     57  CA  GLY A  12     -20.385 -16.424  24.081  1.00 69.84           C  
+ATOM     58  C   GLY A  12     -19.074 -16.597  24.829  1.00 69.44           C  
+ATOM     59  O   GLY A  12     -18.683 -17.716  25.161  1.00 68.67           O  
+ATOM     60  N   LEU A  13     -18.390 -15.488  25.095  1.00 68.78           N  
+ATOM     61  CA  LEU A  13     -17.123 -15.535  25.812  1.00 68.09           C  
+ATOM     62  C   LEU A  13     -17.334 -15.946  27.260  1.00 68.07           C  
+ATOM     63  O   LEU A  13     -16.511 -16.657  27.835  1.00 67.59           O  
+ATOM     64  CB  LEU A  13     -16.430 -14.174  25.765  1.00 66.92           C  
+ATOM     65  CG  LEU A  13     -15.925 -13.725  24.395  1.00 66.91           C  
+ATOM     66  CD1 LEU A  13     -15.236 -12.372  24.532  1.00 66.32           C  
+ATOM     67  CD2 LEU A  13     -14.970 -14.768  23.827  1.00 65.13           C  
+ATOM     68  N   THR A  14     -18.436 -15.490  27.848  1.00 69.17           N  
+ATOM     69  CA  THR A  14     -18.750 -15.823  29.231  1.00 70.47           C  
+ATOM     70  C   THR A  14     -19.257 -17.265  29.295  1.00 70.97           C  
+ATOM     71  O   THR A  14     -19.623 -17.764  30.356  1.00 71.52           O  
+ATOM     72  CB  THR A  14     -19.812 -14.860  29.812  1.00 70.50           C  
+ATOM     73  OG1 THR A  14     -19.996 -15.130  31.208  1.00 70.75           O  
+ATOM     74  CG2 THR A  14     -21.135 -15.028  29.091  1.00 72.18           C  
+ATOM     75  N   LEU A  15     -19.269 -17.925  28.140  1.00 71.58           N  
+ATOM     76  CA  LEU A  15     -19.693 -19.316  28.039  1.00 71.65           C  
+ATOM     77  C   LEU A  15     -18.433 -20.175  28.106  1.00 71.33           C  
+ATOM     78  O   LEU A  15     -18.364 -21.126  28.882  1.00 71.94           O  
+ATOM     79  CB  LEU A  15     -20.406 -19.567  26.710  1.00 73.23           C  
+ATOM     80  CG  LEU A  15     -21.022 -20.955  26.516  1.00 74.67           C  
+ATOM     81  CD1 LEU A  15     -22.367 -21.009  27.222  1.00 74.66           C  
+ATOM     82  CD2 LEU A  15     -21.195 -21.248  25.032  1.00 74.78           C  
+ATOM     83  N   LEU A  16     -17.440 -19.833  27.284  1.00 70.85           N  
+ATOM     84  CA  LEU A  16     -16.169 -20.560  27.262  1.00 69.85           C  
+ATOM     85  C   LEU A  16     -15.546 -20.513  28.648  1.00 67.90           C  
+ATOM     86  O   LEU A  16     -14.964 -21.489  29.114  1.00 67.15           O  
+ATOM     87  CB  LEU A  16     -15.186 -19.926  26.273  1.00 70.69           C  
+ATOM     88  CG  LEU A  16     -15.425 -20.030  24.769  1.00 72.54           C  
+ATOM     89  CD1 LEU A  16     -14.239 -19.402  24.055  1.00 73.03           C  
+ATOM     90  CD2 LEU A  16     -15.576 -21.485  24.347  1.00 73.34           C  
+ATOM     91  N   LEU A  17     -15.663 -19.356  29.287  1.00 65.98           N  
+ATOM     92  CA  LEU A  17     -15.131 -19.147  30.622  1.00 65.42           C  
+ATOM     93  C   LEU A  17     -15.616 -20.281  31.530  1.00 65.03           C  
+ATOM     94  O   LEU A  17     -14.826 -20.908  32.234  1.00 64.78           O  
+ATOM     95  CB  LEU A  17     -15.613 -17.792  31.151  1.00 65.43           C  
+ATOM     96  CG  LEU A  17     -15.053 -17.175  32.438  1.00 65.86           C  
+ATOM     97  CD1 LEU A  17     -15.312 -18.085  33.629  1.00 65.64           C  
+ATOM     98  CD2 LEU A  17     -13.577 -16.918  32.266  1.00 66.40           C  
+ATOM     99  N   VAL A  18     -16.919 -20.548  31.501  1.00 64.68           N  
+ATOM    100  CA  VAL A  18     -17.503 -21.602  32.325  1.00 63.65           C  
+ATOM    101  C   VAL A  18     -17.130 -22.992  31.819  1.00 62.88           C  
+ATOM    102  O   VAL A  18     -16.723 -23.855  32.596  1.00 62.45           O  
+ATOM    103  CB  VAL A  18     -19.039 -21.480  32.376  1.00 64.39           C  
+ATOM    104  CG1 VAL A  18     -19.636 -22.682  33.095  1.00 65.80           C  
+ATOM    105  CG2 VAL A  18     -19.429 -20.192  33.090  1.00 63.76           C  
+ATOM    106  N   ILE A  19     -17.267 -23.204  30.515  1.00 61.85           N  
+ATOM    107  CA  ILE A  19     -16.934 -24.489  29.915  1.00 61.69           C  
+ATOM    108  C   ILE A  19     -15.488 -24.900  30.205  1.00 61.60           C  
+ATOM    109  O   ILE A  19     -15.220 -26.061  30.523  1.00 61.80           O  
+ATOM    110  CB  ILE A  19     -17.157 -24.457  28.386  1.00 63.16           C  
+ATOM    111  CG1 ILE A  19     -18.646 -24.250  28.082  1.00 63.42           C  
+ATOM    112  CG2 ILE A  19     -16.656 -25.744  27.755  1.00 62.94           C  
+ATOM    113  CD1 ILE A  19     -18.966 -24.152  26.605  0.00 63.52           C  
+ATOM    114  N   THR A  20     -14.556 -23.954  30.102  1.00 60.30           N  
+ATOM    115  CA  THR A  20     -13.150 -24.253  30.360  1.00 59.01           C  
+ATOM    116  C   THR A  20     -12.890 -24.418  31.856  1.00 57.61           C  
+ATOM    117  O   THR A  20     -11.990 -25.150  32.256  1.00 56.20           O  
+ATOM    118  CB  THR A  20     -12.217 -23.147  29.821  1.00 59.79           C  
+ATOM    119  OG1 THR A  20     -12.427 -21.941  30.563  1.00 62.81           O  
+ATOM    120  CG2 THR A  20     -12.490 -22.883  28.349  1.00 60.57           C  
+ATOM    121  N   ALA A  21     -13.672 -23.729  32.679  1.00 57.11           N  
+ATOM    122  CA  ALA A  21     -13.520 -23.827  34.125  1.00 58.20           C  
+ATOM    123  C   ALA A  21     -13.938 -25.233  34.551  1.00 59.70           C  
+ATOM    124  O   ALA A  21     -13.218 -25.917  35.286  1.00 58.46           O  
+ATOM    125  CB  ALA A  21     -14.392 -22.787  34.821  1.00 56.75           C  
+ATOM    126  N   VAL A  22     -15.107 -25.656  34.080  1.00 60.17           N  
+ATOM    127  CA  VAL A  22     -15.619 -26.979  34.401  1.00 60.85           C  
+ATOM    128  C   VAL A  22     -14.646 -28.031  33.888  1.00 61.21           C  
+ATOM    129  O   VAL A  22     -14.253 -28.935  34.628  1.00 60.34           O  
+ATOM    130  CB  VAL A  22     -17.016 -27.211  33.769  1.00 61.51           C  
+ATOM    131  CG1 VAL A  22     -17.400 -28.685  33.862  1.00 61.36           C  
+ATOM    132  CG2 VAL A  22     -18.054 -26.353  34.488  1.00 60.83           C  
+ATOM    133  N   ILE A  23     -14.251 -27.903  32.625  1.00 60.84           N  
+ATOM    134  CA  ILE A  23     -13.318 -28.850  32.028  1.00 61.50           C  
+ATOM    135  C   ILE A  23     -12.031 -28.934  32.850  1.00 62.28           C  
+ATOM    136  O   ILE A  23     -11.394 -29.987  32.917  1.00 63.04           O  
+ATOM    137  CB  ILE A  23     -12.983 -28.457  30.569  1.00 61.55           C  
+ATOM    138  CG1 ILE A  23     -14.226 -28.627  29.690  1.00 61.61           C  
+ATOM    139  CG2 ILE A  23     -11.850 -29.316  30.038  1.00 61.25           C  
+ATOM    140  CD1 ILE A  23     -14.021 -28.214  28.247  0.00 61.77           C  
+ATOM    141  N   SER A  24     -11.656 -27.827  33.483  1.00 62.18           N  
+ATOM    142  CA  SER A  24     -10.449 -27.798  34.303  1.00 62.23           C  
+ATOM    143  C   SER A  24     -10.523 -28.875  35.380  1.00 62.31           C  
+ATOM    144  O   SER A  24      -9.526 -29.532  35.689  1.00 61.96           O  
+ATOM    145  CB  SER A  24     -10.283 -26.427  34.967  1.00 61.70           C  
+ATOM    146  OG  SER A  24     -10.039 -25.417  34.006  1.00 61.07           O  
+ATOM    147  N   LEU A  25     -11.713 -29.047  35.949  1.00 61.93           N  
+ATOM    148  CA  LEU A  25     -11.932 -30.044  36.991  1.00 61.42           C  
+ATOM    149  C   LEU A  25     -11.560 -31.440  36.506  1.00 61.05           C  
+ATOM    150  O   LEU A  25     -11.377 -32.351  37.310  1.00 61.25           O  
+ATOM    151  CB  LEU A  25     -13.395 -30.033  37.425  1.00 60.18           C  
+ATOM    152  CG  LEU A  25     -13.924 -28.684  37.903  1.00 59.60           C  
+ATOM    153  CD1 LEU A  25     -15.430 -28.774  38.125  1.00 58.70           C  
+ATOM    154  CD2 LEU A  25     -13.198 -28.276  39.176  1.00 57.55           C  
+ATOM    155  N   GLY A  26     -11.446 -31.596  35.190  1.00 60.95           N  
+ATOM    156  CA  GLY A  26     -11.101 -32.883  34.618  1.00 61.97           C  
+ATOM    157  C   GLY A  26      -9.617 -33.093  34.372  1.00 63.47           C  
+ATOM    158  O   GLY A  26      -9.232 -33.900  33.527  1.00 63.50           O  
+ATOM    159  N   ILE A  27      -8.779 -32.374  35.108  1.00 64.79           N  
+ATOM    160  CA  ILE A  27      -7.336 -32.502  34.952  1.00 66.83           C  
+ATOM    161  C   ILE A  27      -6.645 -32.631  36.307  1.00 67.90           C  
+ATOM    162  O   ILE A  27      -7.024 -31.970  37.276  1.00 67.68           O  
+ATOM    163  CB  ILE A  27      -6.743 -31.280  34.214  1.00 67.74           C  
+ATOM    164  CG1 ILE A  27      -7.369 -31.151  32.824  1.00 68.04           C  
+ATOM    165  CG2 ILE A  27      -5.230 -31.424  34.103  1.00 68.20           C  
+ATOM    166  CD1 ILE A  27      -6.891 -29.945  32.041  0.00 67.87           C  
+ATOM    167  N   GLY A  28      -5.633 -33.489  36.371  1.00 69.67           N  
+ATOM    168  CA  GLY A  28      -4.899 -33.673  37.610  1.00 72.11           C  
+ATOM    169  C   GLY A  28      -5.289 -34.893  38.424  1.00 73.83           C  
+ATOM    170  O   GLY A  28      -6.224 -35.620  38.082  1.00 74.68           O  
+ATOM    171  N   ARG A  29      -4.555 -35.114  39.509  1.00 74.51           N  
+ATOM    172  CA  ARG A  29      -4.799 -36.235  40.406  1.00 74.74           C  
+ATOM    173  C   ARG A  29      -6.207 -36.102  40.982  1.00 74.48           C  
+ATOM    174  O   ARG A  29      -6.681 -34.990  41.216  1.00 73.39           O  
+ATOM    175  CB  ARG A  29      -3.774 -36.215  41.543  1.00 76.09           C  
+ATOM    176  CG  ARG A  29      -3.750 -37.464  42.405  1.00 79.60           C  
+ATOM    177  CD  ARG A  29      -2.873 -38.555  41.790  1.00 82.72           C  
+ATOM    178  NE  ARG A  29      -2.880 -39.783  42.585  1.00 83.86           N  
+ATOM    179  CZ  ARG A  29      -2.585 -39.842  43.881  1.00 83.87           C  
+ATOM    180  NH1 ARG A  29      -2.619 -41.005  44.519  1.00 83.46           N  
+ATOM    181  NH2 ARG A  29      -2.260 -38.737  44.543  1.00 83.41           N  
+ATOM    182  N   TYR A  30      -6.873 -37.232  41.204  1.00 75.02           N  
+ATOM    183  CA  TYR A  30      -8.224 -37.233  41.761  1.00 75.44           C  
+ATOM    184  C   TYR A  30      -9.173 -36.322  40.986  1.00 75.02           C  
+ATOM    185  O   TYR A  30      -9.965 -35.599  41.584  1.00 74.05           O  
+ATOM    186  CB  TYR A  30      -8.186 -36.781  43.225  1.00 77.12           C  
+ATOM    187  CG  TYR A  30      -7.430 -37.703  44.164  1.00 79.53           C  
+ATOM    188  CD1 TYR A  30      -6.957 -37.236  45.390  1.00 80.60           C  
+ATOM    189  CD2 TYR A  30      -7.206 -39.041  43.842  1.00 80.56           C  
+ATOM    190  CE1 TYR A  30      -6.280 -38.077  46.271  1.00 81.57           C  
+ATOM    191  CE2 TYR A  30      -6.531 -39.890  44.717  1.00 81.06           C  
+ATOM    192  CZ  TYR A  30      -6.070 -39.402  45.929  1.00 81.12           C  
+ATOM    193  OH  TYR A  30      -5.401 -40.234  46.801  1.00 81.01           O  
+ATOM    194  N   SER A  31      -9.100 -36.362  39.660  1.00 75.86           N  
+ATOM    195  CA  SER A  31      -9.958 -35.522  38.828  1.00 78.95           C  
+ATOM    196  C   SER A  31     -11.230 -36.236  38.360  1.00 80.81           C  
+ATOM    197  O   SER A  31     -11.680 -37.199  38.981  1.00 81.74           O  
+ATOM    198  CB  SER A  31      -9.170 -35.013  37.611  1.00 78.42           C  
+ATOM    199  OG  SER A  31      -8.680 -36.082  36.815  1.00 78.11           O  
+ATOM    200  N   LEU A  32     -11.814 -35.736  37.273  1.00 82.52           N  
+ATOM    201  CA  LEU A  32     -13.021 -36.309  36.681  1.00 83.55           C  
+ATOM    202  C   LEU A  32     -12.652 -36.726  35.263  1.00 86.26           C  
+ATOM    203  O   LEU A  32     -11.518 -36.503  34.835  1.00 86.37           O  
+ATOM    204  CB  LEU A  32     -14.145 -35.271  36.650  1.00 81.58           C  
+ATOM    205  CG  LEU A  32     -14.816 -34.895  37.978  1.00 80.76           C  
+ATOM    206  CD1 LEU A  32     -13.777 -34.488  39.006  1.00 80.72           C  
+ATOM    207  CD2 LEU A  32     -15.802 -33.762  37.740  1.00 79.54           C  
+ATOM    208  N   SER A  33     -13.588 -37.324  34.529  1.00 89.58           N  
+ATOM    209  CA  SER A  33     -13.289 -37.761  33.163  1.00 92.43           C  
+ATOM    210  C   SER A  33     -14.465 -37.697  32.192  1.00 94.01           C  
+ATOM    211  O   SER A  33     -14.303 -37.316  31.032  1.00 93.58           O  
+ATOM    212  CB  SER A  33     -12.731 -39.189  33.182  1.00 92.84           C  
+ATOM    213  OG  SER A  33     -12.422 -39.636  31.872  1.00 93.42           O  
+ATOM    214  N   VAL A  34     -15.643 -38.083  32.664  1.00 96.85           N  
+ATOM    215  CA  VAL A  34     -16.835 -38.073  31.825  1.00 99.00           C  
+ATOM    216  C   VAL A  34     -18.004 -37.290  32.430  1.00100.50           C  
+ATOM    217  O   VAL A  34     -18.890 -36.835  31.703  1.00100.76           O  
+ATOM    218  CB  VAL A  34     -17.304 -39.516  31.514  1.00 98.72           C  
+ATOM    219  CG1 VAL A  34     -17.708 -40.223  32.798  1.00 98.58           C  
+ATOM    220  CG2 VAL A  34     -18.458 -39.489  30.525  1.00 98.88           C  
+ATOM    221  N   PRO A  35     -18.027 -37.122  33.767  1.00101.53           N  
+ATOM    222  CA  PRO A  35     -19.136 -36.374  34.365  1.00102.25           C  
+ATOM    223  C   PRO A  35     -19.360 -35.015  33.703  1.00103.44           C  
+ATOM    224  O   PRO A  35     -18.506 -34.128  33.771  1.00103.21           O  
+ATOM    225  CB  PRO A  35     -18.712 -36.250  35.825  1.00102.17           C  
+ATOM    226  CG  PRO A  35     -17.980 -37.531  36.058  1.00101.40           C  
+ATOM    227  CD  PRO A  35     -17.124 -37.633  34.816  1.00101.62           C  
+ATOM    228  N   GLN A  36     -20.514 -34.871  33.056  1.00104.65           N  
+ATOM    229  CA  GLN A  36     -20.878 -33.630  32.380  1.00105.18           C  
+ATOM    230  C   GLN A  36     -21.685 -32.777  33.357  1.00105.21           C  
+ATOM    231  O   GLN A  36     -22.893 -32.973  33.520  1.00105.30           O  
+ATOM    232  CB  GLN A  36     -21.713 -33.940  31.132  1.00105.09           C  
+ATOM    233  CG  GLN A  36     -21.872 -32.777  30.155  1.00105.97           C  
+ATOM    234  CD  GLN A  36     -22.688 -31.624  30.715  1.00106.33           C  
+ATOM    235  OE1 GLN A  36     -23.847 -31.794  31.095  1.00106.54           O  
+ATOM    236  NE2 GLN A  36     -22.084 -30.440  30.761  1.00106.02           N  
+ATOM    237  N   ILE A  37     -21.007 -31.837  34.010  1.00104.63           N  
+ATOM    238  CA  ILE A  37     -21.647 -30.957  34.982  1.00103.65           C  
+ATOM    239  C   ILE A  37     -22.244 -29.724  34.311  1.00103.23           C  
+ATOM    240  O   ILE A  37     -22.695 -29.783  33.167  1.00102.51           O  
+ATOM    241  CB  ILE A  37     -20.639 -30.495  36.060  1.00103.33           C  
+ATOM    242  CG1 ILE A  37     -20.025 -31.713  36.756  1.00102.74           C  
+ATOM    243  CG2 ILE A  37     -21.336 -29.605  37.077  1.00102.57           C  
+ATOM    244  CD1 ILE A  37     -18.977 -31.366  37.795  0.00101.93           C  
+ATOM    245  N   ASP A  51     -15.206 -36.708  45.993  1.00 89.41           N  
+ATOM    246  CA  ASP A  51     -16.369 -37.575  45.906  1.00 88.88           C  
+ATOM    247  C   ASP A  51     -16.020 -38.959  46.452  1.00 88.36           C  
+ATOM    248  O   ASP A  51     -16.038 -39.948  45.716  1.00 88.05           O  
+ATOM    249  CB  ASP A  51     -16.822 -37.685  44.449  1.00 89.41           C  
+ATOM    250  CG  ASP A  51     -18.210 -38.264  44.314  1.00 88.97           C  
+ATOM    251  OD1 ASP A  51     -18.430 -39.388  44.805  1.00 89.21           O  
+ATOM    252  OD2 ASP A  51     -19.079 -37.594  43.716  1.00 89.38           O  
+ATOM    253  N   PRO A  52     -15.676 -39.040  47.752  1.00 87.41           N  
+ATOM    254  CA  PRO A  52     -15.605 -37.908  48.684  1.00 86.06           C  
+ATOM    255  C   PRO A  52     -14.274 -37.165  48.549  1.00 84.59           C  
+ATOM    256  O   PRO A  52     -14.174 -35.977  48.865  1.00 84.40           O  
+ATOM    257  CB  PRO A  52     -15.757 -38.582  50.040  1.00 85.89           C  
+ATOM    258  CG  PRO A  52     -14.994 -39.849  49.839  1.00 86.68           C  
+ATOM    259  CD  PRO A  52     -15.467 -40.313  48.469  1.00 87.02           C  
+ATOM    260  N   VAL A  53     -13.257 -37.879  48.073  1.00 82.29           N  
+ATOM    261  CA  VAL A  53     -11.931 -37.306  47.881  1.00 80.10           C  
+ATOM    262  C   VAL A  53     -11.964 -36.237  46.786  1.00 80.02           C  
+ATOM    263  O   VAL A  53     -11.461 -35.128  46.972  1.00 79.50           O  
+ATOM    264  CB  VAL A  53     -10.906 -38.406  47.504  1.00 78.84           C  
+ATOM    265  CG1 VAL A  53     -11.353 -39.137  46.253  1.00 77.19           C  
+ATOM    266  CG2 VAL A  53      -9.537 -37.794  47.297  1.00 78.39           C  
+ATOM    267  N   GLN A  54     -12.563 -36.580  45.649  1.00 79.14           N  
+ATOM    268  CA  GLN A  54     -12.683 -35.667  44.518  1.00 78.62           C  
+ATOM    269  C   GLN A  54     -13.308 -34.347  44.952  1.00 78.30           C  
+ATOM    270  O   GLN A  54     -12.826 -33.269  44.604  1.00 78.34           O  
+ATOM    271  CB  GLN A  54     -13.556 -36.292  43.430  1.00 78.10           C  
+ATOM    272  CG  GLN A  54     -12.965 -37.520  42.763  1.00 78.01           C  
+ATOM    273  CD  GLN A  54     -13.940 -38.178  41.805  1.00 77.91           C  
+ATOM    274  OE1 GLN A  54     -13.565 -39.042  41.014  1.00 78.55           O  
+ATOM    275  NE2 GLN A  54     -15.204 -37.776  41.878  1.00 77.47           N  
+ATOM    276  N   GLN A  55     -14.388 -34.450  45.715  1.00 77.80           N  
+ATOM    277  CA  GLN A  55     -15.112 -33.290  46.200  1.00 77.73           C  
+ATOM    278  C   GLN A  55     -14.224 -32.365  47.023  1.00 77.19           C  
+ATOM    279  O   GLN A  55     -14.375 -31.146  46.967  1.00 77.64           O  
+ATOM    280  CB  GLN A  55     -16.319 -33.749  47.023  1.00 78.99           C  
+ATOM    281  CG  GLN A  55     -17.288 -32.642  47.404  1.00 80.74           C  
+ATOM    282  CD  GLN A  55     -18.593 -33.183  47.964  1.00 82.49           C  
+ATOM    283  OE1 GLN A  55     -19.479 -32.420  48.352  1.00 83.21           O  
+ATOM    284  NE2 GLN A  55     -18.718 -34.507  48.003  1.00 82.37           N  
+ATOM    285  N   GLN A  56     -13.297 -32.939  47.785  1.00 76.29           N  
+ATOM    286  CA  GLN A  56     -12.399 -32.130  48.604  1.00 74.95           C  
+ATOM    287  C   GLN A  56     -11.260 -31.547  47.766  1.00 72.92           C  
+ATOM    288  O   GLN A  56     -10.754 -30.465  48.062  1.00 72.68           O  
+ATOM    289  CB  GLN A  56     -11.831 -32.960  49.759  1.00 75.85           C  
+ATOM    290  CG  GLN A  56     -12.870 -33.370  50.790  1.00 78.00           C  
+ATOM    291  CD  GLN A  56     -12.254 -34.061  51.993  1.00 80.23           C  
+ATOM    292  OE1 GLN A  56     -11.439 -33.475  52.708  1.00 81.32           O  
+ATOM    293  NE2 GLN A  56     -12.641 -35.315  52.223  1.00 80.45           N  
+ATOM    294  N   VAL A  57     -10.861 -32.271  46.725  1.00 70.26           N  
+ATOM    295  CA  VAL A  57      -9.801 -31.811  45.839  1.00 68.64           C  
+ATOM    296  C   VAL A  57     -10.322 -30.633  45.019  1.00 67.50           C  
+ATOM    297  O   VAL A  57      -9.573 -29.717  44.681  1.00 67.10           O  
+ATOM    298  CB  VAL A  57      -9.338 -32.943  44.889  1.00 68.84           C  
+ATOM    299  CG1 VAL A  57      -8.494 -32.377  43.757  1.00 68.37           C  
+ATOM    300  CG2 VAL A  57      -8.525 -33.960  45.671  1.00 69.44           C  
+ATOM    301  N   ILE A  58     -11.614 -30.661  44.714  1.00 65.28           N  
+ATOM    302  CA  ILE A  58     -12.245 -29.596  43.953  1.00 63.62           C  
+ATOM    303  C   ILE A  58     -12.407 -28.333  44.798  1.00 63.76           C  
+ATOM    304  O   ILE A  58     -11.972 -27.257  44.398  1.00 63.90           O  
+ATOM    305  CB  ILE A  58     -13.636 -30.038  43.423  1.00 63.02           C  
+ATOM    306  CG1 ILE A  58     -13.461 -31.003  42.248  1.00 61.71           C  
+ATOM    307  CG2 ILE A  58     -14.462 -28.823  43.010  1.00 62.13           C  
+ATOM    308  CD1 ILE A  58     -14.765 -31.537  41.689  0.00 62.22           C  
+ATOM    309  N   PHE A  59     -13.014 -28.469  45.972  1.00 63.57           N  
+ATOM    310  CA  PHE A  59     -13.253 -27.322  46.846  1.00 65.08           C  
+ATOM    311  C   PHE A  59     -12.027 -26.698  47.513  1.00 64.74           C  
+ATOM    312  O   PHE A  59     -11.967 -25.477  47.679  1.00 63.94           O  
+ATOM    313  CB  PHE A  59     -14.269 -27.693  47.937  1.00 67.02           C  
+ATOM    314  CG  PHE A  59     -15.663 -27.963  47.420  1.00 70.27           C  
+ATOM    315  CD1 PHE A  59     -16.642 -28.477  48.270  1.00 71.63           C  
+ATOM    316  CD2 PHE A  59     -15.999 -27.711  46.091  1.00 70.80           C  
+ATOM    317  CE1 PHE A  59     -17.934 -28.739  47.802  1.00 72.55           C  
+ATOM    318  CE2 PHE A  59     -17.287 -27.969  45.615  1.00 71.39           C  
+ATOM    319  CZ  PHE A  59     -18.255 -28.484  46.471  1.00 72.08           C  
+ATOM    320  N   GLN A  60     -11.053 -27.519  47.891  1.00 64.51           N  
+ATOM    321  CA  GLN A  60      -9.872 -27.005  48.576  1.00 64.06           C  
+ATOM    322  C   GLN A  60      -8.624 -26.810  47.709  1.00 62.39           C  
+ATOM    323  O   GLN A  60      -7.747 -26.017  48.056  1.00 61.52           O  
+ATOM    324  CB  GLN A  60      -9.535 -27.909  49.771  1.00 65.73           C  
+ATOM    325  CG  GLN A  60     -10.725 -28.185  50.691  1.00 70.15           C  
+ATOM    326  CD  GLN A  60     -10.340 -28.900  51.985  1.00 73.13           C  
+ATOM    327  OE1 GLN A  60     -11.198 -29.454  52.678  1.00 73.10           O  
+ATOM    328  NE2 GLN A  60      -9.051 -28.878  52.322  1.00 73.62           N  
+ATOM    329  N   VAL A  61      -8.541 -27.511  46.583  1.00 60.58           N  
+ATOM    330  CA  VAL A  61      -7.371 -27.382  45.723  1.00 59.87           C  
+ATOM    331  C   VAL A  61      -7.646 -26.772  44.346  1.00 59.53           C  
+ATOM    332  O   VAL A  61      -7.299 -25.622  44.088  1.00 58.65           O  
+ATOM    333  CB  VAL A  61      -6.676 -28.757  45.522  1.00 60.48           C  
+ATOM    334  CG1 VAL A  61      -5.485 -28.616  44.584  1.00 59.25           C  
+ATOM    335  CG2 VAL A  61      -6.224 -29.314  46.866  1.00 59.72           C  
+ATOM    336  N   ARG A  62      -8.271 -27.559  43.477  1.00 59.37           N  
+ATOM    337  CA  ARG A  62      -8.584 -27.164  42.107  1.00 59.05           C  
+ATOM    338  C   ARG A  62      -9.353 -25.853  41.919  1.00 59.53           C  
+ATOM    339  O   ARG A  62      -8.875 -24.939  41.246  1.00 61.00           O  
+ATOM    340  CB  ARG A  62      -9.348 -28.298  41.430  1.00 58.92           C  
+ATOM    341  CG  ARG A  62      -9.194 -28.338  39.929  1.00 61.63           C  
+ATOM    342  CD  ARG A  62      -8.822 -29.740  39.498  1.00 62.88           C  
+ATOM    343  NE  ARG A  62      -7.576 -30.176  40.124  1.00 63.84           N  
+ATOM    344  CZ  ARG A  62      -7.225 -31.449  40.285  1.00 64.11           C  
+ATOM    345  NH1 ARG A  62      -6.069 -31.752  40.862  1.00 62.43           N  
+ATOM    346  NH2 ARG A  62      -8.037 -32.419  39.884  1.00 63.45           N  
+ATOM    347  N   LEU A  63     -10.545 -25.763  42.499  1.00 58.62           N  
+ATOM    348  CA  LEU A  63     -11.362 -24.562  42.363  1.00 57.09           C  
+ATOM    349  C   LEU A  63     -10.578 -23.292  42.686  1.00 56.48           C  
+ATOM    350  O   LEU A  63     -10.609 -22.329  41.921  1.00 56.73           O  
+ATOM    351  CB  LEU A  63     -12.603 -24.658  43.256  1.00 55.89           C  
+ATOM    352  CG  LEU A  63     -13.650 -23.545  43.150  1.00 57.37           C  
+ATOM    353  CD1 LEU A  63     -14.135 -23.425  41.710  1.00 55.57           C  
+ATOM    354  CD2 LEU A  63     -14.819 -23.849  44.087  1.00 55.80           C  
+ATOM    355  N   PRO A  64      -9.863 -23.273  43.825  1.00 55.77           N  
+ATOM    356  CA  PRO A  64      -9.076 -22.102  44.225  1.00 54.20           C  
+ATOM    357  C   PRO A  64      -8.091 -21.638  43.147  1.00 53.77           C  
+ATOM    358  O   PRO A  64      -7.939 -20.435  42.918  1.00 51.30           O  
+ATOM    359  CB  PRO A  64      -8.360 -22.583  45.486  1.00 54.43           C  
+ATOM    360  CG  PRO A  64      -9.320 -23.558  46.058  1.00 54.60           C  
+ATOM    361  CD  PRO A  64      -9.775 -24.328  44.850  1.00 55.78           C  
+ATOM    362  N   ARG A  65      -7.420 -22.588  42.493  1.00 52.20           N  
+ATOM    363  CA  ARG A  65      -6.464 -22.233  41.452  1.00 53.06           C  
+ATOM    364  C   ARG A  65      -7.190 -21.749  40.198  1.00 52.88           C  
+ATOM    365  O   ARG A  65      -6.772 -20.776  39.573  1.00 54.38           O  
+ATOM    366  CB  ARG A  65      -5.555 -23.416  41.082  1.00 51.06           C  
+ATOM    367  CG  ARG A  65      -4.325 -22.961  40.292  1.00 52.84           C  
+ATOM    368  CD  ARG A  65      -3.703 -24.021  39.384  1.00 50.49           C  
+ATOM    369  NE  ARG A  65      -2.682 -24.818  40.052  1.00 50.94           N  
+ATOM    370  CZ  ARG A  65      -1.557 -25.232  39.474  1.00 51.78           C  
+ATOM    371  NH1 ARG A  65      -1.292 -24.920  38.210  1.00 50.17           N  
+ATOM    372  NH2 ARG A  65      -0.699 -25.974  40.159  1.00 52.35           N  
+ATOM    373  N   ILE A  66      -8.273 -22.431  39.836  1.00 53.21           N  
+ATOM    374  CA  ILE A  66      -9.057 -22.069  38.656  1.00 52.09           C  
+ATOM    375  C   ILE A  66      -9.552 -20.623  38.732  1.00 52.16           C  
+ATOM    376  O   ILE A  66      -9.406 -19.857  37.779  1.00 52.20           O  
+ATOM    377  CB  ILE A  66     -10.279 -23.004  38.488  1.00 52.37           C  
+ATOM    378  CG1 ILE A  66      -9.809 -24.444  38.250  1.00 50.90           C  
+ATOM    379  CG2 ILE A  66     -11.148 -22.525  37.328  1.00 51.21           C  
+ATOM    380  CD1 ILE A  66     -10.935 -25.453  38.175  0.00 51.61           C  
+ATOM    381  N   LEU A  67     -10.129 -20.252  39.871  1.00 50.43           N  
+ATOM    382  CA  LEU A  67     -10.641 -18.902  40.053  1.00 49.76           C  
+ATOM    383  C   LEU A  67      -9.513 -17.875  40.151  1.00 49.45           C  
+ATOM    384  O   LEU A  67      -9.692 -16.713  39.783  1.00 48.40           O  
+ATOM    385  CB  LEU A  67     -11.535 -18.833  41.300  1.00 48.98           C  
+ATOM    386  CG  LEU A  67     -12.813 -19.687  41.251  1.00 50.12           C  
+ATOM    387  CD1 LEU A  67     -13.591 -19.547  42.549  1.00 49.04           C  
+ATOM    388  CD2 LEU A  67     -13.677 -19.255  40.076  1.00 49.83           C  
+ATOM    389  N   THR A  68      -8.355 -18.303  40.647  1.00 47.84           N  
+ATOM    390  CA  THR A  68      -7.210 -17.408  40.774  1.00 47.23           C  
+ATOM    391  C   THR A  68      -6.658 -17.080  39.382  1.00 47.48           C  
+ATOM    392  O   THR A  68      -6.332 -15.930  39.089  1.00 45.96           O  
+ATOM    393  CB  THR A  68      -6.092 -18.041  41.639  1.00 46.86           C  
+ATOM    394  OG1 THR A  68      -6.570 -18.222  42.979  1.00 46.62           O  
+ATOM    395  CG2 THR A  68      -4.859 -17.141  41.675  1.00 45.76           C  
+ATOM    396  N   ALA A  69      -6.559 -18.094  38.529  1.00 45.76           N  
+ATOM    397  CA  ALA A  69      -6.066 -17.889  37.181  1.00 46.14           C  
+ATOM    398  C   ALA A  69      -7.034 -16.966  36.452  1.00 47.41           C  
+ATOM    399  O   ALA A  69      -6.617 -16.013  35.794  1.00 46.81           O  
+ATOM    400  CB  ALA A  69      -5.956 -19.218  36.447  1.00 44.56           C  
+ATOM    401  N   LEU A  70      -8.328 -17.249  36.585  1.00 47.47           N  
+ATOM    402  CA  LEU A  70      -9.365 -16.452  35.939  1.00 46.43           C  
+ATOM    403  C   LEU A  70      -9.308 -14.962  36.290  1.00 46.23           C  
+ATOM    404  O   LEU A  70      -9.337 -14.113  35.402  1.00 46.67           O  
+ATOM    405  CB  LEU A  70     -10.757 -17.001  36.286  1.00 45.68           C  
+ATOM    406  CG  LEU A  70     -11.202 -18.319  35.642  1.00 45.74           C  
+ATOM    407  CD1 LEU A  70     -12.603 -18.668  36.119  1.00 43.86           C  
+ATOM    408  CD2 LEU A  70     -11.177 -18.202  34.128  1.00 42.48           C  
+ATOM    409  N   CYS A  71      -9.234 -14.647  37.577  1.00 44.97           N  
+ATOM    410  CA  CYS A  71      -9.190 -13.258  38.019  1.00 45.32           C  
+ATOM    411  C   CYS A  71      -7.867 -12.573  37.684  1.00 45.69           C  
+ATOM    412  O   CYS A  71      -7.834 -11.379  37.392  1.00 44.63           O  
+ATOM    413  CB  CYS A  71      -9.444 -13.175  39.526  1.00 46.09           C  
+ATOM    414  SG  CYS A  71     -11.099 -13.725  40.045  1.00 53.09           S  
+ATOM    415  N   VAL A  72      -6.773 -13.324  37.736  1.00 43.89           N  
+ATOM    416  CA  VAL A  72      -5.471 -12.757  37.433  1.00 41.53           C  
+ATOM    417  C   VAL A  72      -5.341 -12.502  35.935  1.00 41.24           C  
+ATOM    418  O   VAL A  72      -4.706 -11.539  35.514  1.00 41.42           O  
+ATOM    419  CB  VAL A  72      -4.337 -13.686  37.938  1.00 40.80           C  
+ATOM    420  CG1 VAL A  72      -3.006 -13.342  37.267  1.00 37.58           C  
+ATOM    421  CG2 VAL A  72      -4.205 -13.530  39.446  1.00 38.19           C  
+ATOM    422  N   GLY A  73      -5.960 -13.359  35.134  1.00 41.12           N  
+ATOM    423  CA  GLY A  73      -5.906 -13.189  33.696  1.00 41.06           C  
+ATOM    424  C   GLY A  73      -6.728 -11.974  33.309  1.00 42.55           C  
+ATOM    425  O   GLY A  73      -6.328 -11.171  32.461  1.00 42.93           O  
+ATOM    426  N   ALA A  74      -7.888 -11.844  33.942  1.00 40.51           N  
+ATOM    427  CA  ALA A  74      -8.784 -10.732  33.690  1.00 41.13           C  
+ATOM    428  C   ALA A  74      -8.109  -9.436  34.128  1.00 40.84           C  
+ATOM    429  O   ALA A  74      -8.186  -8.420  33.438  1.00 39.78           O  
+ATOM    430  CB  ALA A  74     -10.093 -10.935  34.460  1.00 39.82           C  
+ATOM    431  N   GLY A  75      -7.441  -9.495  35.276  1.00 40.73           N  
+ATOM    432  CA  GLY A  75      -6.753  -8.340  35.818  1.00 41.62           C  
+ATOM    433  C   GLY A  75      -5.596  -7.840  34.972  1.00 42.36           C  
+ATOM    434  O   GLY A  75      -5.536  -6.653  34.659  1.00 43.23           O  
+ATOM    435  N   LEU A  76      -4.670  -8.725  34.610  1.00 41.50           N  
+ATOM    436  CA  LEU A  76      -3.530  -8.316  33.791  1.00 42.00           C  
+ATOM    437  C   LEU A  76      -3.988  -7.829  32.416  1.00 41.51           C  
+ATOM    438  O   LEU A  76      -3.380  -6.932  31.841  1.00 40.91           O  
+ATOM    439  CB  LEU A  76      -2.533  -9.466  33.624  1.00 39.94           C  
+ATOM    440  CG  LEU A  76      -1.707  -9.815  34.862  1.00 41.82           C  
+ATOM    441  CD1 LEU A  76      -0.918 -11.095  34.604  1.00 40.67           C  
+ATOM    442  CD2 LEU A  76      -0.771  -8.661  35.205  1.00 40.77           C  
+ATOM    443  N   ALA A  77      -5.053  -8.423  31.888  1.00 40.35           N  
+ATOM    444  CA  ALA A  77      -5.566  -8.005  30.592  1.00 40.81           C  
+ATOM    445  C   ALA A  77      -6.182  -6.609  30.742  1.00 43.03           C  
+ATOM    446  O   ALA A  77      -5.942  -5.715  29.927  1.00 40.63           O  
+ATOM    447  CB  ALA A  77      -6.605  -8.987  30.100  1.00 37.97           C  
+ATOM    448  N   LEU A  78      -6.968  -6.432  31.801  1.00 43.21           N  
+ATOM    449  CA  LEU A  78      -7.609  -5.156  32.071  1.00 44.90           C  
+ATOM    450  C   LEU A  78      -6.543  -4.066  32.123  1.00 45.62           C  
+ATOM    451  O   LEU A  78      -6.641  -3.053  31.429  1.00 46.00           O  
+ATOM    452  CB  LEU A  78      -8.349  -5.201  33.412  1.00 44.43           C  
+ATOM    453  CG  LEU A  78      -9.631  -4.372  33.544  1.00 45.43           C  
+ATOM    454  CD1 LEU A  78      -9.878  -4.058  35.016  1.00 44.32           C  
+ATOM    455  CD2 LEU A  78      -9.517  -3.083  32.752  1.00 45.60           C  
+ATOM    456  N   SER A  79      -5.528  -4.285  32.954  1.00 44.82           N  
+ATOM    457  CA  SER A  79      -4.440  -3.329  33.114  1.00 44.51           C  
+ATOM    458  C   SER A  79      -3.765  -2.993  31.796  1.00 43.28           C  
+ATOM    459  O   SER A  79      -3.433  -1.837  31.534  1.00 43.67           O  
+ATOM    460  CB  SER A  79      -3.397  -3.874  34.081  1.00 45.67           C  
+ATOM    461  OG  SER A  79      -3.973  -4.083  35.356  1.00 54.84           O  
+ATOM    462  N   GLY A  80      -3.553  -4.011  30.974  1.00 40.76           N  
+ATOM    463  CA  GLY A  80      -2.912  -3.793  29.697  1.00 41.11           C  
+ATOM    464  C   GLY A  80      -3.731  -2.902  28.784  1.00 41.41           C  
+ATOM    465  O   GLY A  80      -3.212  -1.946  28.202  1.00 41.43           O  
+ATOM    466  N   VAL A  81      -5.020  -3.200  28.677  1.00 39.31           N  
+ATOM    467  CA  VAL A  81      -5.893  -2.438  27.805  1.00 40.60           C  
+ATOM    468  C   VAL A  81      -6.099  -0.980  28.232  1.00 41.00           C  
+ATOM    469  O   VAL A  81      -6.176  -0.098  27.379  1.00 40.18           O  
+ATOM    470  CB  VAL A  81      -7.267  -3.137  27.650  1.00 40.93           C  
+ATOM    471  CG1 VAL A  81      -8.121  -2.920  28.895  1.00 42.64           C  
+ATOM    472  CG2 VAL A  81      -7.963  -2.626  26.410  1.00 42.47           C  
+ATOM    473  N   VAL A  82      -6.176  -0.712  29.534  1.00 38.62           N  
+ATOM    474  CA  VAL A  82      -6.373   0.663  29.965  1.00 38.93           C  
+ATOM    475  C   VAL A  82      -5.098   1.476  29.780  1.00 39.45           C  
+ATOM    476  O   VAL A  82      -5.156   2.667  29.478  1.00 38.89           O  
+ATOM    477  CB  VAL A  82      -6.842   0.767  31.449  1.00 37.91           C  
+ATOM    478  CG1 VAL A  82      -8.145   0.004  31.637  1.00 36.98           C  
+ATOM    479  CG2 VAL A  82      -5.774   0.260  32.382  1.00 39.51           C  
+ATOM    480  N   LEU A  83      -3.950   0.825  29.951  1.00 38.91           N  
+ATOM    481  CA  LEU A  83      -2.660   1.492  29.801  1.00 38.14           C  
+ATOM    482  C   LEU A  83      -2.380   1.764  28.339  1.00 37.24           C  
+ATOM    483  O   LEU A  83      -1.691   2.722  27.997  1.00 37.12           O  
+ATOM    484  CB  LEU A  83      -1.530   0.638  30.386  1.00 36.88           C  
+ATOM    485  CG  LEU A  83      -1.410   0.638  31.912  1.00 38.79           C  
+ATOM    486  CD1 LEU A  83      -0.335  -0.358  32.342  1.00 38.30           C  
+ATOM    487  CD2 LEU A  83      -1.066   2.040  32.405  1.00 35.68           C  
+ATOM    488  N   GLN A  84      -2.903   0.902  27.478  1.00 36.55           N  
+ATOM    489  CA  GLN A  84      -2.723   1.075  26.052  1.00 37.08           C  
+ATOM    490  C   GLN A  84      -3.535   2.294  25.624  1.00 37.13           C  
+ATOM    491  O   GLN A  84      -3.145   3.015  24.713  1.00 37.53           O  
+ATOM    492  CB  GLN A  84      -3.158  -0.190  25.304  1.00 36.87           C  
+ATOM    493  CG  GLN A  84      -2.052  -1.245  25.240  1.00 41.01           C  
+ATOM    494  CD  GLN A  84      -2.524  -2.609  24.756  1.00 42.11           C  
+ATOM    495  OE1 GLN A  84      -3.489  -2.721  24.003  1.00 43.76           O  
+ATOM    496  NE2 GLN A  84      -1.823  -3.654  25.174  1.00 44.06           N  
+ATOM    497  N   GLY A  85      -4.650   2.528  26.310  1.00 37.59           N  
+ATOM    498  CA  GLY A  85      -5.486   3.676  26.014  1.00 39.08           C  
+ATOM    499  C   GLY A  85      -4.833   4.966  26.498  1.00 41.29           C  
+ATOM    500  O   GLY A  85      -4.889   5.994  25.815  1.00 42.34           O  
+ATOM    501  N   ILE A  86      -4.212   4.914  27.675  1.00 40.68           N  
+ATOM    502  CA  ILE A  86      -3.534   6.078  28.243  1.00 40.79           C  
+ATOM    503  C   ILE A  86      -2.387   6.530  27.337  1.00 40.27           C  
+ATOM    504  O   ILE A  86      -2.256   7.711  27.029  1.00 40.35           O  
+ATOM    505  CB  ILE A  86      -2.943   5.765  29.650  1.00 42.31           C  
+ATOM    506  CG1 ILE A  86      -4.065   5.618  30.682  1.00 40.17           C  
+ATOM    507  CG2 ILE A  86      -1.960   6.860  30.064  1.00 41.79           C  
+ATOM    508  CD1 ILE A  86      -3.576   5.289  32.078  0.00 41.03           C  
+ATOM    509  N   PHE A  87      -1.566   5.579  26.906  1.00 39.04           N  
+ATOM    510  CA  PHE A  87      -0.419   5.876  26.055  1.00 39.16           C  
+ATOM    511  C   PHE A  87      -0.681   5.830  24.548  1.00 38.52           C  
+ATOM    512  O   PHE A  87       0.249   5.923  23.757  1.00 37.16           O  
+ATOM    513  CB  PHE A  87       0.727   4.926  26.409  1.00 39.10           C  
+ATOM    514  CG  PHE A  87       1.274   5.141  27.788  1.00 41.11           C  
+ATOM    515  CD1 PHE A  87       2.206   6.147  28.031  1.00 40.29           C  
+ATOM    516  CD2 PHE A  87       0.813   4.379  28.861  1.00 40.42           C  
+ATOM    517  CE1 PHE A  87       2.669   6.393  29.324  1.00 42.06           C  
+ATOM    518  CE2 PHE A  87       1.267   4.617  30.155  1.00 39.59           C  
+ATOM    519  CZ  PHE A  87       2.196   5.626  30.389  1.00 41.98           C  
+ATOM    520  N   ARG A  88      -1.939   5.677  24.151  1.00 40.13           N  
+ATOM    521  CA  ARG A  88      -2.289   5.640  22.734  1.00 43.15           C  
+ATOM    522  C   ARG A  88      -1.341   4.759  21.920  1.00 44.91           C  
+ATOM    523  O   ARG A  88      -0.893   5.148  20.840  1.00 43.88           O  
+ATOM    524  CB  ARG A  88      -2.264   7.061  22.159  1.00 43.97           C  
+ATOM    525  CG  ARG A  88      -3.076   8.069  22.952  1.00 43.57           C  
+ATOM    526  CD  ARG A  88      -2.668   9.501  22.608  1.00 45.72           C  
+ATOM    527  NE  ARG A  88      -3.420  10.462  23.406  1.00 46.81           N  
+ATOM    528  CZ  ARG A  88      -2.984  11.670  23.734  1.00 45.28           C  
+ATOM    529  NH1 ARG A  88      -3.745  12.466  24.467  1.00 44.64           N  
+ATOM    530  NH2 ARG A  88      -1.787  12.078  23.339  1.00 46.31           N  
+ATOM    531  N   ASN A  89      -1.051   3.568  22.433  1.00 47.09           N  
+ATOM    532  CA  ASN A  89      -0.156   2.647  21.754  1.00 48.45           C  
+ATOM    533  C   ASN A  89      -0.496   1.196  22.079  1.00 50.37           C  
+ATOM    534  O   ASN A  89      -0.453   0.779  23.236  1.00 51.69           O  
+ATOM    535  CB  ASN A  89       1.284   2.938  22.164  1.00 50.72           C  
+ATOM    536  CG  ASN A  89       2.280   2.009  21.500  1.00 53.67           C  
+ATOM    537  OD1 ASN A  89       3.461   2.018  21.832  1.00 58.95           O  
+ATOM    538  ND2 ASN A  89       1.811   1.207  20.554  1.00 55.74           N  
+ATOM    539  N   PRO A  90      -0.824   0.400  21.056  1.00 51.26           N  
+ATOM    540  CA  PRO A  90      -1.163  -1.007  21.283  1.00 51.97           C  
+ATOM    541  C   PRO A  90       0.002  -1.870  21.781  1.00 52.66           C  
+ATOM    542  O   PRO A  90      -0.214  -2.974  22.277  1.00 53.95           O  
+ATOM    543  CB  PRO A  90      -1.680  -1.454  19.917  1.00 52.58           C  
+ATOM    544  CG  PRO A  90      -0.880  -0.608  18.968  1.00 52.31           C  
+ATOM    545  CD  PRO A  90      -0.926   0.746  19.627  1.00 50.48           C  
+ATOM    546  N   LEU A  91       1.226  -1.364  21.663  1.00 53.36           N  
+ATOM    547  CA  LEU A  91       2.415  -2.105  22.088  1.00 53.14           C  
+ATOM    548  C   LEU A  91       2.789  -1.872  23.547  1.00 54.75           C  
+ATOM    549  O   LEU A  91       3.884  -2.225  23.982  1.00 57.00           O  
+ATOM    550  CB  LEU A  91       3.607  -1.745  21.196  1.00 51.31           C  
+ATOM    551  CG  LEU A  91       3.459  -2.084  19.709  1.00 52.19           C  
+ATOM    552  CD1 LEU A  91       4.691  -1.614  18.947  1.00 52.18           C  
+ATOM    553  CD2 LEU A  91       3.272  -3.590  19.535  1.00 50.63           C  
+ATOM    554  N   VAL A  92       1.884  -1.275  24.307  1.00 55.40           N  
+ATOM    555  CA  VAL A  92       2.146  -1.021  25.715  1.00 55.44           C  
+ATOM    556  C   VAL A  92       1.580  -2.142  26.587  1.00 56.86           C  
+ATOM    557  O   VAL A  92       0.556  -2.744  26.260  1.00 56.66           O  
+ATOM    558  CB  VAL A  92       1.546   0.341  26.142  1.00 54.15           C  
+ATOM    559  CG1 VAL A  92       1.199   0.335  27.614  1.00 53.26           C  
+ATOM    560  CG2 VAL A  92       2.549   1.447  25.857  1.00 53.26           C  
+ATOM    561  N   ASN A  93       2.266  -2.426  27.689  1.00 58.16           N  
+ATOM    562  CA  ASN A  93       1.832  -3.461  28.614  1.00 59.90           C  
+ATOM    563  C   ASN A  93       1.877  -2.936  30.048  1.00 61.07           C  
+ATOM    564  O   ASN A  93       2.475  -1.893  30.320  1.00 59.13           O  
+ATOM    565  CB  ASN A  93       2.712  -4.706  28.477  1.00 60.83           C  
+ATOM    566  CG  ASN A  93       4.122  -4.482  28.970  1.00 61.85           C  
+ATOM    567  OD1 ASN A  93       4.923  -5.409  29.008  1.00 64.54           O  
+ATOM    568  ND2 ASN A  93       4.437  -3.250  29.346  1.00 64.36           N  
+ATOM    569  N   PRO A  94       1.252  -3.662  30.988  1.00 63.14           N  
+ATOM    570  CA  PRO A  94       1.223  -3.252  32.396  1.00 64.05           C  
+ATOM    571  C   PRO A  94       2.574  -3.252  33.085  1.00 64.83           C  
+ATOM    572  O   PRO A  94       2.640  -3.337  34.308  1.00 67.13           O  
+ATOM    573  CB  PRO A  94       0.260  -4.255  33.022  1.00 64.64           C  
+ATOM    574  CG  PRO A  94       0.509  -5.496  32.213  1.00 64.38           C  
+ATOM    575  CD  PRO A  94       0.554  -4.949  30.804  1.00 63.44           C  
+ATOM    576  N   HIS A  95       3.646  -3.148  32.305  1.00 65.49           N  
+ATOM    577  CA  HIS A  95       4.998  -3.154  32.859  1.00 65.75           C  
+ATOM    578  C   HIS A  95       5.770  -1.857  32.602  1.00 64.47           C  
+ATOM    579  O   HIS A  95       6.807  -1.624  33.218  1.00 65.54           O  
+ATOM    580  CB  HIS A  95       5.798  -4.327  32.274  1.00 69.28           C  
+ATOM    581  CG  HIS A  95       5.149  -5.667  32.460  1.00 73.82           C  
+ATOM    582  ND1 HIS A  95       5.643  -6.818  31.880  1.00 75.39           N  
+ATOM    583  CD2 HIS A  95       4.053  -6.043  33.162  1.00 74.84           C  
+ATOM    584  CE1 HIS A  95       4.878  -7.842  32.218  1.00 76.39           C  
+ATOM    585  NE2 HIS A  95       3.907  -7.399  32.996  1.00 75.38           N  
+ATOM    586  N   ILE A  96       5.269  -1.016  31.700  1.00 62.17           N  
+ATOM    587  CA  ILE A  96       5.943   0.236  31.361  1.00 59.46           C  
+ATOM    588  C   ILE A  96       5.970   1.299  32.460  1.00 56.80           C  
+ATOM    589  O   ILE A  96       6.776   2.225  32.403  1.00 57.97           O  
+ATOM    590  CB  ILE A  96       5.326   0.877  30.101  1.00 60.77           C  
+ATOM    591  CG1 ILE A  96       3.886   1.314  30.386  1.00 59.00           C  
+ATOM    592  CG2 ILE A  96       5.369  -0.121  28.941  1.00 63.02           C  
+ATOM    593  CD1 ILE A  96       3.281   2.135  29.277  0.00 59.48           C  
+ATOM    594  N   ILE A  97       5.086   1.187  33.444  1.00 53.89           N  
+ATOM    595  CA  ILE A  97       5.061   2.156  34.534  1.00 52.59           C  
+ATOM    596  C   ILE A  97       6.035   1.733  35.630  1.00 51.75           C  
+ATOM    597  O   ILE A  97       6.188   2.418  36.638  1.00 51.69           O  
+ATOM    598  CB  ILE A  97       3.637   2.304  35.138  1.00 53.70           C  
+ATOM    599  CG1 ILE A  97       2.994   0.926  35.315  1.00 53.73           C  
+ATOM    600  CG2 ILE A  97       2.780   3.197  34.249  1.00 51.90           C  
+ATOM    601  CD1 ILE A  97       1.611   0.967  35.934  0.00 53.66           C  
+ATOM    602  N   GLY A  98       6.691   0.597  35.420  1.00 49.90           N  
+ATOM    603  CA  GLY A  98       7.655   0.092  36.380  1.00 49.39           C  
+ATOM    604  C   GLY A  98       7.087  -0.519  37.653  1.00 48.40           C  
+ATOM    605  O   GLY A  98       7.841  -0.879  38.559  1.00 47.58           O  
+ATOM    606  N   VAL A  99       5.770  -0.651  37.736  1.00 46.96           N  
+ATOM    607  CA  VAL A  99       5.164  -1.212  38.937  1.00 47.37           C  
+ATOM    608  C   VAL A  99       5.478  -2.706  39.121  1.00 46.05           C  
+ATOM    609  O   VAL A  99       5.592  -3.183  40.245  1.00 45.44           O  
+ATOM    610  CB  VAL A  99       3.630  -0.985  38.936  1.00 47.90           C  
+ATOM    611  CG1 VAL A  99       2.996  -1.685  37.741  1.00 49.31           C  
+ATOM    612  CG2 VAL A  99       3.029  -1.485  40.240  1.00 49.50           C  
+ATOM    613  N   THR A 100       5.629  -3.437  38.021  1.00 45.16           N  
+ATOM    614  CA  THR A 100       5.936  -4.860  38.101  1.00 46.67           C  
+ATOM    615  C   THR A 100       7.334  -5.097  38.678  1.00 47.22           C  
+ATOM    616  O   THR A 100       7.550  -6.046  39.435  1.00 48.07           O  
+ATOM    617  CB  THR A 100       5.836  -5.537  36.714  1.00 48.15           C  
+ATOM    618  OG1 THR A 100       6.698  -4.871  35.783  1.00 53.01           O  
+ATOM    619  CG2 THR A 100       4.421  -5.472  36.200  1.00 48.71           C  
+ATOM    620  N   SER A 101       8.282  -4.238  38.320  1.00 44.25           N  
+ATOM    621  CA  SER A 101       9.641  -4.360  38.831  1.00 43.93           C  
+ATOM    622  C   SER A 101       9.672  -3.942  40.292  1.00 43.50           C  
+ATOM    623  O   SER A 101      10.395  -4.523  41.095  1.00 43.35           O  
+ATOM    624  CB  SER A 101      10.597  -3.473  38.034  1.00 43.33           C  
+ATOM    625  OG  SER A 101      10.684  -3.919  36.697  1.00 47.13           O  
+ATOM    626  N   GLY A 102       8.889  -2.918  40.625  1.00 43.61           N  
+ATOM    627  CA  GLY A 102       8.835  -2.441  41.993  1.00 42.64           C  
+ATOM    628  C   GLY A 102       8.279  -3.527  42.889  1.00 42.56           C  
+ATOM    629  O   GLY A 102       8.796  -3.768  43.975  1.00 41.29           O  
+ATOM    630  N   SER A 103       7.221  -4.184  42.425  1.00 42.97           N  
+ATOM    631  CA  SER A 103       6.600  -5.269  43.176  1.00 44.41           C  
+ATOM    632  C   SER A 103       7.548  -6.467  43.252  1.00 43.86           C  
+ATOM    633  O   SER A 103       7.627  -7.147  44.274  1.00 44.99           O  
+ATOM    634  CB  SER A 103       5.292  -5.697  42.503  1.00 46.01           C  
+ATOM    635  OG  SER A 103       4.363  -4.626  42.456  1.00 50.74           O  
+ATOM    636  N   ALA A 104       8.260  -6.725  42.161  1.00 42.84           N  
+ATOM    637  CA  ALA A 104       9.200  -7.836  42.111  1.00 42.45           C  
+ATOM    638  C   ALA A 104      10.261  -7.639  43.178  1.00 42.92           C  
+ATOM    639  O   ALA A 104      10.678  -8.589  43.836  1.00 43.30           O  
+ATOM    640  CB  ALA A 104       9.856  -7.911  40.739  1.00 42.23           C  
+ATOM    641  N   PHE A 105      10.690  -6.394  43.343  1.00 41.56           N  
+ATOM    642  CA  PHE A 105      11.704  -6.062  44.326  1.00 40.98           C  
+ATOM    643  C   PHE A 105      11.149  -6.188  45.734  1.00 41.88           C  
+ATOM    644  O   PHE A 105      11.830  -6.683  46.629  1.00 42.08           O  
+ATOM    645  CB  PHE A 105      12.215  -4.637  44.107  1.00 38.78           C  
+ATOM    646  CG  PHE A 105      13.090  -4.139  45.219  1.00 37.58           C  
+ATOM    647  CD1 PHE A 105      14.350  -4.693  45.432  1.00 36.05           C  
+ATOM    648  CD2 PHE A 105      12.640  -3.143  46.079  1.00 36.67           C  
+ATOM    649  CE1 PHE A 105      15.152  -4.262  46.487  1.00 34.84           C  
+ATOM    650  CE2 PHE A 105      13.432  -2.705  47.136  1.00 38.23           C  
+ATOM    651  CZ  PHE A 105      14.694  -3.268  47.339  1.00 36.45           C  
+ATOM    652  N   GLY A 106       9.919  -5.721  45.930  1.00 43.03           N  
+ATOM    653  CA  GLY A 106       9.291  -5.804  47.238  1.00 44.33           C  
+ATOM    654  C   GLY A 106       9.210  -7.247  47.709  1.00 46.74           C  
+ATOM    655  O   GLY A 106       9.541  -7.561  48.855  1.00 47.49           O  
+ATOM    656  N   GLY A 107       8.768  -8.132  46.820  1.00 46.25           N  
+ATOM    657  CA  GLY A 107       8.667  -9.536  47.172  1.00 46.82           C  
+ATOM    658  C   GLY A 107      10.038 -10.136  47.424  1.00 47.36           C  
+ATOM    659  O   GLY A 107      10.237 -10.857  48.401  1.00 47.38           O  
+ATOM    660  N   THR A 108      10.987  -9.829  46.540  1.00 46.84           N  
+ATOM    661  CA  THR A 108      12.349 -10.335  46.660  1.00 46.06           C  
+ATOM    662  C   THR A 108      12.957  -9.942  47.995  1.00 47.02           C  
+ATOM    663  O   THR A 108      13.586 -10.759  48.666  1.00 47.91           O  
+ATOM    664  CB  THR A 108      13.246  -9.805  45.515  1.00 44.90           C  
+ATOM    665  OG1 THR A 108      12.807 -10.367  44.272  1.00 43.98           O  
+ATOM    666  CG2 THR A 108      14.702 -10.192  45.743  1.00 42.98           C  
+ATOM    667  N   LEU A 109      12.766  -8.687  48.376  1.00 47.25           N  
+ATOM    668  CA  LEU A 109      13.290  -8.186  49.634  1.00 50.08           C  
+ATOM    669  C   LEU A 109      12.683  -8.971  50.794  1.00 51.10           C  
+ATOM    670  O   LEU A 109      13.386  -9.386  51.713  1.00 52.06           O  
+ATOM    671  CB  LEU A 109      12.954  -6.702  49.786  1.00 50.50           C  
+ATOM    672  CG  LEU A 109      13.582  -6.003  50.989  1.00 51.71           C  
+ATOM    673  CD1 LEU A 109      15.097  -6.070  50.873  1.00 53.25           C  
+ATOM    674  CD2 LEU A 109      13.115  -4.560  51.047  1.00 52.73           C  
+ATOM    675  N   ALA A 110      11.372  -9.169  50.745  1.00 51.64           N  
+ATOM    676  CA  ALA A 110      10.672  -9.904  51.785  1.00 52.45           C  
+ATOM    677  C   ALA A 110      11.233 -11.320  51.890  1.00 53.61           C  
+ATOM    678  O   ALA A 110      11.432 -11.828  52.987  1.00 54.65           O  
+ATOM    679  CB  ALA A 110       9.178  -9.945  51.480  1.00 51.58           C  
+ATOM    680  N   ILE A 111      11.491 -11.956  50.753  1.00 53.79           N  
+ATOM    681  CA  ILE A 111      12.040 -13.306  50.761  1.00 54.64           C  
+ATOM    682  C   ILE A 111      13.452 -13.305  51.349  1.00 56.65           C  
+ATOM    683  O   ILE A 111      13.820 -14.190  52.122  1.00 58.50           O  
+ATOM    684  CB  ILE A 111      12.100 -13.900  49.333  1.00 53.86           C  
+ATOM    685  CG1 ILE A 111      10.682 -14.142  48.805  1.00 53.52           C  
+ATOM    686  CG2 ILE A 111      12.899 -15.198  49.338  1.00 52.57           C  
+ATOM    687  CD1 ILE A 111      10.634 -14.677  47.388  0.00 53.80           C  
+ATOM    688  N   PHE A 112      14.238 -12.300  50.986  1.00 57.58           N  
+ATOM    689  CA  PHE A 112      15.611 -12.185  51.454  1.00 58.01           C  
+ATOM    690  C   PHE A 112      15.730 -12.092  52.975  1.00 60.24           C  
+ATOM    691  O   PHE A 112      16.632 -12.691  53.569  1.00 61.21           O  
+ATOM    692  CB  PHE A 112      16.267 -10.972  50.790  1.00 56.51           C  
+ATOM    693  CG  PHE A 112      17.683 -10.731  51.217  1.00 53.96           C  
+ATOM    694  CD1 PHE A 112      17.969  -9.854  52.256  1.00 53.43           C  
+ATOM    695  CD2 PHE A 112      18.734 -11.380  50.576  1.00 54.05           C  
+ATOM    696  CE1 PHE A 112      19.285  -9.622  52.653  1.00 53.93           C  
+ATOM    697  CE2 PHE A 112      20.054 -11.158  50.964  1.00 53.78           C  
+ATOM    698  CZ  PHE A 112      20.330 -10.276  52.005  1.00 53.35           C  
+ATOM    699  N   PHE A 113      14.831 -11.343  53.604  1.00 60.73           N  
+ATOM    700  CA  PHE A 113      14.863 -11.196  55.056  1.00 62.92           C  
+ATOM    701  C   PHE A 113      13.988 -12.232  55.751  1.00 64.64           C  
+ATOM    702  O   PHE A 113      13.704 -12.118  56.942  1.00 65.69           O  
+ATOM    703  CB  PHE A 113      14.416  -9.792  55.471  1.00 61.38           C  
+ATOM    704  CG  PHE A 113      15.424  -8.727  55.173  1.00 62.44           C  
+ATOM    705  CD1 PHE A 113      15.187  -7.782  54.181  1.00 62.26           C  
+ATOM    706  CD2 PHE A 113      16.625  -8.679  55.870  1.00 62.72           C  
+ATOM    707  CE1 PHE A 113      16.134  -6.805  53.887  1.00 62.70           C  
+ATOM    708  CE2 PHE A 113      17.579  -7.705  55.583  1.00 63.33           C  
+ATOM    709  CZ  PHE A 113      17.332  -6.766  54.587  1.00 62.89           C  
+ATOM    710  N   GLY A 114      13.565 -13.240  54.998  1.00 66.26           N  
+ATOM    711  CA  GLY A 114      12.730 -14.285  55.555  1.00 68.24           C  
+ATOM    712  C   GLY A 114      11.457 -13.785  56.210  1.00 69.77           C  
+ATOM    713  O   GLY A 114      11.126 -14.199  57.321  1.00 71.04           O  
+ATOM    714  N   PHE A 115      10.743 -12.891  55.533  1.00 70.55           N  
+ATOM    715  CA  PHE A 115       9.490 -12.360  56.061  1.00 70.48           C  
+ATOM    716  C   PHE A 115       8.410 -13.429  55.990  1.00 70.89           C  
+ATOM    717  O   PHE A 115       8.631 -14.518  55.458  1.00 71.17           O  
+ATOM    718  CB  PHE A 115       9.031 -11.143  55.254  1.00 69.78           C  
+ATOM    719  CG  PHE A 115       9.786  -9.882  55.559  1.00 70.03           C  
+ATOM    720  CD1 PHE A 115       9.474  -8.701  54.894  1.00 70.41           C  
+ATOM    721  CD2 PHE A 115      10.794  -9.865  56.517  1.00 70.03           C  
+ATOM    722  CE1 PHE A 115      10.151  -7.521  55.176  1.00 70.57           C  
+ATOM    723  CE2 PHE A 115      11.479  -8.689  56.809  1.00 70.56           C  
+ATOM    724  CZ  PHE A 115      11.156  -7.514  56.137  1.00 71.30           C  
+ATOM    725  N   SER A 116       7.241 -13.110  56.530  1.00 71.35           N  
+ATOM    726  CA  SER A 116       6.120 -14.038  56.510  1.00 71.87           C  
+ATOM    727  C   SER A 116       5.318 -13.793  55.239  1.00 72.40           C  
+ATOM    728  O   SER A 116       5.595 -12.854  54.494  1.00 72.39           O  
+ATOM    729  CB  SER A 116       5.225 -13.823  57.734  1.00 71.47           C  
+ATOM    730  OG  SER A 116       4.669 -12.520  57.739  1.00 70.55           O  
+ATOM    731  N   LEU A 117       4.326 -14.640  54.996  1.00 72.45           N  
+ATOM    732  CA  LEU A 117       3.489 -14.505  53.817  1.00 72.41           C  
+ATOM    733  C   LEU A 117       2.859 -13.116  53.778  1.00 72.74           C  
+ATOM    734  O   LEU A 117       2.881 -12.442  52.745  1.00 72.88           O  
+ATOM    735  CB  LEU A 117       2.410 -15.592  53.825  1.00 72.81           C  
+ATOM    736  CG  LEU A 117       1.399 -15.647  52.677  1.00 73.65           C  
+ATOM    737  CD1 LEU A 117       0.294 -14.629  52.917  1.00 74.35           C  
+ATOM    738  CD2 LEU A 117       2.109 -15.407  51.347  1.00 72.73           C  
+ATOM    739  N   TYR A 118       2.304 -12.689  54.908  1.00 72.59           N  
+ATOM    740  CA  TYR A 118       1.675 -11.374  54.996  1.00 72.68           C  
+ATOM    741  C   TYR A 118       2.705 -10.265  54.846  1.00 69.97           C  
+ATOM    742  O   TYR A 118       2.379  -9.154  54.430  1.00 68.30           O  
+ATOM    743  CB  TYR A 118       0.941 -11.215  56.329  1.00 76.53           C  
+ATOM    744  CG  TYR A 118      -0.336 -12.017  56.415  1.00 81.48           C  
+ATOM    745  CD1 TYR A 118      -0.308 -13.413  56.500  1.00 83.35           C  
+ATOM    746  CD2 TYR A 118      -1.577 -11.382  56.390  1.00 83.60           C  
+ATOM    747  CE1 TYR A 118      -1.489 -14.156  56.557  1.00 85.06           C  
+ATOM    748  CE2 TYR A 118      -2.762 -12.114  56.446  1.00 85.95           C  
+ATOM    749  CZ  TYR A 118      -2.712 -13.498  56.529  1.00 86.02           C  
+ATOM    750  OH  TYR A 118      -3.886 -14.214  56.582  1.00 87.53           O  
+ATOM    751  N   GLY A 119       3.948 -10.577  55.198  1.00 67.92           N  
+ATOM    752  CA  GLY A 119       5.015  -9.604  55.082  1.00 65.48           C  
+ATOM    753  C   GLY A 119       5.386  -9.432  53.624  1.00 63.89           C  
+ATOM    754  O   GLY A 119       5.778  -8.351  53.198  1.00 63.46           O  
+ATOM    755  N   LEU A 120       5.260 -10.513  52.860  1.00 63.18           N  
+ATOM    756  CA  LEU A 120       5.567 -10.492  51.439  1.00 62.13           C  
+ATOM    757  C   LEU A 120       4.506  -9.659  50.724  1.00 61.79           C  
+ATOM    758  O   LEU A 120       4.828  -8.818  49.883  1.00 60.37           O  
+ATOM    759  CB  LEU A 120       5.596 -11.922  50.889  1.00 61.52           C  
+ATOM    760  CG  LEU A 120       5.882 -12.108  49.395  1.00 62.73           C  
+ATOM    761  CD1 LEU A 120       6.355 -13.523  49.132  1.00 61.81           C  
+ATOM    762  CD2 LEU A 120       4.632 -11.801  48.582  1.00 62.37           C  
+ATOM    763  N   PHE A 121       3.243  -9.894  51.070  1.00 60.45           N  
+ATOM    764  CA  PHE A 121       2.138  -9.153  50.475  1.00 59.70           C  
+ATOM    765  C   PHE A 121       2.338  -7.655  50.670  1.00 59.66           C  
+ATOM    766  O   PHE A 121       2.343  -6.886  49.710  1.00 60.03           O  
+ATOM    767  CB  PHE A 121       0.804  -9.551  51.120  1.00 59.95           C  
+ATOM    768  CG  PHE A 121       0.291 -10.903  50.706  1.00 60.88           C  
+ATOM    769  CD1 PHE A 121      -0.919 -11.374  51.210  1.00 61.57           C  
+ATOM    770  CD2 PHE A 121       1.000 -11.701  49.812  1.00 61.48           C  
+ATOM    771  CE1 PHE A 121      -1.418 -12.617  50.828  1.00 61.85           C  
+ATOM    772  CE2 PHE A 121       0.511 -12.947  49.422  1.00 62.30           C  
+ATOM    773  CZ  PHE A 121      -0.702 -13.405  49.932  1.00 63.39           C  
+ATOM    774  N   THR A 122       2.496  -7.244  51.923  1.00 58.43           N  
+ATOM    775  CA  THR A 122       2.672  -5.837  52.233  1.00 58.40           C  
+ATOM    776  C   THR A 122       3.892  -5.253  51.539  1.00 57.56           C  
+ATOM    777  O   THR A 122       3.828  -4.152  50.992  1.00 58.33           O  
+ATOM    778  CB  THR A 122       2.813  -5.603  53.752  1.00 59.59           C  
+ATOM    779  OG1 THR A 122       3.986  -6.272  54.230  1.00 63.63           O  
+ATOM    780  CG2 THR A 122       1.590  -6.133  54.490  1.00 58.35           C  
+ATOM    781  N   SER A 123       5.000  -5.989  51.557  1.00 55.67           N  
+ATOM    782  CA  SER A 123       6.233  -5.518  50.933  1.00 53.04           C  
+ATOM    783  C   SER A 123       6.040  -5.357  49.424  1.00 52.22           C  
+ATOM    784  O   SER A 123       6.454  -4.355  48.838  1.00 51.22           O  
+ATOM    785  CB  SER A 123       7.377  -6.497  51.223  1.00 52.71           C  
+ATOM    786  OG  SER A 123       8.640  -5.939  50.891  1.00 49.65           O  
+ATOM    787  N   THR A 124       5.397  -6.345  48.809  1.00 51.46           N  
+ATOM    788  CA  THR A 124       5.138  -6.332  47.376  1.00 50.46           C  
+ATOM    789  C   THR A 124       4.262  -5.145  46.991  1.00 51.48           C  
+ATOM    790  O   THR A 124       4.563  -4.415  46.041  1.00 49.86           O  
+ATOM    791  CB  THR A 124       4.434  -7.626  46.925  1.00 49.97           C  
+ATOM    792  OG1 THR A 124       5.228  -8.762  47.294  1.00 49.86           O  
+ATOM    793  CG2 THR A 124       4.241  -7.625  45.416  1.00 50.21           C  
+ATOM    794  N   ILE A 125       3.172  -4.962  47.729  1.00 51.95           N  
+ATOM    795  CA  ILE A 125       2.252  -3.863  47.467  1.00 52.92           C  
+ATOM    796  C   ILE A 125       2.869  -2.515  47.854  1.00 53.36           C  
+ATOM    797  O   ILE A 125       2.690  -1.517  47.160  1.00 53.76           O  
+ATOM    798  CB  ILE A 125       0.916  -4.070  48.231  1.00 52.07           C  
+ATOM    799  CG1 ILE A 125       0.112  -5.190  47.568  1.00 50.76           C  
+ATOM    800  CG2 ILE A 125       0.113  -2.782  48.250  1.00 53.20           C  
+ATOM    801  CD1 ILE A 125      -1.199  -5.500  48.259  0.00 51.34           C  
+ATOM    802  N   LEU A 126       3.611  -2.496  48.954  1.00 54.13           N  
+ATOM    803  CA  LEU A 126       4.243  -1.271  49.421  1.00 54.88           C  
+ATOM    804  C   LEU A 126       5.154  -0.684  48.338  1.00 55.33           C  
+ATOM    805  O   LEU A 126       5.009   0.481  47.957  1.00 55.55           O  
+ATOM    806  CB  LEU A 126       5.049  -1.553  50.693  1.00 57.55           C  
+ATOM    807  CG  LEU A 126       5.293  -0.389  51.662  1.00 60.81           C  
+ATOM    808  CD1 LEU A 126       6.171   0.684  51.015  1.00 59.90           C  
+ATOM    809  CD2 LEU A 126       3.941   0.189  52.086  1.00 60.85           C  
+ATOM    810  N   PHE A 127       6.093  -1.484  47.843  1.00 53.33           N  
+ATOM    811  CA  PHE A 127       6.997  -1.001  46.809  1.00 51.82           C  
+ATOM    812  C   PHE A 127       6.298  -0.880  45.459  1.00 51.64           C  
+ATOM    813  O   PHE A 127       6.782  -0.189  44.559  1.00 48.80           O  
+ATOM    814  CB  PHE A 127       8.232  -1.904  46.699  1.00 50.41           C  
+ATOM    815  CG  PHE A 127       9.231  -1.689  47.802  1.00 51.67           C  
+ATOM    816  CD1 PHE A 127       9.119  -2.372  49.010  1.00 51.72           C  
+ATOM    817  CD2 PHE A 127      10.262  -0.767  47.649  1.00 52.85           C  
+ATOM    818  CE1 PHE A 127      10.019  -2.139  50.052  1.00 50.90           C  
+ATOM    819  CE2 PHE A 127      11.169  -0.525  48.685  1.00 52.87           C  
+ATOM    820  CZ  PHE A 127      11.044  -1.216  49.890  1.00 52.49           C  
+ATOM    821  N   GLY A 128       5.157  -1.549  45.328  1.00 52.35           N  
+ATOM    822  CA  GLY A 128       4.400  -1.477  44.092  1.00 54.30           C  
+ATOM    823  C   GLY A 128       3.755  -0.107  44.010  1.00 55.99           C  
+ATOM    824  O   GLY A 128       3.866   0.589  43.000  1.00 54.46           O  
+ATOM    825  N   PHE A 129       3.076   0.281  45.084  1.00 58.21           N  
+ATOM    826  CA  PHE A 129       2.432   1.587  45.142  1.00 61.80           C  
+ATOM    827  C   PHE A 129       3.528   2.636  45.205  1.00 61.25           C  
+ATOM    828  O   PHE A 129       3.442   3.686  44.570  1.00 61.69           O  
+ATOM    829  CB  PHE A 129       1.547   1.700  46.388  1.00 64.80           C  
+ATOM    830  CG  PHE A 129       0.214   1.015  46.256  1.00 69.05           C  
+ATOM    831  CD1 PHE A 129       0.129  -0.310  45.838  1.00 70.97           C  
+ATOM    832  CD2 PHE A 129      -0.960   1.689  46.584  1.00 71.18           C  
+ATOM    833  CE1 PHE A 129      -1.108  -0.955  45.748  1.00 72.21           C  
+ATOM    834  CE2 PHE A 129      -2.201   1.052  46.499  1.00 72.05           C  
+ATOM    835  CZ  PHE A 129      -2.273  -0.273  46.080  1.00 71.92           C  
+ATOM    836  N   GLY A 130       4.564   2.334  45.979  1.00 60.68           N  
+ATOM    837  CA  GLY A 130       5.675   3.250  46.120  1.00 59.85           C  
+ATOM    838  C   GLY A 130       6.230   3.647  44.773  1.00 59.44           C  
+ATOM    839  O   GLY A 130       6.595   4.802  44.563  1.00 61.27           O  
+ATOM    840  N   THR A 131       6.298   2.692  43.853  1.00 58.49           N  
+ATOM    841  CA  THR A 131       6.815   2.975  42.522  1.00 58.69           C  
+ATOM    842  C   THR A 131       5.891   3.953  41.800  1.00 58.70           C  
+ATOM    843  O   THR A 131       6.356   4.917  41.185  1.00 57.29           O  
+ATOM    844  CB  THR A 131       6.947   1.687  41.688  1.00 58.36           C  
+ATOM    845  OG1 THR A 131       7.890   0.811  42.316  1.00 59.67           O  
+ATOM    846  CG2 THR A 131       7.426   2.008  40.278  1.00 58.56           C  
+ATOM    847  N   LEU A 132       4.585   3.699  41.879  1.00 58.79           N  
+ATOM    848  CA  LEU A 132       3.599   4.568  41.247  1.00 59.06           C  
+ATOM    849  C   LEU A 132       3.793   5.973  41.786  1.00 59.11           C  
+ATOM    850  O   LEU A 132       3.821   6.942  41.028  1.00 58.43           O  
+ATOM    851  CB  LEU A 132       2.175   4.096  41.558  1.00 59.18           C  
+ATOM    852  CG  LEU A 132       1.703   2.809  40.878  1.00 60.81           C  
+ATOM    853  CD1 LEU A 132       0.270   2.503  41.290  1.00 59.25           C  
+ATOM    854  CD2 LEU A 132       1.802   2.963  39.370  1.00 59.23           C  
+ATOM    855  N   ALA A 133       3.933   6.068  43.104  1.00 58.90           N  
+ATOM    856  CA  ALA A 133       4.135   7.346  43.763  1.00 59.14           C  
+ATOM    857  C   ALA A 133       5.379   8.022  43.201  1.00 59.68           C  
+ATOM    858  O   ALA A 133       5.359   9.213  42.904  1.00 60.18           O  
+ATOM    859  CB  ALA A 133       4.276   7.143  45.266  1.00 59.45           C  
+ATOM    860  N   LEU A 134       6.463   7.265  43.055  1.00 59.83           N  
+ATOM    861  CA  LEU A 134       7.694   7.832  42.514  1.00 60.94           C  
+ATOM    862  C   LEU A 134       7.468   8.366  41.107  1.00 60.94           C  
+ATOM    863  O   LEU A 134       7.877   9.482  40.791  1.00 60.94           O  
+ATOM    864  CB  LEU A 134       8.822   6.793  42.492  1.00 60.37           C  
+ATOM    865  CG  LEU A 134       9.482   6.481  43.840  1.00 61.90           C  
+ATOM    866  CD1 LEU A 134      10.621   5.492  43.637  1.00 60.73           C  
+ATOM    867  CD2 LEU A 134      10.008   7.768  44.471  1.00 60.28           C  
+ATOM    868  N   VAL A 135       6.814   7.569  40.266  1.00 61.20           N  
+ATOM    869  CA  VAL A 135       6.539   7.979  38.895  1.00 61.62           C  
+ATOM    870  C   VAL A 135       5.763   9.288  38.906  1.00 63.03           C  
+ATOM    871  O   VAL A 135       6.016  10.185  38.098  1.00 61.39           O  
+ATOM    872  CB  VAL A 135       5.714   6.918  38.150  1.00 61.82           C  
+ATOM    873  CG1 VAL A 135       5.344   7.428  36.763  1.00 61.97           C  
+ATOM    874  CG2 VAL A 135       6.513   5.621  38.049  1.00 61.13           C  
+ATOM    875  N   PHE A 136       4.821   9.387  39.838  1.00 64.00           N  
+ATOM    876  CA  PHE A 136       4.000  10.580  39.984  1.00 66.04           C  
+ATOM    877  C   PHE A 136       4.856  11.782  40.380  1.00 66.94           C  
+ATOM    878  O   PHE A 136       4.795  12.833  39.742  1.00 67.01           O  
+ATOM    879  CB  PHE A 136       2.923  10.351  41.046  1.00 66.02           C  
+ATOM    880  CG  PHE A 136       2.027  11.535  41.259  1.00 67.09           C  
+ATOM    881  CD1 PHE A 136       1.075  11.883  40.306  1.00 67.50           C  
+ATOM    882  CD2 PHE A 136       2.148  12.317  42.404  1.00 66.62           C  
+ATOM    883  CE1 PHE A 136       0.257  12.993  40.488  1.00 67.00           C  
+ATOM    884  CE2 PHE A 136       1.337  13.429  42.596  1.00 66.25           C  
+ATOM    885  CZ  PHE A 136       0.389  13.768  41.636  1.00 67.17           C  
+ATOM    886  N   LEU A 137       5.652  11.620  41.434  1.00 68.38           N  
+ATOM    887  CA  LEU A 137       6.517  12.691  41.918  1.00 70.25           C  
+ATOM    888  C   LEU A 137       7.495  13.194  40.864  1.00 71.40           C  
+ATOM    889  O   LEU A 137       7.613  14.398  40.655  1.00 71.62           O  
+ATOM    890  CB  LEU A 137       7.288  12.233  43.157  1.00 70.58           C  
+ATOM    891  CG  LEU A 137       6.588  12.405  44.510  1.00 71.96           C  
+ATOM    892  CD1 LEU A 137       5.199  11.792  44.472  1.00 73.30           C  
+ATOM    893  CD2 LEU A 137       7.431  11.759  45.599  1.00 72.05           C  
+ATOM    894  N   PHE A 138       8.201  12.277  40.211  1.00 72.97           N  
+ATOM    895  CA  PHE A 138       9.154  12.659  39.176  1.00 75.75           C  
+ATOM    896  C   PHE A 138       8.430  13.256  37.973  1.00 78.33           C  
+ATOM    897  O   PHE A 138       9.024  13.982  37.176  1.00 78.16           O  
+ATOM    898  CB  PHE A 138       9.982  11.448  38.739  1.00 75.76           C  
+ATOM    899  CG  PHE A 138      11.123  11.129  39.663  1.00 75.83           C  
+ATOM    900  CD1 PHE A 138      12.181  12.020  39.812  1.00 76.10           C  
+ATOM    901  CD2 PHE A 138      11.139   9.944  40.389  1.00 76.54           C  
+ATOM    902  CE1 PHE A 138      13.239  11.737  40.671  1.00 75.90           C  
+ATOM    903  CE2 PHE A 138      12.194   9.651  41.252  1.00 76.81           C  
+ATOM    904  CZ  PHE A 138      13.245  10.551  41.392  1.00 76.02           C  
+ATOM    905  N   SER A 139       7.146  12.937  37.847  1.00 81.59           N  
+ATOM    906  CA  SER A 139       6.323  13.450  36.758  1.00 84.52           C  
+ATOM    907  C   SER A 139       6.130  14.947  36.966  1.00 87.28           C  
+ATOM    908  O   SER A 139       6.023  15.718  36.010  1.00 87.42           O  
+ATOM    909  CB  SER A 139       4.962  12.752  36.754  1.00 84.20           C  
+ATOM    910  OG  SER A 139       4.062  13.383  35.862  1.00 84.74           O  
+ATOM    911  N   PHE A 140       6.087  15.347  38.233  1.00 89.90           N  
+ATOM    912  CA  PHE A 140       5.913  16.745  38.598  1.00 92.67           C  
+ATOM    913  C   PHE A 140       7.203  17.285  39.203  1.00 94.11           C  
+ATOM    914  O   PHE A 140       7.207  17.800  40.322  1.00 95.29           O  
+ATOM    915  CB  PHE A 140       4.765  16.885  39.603  1.00 93.18           C  
+ATOM    916  CG  PHE A 140       3.410  16.548  39.035  1.00 94.97           C  
+ATOM    917  CD1 PHE A 140       2.278  16.599  39.840  1.00 95.48           C  
+ATOM    918  CD2 PHE A 140       3.262  16.194  37.694  1.00 95.95           C  
+ATOM    919  CE1 PHE A 140       1.018  16.305  39.320  1.00 96.59           C  
+ATOM    920  CE2 PHE A 140       2.008  15.898  37.163  1.00 96.49           C  
+ATOM    921  CZ  PHE A 140       0.883  15.954  37.978  1.00 96.80           C  
+ATOM    922  N   LYS A 141       8.297  17.158  38.456  1.00 94.72           N  
+ATOM    923  CA  LYS A 141       9.604  17.627  38.909  1.00 95.09           C  
+ATOM    924  C   LYS A 141      10.683  17.262  37.894  1.00 94.62           C  
+ATOM    925  O   LYS A 141      10.463  17.337  36.684  1.00 94.36           O  
+ATOM    926  CB  LYS A 141       9.943  17.009  40.271  1.00 96.10           C  
+ATOM    927  CG  LYS A 141      11.246  17.499  40.881  1.00 97.10           C  
+ATOM    928  CD  LYS A 141      11.461  16.908  42.266  1.00 97.90           C  
+ATOM    929  CE  LYS A 141      12.781  17.368  42.869  1.00 98.59           C  
+ATOM    930  NZ  LYS A 141      13.010  16.788  44.224  1.00 99.02           N  
+ATOM    931  N   SER A 146       4.368  14.916  30.083  1.00 57.40           N  
+ATOM    932  CA  SER A 146       4.032  14.230  28.837  1.00 56.25           C  
+ATOM    933  C   SER A 146       4.078  12.712  28.996  1.00 54.26           C  
+ATOM    934  O   SER A 146       4.711  12.186  29.909  1.00 53.30           O  
+ATOM    935  CB  SER A 146       4.997  14.641  27.724  1.00 56.81           C  
+ATOM    936  OG  SER A 146       6.292  14.118  27.965  1.00 57.57           O  
+ATOM    937  N   LEU A 147       3.405  12.020  28.087  1.00 52.82           N  
+ATOM    938  CA  LEU A 147       3.346  10.566  28.098  1.00 52.09           C  
+ATOM    939  C   LEU A 147       4.722   9.922  28.006  1.00 52.42           C  
+ATOM    940  O   LEU A 147       5.070   9.061  28.814  1.00 49.92           O  
+ATOM    941  CB  LEU A 147       2.467  10.079  26.944  1.00 49.41           C  
+ATOM    942  CG  LEU A 147       1.000   9.778  27.266  1.00 48.67           C  
+ATOM    943  CD1 LEU A 147       0.507  10.684  28.371  1.00 49.41           C  
+ATOM    944  CD2 LEU A 147       0.162   9.941  26.006  1.00 49.10           C  
+ATOM    945  N   LEU A 148       5.495  10.343  27.011  1.00 52.43           N  
+ATOM    946  CA  LEU A 148       6.833   9.814  26.793  1.00 53.50           C  
+ATOM    947  C   LEU A 148       7.659   9.906  28.076  1.00 54.16           C  
+ATOM    948  O   LEU A 148       8.411   8.987  28.417  1.00 53.09           O  
+ATOM    949  CB  LEU A 148       7.496  10.590  25.647  1.00 54.80           C  
+ATOM    950  CG  LEU A 148       8.932  10.313  25.200  1.00 55.39           C  
+ATOM    951  CD1 LEU A 148       9.899  11.063  26.094  1.00 58.25           C  
+ATOM    952  CD2 LEU A 148       9.203   8.820  25.209  1.00 56.38           C  
+ATOM    953  N   MET A 149       7.492  11.008  28.798  1.00 53.73           N  
+ATOM    954  CA  MET A 149       8.222  11.218  30.036  1.00 54.39           C  
+ATOM    955  C   MET A 149       7.905  10.156  31.092  1.00 53.20           C  
+ATOM    956  O   MET A 149       8.801   9.693  31.798  1.00 53.53           O  
+ATOM    957  CB  MET A 149       7.926  12.614  30.581  1.00 56.96           C  
+ATOM    958  CG  MET A 149       9.148  13.295  31.173  1.00 63.29           C  
+ATOM    959  SD  MET A 149      10.577  13.160  30.059  1.00 69.26           S  
+ATOM    960  CE  MET A 149      10.087  14.269  28.717  1.00 69.18           C  
+ATOM    961  N   LEU A 150       6.636   9.770  31.201  1.00 51.68           N  
+ATOM    962  CA  LEU A 150       6.236   8.746  32.167  1.00 50.04           C  
+ATOM    963  C   LEU A 150       6.903   7.424  31.816  1.00 49.19           C  
+ATOM    964  O   LEU A 150       7.325   6.683  32.697  1.00 48.10           O  
+ATOM    965  CB  LEU A 150       4.715   8.557  32.172  1.00 48.62           C  
+ATOM    966  CG  LEU A 150       3.855   9.766  32.546  1.00 49.01           C  
+ATOM    967  CD1 LEU A 150       2.387   9.354  32.621  1.00 48.49           C  
+ATOM    968  CD2 LEU A 150       4.319  10.331  33.871  1.00 50.08           C  
+ATOM    969  N   ILE A 151       6.990   7.138  30.520  1.00 49.56           N  
+ATOM    970  CA  ILE A 151       7.610   5.910  30.044  1.00 50.67           C  
+ATOM    971  C   ILE A 151       9.098   5.907  30.378  1.00 52.00           C  
+ATOM    972  O   ILE A 151       9.668   4.873  30.726  1.00 53.51           O  
+ATOM    973  CB  ILE A 151       7.452   5.757  28.521  1.00 50.35           C  
+ATOM    974  CG1 ILE A 151       5.971   5.599  28.162  1.00 52.09           C  
+ATOM    975  CG2 ILE A 151       8.250   4.559  28.037  1.00 50.07           C  
+ATOM    976  CD1 ILE A 151       5.704   5.492  26.675  0.00 51.50           C  
+ATOM    977  N   LEU A 152       9.728   7.067  30.263  1.00 51.75           N  
+ATOM    978  CA  LEU A 152      11.144   7.175  30.559  1.00 52.47           C  
+ATOM    979  C   LEU A 152      11.390   7.043  32.061  1.00 52.35           C  
+ATOM    980  O   LEU A 152      12.316   6.351  32.484  1.00 51.55           O  
+ATOM    981  CB  LEU A 152      11.692   8.504  30.020  1.00 52.62           C  
+ATOM    982  CG  LEU A 152      12.276   8.453  28.595  1.00 53.99           C  
+ATOM    983  CD1 LEU A 152      11.403   7.611  27.679  1.00 52.97           C  
+ATOM    984  CD2 LEU A 152      12.426   9.866  28.050  1.00 52.94           C  
+ATOM    985  N   ILE A 153      10.554   7.698  32.860  1.00 51.01           N  
+ATOM    986  CA  ILE A 153      10.683   7.636  34.306  1.00 50.18           C  
+ATOM    987  C   ILE A 153      10.513   6.197  34.792  1.00 50.69           C  
+ATOM    988  O   ILE A 153      11.314   5.704  35.587  1.00 49.99           O  
+ATOM    989  CB  ILE A 153       9.625   8.514  35.003  1.00 50.42           C  
+ATOM    990  CG1 ILE A 153       9.908   9.996  34.730  1.00 50.02           C  
+ATOM    991  CG2 ILE A 153       9.616   8.220  36.496  1.00 48.95           C  
+ATOM    992  CD1 ILE A 153       8.890  10.940  35.337  0.00 50.19           C  
+ATOM    993  N   GLY A 154       9.464   5.534  34.315  1.00 49.50           N  
+ATOM    994  CA  GLY A 154       9.212   4.161  34.714  1.00 50.88           C  
+ATOM    995  C   GLY A 154      10.321   3.229  34.261  1.00 51.39           C  
+ATOM    996  O   GLY A 154      10.604   2.212  34.898  1.00 50.35           O  
+ATOM    997  N   MET A 155      10.954   3.585  33.150  1.00 51.07           N  
+ATOM    998  CA  MET A 155      12.039   2.795  32.594  1.00 50.75           C  
+ATOM    999  C   MET A 155      13.240   2.883  33.534  1.00 49.16           C  
+ATOM   1000  O   MET A 155      13.936   1.893  33.766  1.00 47.03           O  
+ATOM   1001  CB  MET A 155      12.403   3.337  31.214  1.00 55.70           C  
+ATOM   1002  CG  MET A 155      13.209   2.391  30.351  1.00 61.00           C  
+ATOM   1003  SD  MET A 155      13.342   3.032  28.665  1.00 70.42           S  
+ATOM   1004  CE  MET A 155      14.910   3.916  28.763  1.00 68.02           C  
+ATOM   1005  N   ILE A 156      13.471   4.077  34.073  1.00 45.75           N  
+ATOM   1006  CA  ILE A 156      14.569   4.303  34.999  1.00 44.80           C  
+ATOM   1007  C   ILE A 156      14.354   3.483  36.279  1.00 44.86           C  
+ATOM   1008  O   ILE A 156      15.272   2.814  36.762  1.00 44.21           O  
+ATOM   1009  CB  ILE A 156      14.679   5.800  35.370  1.00 44.62           C  
+ATOM   1010  CG1 ILE A 156      15.260   6.590  34.186  1.00 44.78           C  
+ATOM   1011  CG2 ILE A 156      15.526   5.970  36.627  1.00 41.37           C  
+ATOM   1012  CD1 ILE A 156      15.332   8.082  34.423  0.00 44.81           C  
+ATOM   1013  N   LEU A 157      13.138   3.538  36.816  1.00 42.56           N  
+ATOM   1014  CA  LEU A 157      12.798   2.810  38.031  1.00 42.81           C  
+ATOM   1015  C   LEU A 157      12.925   1.299  37.846  1.00 42.94           C  
+ATOM   1016  O   LEU A 157      13.421   0.613  38.735  1.00 44.23           O  
+ATOM   1017  CB  LEU A 157      11.380   3.172  38.484  1.00 42.11           C  
+ATOM   1018  CG  LEU A 157      11.199   4.626  38.933  1.00 40.87           C  
+ATOM   1019  CD1 LEU A 157       9.731   4.924  39.211  1.00 39.40           C  
+ATOM   1020  CD2 LEU A 157      12.041   4.868  40.171  1.00 42.13           C  
+ATOM   1021  N   SER A 158      12.484   0.783  36.700  1.00 41.20           N  
+ATOM   1022  CA  SER A 158      12.589  -0.648  36.424  1.00 41.43           C  
+ATOM   1023  C   SER A 158      14.054  -1.065  36.441  1.00 41.91           C  
+ATOM   1024  O   SER A 158      14.403  -2.124  36.969  1.00 43.82           O  
+ATOM   1025  CB  SER A 158      11.982  -0.992  35.058  1.00 40.11           C  
+ATOM   1026  OG  SER A 158      10.583  -0.779  35.056  1.00 39.65           O  
+ATOM   1027  N   GLY A 159      14.909  -0.237  35.850  1.00 40.10           N  
+ATOM   1028  CA  GLY A 159      16.324  -0.544  35.842  1.00 38.33           C  
+ATOM   1029  C   GLY A 159      16.854  -0.613  37.265  1.00 37.65           C  
+ATOM   1030  O   GLY A 159      17.569  -1.541  37.625  1.00 38.29           O  
+ATOM   1031  N   LEU A 160      16.490   0.374  38.075  1.00 36.64           N  
+ATOM   1032  CA  LEU A 160      16.927   0.440  39.461  1.00 38.93           C  
+ATOM   1033  C   LEU A 160      16.455  -0.767  40.270  1.00 39.36           C  
+ATOM   1034  O   LEU A 160      17.245  -1.396  40.979  1.00 39.01           O  
+ATOM   1035  CB  LEU A 160      16.410   1.726  40.104  1.00 39.13           C  
+ATOM   1036  CG  LEU A 160      17.380   2.891  40.338  1.00 42.81           C  
+ATOM   1037  CD1 LEU A 160      18.520   2.871  39.337  1.00 42.07           C  
+ATOM   1038  CD2 LEU A 160      16.600   4.200  40.258  1.00 41.29           C  
+ATOM   1039  N   PHE A 161      15.174  -1.093  40.151  1.00 38.13           N  
+ATOM   1040  CA  PHE A 161      14.606  -2.215  40.883  1.00 39.21           C  
+ATOM   1041  C   PHE A 161      15.121  -3.585  40.467  1.00 40.32           C  
+ATOM   1042  O   PHE A 161      15.302  -4.462  41.315  1.00 40.49           O  
+ATOM   1043  CB  PHE A 161      13.081  -2.180  40.790  1.00 37.05           C  
+ATOM   1044  CG  PHE A 161      12.451  -1.166  41.700  1.00 40.15           C  
+ATOM   1045  CD1 PHE A 161      11.511  -0.258  41.215  1.00 39.86           C  
+ATOM   1046  CD2 PHE A 161      12.806  -1.113  43.051  1.00 39.89           C  
+ATOM   1047  CE1 PHE A 161      10.933   0.693  42.058  1.00 41.74           C  
+ATOM   1048  CE2 PHE A 161      12.234  -0.167  43.905  1.00 42.49           C  
+ATOM   1049  CZ  PHE A 161      11.294   0.740  43.407  1.00 42.44           C  
+ATOM   1050  N   SER A 162      15.363  -3.778  39.174  1.00 40.07           N  
+ATOM   1051  CA  SER A 162      15.851  -5.067  38.713  1.00 41.09           C  
+ATOM   1052  C   SER A 162      17.327  -5.227  39.047  1.00 40.17           C  
+ATOM   1053  O   SER A 162      17.856  -6.333  39.032  1.00 42.49           O  
+ATOM   1054  CB  SER A 162      15.616  -5.236  37.203  1.00 39.91           C  
+ATOM   1055  OG  SER A 162      16.404  -4.343  36.449  1.00 46.01           O  
+ATOM   1056  N   ALA A 163      17.990  -4.118  39.347  1.00 39.32           N  
+ATOM   1057  CA  ALA A 163      19.403  -4.154  39.702  1.00 38.14           C  
+ATOM   1058  C   ALA A 163      19.496  -4.493  41.186  1.00 37.90           C  
+ATOM   1059  O   ALA A 163      20.414  -5.188  41.619  1.00 36.50           O  
+ATOM   1060  CB  ALA A 163      20.054  -2.808  39.436  1.00 33.35           C  
+ATOM   1061  N   LEU A 164      18.543  -3.986  41.959  1.00 37.97           N  
+ATOM   1062  CA  LEU A 164      18.517  -4.249  43.384  1.00 40.57           C  
+ATOM   1063  C   LEU A 164      18.139  -5.708  43.591  1.00 40.37           C  
+ATOM   1064  O   LEU A 164      18.662  -6.364  44.481  1.00 42.22           O  
+ATOM   1065  CB  LEU A 164      17.521  -3.316  44.076  1.00 41.99           C  
+ATOM   1066  CG  LEU A 164      17.911  -1.839  43.955  1.00 43.25           C  
+ATOM   1067  CD1 LEU A 164      16.866  -0.962  44.622  1.00 43.69           C  
+ATOM   1068  CD2 LEU A 164      19.278  -1.623  44.592  1.00 43.59           C  
+ATOM   1069  N   VAL A 165      17.242  -6.211  42.746  1.00 40.10           N  
+ATOM   1070  CA  VAL A 165      16.817  -7.600  42.817  1.00 38.82           C  
+ATOM   1071  C   VAL A 165      18.031  -8.482  42.561  1.00 39.80           C  
+ATOM   1072  O   VAL A 165      18.232  -9.494  43.236  1.00 39.63           O  
+ATOM   1073  CB  VAL A 165      15.731  -7.913  41.757  1.00 38.77           C  
+ATOM   1074  CG1 VAL A 165      15.572  -9.424  41.587  1.00 35.28           C  
+ATOM   1075  CG2 VAL A 165      14.407  -7.291  42.173  1.00 34.63           C  
+ATOM   1076  N   SER A 166      18.831  -8.096  41.572  1.00 39.43           N  
+ATOM   1077  CA  SER A 166      20.040  -8.833  41.227  1.00 39.33           C  
+ATOM   1078  C   SER A 166      21.052  -8.750  42.355  1.00 38.18           C  
+ATOM   1079  O   SER A 166      21.784  -9.699  42.608  1.00 37.33           O  
+ATOM   1080  CB  SER A 166      20.686  -8.267  39.960  1.00 36.95           C  
+ATOM   1081  OG  SER A 166      20.003  -8.701  38.808  1.00 41.82           O  
+ATOM   1082  N   LEU A 167      21.103  -7.600  43.014  1.00 38.01           N  
+ATOM   1083  CA  LEU A 167      22.041  -7.406  44.107  1.00 40.08           C  
+ATOM   1084  C   LEU A 167      21.693  -8.365  45.239  1.00 41.32           C  
+ATOM   1085  O   LEU A 167      22.558  -9.075  45.748  1.00 41.02           O  
+ATOM   1086  CB  LEU A 167      21.966  -5.973  44.632  1.00 37.84           C  
+ATOM   1087  CG  LEU A 167      23.239  -5.355  45.221  1.00 39.34           C  
+ATOM   1088  CD1 LEU A 167      22.832  -4.483  46.386  1.00 37.13           C  
+ATOM   1089  CD2 LEU A 167      24.241  -6.411  45.664  1.00 37.21           C  
+ATOM   1090  N   LEU A 168      20.420  -8.371  45.627  1.00 41.88           N  
+ATOM   1091  CA  LEU A 168      19.953  -9.231  46.706  1.00 46.10           C  
+ATOM   1092  C   LEU A 168      20.232 -10.707  46.451  1.00 47.77           C  
+ATOM   1093  O   LEU A 168      20.765 -11.400  47.318  1.00 48.08           O  
+ATOM   1094  CB  LEU A 168      18.455  -9.028  46.949  1.00 46.14           C  
+ATOM   1095  CG  LEU A 168      18.070  -7.725  47.653  1.00 47.35           C  
+ATOM   1096  CD1 LEU A 168      16.565  -7.663  47.802  1.00 50.58           C  
+ATOM   1097  CD2 LEU A 168      18.742  -7.642  49.013  1.00 47.27           C  
+ATOM   1098  N   GLN A 169      19.886 -11.194  45.266  1.00 47.92           N  
+ATOM   1099  CA  GLN A 169      20.124 -12.593  44.991  1.00 50.40           C  
+ATOM   1100  C   GLN A 169      21.616 -12.906  44.911  1.00 50.97           C  
+ATOM   1101  O   GLN A 169      22.025 -14.043  45.144  1.00 51.87           O  
+ATOM   1102  CB  GLN A 169      19.378 -13.033  43.724  1.00 50.60           C  
+ATOM   1103  CG  GLN A 169      19.816 -12.400  42.443  1.00 54.48           C  
+ATOM   1104  CD  GLN A 169      18.860 -12.708  41.296  1.00 55.73           C  
+ATOM   1105  OE1 GLN A 169      19.127 -12.363  40.144  1.00 59.73           O  
+ATOM   1106  NE2 GLN A 169      17.740 -13.349  41.607  1.00 51.83           N  
+ATOM   1107  N   TYR A 170      22.432 -11.899  44.616  1.00 49.31           N  
+ATOM   1108  CA  TYR A 170      23.871 -12.111  44.540  1.00 47.75           C  
+ATOM   1109  C   TYR A 170      24.483 -12.236  45.937  1.00 49.18           C  
+ATOM   1110  O   TYR A 170      25.413 -13.013  46.142  1.00 47.09           O  
+ATOM   1111  CB  TYR A 170      24.562 -10.968  43.786  1.00 44.00           C  
+ATOM   1112  CG  TYR A 170      26.076 -11.068  43.821  1.00 40.28           C  
+ATOM   1113  CD1 TYR A 170      26.827 -10.319  44.731  1.00 40.65           C  
+ATOM   1114  CD2 TYR A 170      26.751 -11.981  43.005  1.00 38.08           C  
+ATOM   1115  CE1 TYR A 170      28.214 -10.483  44.836  1.00 38.82           C  
+ATOM   1116  CE2 TYR A 170      28.128 -12.154  43.100  1.00 36.97           C  
+ATOM   1117  CZ  TYR A 170      28.855 -11.408  44.019  1.00 40.23           C  
+ATOM   1118  OH  TYR A 170      30.213 -11.626  44.153  1.00 42.60           O  
+ATOM   1119  N   ILE A 171      23.962 -11.469  46.889  1.00 50.44           N  
+ATOM   1120  CA  ILE A 171      24.473 -11.500  48.253  1.00 52.69           C  
+ATOM   1121  C   ILE A 171      23.675 -12.455  49.139  1.00 54.71           C  
+ATOM   1122  O   ILE A 171      23.843 -12.461  50.356  1.00 55.94           O  
+ATOM   1123  CB  ILE A 171      24.443 -10.091  48.912  1.00 51.46           C  
+ATOM   1124  CG1 ILE A 171      23.003  -9.599  49.033  1.00 50.91           C  
+ATOM   1125  CG2 ILE A 171      25.267  -9.106  48.092  1.00 50.86           C  
+ATOM   1126  CD1 ILE A 171      22.866  -8.252  49.715  0.00 51.27           C  
+ATOM   1127  N   SER A 172      22.816 -13.265  48.529  1.00 55.84           N  
+ATOM   1128  CA  SER A 172      21.997 -14.201  49.289  1.00 57.75           C  
+ATOM   1129  C   SER A 172      22.549 -15.622  49.253  1.00 59.50           C  
+ATOM   1130  O   SER A 172      23.239 -16.012  48.309  1.00 58.53           O  
+ATOM   1131  CB  SER A 172      20.566 -14.215  48.747  1.00 56.94           C  
+ATOM   1132  OG  SER A 172      20.508 -14.919  47.520  1.00 57.04           O  
+ATOM   1133  N   ASP A 173      22.227 -16.388  50.292  1.00 61.09           N  
+ATOM   1134  CA  ASP A 173      22.657 -17.775  50.408  1.00 63.15           C  
+ATOM   1135  C   ASP A 173      22.171 -18.588  49.216  1.00 63.71           C  
+ATOM   1136  O   ASP A 173      20.971 -18.697  48.976  1.00 61.73           O  
+ATOM   1137  CB  ASP A 173      22.103 -18.387  51.695  1.00 65.30           C  
+ATOM   1138  CG  ASP A 173      22.196 -19.898  51.702  1.00 68.32           C  
+ATOM   1139  OD1 ASP A 173      23.334 -20.419  51.671  1.00 69.17           O  
+ATOM   1140  OD2 ASP A 173      21.129 -20.561  51.730  1.00 69.96           O  
+ATOM   1141  N   THR A 174      23.104 -19.173  48.479  1.00 66.61           N  
+ATOM   1142  CA  THR A 174      22.748 -19.962  47.305  1.00 71.27           C  
+ATOM   1143  C   THR A 174      22.098 -21.315  47.610  1.00 72.73           C  
+ATOM   1144  O   THR A 174      21.621 -21.994  46.700  1.00 73.32           O  
+ATOM   1145  CB  THR A 174      23.983 -20.202  46.413  1.00 71.93           C  
+ATOM   1146  OG1 THR A 174      23.625 -21.057  45.322  1.00 74.08           O  
+ATOM   1147  CG2 THR A 174      25.103 -20.846  47.214  1.00 72.89           C  
+ATOM   1148  N   GLU A 175      22.069 -21.699  48.885  1.00 74.57           N  
+ATOM   1149  CA  GLU A 175      21.488 -22.979  49.289  1.00 76.10           C  
+ATOM   1150  C   GLU A 175      19.966 -22.984  49.345  1.00 75.78           C  
+ATOM   1151  O   GLU A 175      19.323 -23.867  48.776  1.00 76.48           O  
+ATOM   1152  CB  GLU A 175      22.045 -23.406  50.651  1.00 78.95           C  
+ATOM   1153  CG  GLU A 175      23.547 -23.638  50.653  1.00 82.58           C  
+ATOM   1154  CD  GLU A 175      23.970 -24.718  49.671  1.00 85.41           C  
+ATOM   1155  OE1 GLU A 175      23.630 -25.901  49.901  1.00 86.80           O  
+ATOM   1156  OE2 GLU A 175      24.637 -24.383  48.666  1.00 86.84           O  
+ATOM   1157  N   GLU A 176      19.388 -22.008  50.038  1.00 75.21           N  
+ATOM   1158  CA  GLU A 176      17.937 -21.926  50.158  1.00 75.02           C  
+ATOM   1159  C   GLU A 176      17.371 -20.582  49.701  1.00 73.25           C  
+ATOM   1160  O   GLU A 176      16.374 -20.528  48.977  1.00 73.10           O  
+ATOM   1161  CB  GLU A 176      17.526 -22.208  51.609  1.00 77.94           C  
+ATOM   1162  CG  GLU A 176      16.125 -21.736  51.987  1.00 81.71           C  
+ATOM   1163  CD  GLU A 176      16.101 -20.290  52.466  1.00 83.93           C  
+ATOM   1164  OE1 GLU A 176      14.993 -19.750  52.690  1.00 84.62           O  
+ATOM   1165  OE2 GLU A 176      17.191 -19.696  52.627  1.00 85.33           O  
+ATOM   1166  N   LYS A 177      18.022 -19.506  50.127  1.00 70.82           N  
+ATOM   1167  CA  LYS A 177      17.609 -18.146  49.804  1.00 67.72           C  
+ATOM   1168  C   LYS A 177      17.476 -17.887  48.296  1.00 65.49           C  
+ATOM   1169  O   LYS A 177      16.414 -17.492  47.812  1.00 65.35           O  
+ATOM   1170  CB  LYS A 177      18.620 -17.168  50.406  1.00 69.22           C  
+ATOM   1171  CG  LYS A 177      18.089 -15.775  50.682  1.00 71.61           C  
+ATOM   1172  CD  LYS A 177      17.734 -15.599  52.154  1.00 72.64           C  
+ATOM   1173  CE  LYS A 177      16.607 -16.524  52.578  1.00 72.94           C  
+ATOM   1174  NZ  LYS A 177      16.278 -16.356  54.020  1.00 75.14           N  
+ATOM   1175  N   LEU A 178      18.558 -18.122  47.560  1.00 62.36           N  
+ATOM   1176  CA  LEU A 178      18.593 -17.892  46.118  1.00 59.67           C  
+ATOM   1177  C   LEU A 178      17.493 -18.573  45.305  1.00 58.24           C  
+ATOM   1178  O   LEU A 178      16.775 -17.911  44.560  1.00 58.15           O  
+ATOM   1179  CB  LEU A 178      19.974 -18.282  45.570  1.00 59.70           C  
+ATOM   1180  CG  LEU A 178      20.325 -18.051  44.095  1.00 58.75           C  
+ATOM   1181  CD1 LEU A 178      19.661 -19.102  43.229  1.00 59.95           C  
+ATOM   1182  CD2 LEU A 178      19.907 -16.646  43.677  1.00 57.60           C  
+ATOM   1183  N   PRO A 179      17.352 -19.904  45.425  1.00 57.64           N  
+ATOM   1184  CA  PRO A 179      16.317 -20.623  44.672  1.00 55.59           C  
+ATOM   1185  C   PRO A 179      14.903 -20.080  44.912  1.00 54.54           C  
+ATOM   1186  O   PRO A 179      14.055 -20.104  44.019  1.00 52.58           O  
+ATOM   1187  CB  PRO A 179      16.468 -22.062  45.170  1.00 56.40           C  
+ATOM   1188  CG  PRO A 179      17.914 -22.152  45.514  1.00 56.07           C  
+ATOM   1189  CD  PRO A 179      18.156 -20.844  46.226  1.00 57.62           C  
+ATOM   1190  N   SER A 180      14.657 -19.602  46.129  1.00 53.64           N  
+ATOM   1191  CA  SER A 180      13.353 -19.060  46.485  1.00 53.31           C  
+ATOM   1192  C   SER A 180      13.111 -17.765  45.729  1.00 52.02           C  
+ATOM   1193  O   SER A 180      12.032 -17.557  45.184  1.00 51.79           O  
+ATOM   1194  CB  SER A 180      13.277 -18.797  47.988  1.00 53.49           C  
+ATOM   1195  OG  SER A 180      13.485 -19.993  48.713  1.00 58.20           O  
+ATOM   1196  N   ILE A 181      14.120 -16.897  45.706  1.00 50.44           N  
+ATOM   1197  CA  ILE A 181      14.017 -15.627  45.002  1.00 48.97           C  
+ATOM   1198  C   ILE A 181      13.815 -15.902  43.513  1.00 49.61           C  
+ATOM   1199  O   ILE A 181      12.879 -15.397  42.897  1.00 49.54           O  
+ATOM   1200  CB  ILE A 181      15.299 -14.771  45.178  1.00 47.58           C  
+ATOM   1201  CG1 ILE A 181      15.485 -14.387  46.650  1.00 43.55           C  
+ATOM   1202  CG2 ILE A 181      15.216 -13.526  44.299  1.00 44.10           C  
+ATOM   1203  CD1 ILE A 181      16.744 -13.590  46.924  0.00 45.20           C  
+ATOM   1204  N   VAL A 182      14.687 -16.729  42.950  1.00 49.11           N  
+ATOM   1205  CA  VAL A 182      14.626 -17.064  41.534  1.00 50.19           C  
+ATOM   1206  C   VAL A 182      13.291 -17.616  41.047  1.00 52.11           C  
+ATOM   1207  O   VAL A 182      12.769 -17.171  40.025  1.00 52.99           O  
+ATOM   1208  CB  VAL A 182      15.732 -18.073  41.156  1.00 48.71           C  
+ATOM   1209  CG1 VAL A 182      15.598 -18.477  39.696  1.00 47.51           C  
+ATOM   1210  CG2 VAL A 182      17.101 -17.457  41.412  1.00 47.64           C  
+ATOM   1211  N   PHE A 183      12.735 -18.584  41.765  1.00 53.99           N  
+ATOM   1212  CA  PHE A 183      11.475 -19.181  41.339  1.00 55.22           C  
+ATOM   1213  C   PHE A 183      10.258 -18.308  41.599  1.00 54.08           C  
+ATOM   1214  O   PHE A 183       9.282 -18.373  40.856  1.00 54.18           O  
+ATOM   1215  CB  PHE A 183      11.294 -20.562  41.982  1.00 57.68           C  
+ATOM   1216  CG  PHE A 183      12.316 -21.581  41.534  1.00 60.83           C  
+ATOM   1217  CD1 PHE A 183      12.340 -22.854  42.095  1.00 63.77           C  
+ATOM   1218  CD2 PHE A 183      13.268 -21.263  40.565  1.00 62.25           C  
+ATOM   1219  CE1 PHE A 183      13.297 -23.793  41.703  1.00 64.46           C  
+ATOM   1220  CE2 PHE A 183      14.227 -22.193  40.167  1.00 63.37           C  
+ATOM   1221  CZ  PHE A 183      14.242 -23.460  40.739  1.00 63.62           C  
+ATOM   1222  N   TRP A 184      10.304 -17.486  42.640  1.00 53.30           N  
+ATOM   1223  CA  TRP A 184       9.169 -16.617  42.910  1.00 53.51           C  
+ATOM   1224  C   TRP A 184       9.045 -15.579  41.793  1.00 54.72           C  
+ATOM   1225  O   TRP A 184       7.943 -15.159  41.444  1.00 56.16           O  
+ATOM   1226  CB  TRP A 184       9.322 -15.894  44.246  1.00 51.42           C  
+ATOM   1227  CG  TRP A 184       8.147 -15.000  44.525  1.00 52.05           C  
+ATOM   1228  CD1 TRP A 184       6.890 -15.390  44.888  1.00 52.57           C  
+ATOM   1229  CD2 TRP A 184       8.101 -13.574  44.397  1.00 50.88           C  
+ATOM   1230  NE1 TRP A 184       6.063 -14.298  44.991  1.00 52.66           N  
+ATOM   1231  CE2 TRP A 184       6.780 -13.170  44.694  1.00 50.34           C  
+ATOM   1232  CE3 TRP A 184       9.047 -12.598  44.056  1.00 51.34           C  
+ATOM   1233  CZ2 TRP A 184       6.379 -11.833  44.663  1.00 48.91           C  
+ATOM   1234  CZ3 TRP A 184       8.649 -11.267  44.024  1.00 50.17           C  
+ATOM   1235  CH2 TRP A 184       7.325 -10.898  44.327  1.00 49.16           C  
+ATOM   1236  N   LEU A 185      10.179 -15.168  41.233  1.00 54.58           N  
+ATOM   1237  CA  LEU A 185      10.175 -14.181  40.159  1.00 55.14           C  
+ATOM   1238  C   LEU A 185       9.563 -14.755  38.894  1.00 55.60           C  
+ATOM   1239  O   LEU A 185       9.293 -14.024  37.944  1.00 58.14           O  
+ATOM   1240  CB  LEU A 185      11.596 -13.687  39.870  1.00 52.00           C  
+ATOM   1241  CG  LEU A 185      12.262 -12.910  41.009  1.00 50.17           C  
+ATOM   1242  CD1 LEU A 185      13.699 -12.591  40.638  1.00 50.70           C  
+ATOM   1243  CD2 LEU A 185      11.481 -11.640  41.294  1.00 49.66           C  
+ATOM   1244  N   MET A 186       9.341 -16.062  38.876  1.00 55.79           N  
+ATOM   1245  CA  MET A 186       8.747 -16.684  37.706  1.00 57.05           C  
+ATOM   1246  C   MET A 186       7.226 -16.721  37.783  1.00 56.63           C  
+ATOM   1247  O   MET A 186       6.548 -16.812  36.769  1.00 57.34           O  
+ATOM   1248  CB  MET A 186       9.311 -18.089  37.506  1.00 59.40           C  
+ATOM   1249  CG  MET A 186      10.680 -18.076  36.859  1.00 62.33           C  
+ATOM   1250  SD  MET A 186      11.352 -19.714  36.576  1.00 66.64           S  
+ATOM   1251  CE  MET A 186      12.920 -19.591  37.464  1.00 64.57           C  
+ATOM   1252  N   GLY A 187       6.685 -16.641  38.988  1.00 55.40           N  
+ATOM   1253  CA  GLY A 187       5.242 -16.643  39.126  1.00 54.90           C  
+ATOM   1254  C   GLY A 187       4.526 -17.869  38.595  1.00 53.64           C  
+ATOM   1255  O   GLY A 187       4.830 -18.384  37.518  1.00 53.85           O  
+ATOM   1256  N   SER A 188       3.559 -18.336  39.375  1.00 52.42           N  
+ATOM   1257  CA  SER A 188       2.761 -19.500  39.015  1.00 50.85           C  
+ATOM   1258  C   SER A 188       1.563 -19.521  39.939  1.00 48.25           C  
+ATOM   1259  O   SER A 188       1.474 -18.721  40.872  1.00 45.22           O  
+ATOM   1260  CB  SER A 188       3.561 -20.797  39.193  1.00 53.18           C  
+ATOM   1261  OG  SER A 188       3.640 -21.175  40.559  1.00 52.52           O  
+ATOM   1262  N   PHE A 189       0.646 -20.441  39.672  1.00 47.47           N  
+ATOM   1263  CA  PHE A 189      -0.559 -20.582  40.475  1.00 47.84           C  
+ATOM   1264  C   PHE A 189      -0.518 -21.904  41.248  1.00 48.97           C  
+ATOM   1265  O   PHE A 189      -1.522 -22.332  41.824  1.00 49.02           O  
+ATOM   1266  CB  PHE A 189      -1.783 -20.541  39.559  1.00 46.54           C  
+ATOM   1267  CG  PHE A 189      -1.903 -19.266  38.760  1.00 46.06           C  
+ATOM   1268  CD1 PHE A 189      -2.067 -19.308  37.381  1.00 43.81           C  
+ATOM   1269  CD2 PHE A 189      -1.880 -18.023  39.391  1.00 45.55           C  
+ATOM   1270  CE1 PHE A 189      -2.209 -18.133  36.640  1.00 44.32           C  
+ATOM   1271  CE2 PHE A 189      -2.021 -16.843  38.658  1.00 44.37           C  
+ATOM   1272  CZ  PHE A 189      -2.186 -16.899  37.279  1.00 42.23           C  
+ATOM   1273  N   ALA A 190       0.654 -22.535  41.265  1.00 49.13           N  
+ATOM   1274  CA  ALA A 190       0.836 -23.818  41.941  1.00 50.42           C  
+ATOM   1275  C   ALA A 190       0.572 -23.758  43.445  1.00 50.63           C  
+ATOM   1276  O   ALA A 190       0.118 -24.735  44.033  1.00 51.08           O  
+ATOM   1277  CB  ALA A 190       2.242 -24.359  41.672  1.00 47.30           C  
+ATOM   1278  N   THR A 191       0.857 -22.623  44.073  1.00 50.52           N  
+ATOM   1279  CA  THR A 191       0.609 -22.499  45.501  1.00 50.50           C  
+ATOM   1280  C   THR A 191      -0.571 -21.577  45.766  1.00 49.91           C  
+ATOM   1281  O   THR A 191      -0.572 -20.828  46.742  1.00 50.15           O  
+ATOM   1282  CB  THR A 191       1.839 -21.953  46.263  1.00 52.11           C  
+ATOM   1283  OG1 THR A 191       2.106 -20.608  45.848  1.00 54.96           O  
+ATOM   1284  CG2 THR A 191       3.066 -22.826  45.998  1.00 50.77           C  
+ATOM   1285  N   SER A 192      -1.580 -21.631  44.900  1.00 50.53           N  
+ATOM   1286  CA  SER A 192      -2.755 -20.787  45.082  1.00 53.46           C  
+ATOM   1287  C   SER A 192      -3.759 -21.436  46.033  1.00 54.66           C  
+ATOM   1288  O   SER A 192      -4.009 -22.639  45.955  1.00 55.93           O  
+ATOM   1289  CB  SER A 192      -3.420 -20.495  43.732  1.00 53.85           C  
+ATOM   1290  OG  SER A 192      -3.928 -21.672  43.139  1.00 56.82           O  
+ATOM   1291  N   ASN A 193      -4.325 -20.630  46.931  1.00 55.07           N  
+ATOM   1292  CA  ASN A 193      -5.297 -21.105  47.912  1.00 54.69           C  
+ATOM   1293  C   ASN A 193      -6.385 -20.058  48.175  1.00 54.70           C  
+ATOM   1294  O   ASN A 193      -6.290 -18.929  47.697  1.00 53.56           O  
+ATOM   1295  CB  ASN A 193      -4.589 -21.449  49.223  1.00 55.68           C  
+ATOM   1296  CG  ASN A 193      -3.874 -20.259  49.827  1.00 56.20           C  
+ATOM   1297  OD1 ASN A 193      -4.467 -19.195  50.022  1.00 57.21           O  
+ATOM   1298  ND2 ASN A 193      -2.594 -20.432  50.133  1.00 55.42           N  
+ATOM   1299  N   TRP A 194      -7.410 -20.428  48.944  1.00 53.10           N  
+ATOM   1300  CA  TRP A 194      -8.503 -19.505  49.238  1.00 53.85           C  
+ATOM   1301  C   TRP A 194      -8.076 -18.226  49.963  1.00 54.16           C  
+ATOM   1302  O   TRP A 194      -8.717 -17.182  49.826  1.00 52.83           O  
+ATOM   1303  CB  TRP A 194      -9.607 -20.209  50.042  1.00 53.28           C  
+ATOM   1304  CG  TRP A 194     -10.391 -21.207  49.235  1.00 53.89           C  
+ATOM   1305  CD1 TRP A 194     -10.267 -22.567  49.265  1.00 51.95           C  
+ATOM   1306  CD2 TRP A 194     -11.380 -20.918  48.235  1.00 54.13           C  
+ATOM   1307  NE1 TRP A 194     -11.111 -23.141  48.346  1.00 53.43           N  
+ATOM   1308  CE2 TRP A 194     -11.806 -22.153  47.699  1.00 53.71           C  
+ATOM   1309  CE3 TRP A 194     -11.945 -19.733  47.739  1.00 53.68           C  
+ATOM   1310  CZ2 TRP A 194     -12.774 -22.241  46.689  1.00 54.59           C  
+ATOM   1311  CZ3 TRP A 194     -12.907 -19.819  46.734  1.00 53.55           C  
+ATOM   1312  CH2 TRP A 194     -13.310 -21.067  46.221  1.00 54.47           C  
+ATOM   1313  N   GLU A 195      -6.999 -18.297  50.732  1.00 54.90           N  
+ATOM   1314  CA  GLU A 195      -6.536 -17.118  51.450  1.00 56.29           C  
+ATOM   1315  C   GLU A 195      -6.003 -16.062  50.477  1.00 55.67           C  
+ATOM   1316  O   GLU A 195      -6.270 -14.870  50.639  1.00 53.85           O  
+ATOM   1317  CB  GLU A 195      -5.453 -17.506  52.459  1.00 58.34           C  
+ATOM   1318  CG  GLU A 195      -4.887 -16.333  53.235  1.00 62.99           C  
+ATOM   1319  CD  GLU A 195      -3.893 -16.759  54.302  1.00 66.01           C  
+ATOM   1320  OE1 GLU A 195      -2.910 -17.458  53.969  1.00 66.71           O  
+ATOM   1321  OE2 GLU A 195      -4.095 -16.387  55.476  1.00 67.60           O  
+ATOM   1322  N   LYS A 196      -5.255 -16.504  49.468  1.00 54.20           N  
+ATOM   1323  CA  LYS A 196      -4.691 -15.595  48.471  1.00 54.00           C  
+ATOM   1324  C   LYS A 196      -5.758 -15.064  47.523  1.00 53.36           C  
+ATOM   1325  O   LYS A 196      -5.795 -13.873  47.223  1.00 52.02           O  
+ATOM   1326  CB  LYS A 196      -3.605 -16.298  47.655  1.00 54.19           C  
+ATOM   1327  CG  LYS A 196      -2.304 -16.529  48.400  1.00 55.98           C  
+ATOM   1328  CD  LYS A 196      -1.342 -17.336  47.545  1.00 57.88           C  
+ATOM   1329  CE  LYS A 196      -0.028 -17.578  48.255  1.00 58.86           C  
+ATOM   1330  NZ  LYS A 196       0.857 -18.482  47.465  1.00 60.60           N  
+ATOM   1331  N   LEU A 197      -6.625 -15.956  47.056  1.00 53.04           N  
+ATOM   1332  CA  LEU A 197      -7.688 -15.571  46.141  1.00 53.35           C  
+ATOM   1333  C   LEU A 197      -8.528 -14.445  46.729  1.00 54.30           C  
+ATOM   1334  O   LEU A 197      -8.809 -13.457  46.052  1.00 54.35           O  
+ATOM   1335  CB  LEU A 197      -8.594 -16.765  45.833  1.00 52.57           C  
+ATOM   1336  CG  LEU A 197      -9.155 -16.857  44.408  1.00 55.39           C  
+ATOM   1337  CD1 LEU A 197     -10.349 -17.806  44.403  1.00 53.88           C  
+ATOM   1338  CD2 LEU A 197      -9.569 -15.479  43.901  1.00 52.94           C  
+ATOM   1339  N   LEU A 198      -8.927 -14.590  47.989  1.00 54.65           N  
+ATOM   1340  CA  LEU A 198      -9.750 -13.574  48.633  1.00 56.39           C  
+ATOM   1341  C   LEU A 198      -8.980 -12.284  48.892  1.00 56.42           C  
+ATOM   1342  O   LEU A 198      -9.561 -11.198  48.898  1.00 56.54           O  
+ATOM   1343  CB  LEU A 198     -10.336 -14.115  49.942  1.00 57.31           C  
+ATOM   1344  CG  LEU A 198     -11.203 -15.372  49.784  1.00 59.73           C  
+ATOM   1345  CD1 LEU A 198     -11.673 -15.853  51.154  1.00 60.13           C  
+ATOM   1346  CD2 LEU A 198     -12.393 -15.077  48.879  1.00 59.70           C  
+ATOM   1347  N   PHE A 199      -7.674 -12.398  49.105  1.00 55.37           N  
+ATOM   1348  CA  PHE A 199      -6.852 -11.218  49.341  1.00 55.61           C  
+ATOM   1349  C   PHE A 199      -6.831 -10.362  48.071  1.00 55.67           C  
+ATOM   1350  O   PHE A 199      -7.044  -9.151  48.117  1.00 54.87           O  
+ATOM   1351  CB  PHE A 199      -5.421 -11.625  49.696  1.00 56.15           C  
+ATOM   1352  CG  PHE A 199      -4.449 -10.480  49.692  1.00 58.37           C  
+ATOM   1353  CD1 PHE A 199      -4.448  -9.545  50.723  1.00 59.68           C  
+ATOM   1354  CD2 PHE A 199      -3.550 -10.320  48.640  1.00 58.71           C  
+ATOM   1355  CE1 PHE A 199      -3.564  -8.466  50.709  1.00 59.49           C  
+ATOM   1356  CE2 PHE A 199      -2.666  -9.249  48.615  1.00 59.04           C  
+ATOM   1357  CZ  PHE A 199      -2.672  -8.317  49.654  1.00 59.54           C  
+ATOM   1358  N   PHE A 200      -6.572 -11.014  46.943  1.00 53.34           N  
+ATOM   1359  CA  PHE A 200      -6.504 -10.353  45.648  1.00 52.61           C  
+ATOM   1360  C   PHE A 200      -7.878  -9.950  45.121  1.00 53.04           C  
+ATOM   1361  O   PHE A 200      -8.038  -8.882  44.524  1.00 53.01           O  
+ATOM   1362  CB  PHE A 200      -5.806 -11.280  44.647  1.00 49.87           C  
+ATOM   1363  CG  PHE A 200      -5.879 -10.809  43.226  1.00 51.37           C  
+ATOM   1364  CD1 PHE A 200      -6.797 -11.365  42.344  1.00 51.25           C  
+ATOM   1365  CD2 PHE A 200      -5.037  -9.803  42.767  1.00 50.44           C  
+ATOM   1366  CE1 PHE A 200      -6.874 -10.927  41.028  1.00 50.46           C  
+ATOM   1367  CE2 PHE A 200      -5.109  -9.361  41.451  1.00 50.33           C  
+ATOM   1368  CZ  PHE A 200      -6.028  -9.922  40.582  1.00 48.74           C  
+ATOM   1369  N   PHE A 201      -8.868 -10.805  45.353  1.00 52.82           N  
+ATOM   1370  CA  PHE A 201     -10.225 -10.558  44.887  1.00 51.70           C  
+ATOM   1371  C   PHE A 201     -10.812  -9.223  45.322  1.00 50.43           C  
+ATOM   1372  O   PHE A 201     -11.534  -8.589  44.557  1.00 51.51           O  
+ATOM   1373  CB  PHE A 201     -11.152 -11.696  45.325  1.00 52.73           C  
+ATOM   1374  CG  PHE A 201     -12.535 -11.595  44.755  1.00 53.24           C  
+ATOM   1375  CD1 PHE A 201     -13.548 -10.942  45.458  1.00 53.94           C  
+ATOM   1376  CD2 PHE A 201     -12.812 -12.097  43.484  1.00 52.39           C  
+ATOM   1377  CE1 PHE A 201     -14.817 -10.785  44.902  1.00 53.92           C  
+ATOM   1378  CE2 PHE A 201     -14.075 -11.947  42.914  1.00 52.34           C  
+ATOM   1379  CZ  PHE A 201     -15.081 -11.289  43.624  1.00 54.62           C  
+ATOM   1380  N   VAL A 202     -10.515  -8.786  46.538  1.00 49.78           N  
+ATOM   1381  CA  VAL A 202     -11.049  -7.511  47.003  1.00 49.67           C  
+ATOM   1382  C   VAL A 202     -10.546  -6.346  46.133  1.00 49.49           C  
+ATOM   1383  O   VAL A 202     -11.344  -5.575  45.604  1.00 47.88           O  
+ATOM   1384  CB  VAL A 202     -10.692  -7.254  48.492  1.00 49.92           C  
+ATOM   1385  CG1 VAL A 202     -11.156  -5.877  48.912  1.00 47.94           C  
+ATOM   1386  CG2 VAL A 202     -11.350  -8.303  49.373  1.00 50.61           C  
+ATOM   1387  N   PRO A 203      -9.217  -6.204  45.975  1.00 49.09           N  
+ATOM   1388  CA  PRO A 203      -8.693  -5.107  45.148  1.00 49.14           C  
+ATOM   1389  C   PRO A 203      -9.147  -5.285  43.701  1.00 48.81           C  
+ATOM   1390  O   PRO A 203      -9.499  -4.324  43.015  1.00 47.81           O  
+ATOM   1391  CB  PRO A 203      -7.178  -5.259  45.279  1.00 48.51           C  
+ATOM   1392  CG  PRO A 203      -7.009  -5.966  46.595  1.00 50.64           C  
+ATOM   1393  CD  PRO A 203      -8.117  -6.977  46.574  1.00 48.26           C  
+ATOM   1394  N   PHE A 204      -9.144  -6.537  43.257  1.00 47.87           N  
+ATOM   1395  CA  PHE A 204      -9.539  -6.876  41.902  1.00 48.01           C  
+ATOM   1396  C   PHE A 204     -10.940  -6.380  41.585  1.00 49.28           C  
+ATOM   1397  O   PHE A 204     -11.148  -5.691  40.590  1.00 50.27           O  
+ATOM   1398  CB  PHE A 204      -9.455  -8.390  41.703  1.00 46.15           C  
+ATOM   1399  CG  PHE A 204     -10.048  -8.864  40.414  1.00 45.31           C  
+ATOM   1400  CD1 PHE A 204     -11.249  -9.571  40.407  1.00 44.69           C  
+ATOM   1401  CD2 PHE A 204      -9.425  -8.584  39.202  1.00 42.94           C  
+ATOM   1402  CE1 PHE A 204     -11.823  -9.995  39.212  1.00 43.35           C  
+ATOM   1403  CE2 PHE A 204      -9.988  -9.002  38.001  1.00 44.15           C  
+ATOM   1404  CZ  PHE A 204     -11.194  -9.711  38.004  1.00 43.13           C  
+ATOM   1405  N   LEU A 205     -11.898  -6.727  42.437  1.00 50.00           N  
+ATOM   1406  CA  LEU A 205     -13.286  -6.318  42.239  1.00 50.50           C  
+ATOM   1407  C   LEU A 205     -13.441  -4.805  42.343  1.00 50.19           C  
+ATOM   1408  O   LEU A 205     -14.238  -4.199  41.623  1.00 48.13           O  
+ATOM   1409  CB  LEU A 205     -14.186  -6.988  43.277  1.00 51.00           C  
+ATOM   1410  CG  LEU A 205     -15.682  -6.718  43.143  1.00 53.08           C  
+ATOM   1411  CD1 LEU A 205     -16.200  -7.316  41.838  1.00 51.21           C  
+ATOM   1412  CD2 LEU A 205     -16.412  -7.313  44.340  1.00 53.80           C  
+ATOM   1413  N   LEU A 206     -12.679  -4.202  43.248  1.00 49.45           N  
+ATOM   1414  CA  LEU A 206     -12.731  -2.764  43.454  1.00 50.52           C  
+ATOM   1415  C   LEU A 206     -12.251  -2.040  42.196  1.00 50.49           C  
+ATOM   1416  O   LEU A 206     -13.006  -1.306  41.559  1.00 49.21           O  
+ATOM   1417  CB  LEU A 206     -11.841  -2.376  44.633  1.00 52.42           C  
+ATOM   1418  CG  LEU A 206     -12.352  -1.272  45.557  1.00 55.18           C  
+ATOM   1419  CD1 LEU A 206     -12.686  -0.025  44.751  1.00 57.34           C  
+ATOM   1420  CD2 LEU A 206     -13.590  -1.773  46.295  1.00 58.35           C  
+ATOM   1421  N   CYS A 207     -10.988  -2.270  41.847  1.00 50.42           N  
+ATOM   1422  CA  CYS A 207     -10.357  -1.653  40.684  1.00 48.96           C  
+ATOM   1423  C   CYS A 207     -11.106  -1.883  39.380  1.00 47.44           C  
+ATOM   1424  O   CYS A 207     -11.338  -0.945  38.619  1.00 45.59           O  
+ATOM   1425  CB  CYS A 207      -8.922  -2.160  40.541  1.00 49.58           C  
+ATOM   1426  SG  CYS A 207      -7.835  -1.668  41.899  1.00 51.59           S  
+ATOM   1427  N   SER A 208     -11.477  -3.132  39.125  1.00 46.73           N  
+ATOM   1428  CA  SER A 208     -12.192  -3.477  37.906  1.00 47.80           C  
+ATOM   1429  C   SER A 208     -13.535  -2.767  37.803  1.00 48.48           C  
+ATOM   1430  O   SER A 208     -13.992  -2.449  36.704  1.00 49.32           O  
+ATOM   1431  CB  SER A 208     -12.399  -4.986  37.829  1.00 46.28           C  
+ATOM   1432  OG  SER A 208     -11.148  -5.649  37.827  1.00 49.84           O  
+ATOM   1433  N   SER A 209     -14.164  -2.522  38.949  1.00 48.80           N  
+ATOM   1434  CA  SER A 209     -15.454  -1.844  38.983  1.00 49.31           C  
+ATOM   1435  C   SER A 209     -15.323  -0.376  38.603  1.00 47.45           C  
+ATOM   1436  O   SER A 209     -16.083   0.125  37.779  1.00 45.63           O  
+ATOM   1437  CB  SER A 209     -16.079  -1.949  40.375  1.00 50.97           C  
+ATOM   1438  OG  SER A 209     -16.437  -3.288  40.655  1.00 58.17           O  
+ATOM   1439  N   ILE A 210     -14.374   0.315  39.222  1.00 46.65           N  
+ATOM   1440  CA  ILE A 210     -14.161   1.717  38.916  1.00 46.30           C  
+ATOM   1441  C   ILE A 210     -13.774   1.826  37.439  1.00 46.48           C  
+ATOM   1442  O   ILE A 210     -14.394   2.578  36.686  1.00 44.30           O  
+ATOM   1443  CB  ILE A 210     -13.047   2.319  39.801  1.00 48.06           C  
+ATOM   1444  CG1 ILE A 210     -13.397   2.131  41.285  1.00 47.23           C  
+ATOM   1445  CG2 ILE A 210     -12.881   3.803  39.492  1.00 46.56           C  
+ATOM   1446  CD1 ILE A 210     -12.334   2.639  42.238  0.00 47.67           C  
+ATOM   1447  N   LEU A 211     -12.769   1.054  37.023  1.00 45.43           N  
+ATOM   1448  CA  LEU A 211     -12.323   1.075  35.630  1.00 44.98           C  
+ATOM   1449  C   LEU A 211     -13.471   0.806  34.666  1.00 45.62           C  
+ATOM   1450  O   LEU A 211     -13.550   1.425  33.599  1.00 44.76           O  
+ATOM   1451  CB  LEU A 211     -11.209   0.047  35.388  1.00 42.53           C  
+ATOM   1452  CG  LEU A 211      -9.817   0.398  35.913  1.00 41.85           C  
+ATOM   1453  CD1 LEU A 211      -8.879  -0.776  35.704  1.00 40.21           C  
+ATOM   1454  CD2 LEU A 211      -9.297   1.631  35.193  1.00 41.76           C  
+ATOM   1455  N   LEU A 212     -14.354  -0.122  35.024  1.00 44.83           N  
+ATOM   1456  CA  LEU A 212     -15.488  -0.427  34.157  1.00 45.97           C  
+ATOM   1457  C   LEU A 212     -16.492   0.730  34.139  1.00 46.95           C  
+ATOM   1458  O   LEU A 212     -17.176   0.946  33.138  1.00 47.64           O  
+ATOM   1459  CB  LEU A 212     -16.189  -1.710  34.609  1.00 44.98           C  
+ATOM   1460  CG  LEU A 212     -15.587  -3.059  34.190  1.00 48.28           C  
+ATOM   1461  CD1 LEU A 212     -16.328  -4.184  34.901  1.00 46.77           C  
+ATOM   1462  CD2 LEU A 212     -15.685  -3.242  32.683  1.00 46.66           C  
+ATOM   1463  N   SER A 213     -16.581   1.473  35.240  1.00 45.55           N  
+ATOM   1464  CA  SER A 213     -17.513   2.589  35.304  1.00 47.35           C  
+ATOM   1465  C   SER A 213     -16.977   3.766  34.485  1.00 46.85           C  
+ATOM   1466  O   SER A 213     -17.741   4.628  34.053  1.00 47.92           O  
+ATOM   1467  CB  SER A 213     -17.755   3.018  36.758  1.00 46.00           C  
+ATOM   1468  OG  SER A 213     -16.626   3.678  37.308  1.00 48.49           O  
+ATOM   1469  N   LEU A 214     -15.660   3.784  34.289  1.00 45.19           N  
+ATOM   1470  CA  LEU A 214     -14.969   4.808  33.509  1.00 44.46           C  
+ATOM   1471  C   LEU A 214     -14.784   4.253  32.110  1.00 44.32           C  
+ATOM   1472  O   LEU A 214     -13.997   4.766  31.326  1.00 45.17           O  
+ATOM   1473  CB  LEU A 214     -13.585   5.084  34.086  1.00 43.39           C  
+ATOM   1474  CG  LEU A 214     -13.428   5.920  35.347  1.00 45.77           C  
+ATOM   1475  CD1 LEU A 214     -11.998   5.797  35.828  1.00 45.77           C  
+ATOM   1476  CD2 LEU A 214     -13.777   7.380  35.057  1.00 46.20           C  
+ATOM   1477  N   SER A 215     -15.506   3.181  31.822  1.00 46.22           N  
+ATOM   1478  CA  SER A 215     -15.434   2.499  30.537  1.00 46.36           C  
+ATOM   1479  C   SER A 215     -15.471   3.453  29.341  1.00 47.01           C  
+ATOM   1480  O   SER A 215     -14.597   3.414  28.471  1.00 47.33           O  
+ATOM   1481  CB  SER A 215     -16.588   1.504  30.439  1.00 45.32           C  
+ATOM   1482  OG  SER A 215     -16.327   0.510  29.472  1.00 52.96           O  
+ATOM   1483  N   TRP A 216     -16.482   4.312  29.297  1.00 46.31           N  
+ATOM   1484  CA  TRP A 216     -16.607   5.237  28.183  1.00 45.80           C  
+ATOM   1485  C   TRP A 216     -15.598   6.377  28.226  1.00 45.35           C  
+ATOM   1486  O   TRP A 216     -15.007   6.720  27.207  1.00 46.51           O  
+ATOM   1487  CB  TRP A 216     -18.018   5.814  28.120  1.00 43.08           C  
+ATOM   1488  CG  TRP A 216     -18.226   6.656  26.910  1.00 41.95           C  
+ATOM   1489  CD1 TRP A 216     -18.413   6.221  25.628  1.00 39.75           C  
+ATOM   1490  CD2 TRP A 216     -18.216   8.085  26.853  1.00 37.58           C  
+ATOM   1491  NE1 TRP A 216     -18.520   7.290  24.779  1.00 39.71           N  
+ATOM   1492  CE2 TRP A 216     -18.401   8.449  25.503  1.00 38.12           C  
+ATOM   1493  CE3 TRP A 216     -18.067   9.094  27.813  1.00 36.55           C  
+ATOM   1494  CZ2 TRP A 216     -18.442   9.787  25.083  1.00 35.62           C  
+ATOM   1495  CZ3 TRP A 216     -18.107  10.426  27.397  1.00 37.95           C  
+ATOM   1496  CH2 TRP A 216     -18.294  10.757  26.040  1.00 36.03           C  
+ATOM   1497  N   ARG A 217     -15.398   6.964  29.398  1.00 45.38           N  
+ATOM   1498  CA  ARG A 217     -14.453   8.067  29.523  1.00 47.12           C  
+ATOM   1499  C   ARG A 217     -13.053   7.723  29.024  1.00 46.27           C  
+ATOM   1500  O   ARG A 217     -12.321   8.608  28.595  1.00 45.98           O  
+ATOM   1501  CB  ARG A 217     -14.372   8.540  30.973  1.00 48.48           C  
+ATOM   1502  CG  ARG A 217     -15.683   9.068  31.520  1.00 53.03           C  
+ATOM   1503  CD  ARG A 217     -16.034  10.458  30.998  1.00 55.52           C  
+ATOM   1504  NE  ARG A 217     -15.155  11.502  31.526  1.00 55.50           N  
+ATOM   1505  CZ  ARG A 217     -15.423  12.804  31.445  1.00 56.04           C  
+ATOM   1506  NH1 ARG A 217     -14.578  13.702  31.945  1.00 51.79           N  
+ATOM   1507  NH2 ARG A 217     -16.550  13.208  30.870  1.00 54.11           N  
+ATOM   1508  N   LEU A 218     -12.675   6.449  29.076  1.00 45.92           N  
+ATOM   1509  CA  LEU A 218     -11.343   6.059  28.621  1.00 44.37           C  
+ATOM   1510  C   LEU A 218     -11.134   6.396  27.147  1.00 42.66           C  
+ATOM   1511  O   LEU A 218     -10.000   6.560  26.699  1.00 41.23           O  
+ATOM   1512  CB  LEU A 218     -11.106   4.564  28.862  1.00 47.06           C  
+ATOM   1513  CG  LEU A 218     -11.094   4.124  30.333  1.00 49.27           C  
+ATOM   1514  CD1 LEU A 218     -10.815   2.639  30.402  1.00 49.97           C  
+ATOM   1515  CD2 LEU A 218     -10.039   4.900  31.119  1.00 49.06           C  
+ATOM   1516  N   ASN A 219     -12.227   6.491  26.391  1.00 41.71           N  
+ATOM   1517  CA  ASN A 219     -12.136   6.848  24.980  1.00 40.36           C  
+ATOM   1518  C   ASN A 219     -11.568   8.259  24.834  1.00 39.80           C  
+ATOM   1519  O   ASN A 219     -10.944   8.577  23.825  1.00 38.92           O  
+ATOM   1520  CB  ASN A 219     -13.510   6.805  24.304  1.00 41.99           C  
+ATOM   1521  CG  ASN A 219     -13.999   5.386  24.049  1.00 44.07           C  
+ATOM   1522  OD1 ASN A 219     -13.217   4.496  23.724  1.00 45.14           O  
+ATOM   1523  ND2 ASN A 219     -15.304   5.180  24.174  1.00 44.09           N  
+ATOM   1524  N   LEU A 220     -11.782   9.093  25.852  1.00 38.63           N  
+ATOM   1525  CA  LEU A 220     -11.321  10.479  25.854  1.00 39.84           C  
+ATOM   1526  C   LEU A 220      -9.818  10.619  26.073  1.00 41.80           C  
+ATOM   1527  O   LEU A 220      -9.264  11.717  25.950  1.00 41.72           O  
+ATOM   1528  CB  LEU A 220     -12.060  11.275  26.936  1.00 40.47           C  
+ATOM   1529  CG  LEU A 220     -13.586  11.194  26.943  1.00 39.63           C  
+ATOM   1530  CD1 LEU A 220     -14.130  11.965  28.128  1.00 42.01           C  
+ATOM   1531  CD2 LEU A 220     -14.138  11.734  25.648  1.00 41.55           C  
+ATOM   1532  N   LEU A 221      -9.170   9.511  26.423  1.00 43.75           N  
+ATOM   1533  CA  LEU A 221      -7.722   9.474  26.648  1.00 44.23           C  
+ATOM   1534  C   LEU A 221      -6.993   9.674  25.320  1.00 43.30           C  
+ATOM   1535  O   LEU A 221      -5.824  10.037  25.288  1.00 44.44           O  
+ATOM   1536  CB  LEU A 221      -7.319   8.113  27.233  1.00 45.58           C  
+ATOM   1537  CG  LEU A 221      -7.093   7.865  28.730  1.00 45.78           C  
+ATOM   1538  CD1 LEU A 221      -7.794   8.884  29.598  1.00 44.95           C  
+ATOM   1539  CD2 LEU A 221      -7.578   6.452  29.038  1.00 46.77           C  
+ATOM   1540  N   SER A 222      -7.693   9.413  24.225  1.00 43.09           N  
+ATOM   1541  CA  SER A 222      -7.121   9.558  22.893  1.00 45.88           C  
+ATOM   1542  C   SER A 222      -7.171  11.005  22.390  1.00 46.08           C  
+ATOM   1543  O   SER A 222      -6.572  11.331  21.375  1.00 46.05           O  
+ATOM   1544  CB  SER A 222      -7.877   8.663  21.920  1.00 47.38           C  
+ATOM   1545  OG  SER A 222      -9.231   9.067  21.839  1.00 51.20           O  
+ATOM   1546  N   LEU A 223      -7.896  11.858  23.106  1.00 46.36           N  
+ATOM   1547  CA  LEU A 223      -8.043  13.267  22.748  1.00 46.59           C  
+ATOM   1548  C   LEU A 223      -6.734  14.040  22.906  1.00 48.39           C  
+ATOM   1549  O   LEU A 223      -5.886  13.683  23.728  1.00 49.03           O  
+ATOM   1550  CB  LEU A 223      -9.104  13.914  23.641  1.00 44.61           C  
+ATOM   1551  CG  LEU A 223     -10.534  14.159  23.152  1.00 45.05           C  
+ATOM   1552  CD1 LEU A 223     -11.017  13.031  22.286  1.00 43.44           C  
+ATOM   1553  CD2 LEU A 223     -11.437  14.352  24.365  1.00 43.26           C  
+ATOM   1554  N   ASP A 224      -6.567  15.096  22.115  1.00 48.88           N  
+ATOM   1555  CA  ASP A 224      -5.374  15.920  22.231  1.00 48.25           C  
+ATOM   1556  C   ASP A 224      -5.700  17.026  23.233  1.00 45.86           C  
+ATOM   1557  O   ASP A 224      -6.864  17.306  23.504  1.00 42.90           O  
+ATOM   1558  CB  ASP A 224      -4.966  16.520  20.880  1.00 51.38           C  
+ATOM   1559  CG  ASP A 224      -3.510  16.209  20.519  1.00 56.18           C  
+ATOM   1560  OD1 ASP A 224      -2.935  16.893  19.638  1.00 58.63           O  
+ATOM   1561  OD2 ASP A 224      -2.938  15.267  21.115  1.00 58.36           O  
+ATOM   1562  N   GLU A 225      -4.660  17.639  23.780  1.00 46.72           N  
+ATOM   1563  CA  GLU A 225      -4.793  18.688  24.786  1.00 47.75           C  
+ATOM   1564  C   GLU A 225      -5.918  19.701  24.571  1.00 45.65           C  
+ATOM   1565  O   GLU A 225      -6.806  19.836  25.411  1.00 44.02           O  
+ATOM   1566  CB  GLU A 225      -3.451  19.416  24.934  1.00 50.35           C  
+ATOM   1567  CG  GLU A 225      -3.462  20.534  25.961  1.00 57.59           C  
+ATOM   1568  CD  GLU A 225      -2.068  20.895  26.451  1.00 60.61           C  
+ATOM   1569  OE1 GLU A 225      -1.202  21.214  25.606  1.00 62.10           O  
+ATOM   1570  OE2 GLU A 225      -1.844  20.859  27.685  1.00 61.27           O  
+ATOM   1571  N   LYS A 226      -5.886  20.405  23.447  1.00 44.09           N  
+ATOM   1572  CA  LYS A 226      -6.898  21.411  23.168  1.00 44.55           C  
+ATOM   1573  C   LYS A 226      -8.335  20.909  23.190  1.00 42.65           C  
+ATOM   1574  O   LYS A 226      -9.191  21.504  23.847  1.00 41.88           O  
+ATOM   1575  CB  LYS A 226      -6.604  22.097  21.830  1.00 46.52           C  
+ATOM   1576  CG  LYS A 226      -5.572  23.206  21.945  1.00 49.12           C  
+ATOM   1577  CD  LYS A 226      -5.439  23.997  20.654  1.00 51.85           C  
+ATOM   1578  CE  LYS A 226      -4.584  23.257  19.658  1.00 53.67           C  
+ATOM   1579  NZ  LYS A 226      -3.220  23.049  20.212  1.00 55.45           N  
+ATOM   1580  N   GLU A 227      -8.603  19.823  22.475  1.00 41.82           N  
+ATOM   1581  CA  GLU A 227      -9.953  19.270  22.430  1.00 41.70           C  
+ATOM   1582  C   GLU A 227     -10.387  18.790  23.815  1.00 42.03           C  
+ATOM   1583  O   GLU A 227     -11.552  18.931  24.202  1.00 39.05           O  
+ATOM   1584  CB  GLU A 227     -10.014  18.100  21.447  1.00 42.63           C  
+ATOM   1585  CG  GLU A 227     -11.398  17.473  21.339  1.00 43.61           C  
+ATOM   1586  CD  GLU A 227     -12.396  18.391  20.665  1.00 44.04           C  
+ATOM   1587  OE1 GLU A 227     -13.611  18.099  20.708  1.00 46.36           O  
+ATOM   1588  OE2 GLU A 227     -11.961  19.404  20.079  1.00 44.12           O  
+ATOM   1589  N   ALA A 228      -9.439  18.224  24.557  1.00 42.18           N  
+ATOM   1590  CA  ALA A 228      -9.721  17.718  25.894  1.00 43.22           C  
+ATOM   1591  C   ALA A 228     -10.171  18.842  26.812  1.00 43.81           C  
+ATOM   1592  O   ALA A 228     -11.134  18.690  27.563  1.00 43.39           O  
+ATOM   1593  CB  ALA A 228      -8.485  17.032  26.467  1.00 43.10           C  
+ATOM   1594  N   LYS A 229      -9.480  19.974  26.746  1.00 44.96           N  
+ATOM   1595  CA  LYS A 229      -9.829  21.108  27.588  1.00 48.23           C  
+ATOM   1596  C   LYS A 229     -11.201  21.647  27.187  1.00 49.13           C  
+ATOM   1597  O   LYS A 229     -12.025  21.975  28.044  1.00 48.50           O  
+ATOM   1598  CB  LYS A 229      -8.773  22.207  27.454  1.00 51.85           C  
+ATOM   1599  CG  LYS A 229      -8.441  22.929  28.760  1.00 57.81           C  
+ATOM   1600  CD  LYS A 229      -9.642  23.672  29.329  1.00 61.62           C  
+ATOM   1601  CE  LYS A 229      -9.286  24.388  30.633  1.00 64.13           C  
+ATOM   1602  NZ  LYS A 229      -8.850  23.445  31.705  1.00 64.63           N  
+ATOM   1603  N   ALA A 230     -11.441  21.729  25.880  1.00 48.79           N  
+ATOM   1604  CA  ALA A 230     -12.712  22.230  25.367  1.00 48.44           C  
+ATOM   1605  C   ALA A 230     -13.854  21.318  25.790  1.00 48.57           C  
+ATOM   1606  O   ALA A 230     -14.944  21.784  26.118  1.00 48.15           O  
+ATOM   1607  CB  ALA A 230     -12.663  22.331  23.841  1.00 47.38           C  
+ATOM   1608  N   LEU A 231     -13.596  20.014  25.789  1.00 48.63           N  
+ATOM   1609  CA  LEU A 231     -14.613  19.046  26.166  1.00 48.24           C  
+ATOM   1610  C   LEU A 231     -14.744  18.850  27.670  1.00 51.47           C  
+ATOM   1611  O   LEU A 231     -15.473  17.962  28.121  1.00 54.04           O  
+ATOM   1612  CB  LEU A 231     -14.336  17.706  25.490  1.00 44.61           C  
+ATOM   1613  CG  LEU A 231     -14.512  17.730  23.974  1.00 39.74           C  
+ATOM   1614  CD1 LEU A 231     -14.241  16.351  23.404  1.00 35.00           C  
+ATOM   1615  CD2 LEU A 231     -15.929  18.188  23.645  1.00 35.32           C  
+ATOM   1616  N   GLY A 232     -14.045  19.678  28.443  1.00 52.59           N  
+ATOM   1617  CA  GLY A 232     -14.124  19.583  29.890  1.00 53.23           C  
+ATOM   1618  C   GLY A 232     -13.518  18.326  30.489  1.00 54.84           C  
+ATOM   1619  O   GLY A 232     -13.803  17.979  31.634  1.00 55.50           O  
+ATOM   1620  N   VAL A 233     -12.685  17.638  29.719  1.00 55.46           N  
+ATOM   1621  CA  VAL A 233     -12.036  16.429  30.199  1.00 57.06           C  
+ATOM   1622  C   VAL A 233     -10.821  16.818  31.033  1.00 59.30           C  
+ATOM   1623  O   VAL A 233      -9.998  17.624  30.600  1.00 60.67           O  
+ATOM   1624  CB  VAL A 233     -11.565  15.545  29.027  1.00 56.71           C  
+ATOM   1625  CG1 VAL A 233     -10.846  14.314  29.554  1.00 57.43           C  
+ATOM   1626  CG2 VAL A 233     -12.754  15.144  28.172  1.00 56.52           C  
+ATOM   1627  N   LYS A 234     -10.717  16.250  32.230  1.00 60.69           N  
+ATOM   1628  CA  LYS A 234      -9.592  16.528  33.118  1.00 61.37           C  
+ATOM   1629  C   LYS A 234      -8.562  15.413  32.947  1.00 61.20           C  
+ATOM   1630  O   LYS A 234      -8.486  14.474  33.744  1.00 60.55           O  
+ATOM   1631  CB  LYS A 234     -10.084  16.616  34.565  1.00 63.21           C  
+ATOM   1632  CG  LYS A 234     -11.157  17.686  34.757  1.00 66.78           C  
+ATOM   1633  CD  LYS A 234     -11.558  17.860  36.213  1.00 70.18           C  
+ATOM   1634  CE  LYS A 234     -12.618  18.950  36.360  1.00 72.63           C  
+ATOM   1635  NZ  LYS A 234     -13.016  19.186  37.782  1.00 74.19           N  
+ATOM   1636  N   MET A 235      -7.773  15.543  31.885  1.00 60.45           N  
+ATOM   1637  CA  MET A 235      -6.750  14.575  31.513  1.00 60.28           C  
+ATOM   1638  C   MET A 235      -5.852  14.091  32.646  1.00 59.16           C  
+ATOM   1639  O   MET A 235      -5.800  12.895  32.926  1.00 59.20           O  
+ATOM   1640  CB  MET A 235      -5.879  15.157  30.398  1.00 62.20           C  
+ATOM   1641  CG  MET A 235      -5.215  14.118  29.503  1.00 65.51           C  
+ATOM   1642  SD  MET A 235      -6.386  13.338  28.357  1.00 69.53           S  
+ATOM   1643  CE  MET A 235      -6.734  11.841  29.219  1.00 68.50           C  
+ATOM   1644  N   ALA A 236      -5.141  15.013  33.287  1.00 56.79           N  
+ATOM   1645  CA  ALA A 236      -4.228  14.657  34.367  1.00 56.34           C  
+ATOM   1646  C   ALA A 236      -4.864  13.767  35.441  1.00 55.94           C  
+ATOM   1647  O   ALA A 236      -4.388  12.663  35.690  1.00 55.55           O  
+ATOM   1648  CB  ALA A 236      -3.649  15.918  34.997  1.00 55.55           C  
+ATOM   1649  N   PRO A 237      -5.947  14.234  36.087  1.00 54.95           N  
+ATOM   1650  CA  PRO A 237      -6.612  13.438  37.127  1.00 54.28           C  
+ATOM   1651  C   PRO A 237      -7.073  12.081  36.602  1.00 53.77           C  
+ATOM   1652  O   PRO A 237      -6.907  11.058  37.265  1.00 54.34           O  
+ATOM   1653  CB  PRO A 237      -7.796  14.311  37.534  1.00 54.52           C  
+ATOM   1654  CG  PRO A 237      -7.308  15.698  37.254  1.00 56.32           C  
+ATOM   1655  CD  PRO A 237      -6.612  15.538  35.928  1.00 55.32           C  
+ATOM   1656  N   LEU A 238      -7.658  12.081  35.408  1.00 51.96           N  
+ATOM   1657  CA  LEU A 238      -8.148  10.849  34.802  1.00 50.12           C  
+ATOM   1658  C   LEU A 238      -7.024   9.841  34.521  1.00 50.02           C  
+ATOM   1659  O   LEU A 238      -7.167   8.655  34.820  1.00 48.48           O  
+ATOM   1660  CB  LEU A 238      -8.903  11.166  33.509  1.00 49.10           C  
+ATOM   1661  CG  LEU A 238      -9.470   9.974  32.732  1.00 49.49           C  
+ATOM   1662  CD1 LEU A 238     -10.463   9.222  33.596  1.00 47.99           C  
+ATOM   1663  CD2 LEU A 238     -10.138  10.467  31.460  1.00 48.44           C  
+ATOM   1664  N   ARG A 239      -5.914  10.306  33.950  1.00 48.54           N  
+ATOM   1665  CA  ARG A 239      -4.792   9.419  33.651  1.00 48.28           C  
+ATOM   1666  C   ARG A 239      -4.264   8.768  34.920  1.00 48.01           C  
+ATOM   1667  O   ARG A 239      -4.043   7.559  34.962  1.00 47.72           O  
+ATOM   1668  CB  ARG A 239      -3.640  10.181  32.989  1.00 48.91           C  
+ATOM   1669  CG  ARG A 239      -3.818  10.498  31.513  1.00 50.74           C  
+ATOM   1670  CD  ARG A 239      -2.635  11.319  31.000  1.00 51.14           C  
+ATOM   1671  NE  ARG A 239      -2.786  11.687  29.595  1.00 52.42           N  
+ATOM   1672  CZ  ARG A 239      -1.971  12.510  28.939  1.00 51.59           C  
+ATOM   1673  NH1 ARG A 239      -2.192  12.780  27.661  1.00 52.55           N  
+ATOM   1674  NH2 ARG A 239      -0.937  13.063  29.555  1.00 50.36           N  
+ATOM   1675  N   TRP A 240      -4.058   9.577  35.953  1.00 48.22           N  
+ATOM   1676  CA  TRP A 240      -3.541   9.071  37.211  1.00 49.16           C  
+ATOM   1677  C   TRP A 240      -4.501   8.105  37.898  1.00 47.37           C  
+ATOM   1678  O   TRP A 240      -4.069   7.113  38.466  1.00 47.30           O  
+ATOM   1679  CB  TRP A 240      -3.172  10.235  38.135  1.00 50.08           C  
+ATOM   1680  CG  TRP A 240      -1.952  10.976  37.660  1.00 55.15           C  
+ATOM   1681  CD1 TRP A 240      -1.891  12.273  37.224  1.00 57.87           C  
+ATOM   1682  CD2 TRP A 240      -0.624  10.447  37.525  1.00 56.55           C  
+ATOM   1683  NE1 TRP A 240      -0.609  12.581  36.822  1.00 57.41           N  
+ATOM   1684  CE2 TRP A 240       0.187  11.479  36.996  1.00 57.47           C  
+ATOM   1685  CE3 TRP A 240      -0.041   9.200  37.797  1.00 56.70           C  
+ATOM   1686  CZ2 TRP A 240       1.552  11.302  36.734  1.00 58.12           C  
+ATOM   1687  CZ3 TRP A 240       1.316   9.024  37.536  1.00 57.70           C  
+ATOM   1688  CH2 TRP A 240       2.097  10.072  37.008  1.00 58.35           C  
+ATOM   1689  N   LEU A 241      -5.799   8.383  37.836  1.00 46.34           N  
+ATOM   1690  CA  LEU A 241      -6.782   7.501  38.450  1.00 44.69           C  
+ATOM   1691  C   LEU A 241      -6.659   6.133  37.783  1.00 44.50           C  
+ATOM   1692  O   LEU A 241      -6.722   5.098  38.447  1.00 43.60           O  
+ATOM   1693  CB  LEU A 241      -8.197   8.040  38.238  1.00 44.28           C  
+ATOM   1694  CG  LEU A 241      -9.300   7.704  39.255  1.00 47.85           C  
+ATOM   1695  CD1 LEU A 241     -10.560   7.371  38.477  1.00 46.86           C  
+ATOM   1696  CD2 LEU A 241      -8.920   6.538  40.169  1.00 44.83           C  
+ATOM   1697  N   VAL A 242      -6.478   6.135  36.466  1.00 43.25           N  
+ATOM   1698  CA  VAL A 242      -6.345   4.892  35.720  1.00 44.08           C  
+ATOM   1699  C   VAL A 242      -4.991   4.233  35.973  1.00 44.83           C  
+ATOM   1700  O   VAL A 242      -4.924   3.022  36.133  1.00 45.25           O  
+ATOM   1701  CB  VAL A 242      -6.532   5.115  34.199  1.00 43.04           C  
+ATOM   1702  CG1 VAL A 242      -6.298   3.819  33.449  1.00 43.17           C  
+ATOM   1703  CG2 VAL A 242      -7.940   5.610  33.916  1.00 42.96           C  
+ATOM   1704  N   ILE A 243      -3.919   5.024  36.008  1.00 44.55           N  
+ATOM   1705  CA  ILE A 243      -2.586   4.481  36.258  1.00 45.48           C  
+ATOM   1706  C   ILE A 243      -2.548   3.789  37.627  1.00 47.90           C  
+ATOM   1707  O   ILE A 243      -1.991   2.698  37.763  1.00 48.80           O  
+ATOM   1708  CB  ILE A 243      -1.485   5.598  36.211  1.00 44.95           C  
+ATOM   1709  CG1 ILE A 243      -1.217   6.026  34.763  1.00 42.03           C  
+ATOM   1710  CG2 ILE A 243      -0.195   5.104  36.854  1.00 40.45           C  
+ATOM   1711  CD1 ILE A 243      -0.206   7.147  34.627  0.00 43.27           C  
+ATOM   1712  N   PHE A 244      -3.150   4.423  38.630  1.00 48.64           N  
+ATOM   1713  CA  PHE A 244      -3.190   3.885  39.986  1.00 48.89           C  
+ATOM   1714  C   PHE A 244      -3.968   2.574  40.066  1.00 48.87           C  
+ATOM   1715  O   PHE A 244      -3.487   1.590  40.629  1.00 48.40           O  
+ATOM   1716  CB  PHE A 244      -3.822   4.906  40.934  1.00 53.09           C  
+ATOM   1717  CG  PHE A 244      -4.047   4.384  42.329  1.00 58.68           C  
+ATOM   1718  CD1 PHE A 244      -2.978   4.218  43.209  1.00 61.13           C  
+ATOM   1719  CD2 PHE A 244      -5.328   4.040  42.760  1.00 60.55           C  
+ATOM   1720  CE1 PHE A 244      -3.181   3.715  44.501  1.00 61.90           C  
+ATOM   1721  CE2 PHE A 244      -5.543   3.535  44.050  1.00 61.27           C  
+ATOM   1722  CZ  PHE A 244      -4.468   3.373  44.920  1.00 61.16           C  
+ATOM   1723  N   LEU A 245      -5.176   2.567  39.511  1.00 46.72           N  
+ATOM   1724  CA  LEU A 245      -6.013   1.376  39.528  1.00 47.02           C  
+ATOM   1725  C   LEU A 245      -5.355   0.258  38.726  1.00 47.18           C  
+ATOM   1726  O   LEU A 245      -5.418  -0.913  39.094  1.00 45.67           O  
+ATOM   1727  CB  LEU A 245      -7.392   1.691  38.940  1.00 46.79           C  
+ATOM   1728  CG  LEU A 245      -8.238   2.737  39.676  1.00 47.87           C  
+ATOM   1729  CD1 LEU A 245      -9.457   3.097  38.839  1.00 45.75           C  
+ATOM   1730  CD2 LEU A 245      -8.655   2.197  41.032  1.00 45.93           C  
+ATOM   1731  N   SER A 246      -4.725   0.642  37.623  1.00 47.35           N  
+ATOM   1732  CA  SER A 246      -4.037  -0.293  36.745  1.00 47.41           C  
+ATOM   1733  C   SER A 246      -2.838  -0.896  37.477  1.00 46.76           C  
+ATOM   1734  O   SER A 246      -2.600  -2.103  37.414  1.00 44.66           O  
+ATOM   1735  CB  SER A 246      -3.570   0.442  35.485  1.00 46.45           C  
+ATOM   1736  OG  SER A 246      -2.981  -0.444  34.555  1.00 52.27           O  
+ATOM   1737  N   GLY A 247      -2.096  -0.037  38.173  1.00 46.73           N  
+ATOM   1738  CA  GLY A 247      -0.928  -0.472  38.916  1.00 46.22           C  
+ATOM   1739  C   GLY A 247      -1.288  -1.237  40.174  1.00 47.28           C  
+ATOM   1740  O   GLY A 247      -0.542  -2.117  40.602  1.00 47.20           O  
+ATOM   1741  N   SER A 248      -2.424  -0.898  40.778  1.00 47.89           N  
+ATOM   1742  CA  SER A 248      -2.875  -1.585  41.984  1.00 47.88           C  
+ATOM   1743  C   SER A 248      -3.198  -3.040  41.656  1.00 48.11           C  
+ATOM   1744  O   SER A 248      -2.858  -3.945  42.417  1.00 47.57           O  
+ATOM   1745  CB  SER A 248      -4.112  -0.899  42.565  1.00 48.06           C  
+ATOM   1746  OG  SER A 248      -3.762   0.323  43.186  1.00 49.01           O  
+ATOM   1747  N   LEU A 249      -3.858  -3.262  40.522  1.00 46.68           N  
+ATOM   1748  CA  LEU A 249      -4.193  -4.617  40.108  1.00 47.09           C  
+ATOM   1749  C   LEU A 249      -2.926  -5.455  39.996  1.00 46.77           C  
+ATOM   1750  O   LEU A 249      -2.834  -6.543  40.560  1.00 49.16           O  
+ATOM   1751  CB  LEU A 249      -4.905  -4.617  38.752  1.00 44.88           C  
+ATOM   1752  CG  LEU A 249      -6.419  -4.431  38.696  1.00 45.46           C  
+ATOM   1753  CD1 LEU A 249      -6.856  -4.290  37.240  1.00 44.57           C  
+ATOM   1754  CD2 LEU A 249      -7.109  -5.620  39.345  1.00 44.64           C  
+ATOM   1755  N   VAL A 250      -1.949  -4.937  39.262  1.00 45.87           N  
+ATOM   1756  CA  VAL A 250      -0.691  -5.641  39.054  1.00 44.96           C  
+ATOM   1757  C   VAL A 250       0.108  -5.885  40.337  1.00 44.29           C  
+ATOM   1758  O   VAL A 250       0.643  -6.974  40.530  1.00 44.55           O  
+ATOM   1759  CB  VAL A 250       0.171  -4.890  38.013  1.00 44.14           C  
+ATOM   1760  CG1 VAL A 250       1.594  -5.430  37.998  1.00 42.66           C  
+ATOM   1761  CG2 VAL A 250      -0.465  -5.048  36.635  1.00 44.19           C  
+ATOM   1762  N   ALA A 251       0.184  -4.885  41.208  1.00 41.77           N  
+ATOM   1763  CA  ALA A 251       0.912  -5.031  42.464  1.00 42.63           C  
+ATOM   1764  C   ALA A 251       0.312  -6.170  43.287  1.00 43.77           C  
+ATOM   1765  O   ALA A 251       1.031  -7.029  43.801  1.00 42.58           O  
+ATOM   1766  CB  ALA A 251       0.858  -3.737  43.260  1.00 40.41           C  
+ATOM   1767  N   CYS A 252      -1.011  -6.167  43.406  1.00 44.14           N  
+ATOM   1768  CA  CYS A 252      -1.715  -7.189  44.161  1.00 44.46           C  
+ATOM   1769  C   CYS A 252      -1.617  -8.541  43.459  1.00 44.77           C  
+ATOM   1770  O   CYS A 252      -1.612  -9.590  44.101  1.00 45.77           O  
+ATOM   1771  CB  CYS A 252      -3.180  -6.784  44.339  1.00 44.46           C  
+ATOM   1772  SG  CYS A 252      -3.405  -5.303  45.360  1.00 46.59           S  
+ATOM   1773  N   GLN A 253      -1.538  -8.516  42.135  1.00 43.07           N  
+ATOM   1774  CA  GLN A 253      -1.423  -9.751  41.380  1.00 42.47           C  
+ATOM   1775  C   GLN A 253      -0.052 -10.392  41.622  1.00 43.61           C  
+ATOM   1776  O   GLN A 253       0.055 -11.602  41.840  1.00 43.42           O  
+ATOM   1777  CB  GLN A 253      -1.629  -9.479  39.890  1.00 39.34           C  
+ATOM   1778  CG  GLN A 253      -1.278 -10.648  38.999  1.00 38.82           C  
+ATOM   1779  CD  GLN A 253       0.169 -10.619  38.540  1.00 43.00           C  
+ATOM   1780  OE1 GLN A 253       0.778 -11.662  38.303  1.00 45.41           O  
+ATOM   1781  NE2 GLN A 253       0.722  -9.418  38.395  1.00 44.11           N  
+ATOM   1782  N   VAL A 254       0.993  -9.572  41.586  1.00 42.99           N  
+ATOM   1783  CA  VAL A 254       2.349 -10.057  41.797  1.00 42.97           C  
+ATOM   1784  C   VAL A 254       2.487 -10.594  43.227  1.00 44.18           C  
+ATOM   1785  O   VAL A 254       3.159 -11.603  43.466  1.00 42.49           O  
+ATOM   1786  CB  VAL A 254       3.375  -8.919  41.539  1.00 41.96           C  
+ATOM   1787  CG1 VAL A 254       4.776  -9.338  41.988  1.00 40.90           C  
+ATOM   1788  CG2 VAL A 254       3.383  -8.571  40.049  1.00 39.80           C  
+ATOM   1789  N   ALA A 255       1.826  -9.924  44.165  1.00 43.86           N  
+ATOM   1790  CA  ALA A 255       1.866 -10.314  45.563  1.00 45.45           C  
+ATOM   1791  C   ALA A 255       1.408 -11.760  45.801  1.00 46.69           C  
+ATOM   1792  O   ALA A 255       1.965 -12.446  46.656  1.00 47.27           O  
+ATOM   1793  CB  ALA A 255       1.026  -9.352  46.393  1.00 45.36           C  
+ATOM   1794  N   ILE A 256       0.414 -12.226  45.043  1.00 46.36           N  
+ATOM   1795  CA  ILE A 256      -0.086 -13.586  45.218  1.00 45.99           C  
+ATOM   1796  C   ILE A 256       0.291 -14.594  44.132  1.00 47.48           C  
+ATOM   1797  O   ILE A 256      -0.038 -15.777  44.258  1.00 48.59           O  
+ATOM   1798  CB  ILE A 256      -1.636 -13.629  45.354  1.00 46.93           C  
+ATOM   1799  CG1 ILE A 256      -2.301 -13.327  44.003  1.00 45.51           C  
+ATOM   1800  CG2 ILE A 256      -2.091 -12.653  46.436  1.00 46.06           C  
+ATOM   1801  CD1 ILE A 256      -3.770 -13.667  43.958  0.00 46.06           C  
+ATOM   1802  N   SER A 257       0.965 -14.157  43.071  1.00 46.41           N  
+ATOM   1803  CA  SER A 257       1.329 -15.100  42.017  1.00 44.26           C  
+ATOM   1804  C   SER A 257       2.642 -14.820  41.299  1.00 43.35           C  
+ATOM   1805  O   SER A 257       2.959 -15.482  40.309  1.00 42.22           O  
+ATOM   1806  CB  SER A 257       0.200 -15.201  40.988  1.00 46.63           C  
+ATOM   1807  OG  SER A 257      -0.029 -13.963  40.334  1.00 47.17           O  
+ATOM   1808  N   GLY A 258       3.410 -13.854  41.793  1.00 42.75           N  
+ATOM   1809  CA  GLY A 258       4.680 -13.535  41.159  1.00 43.81           C  
+ATOM   1810  C   GLY A 258       4.578 -12.768  39.844  1.00 43.83           C  
+ATOM   1811  O   GLY A 258       3.531 -12.204  39.519  1.00 44.59           O  
+ATOM   1812  N   SER A 259       5.671 -12.762  39.084  1.00 43.90           N  
+ATOM   1813  CA  SER A 259       5.745 -12.054  37.804  1.00 42.56           C  
+ATOM   1814  C   SER A 259       5.227 -12.836  36.605  1.00 41.54           C  
+ATOM   1815  O   SER A 259       5.820 -13.834  36.198  1.00 42.21           O  
+ATOM   1816  CB  SER A 259       7.189 -11.645  37.518  1.00 42.97           C  
+ATOM   1817  OG  SER A 259       7.710 -10.852  38.568  1.00 45.81           O  
+ATOM   1818  N   ILE A 260       4.122 -12.369  36.035  1.00 40.35           N  
+ATOM   1819  CA  ILE A 260       3.533 -13.001  34.862  1.00 40.93           C  
+ATOM   1820  C   ILE A 260       3.516 -11.969  33.728  1.00 42.96           C  
+ATOM   1821  O   ILE A 260       3.055 -10.839  33.915  1.00 43.35           O  
+ATOM   1822  CB  ILE A 260       2.085 -13.465  35.140  1.00 40.00           C  
+ATOM   1823  CG1 ILE A 260       2.057 -14.424  36.343  1.00 39.95           C  
+ATOM   1824  CG2 ILE A 260       1.507 -14.131  33.895  1.00 36.89           C  
+ATOM   1825  CD1 ILE A 260       0.669 -14.893  36.725  0.00 39.92           C  
+ATOM   1826  N   GLY A 261       4.022 -12.355  32.561  1.00 43.03           N  
+ATOM   1827  CA  GLY A 261       4.046 -11.438  31.434  1.00 43.49           C  
+ATOM   1828  C   GLY A 261       3.403 -11.981  30.172  1.00 44.22           C  
+ATOM   1829  O   GLY A 261       2.767 -13.041  30.189  1.00 44.49           O  
+ATOM   1830  N   TRP A 262       3.568 -11.243  29.076  1.00 42.87           N  
+ATOM   1831  CA  TRP A 262       3.019 -11.616  27.778  1.00 42.58           C  
+ATOM   1832  C   TRP A 262       1.516 -11.849  27.782  1.00 44.31           C  
+ATOM   1833  O   TRP A 262       1.006 -12.700  27.048  1.00 45.41           O  
+ATOM   1834  CB  TRP A 262       3.731 -12.858  27.230  1.00 43.21           C  
+ATOM   1835  CG  TRP A 262       5.118 -12.557  26.773  1.00 44.41           C  
+ATOM   1836  CD1 TRP A 262       6.259 -12.604  27.522  1.00 43.06           C  
+ATOM   1837  CD2 TRP A 262       5.501 -12.060  25.485  1.00 43.42           C  
+ATOM   1838  NE1 TRP A 262       7.330 -12.161  26.782  1.00 44.22           N  
+ATOM   1839  CE2 TRP A 262       6.894 -11.820  25.528  1.00 43.50           C  
+ATOM   1840  CE3 TRP A 262       4.802 -11.789  24.301  1.00 43.91           C  
+ATOM   1841  CZ2 TRP A 262       7.604 -11.321  24.430  1.00 42.46           C  
+ATOM   1842  CZ3 TRP A 262       5.510 -11.290  23.206  1.00 45.88           C  
+ATOM   1843  CH2 TRP A 262       6.900 -11.062  23.283  1.00 43.41           C  
+ATOM   1844  N   VAL A 263       0.803 -11.089  28.602  1.00 44.61           N  
+ATOM   1845  CA  VAL A 263      -0.645 -11.228  28.674  1.00 46.47           C  
+ATOM   1846  C   VAL A 263      -1.330  -9.932  28.257  1.00 47.60           C  
+ATOM   1847  O   VAL A 263      -2.074  -9.897  27.273  1.00 44.76           O  
+ATOM   1848  CB  VAL A 263      -1.106 -11.603  30.110  1.00 46.59           C  
+ATOM   1849  CG1 VAL A 263      -2.624 -11.513  30.208  1.00 45.88           C  
+ATOM   1850  CG2 VAL A 263      -0.636 -13.015  30.464  1.00 45.18           C  
+ATOM   1851  N   GLY A 264      -1.064  -8.873  29.018  1.00 50.35           N  
+ATOM   1852  CA  GLY A 264      -1.656  -7.576  28.751  1.00 52.62           C  
+ATOM   1853  C   GLY A 264      -1.352  -7.063  27.363  1.00 53.68           C  
+ATOM   1854  O   GLY A 264      -2.039  -6.182  26.856  1.00 55.31           O  
+ATOM   1855  N   LEU A 265      -0.324  -7.618  26.738  1.00 54.01           N  
+ATOM   1856  CA  LEU A 265       0.048  -7.193  25.401  1.00 53.91           C  
+ATOM   1857  C   LEU A 265      -0.898  -7.728  24.328  1.00 55.09           C  
+ATOM   1858  O   LEU A 265      -1.504  -6.949  23.586  1.00 58.19           O  
+ATOM   1859  CB  LEU A 265       1.476  -7.644  25.088  1.00 55.43           C  
+ATOM   1860  CG  LEU A 265       2.131  -7.016  23.857  1.00 56.41           C  
+ATOM   1861  CD1 LEU A 265       2.224  -5.501  24.053  1.00 56.35           C  
+ATOM   1862  CD2 LEU A 265       3.520  -7.611  23.647  1.00 55.79           C  
+ATOM   1863  N   ILE A 266      -1.045  -9.052  24.267  1.00 53.94           N  
+ATOM   1864  CA  ILE A 266      -1.875  -9.693  23.248  1.00 51.43           C  
+ATOM   1865  C   ILE A 266      -3.381  -9.806  23.474  1.00 50.24           C  
+ATOM   1866  O   ILE A 266      -4.146  -9.870  22.505  1.00 49.51           O  
+ATOM   1867  CB  ILE A 266      -1.355 -11.120  22.933  1.00 52.81           C  
+ATOM   1868  CG1 ILE A 266      -1.685 -12.076  24.084  1.00 52.15           C  
+ATOM   1869  CG2 ILE A 266       0.148 -11.080  22.703  1.00 54.47           C  
+ATOM   1870  CD1 ILE A 266      -1.259 -13.509  23.838  0.00 52.49           C  
+ATOM   1871  N   ILE A 267      -3.821  -9.841  24.726  1.00 47.64           N  
+ATOM   1872  CA  ILE A 267      -5.249  -9.989  24.976  1.00 47.10           C  
+ATOM   1873  C   ILE A 267      -6.082  -8.813  24.476  1.00 47.12           C  
+ATOM   1874  O   ILE A 267      -7.068  -9.013  23.761  1.00 47.35           O  
+ATOM   1875  CB  ILE A 267      -5.538 -10.265  26.476  1.00 46.98           C  
+ATOM   1876  CG1 ILE A 267      -4.947 -11.626  26.855  1.00 47.46           C  
+ATOM   1877  CG2 ILE A 267      -7.051 -10.279  26.737  1.00 46.14           C  
+ATOM   1878  CD1 ILE A 267      -5.152 -12.008  28.298  0.00 47.31           C  
+ATOM   1879  N   PRO A 268      -5.714  -7.575  24.844  1.00 47.14           N  
+ATOM   1880  CA  PRO A 268      -6.535  -6.471  24.337  1.00 47.58           C  
+ATOM   1881  C   PRO A 268      -6.613  -6.447  22.811  1.00 47.09           C  
+ATOM   1882  O   PRO A 268      -7.638  -6.066  22.248  1.00 47.03           O  
+ATOM   1883  CB  PRO A 268      -5.876  -5.225  24.941  1.00 46.46           C  
+ATOM   1884  CG  PRO A 268      -4.528  -5.694  25.407  1.00 47.36           C  
+ATOM   1885  CD  PRO A 268      -4.752  -7.100  25.848  1.00 46.63           C  
+ATOM   1886  N   HIS A 269      -5.549  -6.877  22.140  1.00 48.08           N  
+ATOM   1887  CA  HIS A 269      -5.568  -6.915  20.679  1.00 50.70           C  
+ATOM   1888  C   HIS A 269      -6.647  -7.890  20.199  1.00 51.19           C  
+ATOM   1889  O   HIS A 269      -7.490  -7.536  19.372  1.00 51.65           O  
+ATOM   1890  CB  HIS A 269      -4.210  -7.344  20.117  1.00 53.97           C  
+ATOM   1891  CG  HIS A 269      -4.230  -7.605  18.643  1.00 59.64           C  
+ATOM   1892  ND1 HIS A 269      -4.647  -6.663  17.725  1.00 62.42           N  
+ATOM   1893  CD2 HIS A 269      -3.923  -8.714  17.928  1.00 62.41           C  
+ATOM   1894  CE1 HIS A 269      -4.599  -7.181  16.510  1.00 63.13           C  
+ATOM   1895  NE2 HIS A 269      -4.164  -8.425  16.606  1.00 64.54           N  
+ATOM   1896  N   LEU A 270      -6.617  -9.118  20.713  1.00 50.29           N  
+ATOM   1897  CA  LEU A 270      -7.615 -10.114  20.334  1.00 49.96           C  
+ATOM   1898  C   LEU A 270      -9.011  -9.575  20.613  1.00 48.94           C  
+ATOM   1899  O   LEU A 270      -9.943  -9.804  19.847  1.00 48.99           O  
+ATOM   1900  CB  LEU A 270      -7.417 -11.413  21.120  1.00 50.79           C  
+ATOM   1901  CG  LEU A 270      -6.191 -12.267  20.799  1.00 51.19           C  
+ATOM   1902  CD1 LEU A 270      -6.184 -13.486  21.698  1.00 51.71           C  
+ATOM   1903  CD2 LEU A 270      -6.224 -12.687  19.336  1.00 51.76           C  
+ATOM   1904  N   SER A 271      -9.151  -8.852  21.716  1.00 48.28           N  
+ATOM   1905  CA  SER A 271     -10.441  -8.295  22.082  1.00 48.21           C  
+ATOM   1906  C   SER A 271     -10.900  -7.245  21.083  1.00 49.33           C  
+ATOM   1907  O   SER A 271     -12.078  -7.205  20.729  1.00 50.19           O  
+ATOM   1908  CB  SER A 271     -10.376  -7.694  23.483  1.00 47.88           C  
+ATOM   1909  OG  SER A 271     -10.015  -8.678  24.435  1.00 46.23           O  
+ATOM   1910  N   ARG A 272      -9.985  -6.390  20.631  1.00 49.38           N  
+ATOM   1911  CA  ARG A 272     -10.358  -5.368  19.658  1.00 51.11           C  
+ATOM   1912  C   ARG A 272     -10.733  -6.041  18.341  1.00 52.55           C  
+ATOM   1913  O   ARG A 272     -11.470  -5.477  17.532  1.00 52.20           O  
+ATOM   1914  CB  ARG A 272      -9.226  -4.345  19.458  1.00 49.48           C  
+ATOM   1915  CG  ARG A 272      -9.212  -3.250  20.529  1.00 48.72           C  
+ATOM   1916  CD  ARG A 272      -8.098  -2.223  20.329  1.00 48.51           C  
+ATOM   1917  NE  ARG A 272      -6.776  -2.813  20.501  1.00 48.19           N  
+ATOM   1918  CZ  ARG A 272      -5.993  -2.624  21.560  1.00 46.74           C  
+ATOM   1919  NH1 ARG A 272      -4.809  -3.219  21.609  1.00 45.41           N  
+ATOM   1920  NH2 ARG A 272      -6.379  -1.837  22.557  1.00 44.67           N  
+ATOM   1921  N   MET A 273     -10.239  -7.257  18.130  1.00 54.02           N  
+ATOM   1922  CA  MET A 273     -10.585  -7.992  16.918  1.00 56.32           C  
+ATOM   1923  C   MET A 273     -12.032  -8.470  17.037  1.00 56.43           C  
+ATOM   1924  O   MET A 273     -12.724  -8.655  16.037  1.00 56.69           O  
+ATOM   1925  CB  MET A 273      -9.665  -9.201  16.731  1.00 57.47           C  
+ATOM   1926  CG  MET A 273      -8.256  -8.850  16.286  1.00 61.31           C  
+ATOM   1927  SD  MET A 273      -7.197 -10.306  16.096  1.00 65.08           S  
+ATOM   1928  CE  MET A 273      -7.665 -10.875  14.450  1.00 64.60           C  
+ATOM   1929  N   LEU A 274     -12.489  -8.648  18.272  1.00 55.39           N  
+ATOM   1930  CA  LEU A 274     -13.839  -9.123  18.525  1.00 55.49           C  
+ATOM   1931  C   LEU A 274     -14.914  -8.058  18.657  1.00 55.61           C  
+ATOM   1932  O   LEU A 274     -15.945  -8.134  17.991  1.00 56.62           O  
+ATOM   1933  CB  LEU A 274     -13.860  -9.994  19.788  1.00 56.04           C  
+ATOM   1934  CG  LEU A 274     -13.426 -11.462  19.691  1.00 56.72           C  
+ATOM   1935  CD1 LEU A 274     -12.130 -11.588  18.904  1.00 58.60           C  
+ATOM   1936  CD2 LEU A 274     -13.262 -12.028  21.091  1.00 56.55           C  
+ATOM   1937  N   VAL A 275     -14.679  -7.062  19.505  1.00 55.32           N  
+ATOM   1938  CA  VAL A 275     -15.685  -6.036  19.749  1.00 54.47           C  
+ATOM   1939  C   VAL A 275     -15.344  -4.602  19.320  1.00 54.04           C  
+ATOM   1940  O   VAL A 275     -16.139  -3.688  19.531  1.00 55.16           O  
+ATOM   1941  CB  VAL A 275     -16.071  -6.046  21.255  1.00 55.32           C  
+ATOM   1942  CG1 VAL A 275     -14.947  -5.453  22.088  1.00 54.87           C  
+ATOM   1943  CG2 VAL A 275     -17.369  -5.293  21.479  1.00 58.42           C  
+ATOM   1944  N   GLY A 276     -14.178  -4.390  18.721  1.00 52.73           N  
+ATOM   1945  CA  GLY A 276     -13.826  -3.045  18.296  1.00 50.59           C  
+ATOM   1946  C   GLY A 276     -13.049  -2.212  19.304  1.00 50.43           C  
+ATOM   1947  O   GLY A 276     -12.658  -2.697  20.369  1.00 49.87           O  
+ATOM   1948  N   ALA A 277     -12.855  -0.936  18.972  1.00 48.95           N  
+ATOM   1949  CA  ALA A 277     -12.091  -0.003  19.797  1.00 47.88           C  
+ATOM   1950  C   ALA A 277     -12.820   0.713  20.935  1.00 47.46           C  
+ATOM   1951  O   ALA A 277     -12.185   1.117  21.910  1.00 48.73           O  
+ATOM   1952  CB  ALA A 277     -11.422   1.031  18.894  1.00 48.50           C  
+ATOM   1953  N   ASN A 278     -14.131   0.893  20.827  1.00 47.04           N  
+ATOM   1954  CA  ASN A 278     -14.862   1.575  21.891  1.00 46.98           C  
+ATOM   1955  C   ASN A 278     -14.605   0.858  23.219  1.00 48.71           C  
+ATOM   1956  O   ASN A 278     -14.974  -0.304  23.389  1.00 47.72           O  
+ATOM   1957  CB  ASN A 278     -16.360   1.610  21.568  1.00 45.39           C  
+ATOM   1958  CG  ASN A 278     -17.171   2.321  22.638  1.00 48.43           C  
+ATOM   1959  OD1 ASN A 278     -16.667   3.205  23.328  1.00 47.38           O  
+ATOM   1960  ND2 ASN A 278     -18.441   1.946  22.771  1.00 50.82           N  
+ATOM   1961  N   HIS A 279     -13.962   1.554  24.153  1.00 51.38           N  
+ATOM   1962  CA  HIS A 279     -13.631   0.969  25.451  1.00 54.33           C  
+ATOM   1963  C   HIS A 279     -14.829   0.492  26.255  1.00 55.91           C  
+ATOM   1964  O   HIS A 279     -14.719  -0.456  27.039  1.00 55.75           O  
+ATOM   1965  CB  HIS A 279     -12.814   1.953  26.299  1.00 53.88           C  
+ATOM   1966  CG  HIS A 279     -11.437   2.206  25.768  1.00 55.72           C  
+ATOM   1967  ND1 HIS A 279     -11.168   3.172  24.822  1.00 56.40           N  
+ATOM   1968  CD2 HIS A 279     -10.258   1.592  26.025  1.00 55.05           C  
+ATOM   1969  CE1 HIS A 279      -9.882   3.143  24.520  1.00 56.41           C  
+ATOM   1970  NE2 HIS A 279      -9.308   2.192  25.236  1.00 56.12           N  
+ATOM   1971  N   GLN A 280     -15.970   1.144  26.064  1.00 57.60           N  
+ATOM   1972  CA  GLN A 280     -17.179   0.773  26.786  1.00 58.45           C  
+ATOM   1973  C   GLN A 280     -17.498  -0.708  26.582  1.00 57.91           C  
+ATOM   1974  O   GLN A 280     -18.103  -1.351  27.443  1.00 57.69           O  
+ATOM   1975  CB  GLN A 280     -18.352   1.636  26.319  1.00 61.09           C  
+ATOM   1976  CG  GLN A 280     -19.633   1.425  27.110  1.00 65.06           C  
+ATOM   1977  CD  GLN A 280     -20.753   2.361  26.679  1.00 68.02           C  
+ATOM   1978  OE1 GLN A 280     -21.878   2.263  27.174  1.00 70.39           O  
+ATOM   1979  NE2 GLN A 280     -20.451   3.273  25.754  1.00 67.24           N  
+ATOM   1980  N   SER A 281     -17.079  -1.247  25.442  1.00 56.67           N  
+ATOM   1981  CA  SER A 281     -17.315  -2.650  25.122  1.00 55.81           C  
+ATOM   1982  C   SER A 281     -16.024  -3.458  25.200  1.00 53.82           C  
+ATOM   1983  O   SER A 281     -16.053  -4.674  25.393  1.00 53.21           O  
+ATOM   1984  CB  SER A 281     -17.902  -2.780  23.713  1.00 57.37           C  
+ATOM   1985  OG  SER A 281     -19.173  -2.160  23.629  1.00 62.17           O  
+ATOM   1986  N   LEU A 282     -14.897  -2.769  25.055  1.00 51.15           N  
+ATOM   1987  CA  LEU A 282     -13.585  -3.403  25.072  1.00 49.20           C  
+ATOM   1988  C   LEU A 282     -13.164  -3.949  26.435  1.00 47.11           C  
+ATOM   1989  O   LEU A 282     -12.688  -5.074  26.522  1.00 45.79           O  
+ATOM   1990  CB  LEU A 282     -12.515  -2.417  24.594  1.00 47.05           C  
+ATOM   1991  CG  LEU A 282     -11.522  -2.827  23.501  1.00 49.04           C  
+ATOM   1992  CD1 LEU A 282     -10.278  -1.948  23.650  1.00 48.56           C  
+ATOM   1993  CD2 LEU A 282     -11.131  -4.297  23.601  1.00 43.30           C  
+ATOM   1994  N   LEU A 283     -13.318  -3.151  27.488  1.00 46.10           N  
+ATOM   1995  CA  LEU A 283     -12.914  -3.590  28.817  1.00 46.39           C  
+ATOM   1996  C   LEU A 283     -13.562  -4.908  29.231  1.00 48.75           C  
+ATOM   1997  O   LEU A 283     -12.864  -5.856  29.590  1.00 48.35           O  
+ATOM   1998  CB  LEU A 283     -13.214  -2.518  29.872  1.00 44.04           C  
+ATOM   1999  CG  LEU A 283     -12.457  -1.186  29.828  1.00 44.77           C  
+ATOM   2000  CD1 LEU A 283     -12.309  -0.657  31.249  1.00 41.41           C  
+ATOM   2001  CD2 LEU A 283     -11.092  -1.355  29.208  1.00 44.20           C  
+ATOM   2002  N   PRO A 284     -14.903  -4.990  29.192  1.00 50.04           N  
+ATOM   2003  CA  PRO A 284     -15.555  -6.246  29.581  1.00 50.19           C  
+ATOM   2004  C   PRO A 284     -15.110  -7.428  28.724  1.00 49.54           C  
+ATOM   2005  O   PRO A 284     -14.927  -8.538  29.230  1.00 49.75           O  
+ATOM   2006  CB  PRO A 284     -17.043  -5.929  29.435  1.00 50.59           C  
+ATOM   2007  CG  PRO A 284     -17.063  -4.840  28.390  1.00 52.67           C  
+ATOM   2008  CD  PRO A 284     -15.901  -3.980  28.798  1.00 50.00           C  
+ATOM   2009  N   CYS A 285     -14.917  -7.185  27.431  1.00 47.11           N  
+ATOM   2010  CA  CYS A 285     -14.485  -8.235  26.519  1.00 44.84           C  
+ATOM   2011  C   CYS A 285     -13.049  -8.683  26.789  1.00 45.24           C  
+ATOM   2012  O   CYS A 285     -12.749  -9.874  26.722  1.00 46.12           O  
+ATOM   2013  CB  CYS A 285     -14.616  -7.768  25.068  1.00 43.73           C  
+ATOM   2014  SG  CYS A 285     -14.045  -8.965  23.824  1.00 47.61           S  
+ATOM   2015  N   THR A 286     -12.157  -7.745  27.100  1.00 45.16           N  
+ATOM   2016  CA  THR A 286     -10.770  -8.115  27.360  1.00 43.79           C  
+ATOM   2017  C   THR A 286     -10.661  -8.863  28.687  1.00 42.53           C  
+ATOM   2018  O   THR A 286      -9.820  -9.749  28.838  1.00 40.85           O  
+ATOM   2019  CB  THR A 286      -9.822  -6.885  27.393  1.00 43.75           C  
+ATOM   2020  OG1 THR A 286     -10.062  -6.123  28.579  1.00 50.55           O  
+ATOM   2021  CG2 THR A 286     -10.053  -5.998  26.188  1.00 42.31           C  
+ATOM   2022  N   MET A 287     -11.507  -8.498  29.647  1.00 41.95           N  
+ATOM   2023  CA  MET A 287     -11.516  -9.163  30.947  1.00 42.96           C  
+ATOM   2024  C   MET A 287     -11.900 -10.628  30.768  1.00 43.09           C  
+ATOM   2025  O   MET A 287     -11.259 -11.513  31.316  1.00 43.79           O  
+ATOM   2026  CB  MET A 287     -12.513  -8.496  31.891  1.00 41.74           C  
+ATOM   2027  CG  MET A 287     -12.043  -7.180  32.470  1.00 41.92           C  
+ATOM   2028  SD  MET A 287     -13.194  -6.585  33.710  1.00 44.80           S  
+ATOM   2029  CE  MET A 287     -12.541  -7.421  35.210  1.00 46.71           C  
+ATOM   2030  N   LEU A 288     -12.943 -10.872  29.984  1.00 43.67           N  
+ATOM   2031  CA  LEU A 288     -13.416 -12.221  29.723  1.00 45.68           C  
+ATOM   2032  C   LEU A 288     -12.441 -13.065  28.900  1.00 46.76           C  
+ATOM   2033  O   LEU A 288     -12.252 -14.254  29.176  1.00 46.61           O  
+ATOM   2034  CB  LEU A 288     -14.775 -12.167  29.023  1.00 46.39           C  
+ATOM   2035  CG  LEU A 288     -15.932 -11.764  29.939  1.00 48.02           C  
+ATOM   2036  CD1 LEU A 288     -17.208 -11.568  29.133  1.00 48.13           C  
+ATOM   2037  CD2 LEU A 288     -16.120 -12.849  30.997  1.00 49.24           C  
+ATOM   2038  N   VAL A 289     -11.830 -12.463  27.884  1.00 45.60           N  
+ATOM   2039  CA  VAL A 289     -10.879 -13.194  27.055  1.00 43.88           C  
+ATOM   2040  C   VAL A 289      -9.602 -13.450  27.853  1.00 44.28           C  
+ATOM   2041  O   VAL A 289      -8.951 -14.482  27.689  1.00 44.14           O  
+ATOM   2042  CB  VAL A 289     -10.519 -12.408  25.773  1.00 42.31           C  
+ATOM   2043  CG1 VAL A 289      -9.420 -13.130  25.008  1.00 41.10           C  
+ATOM   2044  CG2 VAL A 289     -11.745 -12.257  24.900  1.00 41.30           C  
+ATOM   2045  N   GLY A 290      -9.255 -12.503  28.718  1.00 42.65           N  
+ATOM   2046  CA  GLY A 290      -8.059 -12.645  29.520  1.00 42.72           C  
+ATOM   2047  C   GLY A 290      -8.199 -13.748  30.549  1.00 44.13           C  
+ATOM   2048  O   GLY A 290      -7.271 -14.535  30.762  1.00 42.41           O  
+ATOM   2049  N   ALA A 291      -9.365 -13.799  31.187  1.00 42.96           N  
+ATOM   2050  CA  ALA A 291      -9.652 -14.803  32.202  1.00 43.13           C  
+ATOM   2051  C   ALA A 291      -9.533 -16.204  31.613  1.00 42.49           C  
+ATOM   2052  O   ALA A 291      -8.781 -17.037  32.120  1.00 40.32           O  
+ATOM   2053  CB  ALA A 291     -11.053 -14.587  32.774  1.00 42.03           C  
+ATOM   2054  N   THR A 292     -10.270 -16.454  30.537  1.00 43.30           N  
+ATOM   2055  CA  THR A 292     -10.250 -17.754  29.885  1.00 44.73           C  
+ATOM   2056  C   THR A 292      -8.851 -18.121  29.406  1.00 44.83           C  
+ATOM   2057  O   THR A 292      -8.391 -19.251  29.596  1.00 46.09           O  
+ATOM   2058  CB  THR A 292     -11.209 -17.794  28.675  1.00 45.23           C  
+ATOM   2059  OG1 THR A 292     -12.548 -17.529  29.114  1.00 47.71           O  
+ATOM   2060  CG2 THR A 292     -11.163 -19.169  28.004  1.00 44.06           C  
+ATOM   2061  N   TYR A 293      -8.180 -17.164  28.779  1.00 43.77           N  
+ATOM   2062  CA  TYR A 293      -6.839 -17.389  28.263  1.00 42.35           C  
+ATOM   2063  C   TYR A 293      -5.854 -17.803  29.360  1.00 41.40           C  
+ATOM   2064  O   TYR A 293      -5.062 -18.718  29.177  1.00 41.08           O  
+ATOM   2065  CB  TYR A 293      -6.351 -16.123  27.541  1.00 42.46           C  
+ATOM   2066  CG  TYR A 293      -4.940 -16.200  27.008  1.00 40.84           C  
+ATOM   2067  CD1 TYR A 293      -3.861 -15.771  27.775  1.00 42.03           C  
+ATOM   2068  CD2 TYR A 293      -4.683 -16.720  25.743  1.00 41.63           C  
+ATOM   2069  CE1 TYR A 293      -2.556 -15.857  27.294  1.00 43.74           C  
+ATOM   2070  CE2 TYR A 293      -3.386 -16.813  25.252  1.00 43.55           C  
+ATOM   2071  CZ  TYR A 293      -2.325 -16.380  26.032  1.00 45.58           C  
+ATOM   2072  OH  TYR A 293      -1.034 -16.474  25.553  1.00 47.27           O  
+ATOM   2073  N   MET A 294      -5.903 -17.140  30.506  1.00 42.73           N  
+ATOM   2074  CA  MET A 294      -4.979 -17.487  31.577  1.00 45.44           C  
+ATOM   2075  C   MET A 294      -5.276 -18.898  32.095  1.00 46.02           C  
+ATOM   2076  O   MET A 294      -4.364 -19.699  32.288  1.00 46.64           O  
+ATOM   2077  CB  MET A 294      -5.068 -16.468  32.718  1.00 45.41           C  
+ATOM   2078  CG  MET A 294      -3.932 -16.585  33.733  1.00 48.64           C  
+ATOM   2079  SD  MET A 294      -2.299 -16.108  33.076  1.00 50.48           S  
+ATOM   2080  CE  MET A 294      -2.084 -14.554  33.911  1.00 51.28           C  
+ATOM   2081  N   LEU A 295      -6.555 -19.191  32.315  1.00 46.11           N  
+ATOM   2082  CA  LEU A 295      -6.977 -20.502  32.791  1.00 46.96           C  
+ATOM   2083  C   LEU A 295      -6.485 -21.584  31.827  1.00 47.78           C  
+ATOM   2084  O   LEU A 295      -5.942 -22.598  32.254  1.00 47.13           O  
+ATOM   2085  CB  LEU A 295      -8.505 -20.557  32.904  1.00 46.02           C  
+ATOM   2086  CG  LEU A 295      -9.126 -21.886  33.360  1.00 48.48           C  
+ATOM   2087  CD1 LEU A 295      -8.581 -22.282  34.739  1.00 46.15           C  
+ATOM   2088  CD2 LEU A 295     -10.647 -21.754  33.400  1.00 43.56           C  
+ATOM   2089  N   LEU A 296      -6.669 -21.365  30.529  1.00 49.16           N  
+ATOM   2090  CA  LEU A 296      -6.215 -22.337  29.541  1.00 52.82           C  
+ATOM   2091  C   LEU A 296      -4.716 -22.579  29.689  1.00 54.56           C  
+ATOM   2092  O   LEU A 296      -4.255 -23.719  29.695  1.00 55.44           O  
+ATOM   2093  CB  LEU A 296      -6.506 -21.848  28.116  1.00 51.97           C  
+ATOM   2094  CG  LEU A 296      -7.966 -21.810  27.655  1.00 53.81           C  
+ATOM   2095  CD1 LEU A 296      -8.038 -21.209  26.255  1.00 51.62           C  
+ATOM   2096  CD2 LEU A 296      -8.559 -23.218  27.665  1.00 51.52           C  
+ATOM   2097  N   VAL A 297      -3.954 -21.500  29.813  1.00 55.62           N  
+ATOM   2098  CA  VAL A 297      -2.511 -21.617  29.950  1.00 56.52           C  
+ATOM   2099  C   VAL A 297      -2.111 -22.278  31.266  1.00 58.06           C  
+ATOM   2100  O   VAL A 297      -1.180 -23.082  31.300  1.00 56.90           O  
+ATOM   2101  CB  VAL A 297      -1.831 -20.225  29.850  1.00 56.12           C  
+ATOM   2102  CG1 VAL A 297      -0.329 -20.346  30.098  1.00 51.75           C  
+ATOM   2103  CG2 VAL A 297      -2.093 -19.624  28.474  1.00 55.76           C  
+ATOM   2104  N   ASP A 298      -2.814 -21.944  32.345  1.00 59.16           N  
+ATOM   2105  CA  ASP A 298      -2.494 -22.509  33.649  1.00 62.05           C  
+ATOM   2106  C   ASP A 298      -2.734 -24.008  33.758  1.00 63.79           C  
+ATOM   2107  O   ASP A 298      -1.933 -24.720  34.357  1.00 63.53           O  
+ATOM   2108  CB  ASP A 298      -3.278 -21.809  34.756  1.00 61.87           C  
+ATOM   2109  CG  ASP A 298      -2.973 -22.383  36.133  1.00 63.69           C  
+ATOM   2110  OD1 ASP A 298      -3.917 -22.856  36.804  1.00 64.41           O  
+ATOM   2111  OD2 ASP A 298      -1.788 -22.362  36.541  1.00 62.85           O  
+ATOM   2112  N   ASN A 299      -3.838 -24.496  33.203  1.00 66.08           N  
+ATOM   2113  CA  ASN A 299      -4.097 -25.923  33.287  1.00 68.98           C  
+ATOM   2114  C   ASN A 299      -3.334 -26.666  32.191  1.00 69.93           C  
+ATOM   2115  O   ASN A 299      -3.560 -27.851  31.940  1.00 71.25           O  
+ATOM   2116  CB  ASN A 299      -5.611 -26.220  33.266  1.00 68.34           C  
+ATOM   2117  CG  ASN A 299      -6.276 -25.851  31.962  1.00 69.42           C  
+ATOM   2118  OD1 ASN A 299      -7.491 -25.636  31.916  1.00 69.06           O  
+ATOM   2119  ND2 ASN A 299      -5.497 -25.794  30.889  1.00 70.57           N  
+ATOM   2120  N   VAL A 300      -2.425 -25.946  31.541  1.00 70.13           N  
+ATOM   2121  CA  VAL A 300      -1.564 -26.531  30.520  1.00 70.95           C  
+ATOM   2122  C   VAL A 300      -0.238 -26.722  31.246  1.00 71.65           C  
+ATOM   2123  O   VAL A 300       0.507 -27.659  30.974  1.00 71.88           O  
+ATOM   2124  CB  VAL A 300      -1.361 -25.592  29.303  1.00 70.66           C  
+ATOM   2125  CG1 VAL A 300      -0.129 -26.014  28.512  1.00 69.00           C  
+ATOM   2126  CG2 VAL A 300      -2.580 -25.652  28.398  1.00 70.65           C  
+ATOM   2127  N   ALA A 301       0.033 -25.823  32.188  1.00 72.85           N  
+ATOM   2128  CA  ALA A 301       1.247 -25.886  32.990  1.00 75.20           C  
+ATOM   2129  C   ALA A 301       1.183 -27.144  33.850  1.00 77.14           C  
+ATOM   2130  O   ALA A 301       2.209 -27.673  34.283  1.00 77.61           O  
+ATOM   2131  CB  ALA A 301       1.354 -24.652  33.874  1.00 74.20           C  
+ATOM   2132  N   ARG A 302      -0.038 -27.612  34.095  1.00 79.18           N  
+ATOM   2133  CA  ARG A 302      -0.260 -28.813  34.889  1.00 81.20           C  
+ATOM   2134  C   ARG A 302      -0.224 -30.029  33.970  1.00 82.96           C  
+ATOM   2135  O   ARG A 302       0.537 -30.969  34.197  1.00 84.12           O  
+ATOM   2136  CB  ARG A 302      -1.617 -28.751  35.594  1.00 79.86           C  
+ATOM   2137  CG  ARG A 302      -1.815 -27.556  36.505  1.00 77.35           C  
+ATOM   2138  CD  ARG A 302      -3.119 -27.693  37.274  1.00 77.42           C  
+ATOM   2139  NE  ARG A 302      -4.280 -27.785  36.389  1.00 77.88           N  
+ATOM   2140  CZ  ARG A 302      -5.479 -28.225  36.766  1.00 77.01           C  
+ATOM   2141  NH1 ARG A 302      -6.476 -28.271  35.894  1.00 74.75           N  
+ATOM   2142  NH2 ARG A 302      -5.679 -28.631  38.012  1.00 77.06           N  
+ATOM   2143  N   SER A 303      -1.051 -30.002  32.929  1.00 84.53           N  
+ATOM   2144  CA  SER A 303      -1.116 -31.097  31.967  1.00 86.61           C  
+ATOM   2145  C   SER A 303       0.256 -31.396  31.369  1.00 88.13           C  
+ATOM   2146  O   SER A 303       0.770 -32.507  31.495  1.00 88.27           O  
+ATOM   2147  CB  SER A 303      -2.085 -30.752  30.833  1.00 86.59           C  
+ATOM   2148  OG  SER A 303      -3.392 -30.512  31.320  1.00 88.65           O  
+ATOM   2149  N   LEU A 304       0.831 -30.384  30.721  1.00 89.66           N  
+ATOM   2150  CA  LEU A 304       2.132 -30.474  30.061  1.00 90.14           C  
+ATOM   2151  C   LEU A 304       3.102 -31.481  30.673  1.00 90.37           C  
+ATOM   2152  O   LEU A 304       3.631 -32.340  29.967  1.00 91.13           O  
+ATOM   2153  CB  LEU A 304       2.791 -29.089  30.020  0.00 90.24           C  
+ATOM   2154  CG  LEU A 304       4.020 -28.862  29.128  0.00 90.34           C  
+ATOM   2155  CD1 LEU A 304       5.229 -29.604  29.675  0.00 90.39           C  
+ATOM   2156  CD2 LEU A 304       3.701 -29.310  27.710  0.00 90.39           C  
+ATOM   2157  N   SER A 305       3.341 -31.382  31.976  1.00 89.79           N  
+ATOM   2158  CA  SER A 305       4.275 -32.296  32.627  1.00 89.25           C  
+ATOM   2159  C   SER A 305       3.803 -32.776  33.993  1.00 88.33           C  
+ATOM   2160  O   SER A 305       2.748 -32.367  34.475  1.00 88.25           O  
+ATOM   2161  CB  SER A 305       5.640 -31.615  32.768  1.00 89.57           C  
+ATOM   2162  OG  SER A 305       6.567 -32.450  33.438  1.00 90.99           O  
+ATOM   2163  N   ASP A 306       4.593 -33.658  34.603  1.00 87.81           N  
+ATOM   2164  CA  ASP A 306       4.284 -34.189  35.930  1.00 86.29           C  
+ATOM   2165  C   ASP A 306       4.638 -33.101  36.935  1.00 84.47           C  
+ATOM   2166  O   ASP A 306       3.969 -32.935  37.959  1.00 83.81           O  
+ATOM   2167  CB  ASP A 306       5.114 -35.448  36.219  1.00 86.75           C  
+ATOM   2168  CG  ASP A 306       4.791 -36.591  35.275  1.00 86.96           C  
+ATOM   2169  OD1 ASP A 306       4.970 -36.422  34.051  0.00 87.00           O  
+ATOM   2170  OD2 ASP A 306       4.359 -37.659  35.758  0.00 87.00           O  
+ATOM   2171  N   ALA A 307       5.698 -32.362  36.622  1.00 81.89           N  
+ATOM   2172  CA  ALA A 307       6.161 -31.272  37.469  1.00 79.83           C  
+ATOM   2173  C   ALA A 307       5.474 -29.970  37.063  1.00 78.18           C  
+ATOM   2174  O   ALA A 307       5.051 -29.805  35.915  1.00 78.87           O  
+ATOM   2175  CB  ALA A 307       7.676 -31.124  37.352  1.00 79.47           C  
+ATOM   2176  N   GLU A 308       5.363 -29.049  38.012  1.00 75.02           N  
+ATOM   2177  CA  GLU A 308       4.731 -27.764  37.759  1.00 71.72           C  
+ATOM   2178  C   GLU A 308       5.701 -26.788  37.109  1.00 68.30           C  
+ATOM   2179  O   GLU A 308       6.632 -26.314  37.757  1.00 68.29           O  
+ATOM   2180  CB  GLU A 308       4.219 -27.157  39.070  1.00 72.78           C  
+ATOM   2181  CG  GLU A 308       2.910 -27.738  39.584  1.00 75.54           C  
+ATOM   2182  CD  GLU A 308       1.722 -27.367  38.711  1.00 76.95           C  
+ATOM   2183  OE1 GLU A 308       1.496 -26.157  38.500  1.00 77.33           O  
+ATOM   2184  OE2 GLU A 308       1.014 -28.284  38.240  1.00 78.64           O  
+ATOM   2185  N   ILE A 309       5.496 -26.499  35.828  1.00 63.54           N  
+ATOM   2186  CA  ILE A 309       6.350 -25.537  35.141  1.00 59.93           C  
+ATOM   2187  C   ILE A 309       5.730 -24.164  35.394  1.00 56.20           C  
+ATOM   2188  O   ILE A 309       4.545 -23.962  35.145  1.00 53.54           O  
+ATOM   2189  CB  ILE A 309       6.411 -25.813  33.618  1.00 60.55           C  
+ATOM   2190  CG1 ILE A 309       7.173 -24.690  32.909  1.00 59.96           C  
+ATOM   2191  CG2 ILE A 309       5.015 -25.938  33.056  1.00 61.20           C  
+ATOM   2192  CD1 ILE A 309       7.455 -24.967  31.446  0.00 60.20           C  
+ATOM   2193  N   PRO A 310       6.516 -23.210  35.921  1.00 54.92           N  
+ATOM   2194  CA  PRO A 310       5.964 -21.875  36.185  1.00 54.60           C  
+ATOM   2195  C   PRO A 310       5.220 -21.320  34.970  1.00 53.25           C  
+ATOM   2196  O   PRO A 310       5.717 -21.374  33.842  1.00 51.37           O  
+ATOM   2197  CB  PRO A 310       7.198 -21.054  36.577  1.00 55.67           C  
+ATOM   2198  CG  PRO A 310       8.340 -21.792  35.925  1.00 55.96           C  
+ATOM   2199  CD  PRO A 310       7.970 -23.233  36.149  1.00 54.75           C  
+ATOM   2200  N   ILE A 311       4.022 -20.799  35.214  1.00 51.85           N  
+ATOM   2201  CA  ILE A 311       3.175 -20.276  34.149  1.00 50.55           C  
+ATOM   2202  C   ILE A 311       3.811 -19.137  33.349  1.00 49.22           C  
+ATOM   2203  O   ILE A 311       3.408 -18.871  32.220  1.00 48.73           O  
+ATOM   2204  CB  ILE A 311       1.792 -19.828  34.718  1.00 50.31           C  
+ATOM   2205  CG1 ILE A 311       0.765 -19.750  33.587  1.00 49.66           C  
+ATOM   2206  CG2 ILE A 311       1.923 -18.489  35.437  1.00 50.10           C  
+ATOM   2207  CD1 ILE A 311      -0.634 -19.409  34.044  0.00 49.78           C  
+ATOM   2208  N   SER A 312       4.810 -18.476  33.920  1.00 48.48           N  
+ATOM   2209  CA  SER A 312       5.470 -17.383  33.218  1.00 49.38           C  
+ATOM   2210  C   SER A 312       6.224 -17.909  32.002  1.00 49.44           C  
+ATOM   2211  O   SER A 312       6.311 -17.238  30.970  1.00 48.61           O  
+ATOM   2212  CB  SER A 312       6.433 -16.651  34.151  1.00 50.88           C  
+ATOM   2213  OG  SER A 312       7.388 -17.544  34.703  1.00 52.99           O  
+ATOM   2214  N   ILE A 313       6.775 -19.111  32.122  1.00 48.51           N  
+ATOM   2215  CA  ILE A 313       7.492 -19.710  31.007  1.00 47.70           C  
+ATOM   2216  C   ILE A 313       6.500 -19.983  29.877  1.00 47.66           C  
+ATOM   2217  O   ILE A 313       6.800 -19.744  28.708  1.00 48.78           O  
+ATOM   2218  CB  ILE A 313       8.164 -21.043  31.409  1.00 48.13           C  
+ATOM   2219  CG1 ILE A 313       9.206 -20.802  32.506  1.00 48.53           C  
+ATOM   2220  CG2 ILE A 313       8.814 -21.680  30.189  1.00 50.20           C  
+ATOM   2221  CD1 ILE A 313       9.929 -22.055  32.956  0.00 48.38           C  
+ATOM   2222  N   LEU A 314       5.315 -20.475  30.233  1.00 46.62           N  
+ATOM   2223  CA  LEU A 314       4.286 -20.790  29.244  1.00 46.67           C  
+ATOM   2224  C   LEU A 314       3.625 -19.588  28.568  1.00 45.60           C  
+ATOM   2225  O   LEU A 314       3.303 -19.650  27.381  1.00 44.95           O  
+ATOM   2226  CB  LEU A 314       3.199 -21.677  29.863  1.00 48.65           C  
+ATOM   2227  CG  LEU A 314       3.479 -23.182  29.980  1.00 51.09           C  
+ATOM   2228  CD1 LEU A 314       3.904 -23.739  28.617  1.00 49.87           C  
+ATOM   2229  CD2 LEU A 314       4.560 -23.425  31.007  1.00 51.32           C  
+ATOM   2230  N   THR A 315       3.395 -18.507  29.307  1.00 43.82           N  
+ATOM   2231  CA  THR A 315       2.789 -17.334  28.686  1.00 45.29           C  
+ATOM   2232  C   THR A 315       3.743 -16.763  27.632  1.00 45.09           C  
+ATOM   2233  O   THR A 315       3.305 -16.242  26.610  1.00 45.59           O  
+ATOM   2234  CB  THR A 315       2.460 -16.228  29.713  1.00 44.63           C  
+ATOM   2235  OG1 THR A 315       3.632 -15.901  30.466  1.00 43.89           O  
+ATOM   2236  CG2 THR A 315       1.348 -16.685  30.649  1.00 44.91           C  
+ATOM   2237  N   ALA A 316       5.045 -16.888  27.877  1.00 44.25           N  
+ATOM   2238  CA  ALA A 316       6.054 -16.393  26.947  1.00 45.29           C  
+ATOM   2239  C   ALA A 316       6.196 -17.290  25.720  1.00 46.59           C  
+ATOM   2240  O   ALA A 316       6.313 -16.802  24.598  1.00 47.67           O  
+ATOM   2241  CB  ALA A 316       7.398 -16.263  27.656  1.00 42.81           C  
+ATOM   2242  N   LEU A 317       6.184 -18.601  25.931  1.00 48.19           N  
+ATOM   2243  CA  LEU A 317       6.322 -19.545  24.825  1.00 48.33           C  
+ATOM   2244  C   LEU A 317       5.079 -19.567  23.952  1.00 48.43           C  
+ATOM   2245  O   LEU A 317       5.154 -19.872  22.765  1.00 48.14           O  
+ATOM   2246  CB  LEU A 317       6.595 -20.956  25.350  1.00 48.74           C  
+ATOM   2247  CG  LEU A 317       7.941 -21.203  26.029  1.00 51.25           C  
+ATOM   2248  CD1 LEU A 317       7.993 -22.638  26.537  1.00 53.24           C  
+ATOM   2249  CD2 LEU A 317       9.073 -20.954  25.043  1.00 51.87           C  
+ATOM   2250  N   ILE A 318       3.931 -19.258  24.545  1.00 48.83           N  
+ATOM   2251  CA  ILE A 318       2.678 -19.241  23.799  1.00 48.47           C  
+ATOM   2252  C   ILE A 318       2.452 -17.830  23.272  1.00 49.22           C  
+ATOM   2253  O   ILE A 318       2.165 -17.626  22.088  1.00 48.46           O  
+ATOM   2254  CB  ILE A 318       1.466 -19.623  24.692  1.00 48.25           C  
+ATOM   2255  CG1 ILE A 318       1.630 -21.045  25.244  1.00 47.46           C  
+ATOM   2256  CG2 ILE A 318       0.182 -19.525  23.882  1.00 47.04           C  
+ATOM   2257  CD1 ILE A 318       0.516 -21.477  26.176  0.00 47.89           C  
+ATOM   2258  N   GLY A 319       2.599 -16.863  24.171  1.00 49.13           N  
+ATOM   2259  CA  GLY A 319       2.399 -15.471  23.819  1.00 51.20           C  
+ATOM   2260  C   GLY A 319       3.228 -14.953  22.665  1.00 52.33           C  
+ATOM   2261  O   GLY A 319       2.680 -14.538  21.649  1.00 52.55           O  
+ATOM   2262  N   ALA A 320       4.548 -14.971  22.817  1.00 55.13           N  
+ATOM   2263  CA  ALA A 320       5.445 -14.475  21.779  1.00 56.80           C  
+ATOM   2264  C   ALA A 320       5.036 -14.913  20.372  1.00 57.76           C  
+ATOM   2265  O   ALA A 320       4.719 -14.078  19.523  1.00 58.09           O  
+ATOM   2266  CB  ALA A 320       6.875 -14.908  22.072  1.00 56.75           C  
+ATOM   2267  N   PRO A 321       5.025 -16.228  20.104  1.00 59.23           N  
+ATOM   2268  CA  PRO A 321       4.637 -16.669  18.761  1.00 59.39           C  
+ATOM   2269  C   PRO A 321       3.233 -16.216  18.369  1.00 59.27           C  
+ATOM   2270  O   PRO A 321       2.984 -15.866  17.213  1.00 60.08           O  
+ATOM   2271  CB  PRO A 321       4.772 -18.188  18.845  1.00 59.23           C  
+ATOM   2272  CG  PRO A 321       4.479 -18.469  20.269  1.00 60.48           C  
+ATOM   2273  CD  PRO A 321       5.235 -17.382  20.993  1.00 59.07           C  
+ATOM   2274  N   LEU A 322       2.320 -16.212  19.333  1.00 58.23           N  
+ATOM   2275  CA  LEU A 322       0.955 -15.788  19.061  1.00 58.21           C  
+ATOM   2276  C   LEU A 322       0.964 -14.311  18.678  1.00 59.45           C  
+ATOM   2277  O   LEU A 322       0.197 -13.870  17.815  1.00 58.93           O  
+ATOM   2278  CB  LEU A 322       0.077 -16.002  20.293  1.00 57.36           C  
+ATOM   2279  CG  LEU A 322      -1.409 -15.689  20.109  1.00 58.11           C  
+ATOM   2280  CD1 LEU A 322      -1.993 -16.581  19.026  1.00 58.02           C  
+ATOM   2281  CD2 LEU A 322      -2.142 -15.895  21.423  1.00 58.17           C  
+ATOM   2282  N   PHE A 323       1.842 -13.554  19.330  1.00 60.03           N  
+ATOM   2283  CA  PHE A 323       1.987 -12.128  19.073  1.00 60.34           C  
+ATOM   2284  C   PHE A 323       2.410 -11.957  17.619  1.00 61.51           C  
+ATOM   2285  O   PHE A 323       1.871 -11.120  16.895  1.00 60.06           O  
+ATOM   2286  CB  PHE A 323       3.053 -11.540  20.000  1.00 59.72           C  
+ATOM   2287  CG  PHE A 323       3.244 -10.056  19.853  1.00 58.44           C  
+ATOM   2288  CD1 PHE A 323       2.252  -9.169  20.252  1.00 59.30           C  
+ATOM   2289  CD2 PHE A 323       4.429  -9.544  19.331  1.00 58.62           C  
+ATOM   2290  CE1 PHE A 323       2.438  -7.790  20.136  1.00 58.46           C  
+ATOM   2291  CE2 PHE A 323       4.625  -8.169  19.210  1.00 57.55           C  
+ATOM   2292  CZ  PHE A 323       3.629  -7.292  19.614  1.00 58.74           C  
+ATOM   2293  N   GLY A 324       3.378 -12.765  17.198  1.00 63.27           N  
+ATOM   2294  CA  GLY A 324       3.853 -12.697  15.831  1.00 65.22           C  
+ATOM   2295  C   GLY A 324       2.718 -12.954  14.863  1.00 66.85           C  
+ATOM   2296  O   GLY A 324       2.516 -12.200  13.911  1.00 66.60           O  
+ATOM   2297  N   VAL A 325       1.970 -14.024  15.114  1.00 67.88           N  
+ATOM   2298  CA  VAL A 325       0.845 -14.393  14.267  1.00 68.53           C  
+ATOM   2299  C   VAL A 325      -0.174 -13.269  14.173  1.00 69.27           C  
+ATOM   2300  O   VAL A 325      -0.712 -13.000  13.100  1.00 69.19           O  
+ATOM   2301  CB  VAL A 325       0.147 -15.660  14.797  1.00 68.48           C  
+ATOM   2302  CG1 VAL A 325      -1.146 -15.905  14.037  1.00 69.10           C  
+ATOM   2303  CG2 VAL A 325       1.076 -16.855  14.651  1.00 68.06           C  
+ATOM   2304  N   LEU A 326      -0.440 -12.613  15.296  1.00 70.96           N  
+ATOM   2305  CA  LEU A 326      -1.400 -11.516  15.314  1.00 73.29           C  
+ATOM   2306  C   LEU A 326      -0.882 -10.322  14.517  1.00 75.05           C  
+ATOM   2307  O   LEU A 326      -1.654  -9.631  13.850  1.00 75.21           O  
+ATOM   2308  CB  LEU A 326      -1.706 -11.104  16.757  1.00 73.01           C  
+ATOM   2309  CG  LEU A 326      -2.445 -12.166  17.583  1.00 74.29           C  
+ATOM   2310  CD1 LEU A 326      -2.648 -11.679  19.010  1.00 73.18           C  
+ATOM   2311  CD2 LEU A 326      -3.786 -12.474  16.927  1.00 73.09           C  
+ATOM   2312  N   VAL A 327       0.426 -10.089  14.585  1.00 77.14           N  
+ATOM   2313  CA  VAL A 327       1.052  -8.988  13.860  1.00 79.41           C  
+ATOM   2314  C   VAL A 327       1.144  -9.339  12.378  1.00 81.79           C  
+ATOM   2315  O   VAL A 327       0.903  -8.497  11.512  1.00 81.80           O  
+ATOM   2316  CB  VAL A 327       2.472  -8.700  14.396  1.00 78.98           C  
+ATOM   2317  CG1 VAL A 327       3.202  -7.751  13.460  1.00 78.94           C  
+ATOM   2318  CG2 VAL A 327       2.388  -8.093  15.791  1.00 78.40           C  
+ATOM   2319  N   TYR A 328       1.496 -10.590  12.100  1.00 84.49           N  
+ATOM   2320  CA  TYR A 328       1.613 -11.078  10.732  1.00 87.31           C  
+ATOM   2321  C   TYR A 328       0.368 -10.714   9.926  1.00 88.84           C  
+ATOM   2322  O   TYR A 328       0.470 -10.269   8.782  1.00 89.40           O  
+ATOM   2323  CB  TYR A 328       1.810 -12.599  10.738  1.00 88.57           C  
+ATOM   2324  CG  TYR A 328       1.738 -13.246   9.371  1.00 90.19           C  
+ATOM   2325  CD1 TYR A 328       2.619 -12.879   8.354  1.00 90.39           C  
+ATOM   2326  CD2 TYR A 328       0.780 -14.223   9.092  1.00 90.60           C  
+ATOM   2327  CE1 TYR A 328       2.548 -13.466   7.092  1.00 90.75           C  
+ATOM   2328  CE2 TYR A 328       0.699 -14.817   7.835  1.00 90.96           C  
+ATOM   2329  CZ  TYR A 328       1.585 -14.434   6.840  1.00 91.59           C  
+ATOM   2330  OH  TYR A 328       1.502 -15.010   5.592  1.00 92.09           O  
+ATOM   2331  N   LYS A 329      -0.803 -10.900  10.531  1.00 90.44           N  
+ATOM   2332  CA  LYS A 329      -2.066 -10.586   9.870  1.00 91.69           C  
+ATOM   2333  C   LYS A 329      -2.440  -9.115  10.043  1.00 93.20           C  
+ATOM   2334  O   LYS A 329      -3.361  -8.778  10.788  1.00 92.94           O  
+ATOM   2335  CB  LYS A 329      -3.195 -11.473  10.415  1.00 91.90           C  
+ATOM   2336  CG  LYS A 329      -3.425 -11.364  11.921  1.00 92.94           C  
+ATOM   2337  CD  LYS A 329      -4.768 -11.966  12.345  1.00 92.93           C  
+ATOM   2338  CE  LYS A 329      -4.841 -13.467  12.088  1.00 92.96           C  
+ATOM   2339  NZ  LYS A 329      -6.151 -14.040  12.516  1.00 91.93           N  
+ATOM   2340  N   LEU A 330      -1.718  -8.239   9.351  1.00 94.33           N  
+ATOM   2341  CA  LEU A 330      -1.985  -6.807   9.423  1.00 94.40           C  
+ATOM   2342  C   LEU A 330      -3.237  -6.469   8.622  1.00 93.71           C  
+ATOM   2343  O   LEU A 330      -3.827  -7.399   8.033  0.00 93.76           O  
+ATOM   2344  CB  LEU A 330      -0.795  -6.012   8.874  1.00 95.29           C  
+ATOM   2345  CG  LEU A 330       0.515  -6.071   9.666  1.00 96.50           C  
+ATOM   2346  CD1 LEU A 330       1.614  -5.347   8.901  1.00 96.16           C  
+ATOM   2347  CD2 LEU A 330       0.312  -5.444  11.039  1.00 96.29           C  
+TER    2348      LEU A 330                                                      
+ATOM   2349  N   ASN C   2     -25.162  40.320  21.248  1.00 60.07           N  
+ATOM   2350  CA  ASN C   2     -24.385  40.442  22.519  1.00 59.62           C  
+ATOM   2351  C   ASN C   2     -22.991  39.835  22.327  1.00 57.17           C  
+ATOM   2352  O   ASN C   2     -22.751  39.108  21.365  1.00 55.10           O  
+ATOM   2353  CB  ASN C   2     -25.123  39.717  23.656  1.00 61.61           C  
+ATOM   2354  CG  ASN C   2     -24.748  40.245  25.042  1.00 66.11           C  
+ATOM   2355  OD1 ASN C   2     -23.574  40.241  25.435  1.00 67.16           O  
+ATOM   2356  ND2 ASN C   2     -25.751  40.699  25.791  1.00 65.28           N  
+ATOM   2357  N   LYS C   3     -22.082  40.145  23.248  1.00 55.09           N  
+ATOM   2358  CA  LYS C   3     -20.713  39.642  23.198  1.00 52.93           C  
+ATOM   2359  C   LYS C   3     -20.614  38.118  23.196  1.00 49.17           C  
+ATOM   2360  O   LYS C   3     -21.454  37.421  23.761  1.00 48.05           O  
+ATOM   2361  CB  LYS C   3     -19.899  40.197  24.372  1.00 56.54           C  
+ATOM   2362  CG  LYS C   3     -19.315  41.586  24.139  1.00 59.85           C  
+ATOM   2363  CD  LYS C   3     -18.503  42.059  25.343  1.00 62.71           C  
+ATOM   2364  CE  LYS C   3     -17.667  43.297  25.015  1.00 65.02           C  
+ATOM   2365  NZ  LYS C   3     -18.488  44.450  24.530  1.00 66.98           N  
+ATOM   2366  N   ALA C   4     -19.578  37.614  22.538  1.00 46.35           N  
+ATOM   2367  CA  ALA C   4     -19.335  36.182  22.456  1.00 44.79           C  
+ATOM   2368  C   ALA C   4     -17.964  35.921  23.055  1.00 42.55           C  
+ATOM   2369  O   ALA C   4     -17.752  34.942  23.767  1.00 40.84           O  
+ATOM   2370  CB  ALA C   4     -19.367  35.725  21.003  1.00 44.78           C  
+ATOM   2371  N   LEU C   5     -17.041  36.830  22.774  1.00 41.09           N  
+ATOM   2372  CA  LEU C   5     -15.678  36.711  23.256  1.00 39.89           C  
+ATOM   2373  C   LEU C   5     -15.018  38.078  23.374  1.00 39.36           C  
+ATOM   2374  O   LEU C   5     -15.297  38.993  22.592  1.00 37.08           O  
+ATOM   2375  CB  LEU C   5     -14.867  35.842  22.290  1.00 42.57           C  
+ATOM   2376  CG  LEU C   5     -13.349  35.777  22.475  1.00 43.21           C  
+ATOM   2377  CD1 LEU C   5     -13.010  35.003  23.751  1.00 43.98           C  
+ATOM   2378  CD2 LEU C   5     -12.732  35.096  21.263  1.00 46.34           C  
+ATOM   2379  N   SER C   6     -14.126  38.200  24.349  1.00 38.09           N  
+ATOM   2380  CA  SER C   6     -13.402  39.438  24.560  1.00 40.38           C  
+ATOM   2381  C   SER C   6     -11.951  39.158  24.928  1.00 39.08           C  
+ATOM   2382  O   SER C   6     -11.660  38.321  25.781  1.00 39.42           O  
+ATOM   2383  CB  SER C   6     -14.066  40.270  25.659  1.00 42.06           C  
+ATOM   2384  OG  SER C   6     -13.293  41.427  25.925  1.00 44.68           O  
+ATOM   2385  N   VAL C   7     -11.046  39.872  24.273  1.00 39.74           N  
+ATOM   2386  CA  VAL C   7      -9.618  39.726  24.500  1.00 40.96           C  
+ATOM   2387  C   VAL C   7      -9.085  41.124  24.765  1.00 42.97           C  
+ATOM   2388  O   VAL C   7      -9.112  41.982  23.885  1.00 43.61           O  
+ATOM   2389  CB  VAL C   7      -8.934  39.106  23.259  1.00 40.82           C  
+ATOM   2390  CG1 VAL C   7      -7.432  39.017  23.468  1.00 39.67           C  
+ATOM   2391  CG2 VAL C   7      -9.517  37.714  22.998  1.00 40.41           C  
+ATOM   2392  N   GLU C   8      -8.599  41.351  25.982  1.00 45.71           N  
+ATOM   2393  CA  GLU C   8      -8.114  42.671  26.360  1.00 47.29           C  
+ATOM   2394  C   GLU C   8      -6.674  42.722  26.843  1.00 46.01           C  
+ATOM   2395  O   GLU C   8      -6.294  41.999  27.766  1.00 48.07           O  
+ATOM   2396  CB  GLU C   8      -9.025  43.240  27.452  1.00 52.22           C  
+ATOM   2397  CG  GLU C   8     -10.513  43.139  27.127  1.00 58.26           C  
+ATOM   2398  CD  GLU C   8     -11.403  43.577  28.277  1.00 62.81           C  
+ATOM   2399  OE1 GLU C   8     -12.644  43.509  28.129  1.00 64.46           O  
+ATOM   2400  OE2 GLU C   8     -10.865  43.988  29.328  1.00 66.39           O  
+ATOM   2401  N   ASN C   9      -5.876  43.573  26.206  1.00 43.91           N  
+ATOM   2402  CA  ASN C   9      -4.486  43.771  26.600  1.00 44.83           C  
+ATOM   2403  C   ASN C   9      -3.705  42.453  26.704  1.00 45.67           C  
+ATOM   2404  O   ASN C   9      -2.783  42.319  27.520  1.00 44.93           O  
+ATOM   2405  CB  ASN C   9      -4.470  44.502  27.952  1.00 45.56           C  
+ATOM   2406  CG  ASN C   9      -3.124  45.104  28.283  1.00 48.04           C  
+ATOM   2407  OD1 ASN C   9      -2.690  45.085  29.440  1.00 51.48           O  
+ATOM   2408  ND2 ASN C   9      -2.460  45.659  27.276  1.00 46.80           N  
+ATOM   2409  N   LEU C  10      -4.064  41.487  25.865  1.00 45.03           N  
+ATOM   2410  CA  LEU C  10      -3.409  40.191  25.882  1.00 42.75           C  
+ATOM   2411  C   LEU C  10      -1.960  40.233  25.424  1.00 41.96           C  
+ATOM   2412  O   LEU C  10      -1.632  40.843  24.412  1.00 40.01           O  
+ATOM   2413  CB  LEU C  10      -4.180  39.203  25.012  1.00 44.27           C  
+ATOM   2414  CG  LEU C  10      -3.825  37.735  25.243  1.00 45.90           C  
+ATOM   2415  CD1 LEU C  10      -4.282  37.348  26.643  1.00 45.76           C  
+ATOM   2416  CD2 LEU C  10      -4.508  36.849  24.194  1.00 45.37           C  
+ATOM   2417  N   GLY C  11      -1.101  39.573  26.195  1.00 42.39           N  
+ATOM   2418  CA  GLY C  11       0.314  39.485  25.885  1.00 42.67           C  
+ATOM   2419  C   GLY C  11       0.735  38.038  26.114  1.00 45.87           C  
+ATOM   2420  O   GLY C  11       0.362  37.427  27.118  1.00 43.75           O  
+ATOM   2421  N   PHE C  12       1.507  37.474  25.195  1.00 49.23           N  
+ATOM   2422  CA  PHE C  12       1.925  36.079  25.341  1.00 51.80           C  
+ATOM   2423  C   PHE C  12       3.176  35.746  24.541  1.00 52.84           C  
+ATOM   2424  O   PHE C  12       3.486  36.400  23.547  1.00 51.24           O  
+ATOM   2425  CB  PHE C  12       0.779  35.154  24.921  1.00 51.73           C  
+ATOM   2426  CG  PHE C  12       0.316  35.366  23.508  1.00 50.39           C  
+ATOM   2427  CD1 PHE C  12       0.795  34.567  22.478  1.00 50.63           C  
+ATOM   2428  CD2 PHE C  12      -0.606  36.364  23.208  1.00 51.45           C  
+ATOM   2429  CE1 PHE C  12       0.359  34.756  21.166  1.00 50.89           C  
+ATOM   2430  CE2 PHE C  12      -1.046  36.563  21.897  1.00 50.23           C  
+ATOM   2431  CZ  PHE C  12      -0.564  35.757  20.877  1.00 49.44           C  
+ATOM   2432  N   TYR C  13       3.885  34.714  24.982  1.00 55.84           N  
+ATOM   2433  CA  TYR C  13       5.112  34.301  24.320  1.00 58.88           C  
+ATOM   2434  C   TYR C  13       4.895  33.068  23.462  1.00 60.50           C  
+ATOM   2435  O   TYR C  13       4.092  32.196  23.793  1.00 60.33           O  
+ATOM   2436  CB  TYR C  13       6.194  34.009  25.364  1.00 60.49           C  
+ATOM   2437  CG  TYR C  13       7.595  33.881  24.805  1.00 63.43           C  
+ATOM   2438  CD1 TYR C  13       8.239  32.643  24.744  1.00 63.99           C  
+ATOM   2439  CD2 TYR C  13       8.291  35.006  24.364  1.00 65.36           C  
+ATOM   2440  CE1 TYR C  13       9.549  32.532  24.261  1.00 65.36           C  
+ATOM   2441  CE2 TYR C  13       9.595  34.908  23.879  1.00 66.75           C  
+ATOM   2442  CZ  TYR C  13      10.220  33.671  23.831  1.00 67.42           C  
+ATOM   2443  OH  TYR C  13      11.516  33.588  23.358  1.00 69.17           O  
+ATOM   2444  N   TYR C  14       5.612  33.015  22.348  1.00 62.94           N  
+ATOM   2445  CA  TYR C  14       5.548  31.881  21.442  1.00 66.20           C  
+ATOM   2446  C   TYR C  14       6.981  31.386  21.333  1.00 66.99           C  
+ATOM   2447  O   TYR C  14       7.804  31.997  20.648  1.00 65.82           O  
+ATOM   2448  CB  TYR C  14       5.022  32.312  20.069  1.00 67.81           C  
+ATOM   2449  CG  TYR C  14       4.979  31.193  19.050  1.00 69.99           C  
+ATOM   2450  CD1 TYR C  14       4.282  30.013  19.310  1.00 70.89           C  
+ATOM   2451  CD2 TYR C  14       5.642  31.310  17.828  1.00 70.66           C  
+ATOM   2452  CE1 TYR C  14       4.248  28.974  18.379  1.00 72.62           C  
+ATOM   2453  CE2 TYR C  14       5.615  30.281  16.889  1.00 72.16           C  
+ATOM   2454  CZ  TYR C  14       4.918  29.115  17.172  1.00 73.56           C  
+ATOM   2455  OH  TYR C  14       4.902  28.087  16.254  1.00 74.58           O  
+ATOM   2456  N   GLN C  15       7.272  30.293  22.035  1.00 69.18           N  
+ATOM   2457  CA  GLN C  15       8.611  29.704  22.055  1.00 72.49           C  
+ATOM   2458  C   GLN C  15       9.212  29.510  20.673  1.00 73.06           C  
+ATOM   2459  O   GLN C  15      10.245  30.096  20.348  1.00 73.51           O  
+ATOM   2460  CB  GLN C  15       8.585  28.350  22.763  1.00 74.02           C  
+ATOM   2461  CG  GLN C  15       8.125  28.399  24.201  1.00 77.54           C  
+ATOM   2462  CD  GLN C  15       7.987  27.015  24.801  1.00 80.08           C  
+ATOM   2463  OE1 GLN C  15       8.954  26.251  24.861  1.00 81.14           O  
+ATOM   2464  NE2 GLN C  15       6.778  26.680  25.246  1.00 81.13           N  
+ATOM   2465  N   ALA C  16       8.558  28.676  19.870  1.00 73.82           N  
+ATOM   2466  CA  ALA C  16       9.017  28.364  18.523  1.00 74.67           C  
+ATOM   2467  C   ALA C  16       9.769  29.498  17.833  1.00 75.49           C  
+ATOM   2468  O   ALA C  16      10.936  29.341  17.475  1.00 76.05           O  
+ATOM   2469  CB  ALA C  16       7.844  27.924  17.669  1.00 74.32           C  
+ATOM   2470  N   GLU C  17       9.115  30.641  17.651  1.00 76.30           N  
+ATOM   2471  CA  GLU C  17       9.758  31.767  16.977  1.00 77.04           C  
+ATOM   2472  C   GLU C  17      10.319  32.807  17.935  1.00 76.94           C  
+ATOM   2473  O   GLU C  17      10.739  33.886  17.521  1.00 75.49           O  
+ATOM   2474  CB  GLU C  17       8.776  32.422  16.005  1.00 78.24           C  
+ATOM   2475  CG  GLU C  17       8.173  31.441  15.010  1.00 79.98           C  
+ATOM   2476  CD  GLU C  17       9.227  30.673  14.228  1.00 80.83           C  
+ATOM   2477  OE1 GLU C  17       8.859  29.706  13.524  1.00 82.38           O  
+ATOM   2478  OE2 GLU C  17      10.420  31.037  14.313  1.00 79.92           O  
+ATOM   2479  N   ASN C  18      10.321  32.467  19.219  1.00 78.19           N  
+ATOM   2480  CA  ASN C  18      10.838  33.341  20.264  1.00 78.75           C  
+ATOM   2481  C   ASN C  18      10.415  34.800  20.149  1.00 78.55           C  
+ATOM   2482  O   ASN C  18      11.262  35.695  20.159  1.00 79.17           O  
+ATOM   2483  CB  ASN C  18      12.368  33.268  20.301  1.00 80.40           C  
+ATOM   2484  CG  ASN C  18      12.881  31.891  20.689  1.00 82.44           C  
+ATOM   2485  OD1 ASN C  18      12.704  30.915  19.954  1.00 82.84           O  
+ATOM   2486  ND2 ASN C  18      13.519  31.806  21.853  1.00 82.76           N  
+ATOM   2487  N   PHE C  19       9.115  35.048  20.024  1.00 76.95           N  
+ATOM   2488  CA  PHE C  19       8.644  36.423  19.954  1.00 75.52           C  
+ATOM   2489  C   PHE C  19       7.469  36.682  20.901  1.00 74.38           C  
+ATOM   2490  O   PHE C  19       6.613  35.820  21.112  1.00 73.92           O  
+ATOM   2491  CB  PHE C  19       8.339  36.835  18.498  0.00 75.89           C  
+ATOM   2492  CG  PHE C  19       7.310  35.988  17.790  0.00 76.12           C  
+ATOM   2493  CD1 PHE C  19       7.217  36.041  16.401  0.00 76.24           C  
+ATOM   2494  CD2 PHE C  19       6.413  35.187  18.483  0.00 76.24           C  
+ATOM   2495  CE1 PHE C  19       6.251  35.312  15.717  0.00 76.33           C  
+ATOM   2496  CE2 PHE C  19       5.442  34.457  17.806  0.00 76.33           C  
+ATOM   2497  CZ  PHE C  19       5.360  34.519  16.421  0.00 76.35           C  
+ATOM   2498  N   LEU C  20       7.459  37.875  21.490  1.00 72.12           N  
+ATOM   2499  CA  LEU C  20       6.443  38.263  22.462  1.00 68.76           C  
+ATOM   2500  C   LEU C  20       5.391  39.207  21.884  1.00 67.43           C  
+ATOM   2501  O   LEU C  20       5.715  40.305  21.436  1.00 67.20           O  
+ATOM   2502  CB  LEU C  20       7.142  38.931  23.654  1.00 69.19           C  
+ATOM   2503  CG  LEU C  20       6.528  39.023  25.056  1.00 69.77           C  
+ATOM   2504  CD1 LEU C  20       5.220  39.786  25.025  1.00 70.03           C  
+ATOM   2505  CD2 LEU C  20       6.322  37.625  25.600  1.00 71.48           C  
+ATOM   2506  N   PHE C  21       4.134  38.772  21.894  1.00 66.16           N  
+ATOM   2507  CA  PHE C  21       3.024  39.590  21.404  1.00 65.40           C  
+ATOM   2508  C   PHE C  21       2.528  40.451  22.563  1.00 64.68           C  
+ATOM   2509  O   PHE C  21       2.402  39.963  23.687  1.00 63.10           O  
+ATOM   2510  CB  PHE C  21       1.873  38.705  20.921  1.00 65.96           C  
+ATOM   2511  CG  PHE C  21       2.121  38.048  19.599  1.00 67.44           C  
+ATOM   2512  CD1 PHE C  21       2.141  38.800  18.429  1.00 67.18           C  
+ATOM   2513  CD2 PHE C  21       2.327  36.674  19.520  1.00 67.50           C  
+ATOM   2514  CE1 PHE C  21       2.363  38.192  17.196  1.00 68.45           C  
+ATOM   2515  CE2 PHE C  21       2.550  36.055  18.293  1.00 69.40           C  
+ATOM   2516  CZ  PHE C  21       2.568  36.816  17.126  1.00 69.04           C  
+ATOM   2517  N   GLN C  22       2.234  41.720  22.296  1.00 63.88           N  
+ATOM   2518  CA  GLN C  22       1.764  42.604  23.354  1.00 64.19           C  
+ATOM   2519  C   GLN C  22       0.505  43.401  23.042  1.00 62.78           C  
+ATOM   2520  O   GLN C  22       0.215  43.711  21.890  1.00 63.07           O  
+ATOM   2521  CB  GLN C  22       2.874  43.577  23.754  1.00 65.22           C  
+ATOM   2522  CG  GLN C  22       4.054  42.919  24.434  1.00 68.70           C  
+ATOM   2523  CD  GLN C  22       5.050  43.928  24.970  1.00 69.64           C  
+ATOM   2524  OE1 GLN C  22       4.683  44.854  25.694  1.00 71.32           O  
+ATOM   2525  NE2 GLN C  22       6.319  43.751  24.622  1.00 70.66           N  
+ATOM   2526  N   GLN C  23      -0.231  43.724  24.099  1.00 61.99           N  
+ATOM   2527  CA  GLN C  23      -1.460  44.515  24.025  1.00 61.67           C  
+ATOM   2528  C   GLN C  23      -2.425  44.150  22.899  1.00 59.09           C  
+ATOM   2529  O   GLN C  23      -2.904  45.016  22.160  1.00 57.26           O  
+ATOM   2530  CB  GLN C  23      -1.099  46.003  23.945  1.00 62.93           C  
+ATOM   2531  CG  GLN C  23      -0.323  46.492  25.156  1.00 66.28           C  
+ATOM   2532  CD  GLN C  23       0.132  47.927  25.016  1.00 68.60           C  
+ATOM   2533  OE1 GLN C  23      -0.678  48.832  24.810  1.00 69.69           O  
+ATOM   2534  NE2 GLN C  23       1.436  48.144  25.130  1.00 70.10           N  
+ATOM   2535  N   LEU C  24      -2.722  42.862  22.790  1.00 56.26           N  
+ATOM   2536  CA  LEU C  24      -3.632  42.375  21.772  1.00 52.72           C  
+ATOM   2537  C   LEU C  24      -5.053  42.618  22.273  1.00 50.75           C  
+ATOM   2538  O   LEU C  24      -5.400  42.243  23.396  1.00 49.55           O  
+ATOM   2539  CB  LEU C  24      -3.402  40.879  21.549  1.00 54.48           C  
+ATOM   2540  CG  LEU C  24      -3.864  40.206  20.252  1.00 56.46           C  
+ATOM   2541  CD1 LEU C  24      -3.875  38.692  20.461  1.00 55.42           C  
+ATOM   2542  CD2 LEU C  24      -5.245  40.688  19.858  1.00 56.17           C  
+ATOM   2543  N   ASN C  25      -5.872  43.253  21.443  1.00 48.32           N  
+ATOM   2544  CA  ASN C  25      -7.255  43.525  21.802  1.00 47.50           C  
+ATOM   2545  C   ASN C  25      -8.198  43.184  20.655  1.00 48.21           C  
+ATOM   2546  O   ASN C  25      -7.850  43.324  19.479  1.00 49.91           O  
+ATOM   2547  CB  ASN C  25      -7.472  45.012  22.142  1.00 47.00           C  
+ATOM   2548  CG  ASN C  25      -6.725  45.456  23.381  1.00 45.90           C  
+ATOM   2549  OD1 ASN C  25      -5.547  45.798  23.315  1.00 45.06           O  
+ATOM   2550  ND2 ASN C  25      -7.409  45.448  24.522  1.00 42.45           N  
+ATOM   2551  N   PHE C  26      -9.393  42.734  21.019  1.00 45.87           N  
+ATOM   2552  CA  PHE C  26     -10.453  42.432  20.072  1.00 45.00           C  
+ATOM   2553  C   PHE C  26     -11.593  41.730  20.771  1.00 45.12           C  
+ATOM   2554  O   PHE C  26     -11.395  41.047  21.773  1.00 46.28           O  
+ATOM   2555  CB  PHE C  26      -9.965  41.608  18.861  1.00 42.29           C  
+ATOM   2556  CG  PHE C  26      -9.586  40.186  19.170  1.00 42.82           C  
+ATOM   2557  CD1 PHE C  26      -8.267  39.846  19.435  1.00 40.44           C  
+ATOM   2558  CD2 PHE C  26     -10.541  39.177  19.148  1.00 43.13           C  
+ATOM   2559  CE1 PHE C  26      -7.901  38.525  19.670  1.00 43.02           C  
+ATOM   2560  CE2 PHE C  26     -10.184  37.850  19.382  1.00 43.63           C  
+ATOM   2561  CZ  PHE C  26      -8.861  37.525  19.643  1.00 42.10           C  
+ATOM   2562  N   ASP C  27     -12.796  41.946  20.255  1.00 45.21           N  
+ATOM   2563  CA  ASP C  27     -13.995  41.337  20.797  1.00 46.05           C  
+ATOM   2564  C   ASP C  27     -14.826  40.794  19.647  1.00 43.85           C  
+ATOM   2565  O   ASP C  27     -14.743  41.283  18.523  1.00 40.95           O  
+ATOM   2566  CB  ASP C  27     -14.824  42.357  21.591  1.00 52.00           C  
+ATOM   2567  CG  ASP C  27     -14.419  43.794  21.311  1.00 58.70           C  
+ATOM   2568  OD1 ASP C  27     -14.305  44.175  20.119  1.00 59.98           O  
+ATOM   2569  OD2 ASP C  27     -14.218  44.546  22.296  1.00 61.72           O  
+ATOM   2570  N   LEU C  28     -15.622  39.775  19.939  1.00 41.79           N  
+ATOM   2571  CA  LEU C  28     -16.476  39.173  18.937  1.00 41.56           C  
+ATOM   2572  C   LEU C  28     -17.888  39.052  19.475  1.00 41.18           C  
+ATOM   2573  O   LEU C  28     -18.088  38.799  20.665  1.00 41.99           O  
+ATOM   2574  CB  LEU C  28     -15.971  37.778  18.562  1.00 40.80           C  
+ATOM   2575  CG  LEU C  28     -14.615  37.640  17.879  1.00 41.68           C  
+ATOM   2576  CD1 LEU C  28     -14.373  36.166  17.569  1.00 40.42           C  
+ATOM   2577  CD2 LEU C  28     -14.577  38.481  16.607  1.00 41.15           C  
+ATOM   2578  N   ASN C  29     -18.866  39.230  18.595  1.00 40.40           N  
+ATOM   2579  CA  ASN C  29     -20.263  39.110  18.981  1.00 41.31           C  
+ATOM   2580  C   ASN C  29     -20.797  37.828  18.379  1.00 41.59           C  
+ATOM   2581  O   ASN C  29     -20.142  37.207  17.535  1.00 42.56           O  
+ATOM   2582  CB  ASN C  29     -21.075  40.291  18.451  1.00 42.46           C  
+ATOM   2583  CG  ASN C  29     -20.624  41.609  19.029  1.00 42.56           C  
+ATOM   2584  OD1 ASN C  29     -20.156  42.488  18.307  1.00 45.81           O  
+ATOM   2585  ND2 ASN C  29     -20.751  41.753  20.340  1.00 43.63           N  
+ATOM   2586  N   LYS C  30     -21.987  37.433  18.811  1.00 40.08           N  
+ATOM   2587  CA  LYS C  30     -22.607  36.228  18.292  1.00 40.27           C  
+ATOM   2588  C   LYS C  30     -22.840  36.398  16.798  1.00 37.97           C  
+ATOM   2589  O   LYS C  30     -23.217  37.480  16.341  1.00 39.16           O  
+ATOM   2590  CB  LYS C  30     -23.938  35.974  19.000  1.00 41.79           C  
+ATOM   2591  CG  LYS C  30     -23.814  35.782  20.499  1.00 47.42           C  
+ATOM   2592  CD  LYS C  30     -25.190  35.589  21.137  1.00 52.41           C  
+ATOM   2593  CE  LYS C  30     -25.083  35.341  22.635  1.00 55.09           C  
+ATOM   2594  NZ  LYS C  30     -26.400  34.933  23.208  1.00 58.64           N  
+ATOM   2595  N   GLY C  31     -22.601  35.338  16.035  1.00 35.78           N  
+ATOM   2596  CA  GLY C  31     -22.802  35.416  14.599  1.00 33.98           C  
+ATOM   2597  C   GLY C  31     -21.591  35.881  13.802  1.00 31.71           C  
+ATOM   2598  O   GLY C  31     -21.597  35.800  12.583  1.00 36.69           O  
+ATOM   2599  N   ASP C  32     -20.558  36.374  14.473  1.00 30.14           N  
+ATOM   2600  CA  ASP C  32     -19.342  36.827  13.786  1.00 30.10           C  
+ATOM   2601  C   ASP C  32     -18.505  35.650  13.290  1.00 30.54           C  
+ATOM   2602  O   ASP C  32     -18.584  34.541  13.826  1.00 30.56           O  
+ATOM   2603  CB  ASP C  32     -18.451  37.643  14.730  1.00 30.05           C  
+ATOM   2604  CG  ASP C  32     -18.855  39.103  14.824  1.00 33.06           C  
+ATOM   2605  OD1 ASP C  32     -18.273  39.803  15.685  1.00 30.55           O  
+ATOM   2606  OD2 ASP C  32     -19.734  39.552  14.041  1.00 35.16           O  
+ATOM   2607  N   ILE C  33     -17.716  35.893  12.251  1.00 30.57           N  
+ATOM   2608  CA  ILE C  33     -16.814  34.881  11.729  1.00 29.03           C  
+ATOM   2609  C   ILE C  33     -15.486  35.609  11.670  1.00 28.50           C  
+ATOM   2610  O   ILE C  33     -15.313  36.545  10.884  1.00 28.57           O  
+ATOM   2611  CB  ILE C  33     -17.190  34.381  10.310  1.00 30.96           C  
+ATOM   2612  CG1 ILE C  33     -18.508  33.601  10.347  1.00 31.28           C  
+ATOM   2613  CG2 ILE C  33     -16.085  33.463   9.775  1.00 26.91           C  
+ATOM   2614  CD1 ILE C  33     -18.981  33.122   8.989  0.00 31.11           C  
+ATOM   2615  N   LEU C  34     -14.567  35.203  12.538  1.00 27.87           N  
+ATOM   2616  CA  LEU C  34     -13.246  35.812  12.596  1.00 27.29           C  
+ATOM   2617  C   LEU C  34     -12.196  34.895  11.980  1.00 27.16           C  
+ATOM   2618  O   LEU C  34     -12.117  33.715  12.312  1.00 27.37           O  
+ATOM   2619  CB  LEU C  34     -12.855  36.107  14.046  1.00 24.12           C  
+ATOM   2620  CG  LEU C  34     -11.364  36.423  14.238  1.00 26.26           C  
+ATOM   2621  CD1 LEU C  34     -11.052  37.788  13.629  1.00 21.10           C  
+ATOM   2622  CD2 LEU C  34     -10.999  36.409  15.721  1.00 21.72           C  
+ATOM   2623  N   ALA C  35     -11.395  35.443  11.080  1.00 26.34           N  
+ATOM   2624  CA  ALA C  35     -10.337  34.676  10.462  1.00 26.24           C  
+ATOM   2625  C   ALA C  35      -9.026  35.148  11.059  1.00 27.16           C  
+ATOM   2626  O   ALA C  35      -8.776  36.353  11.148  1.00 29.03           O  
+ATOM   2627  CB  ALA C  35     -10.327  34.886   8.953  1.00 27.68           C  
+ATOM   2628  N   VAL C  36      -8.213  34.204  11.518  1.00 25.83           N  
+ATOM   2629  CA  VAL C  36      -6.904  34.544  12.058  1.00 26.83           C  
+ATOM   2630  C   VAL C  36      -5.957  34.181  10.926  1.00 27.13           C  
+ATOM   2631  O   VAL C  36      -5.649  33.018  10.732  1.00 28.22           O  
+ATOM   2632  CB  VAL C  36      -6.571  33.720  13.321  1.00 28.74           C  
+ATOM   2633  CG1 VAL C  36      -5.180  34.093  13.850  1.00 21.74           C  
+ATOM   2634  CG2 VAL C  36      -7.632  33.983  14.389  1.00 25.47           C  
+ATOM   2635  N   LEU C  37      -5.540  35.187  10.160  1.00 29.48           N  
+ATOM   2636  CA  LEU C  37      -4.655  35.003   9.016  1.00 31.13           C  
+ATOM   2637  C   LEU C  37      -3.179  35.178   9.356  1.00 33.49           C  
+ATOM   2638  O   LEU C  37      -2.750  36.243   9.808  1.00 33.28           O  
+ATOM   2639  CB  LEU C  37      -5.043  35.990   7.907  1.00 30.32           C  
+ATOM   2640  CG  LEU C  37      -4.366  35.908   6.534  1.00 32.23           C  
+ATOM   2641  CD1 LEU C  37      -4.639  34.551   5.866  1.00 27.67           C  
+ATOM   2642  CD2 LEU C  37      -4.917  37.041   5.666  1.00 34.28           C  
+ATOM   2643  N   GLY C  38      -2.410  34.119   9.128  1.00 35.43           N  
+ATOM   2644  CA  GLY C  38      -0.983  34.144   9.388  1.00 38.40           C  
+ATOM   2645  C   GLY C  38      -0.339  32.991   8.647  1.00 41.60           C  
+ATOM   2646  O   GLY C  38      -1.041  32.179   8.049  1.00 45.08           O  
+ATOM   2647  N   GLN C  39       0.985  32.906   8.668  1.00 45.53           N  
+ATOM   2648  CA  GLN C  39       1.676  31.815   7.985  1.00 50.09           C  
+ATOM   2649  C   GLN C  39       2.293  30.845   8.989  1.00 55.60           C  
+ATOM   2650  O   GLN C  39       2.560  31.207  10.138  1.00 56.17           O  
+ATOM   2651  CB  GLN C  39       2.774  32.358   7.076  1.00 46.79           C  
+ATOM   2652  CG  GLN C  39       2.294  33.411   6.108  1.00 47.28           C  
+ATOM   2653  CD  GLN C  39       3.224  33.586   4.927  1.00 46.06           C  
+ATOM   2654  OE1 GLN C  39       3.131  32.861   3.928  1.00 42.11           O  
+ATOM   2655  NE2 GLN C  39       4.137  34.543   5.035  1.00 42.05           N  
+ATOM   2656  N   ASN C  40       2.510  29.614   8.533  1.00 60.46           N  
+ATOM   2657  CA  ASN C  40       3.099  28.536   9.330  1.00 64.98           C  
+ATOM   2658  C   ASN C  40       3.787  29.005  10.614  1.00 66.44           C  
+ATOM   2659  O   ASN C  40       4.693  29.842  10.575  1.00 67.11           O  
+ATOM   2660  CB  ASN C  40       4.109  27.769   8.472  1.00 67.36           C  
+ATOM   2661  CG  ASN C  40       3.538  27.359   7.124  1.00 70.08           C  
+ATOM   2662  OD1 ASN C  40       2.743  26.422   7.030  1.00 71.18           O  
+ATOM   2663  ND2 ASN C  40       3.933  28.073   6.073  1.00 69.57           N  
+ATOM   2664  N   GLY C  41       3.354  28.455  11.746  1.00 67.30           N  
+ATOM   2665  CA  GLY C  41       3.948  28.815  13.023  1.00 68.16           C  
+ATOM   2666  C   GLY C  41       4.117  30.309  13.217  1.00 68.48           C  
+ATOM   2667  O   GLY C  41       5.237  30.825  13.193  1.00 69.74           O  
+ATOM   2668  N   CYS C  42       3.000  31.001  13.423  1.00 67.09           N  
+ATOM   2669  CA  CYS C  42       2.996  32.449  13.617  1.00 64.97           C  
+ATOM   2670  C   CYS C  42       2.449  32.810  14.995  1.00 64.12           C  
+ATOM   2671  O   CYS C  42       2.452  33.977  15.390  1.00 63.65           O  
+ATOM   2672  CB  CYS C  42       2.115  33.095  12.554  1.00 64.97           C  
+ATOM   2673  SG  CYS C  42       0.470  32.354  12.509  1.00 62.72           S  
+ATOM   2674  N   GLY C  43       1.967  31.801  15.713  1.00 62.98           N  
+ATOM   2675  CA  GLY C  43       1.408  32.035  17.028  1.00 60.97           C  
+ATOM   2676  C   GLY C  43      -0.053  31.630  17.107  1.00 59.83           C  
+ATOM   2677  O   GLY C  43      -0.676  31.769  18.158  1.00 60.91           O  
+ATOM   2678  N   LYS C  44      -0.608  31.141  16.000  1.00 58.50           N  
+ATOM   2679  CA  LYS C  44      -2.005  30.702  15.978  1.00 58.93           C  
+ATOM   2680  C   LYS C  44      -2.191  29.636  17.053  1.00 58.76           C  
+ATOM   2681  O   LYS C  44      -3.191  29.618  17.774  1.00 59.44           O  
+ATOM   2682  CB  LYS C  44      -2.357  30.097  14.619  1.00 58.22           C  
+ATOM   2683  CG  LYS C  44      -2.355  31.073  13.458  1.00 57.09           C  
+ATOM   2684  CD  LYS C  44      -2.481  30.306  12.162  1.00 57.01           C  
+ATOM   2685  CE  LYS C  44      -2.369  31.192  10.941  1.00 55.09           C  
+ATOM   2686  NZ  LYS C  44      -2.108  30.343   9.736  1.00 51.39           N  
+ATOM   2687  N   SER C  45      -1.208  28.750  17.139  1.00 57.99           N  
+ATOM   2688  CA  SER C  45      -1.202  27.665  18.105  1.00 57.43           C  
+ATOM   2689  C   SER C  45      -1.349  28.204  19.519  1.00 56.50           C  
+ATOM   2690  O   SER C  45      -2.192  27.742  20.291  1.00 55.04           O  
+ATOM   2691  CB  SER C  45       0.114  26.887  17.990  1.00 59.44           C  
+ATOM   2692  OG  SER C  45       0.245  25.935  19.031  1.00 61.80           O  
+ATOM   2693  N   THR C  46      -0.517  29.181  19.859  1.00 54.55           N  
+ATOM   2694  CA  THR C  46      -0.561  29.761  21.187  1.00 52.76           C  
+ATOM   2695  C   THR C  46      -1.880  30.497  21.386  1.00 50.44           C  
+ATOM   2696  O   THR C  46      -2.532  30.347  22.421  1.00 51.12           O  
+ATOM   2697  CB  THR C  46       0.612  30.738  21.402  1.00 54.00           C  
+ATOM   2698  OG1 THR C  46       1.838  30.089  21.051  1.00 55.39           O  
+ATOM   2699  CG2 THR C  46       0.689  31.169  22.864  1.00 53.40           C  
+ATOM   2700  N   LEU C  47      -2.276  31.276  20.386  1.00 47.83           N  
+ATOM   2701  CA  LEU C  47      -3.514  32.044  20.460  1.00 47.21           C  
+ATOM   2702  C   LEU C  47      -4.691  31.146  20.834  1.00 46.46           C  
+ATOM   2703  O   LEU C  47      -5.431  31.446  21.775  1.00 45.20           O  
+ATOM   2704  CB  LEU C  47      -3.795  32.733  19.122  1.00 46.94           C  
+ATOM   2705  CG  LEU C  47      -4.516  34.086  19.160  1.00 49.23           C  
+ATOM   2706  CD1 LEU C  47      -4.890  34.497  17.738  1.00 45.84           C  
+ATOM   2707  CD2 LEU C  47      -5.758  34.008  20.029  1.00 50.16           C  
+ATOM   2708  N   LEU C  48      -4.860  30.048  20.098  1.00 45.70           N  
+ATOM   2709  CA  LEU C  48      -5.950  29.112  20.366  1.00 46.75           C  
+ATOM   2710  C   LEU C  48      -5.806  28.507  21.755  1.00 46.39           C  
+ATOM   2711  O   LEU C  48      -6.790  28.367  22.481  1.00 46.01           O  
+ATOM   2712  CB  LEU C  48      -5.980  28.001  19.310  1.00 46.53           C  
+ATOM   2713  CG  LEU C  48      -6.261  28.473  17.880  1.00 46.31           C  
+ATOM   2714  CD1 LEU C  48      -6.012  27.330  16.906  1.00 50.68           C  
+ATOM   2715  CD2 LEU C  48      -7.687  28.975  17.767  1.00 45.07           C  
+ATOM   2716  N   ASP C  49      -4.581  28.150  22.125  1.00 48.72           N  
+ATOM   2717  CA  ASP C  49      -4.326  27.585  23.452  1.00 51.59           C  
+ATOM   2718  C   ASP C  49      -4.867  28.540  24.507  1.00 50.77           C  
+ATOM   2719  O   ASP C  49      -5.570  28.128  25.434  1.00 49.33           O  
+ATOM   2720  CB  ASP C  49      -2.823  27.395  23.696  1.00 55.63           C  
+ATOM   2721  CG  ASP C  49      -2.263  26.151  23.020  1.00 60.28           C  
+ATOM   2722  OD1 ASP C  49      -1.032  25.938  23.116  1.00 62.15           O  
+ATOM   2723  OD2 ASP C  49      -3.043  25.389  22.402  1.00 62.84           O  
+ATOM   2724  N   LEU C  50      -4.534  29.820  24.355  1.00 49.02           N  
+ATOM   2725  CA  LEU C  50      -4.979  30.837  25.298  1.00 48.36           C  
+ATOM   2726  C   LEU C  50      -6.495  30.957  25.323  1.00 47.22           C  
+ATOM   2727  O   LEU C  50      -7.095  31.011  26.394  1.00 47.76           O  
+ATOM   2728  CB  LEU C  50      -4.352  32.192  24.960  1.00 48.06           C  
+ATOM   2729  CG  LEU C  50      -2.839  32.296  25.169  1.00 48.95           C  
+ATOM   2730  CD1 LEU C  50      -2.338  33.624  24.638  1.00 48.59           C  
+ATOM   2731  CD2 LEU C  50      -2.514  32.152  26.652  1.00 49.16           C  
+ATOM   2732  N   LEU C  51      -7.121  30.981  24.152  1.00 46.20           N  
+ATOM   2733  CA  LEU C  51      -8.574  31.100  24.107  1.00 47.05           C  
+ATOM   2734  C   LEU C  51      -9.264  29.941  24.821  1.00 47.07           C  
+ATOM   2735  O   LEU C  51     -10.321  30.124  25.417  1.00 46.95           O  
+ATOM   2736  CB  LEU C  51      -9.064  31.207  22.658  1.00 45.78           C  
+ATOM   2737  CG  LEU C  51      -8.602  32.460  21.901  1.00 48.24           C  
+ATOM   2738  CD1 LEU C  51      -9.172  32.451  20.488  1.00 47.68           C  
+ATOM   2739  CD2 LEU C  51      -9.054  33.714  22.647  1.00 47.98           C  
+ATOM   2740  N   LEU C  52      -8.663  28.755  24.762  1.00 49.11           N  
+ATOM   2741  CA  LEU C  52      -9.217  27.573  25.419  1.00 51.76           C  
+ATOM   2742  C   LEU C  52      -8.729  27.488  26.863  1.00 54.08           C  
+ATOM   2743  O   LEU C  52      -9.140  26.608  27.625  1.00 55.24           O  
+ATOM   2744  CB  LEU C  52      -8.809  26.310  24.663  1.00 51.74           C  
+ATOM   2745  CG  LEU C  52      -9.471  26.106  23.299  1.00 52.32           C  
+ATOM   2746  CD1 LEU C  52      -8.795  24.968  22.559  1.00 50.25           C  
+ATOM   2747  CD2 LEU C  52     -10.960  25.826  23.498  1.00 52.21           C  
+ATOM   2748  N   GLY C  53      -7.846  28.409  27.228  1.00 54.96           N  
+ATOM   2749  CA  GLY C  53      -7.318  28.443  28.576  1.00 56.48           C  
+ATOM   2750  C   GLY C  53      -6.460  27.266  29.006  1.00 57.68           C  
+ATOM   2751  O   GLY C  53      -6.575  26.817  30.144  1.00 57.89           O  
+ATOM   2752  N   ILE C  54      -5.605  26.748  28.127  1.00 58.20           N  
+ATOM   2753  CA  ILE C  54      -4.763  25.634  28.539  1.00 59.50           C  
+ATOM   2754  C   ILE C  54      -3.775  26.224  29.540  1.00 60.62           C  
+ATOM   2755  O   ILE C  54      -3.392  25.575  30.515  1.00 62.28           O  
+ATOM   2756  CB  ILE C  54      -3.999  24.980  27.357  1.00 59.28           C  
+ATOM   2757  CG1 ILE C  54      -2.878  25.897  26.872  1.00 59.65           C  
+ATOM   2758  CG2 ILE C  54      -4.975  24.645  26.236  1.00 56.41           C  
+ATOM   2759  CD1 ILE C  54      -1.868  25.200  25.989  0.00 59.55           C  
+ATOM   2760  N   HIS C  55      -3.368  27.464  29.292  1.00 60.58           N  
+ATOM   2761  CA  HIS C  55      -2.470  28.160  30.200  1.00 60.01           C  
+ATOM   2762  C   HIS C  55      -2.782  29.650  30.201  1.00 58.51           C  
+ATOM   2763  O   HIS C  55      -3.438  30.162  29.294  1.00 56.36           O  
+ATOM   2764  CB  HIS C  55      -0.993  27.924  29.843  1.00 61.87           C  
+ATOM   2765  CG  HIS C  55      -0.534  28.625  28.600  1.00 63.84           C  
+ATOM   2766  ND1 HIS C  55      -0.523  28.018  27.362  1.00 63.92           N  
+ATOM   2767  CD2 HIS C  55      -0.031  29.868  28.414  1.00 63.99           C  
+ATOM   2768  CE1 HIS C  55      -0.030  28.856  26.467  1.00 63.27           C  
+ATOM   2769  NE2 HIS C  55       0.276  29.986  27.080  1.00 64.77           N  
+ATOM   2770  N   ARG C  56      -2.320  30.333  31.240  1.00 57.39           N  
+ATOM   2771  CA  ARG C  56      -2.541  31.761  31.395  1.00 54.99           C  
+ATOM   2772  C   ARG C  56      -1.530  32.550  30.573  1.00 52.18           C  
+ATOM   2773  O   ARG C  56      -0.433  32.075  30.302  1.00 51.54           O  
+ATOM   2774  CB  ARG C  56      -2.428  32.132  32.879  1.00 57.50           C  
+ATOM   2775  CG  ARG C  56      -3.523  31.516  33.746  1.00 60.36           C  
+ATOM   2776  CD  ARG C  56      -3.137  31.422  35.223  1.00 64.84           C  
+ATOM   2777  NE  ARG C  56      -2.676  32.691  35.780  1.00 68.34           N  
+ATOM   2778  CZ  ARG C  56      -1.395  33.018  35.942  1.00 71.38           C  
+ATOM   2779  NH1 ARG C  56      -1.072  34.200  36.455  1.00 71.66           N  
+ATOM   2780  NH2 ARG C  56      -0.436  32.161  35.605  1.00 71.99           N  
+ATOM   2781  N   PRO C  57      -1.902  33.763  30.145  1.00 49.69           N  
+ATOM   2782  CA  PRO C  57      -1.016  34.618  29.351  1.00 48.33           C  
+ATOM   2783  C   PRO C  57      -0.115  35.461  30.254  1.00 47.90           C  
+ATOM   2784  O   PRO C  57      -0.309  35.495  31.463  1.00 47.91           O  
+ATOM   2785  CB  PRO C  57      -1.997  35.478  28.568  1.00 47.61           C  
+ATOM   2786  CG  PRO C  57      -3.086  35.697  29.570  1.00 46.81           C  
+ATOM   2787  CD  PRO C  57      -3.270  34.315  30.181  1.00 48.74           C  
+ATOM   2788  N   ILE C  58       0.871  36.131  29.670  1.00 48.40           N  
+ATOM   2789  CA  ILE C  58       1.757  36.986  30.449  1.00 51.88           C  
+ATOM   2790  C   ILE C  58       0.951  38.182  30.977  1.00 53.02           C  
+ATOM   2791  O   ILE C  58       0.969  38.472  32.174  1.00 52.96           O  
+ATOM   2792  CB  ILE C  58       2.939  37.502  29.594  1.00 53.52           C  
+ATOM   2793  CG1 ILE C  58       3.838  36.330  29.196  1.00 54.13           C  
+ATOM   2794  CG2 ILE C  58       3.734  38.547  30.372  1.00 54.86           C  
+ATOM   2795  CD1 ILE C  58       5.071  36.731  28.425  0.00 54.02           C  
+ATOM   2796  N   GLN C  59       0.242  38.862  30.077  1.00 52.85           N  
+ATOM   2797  CA  GLN C  59      -0.584  40.012  30.443  1.00 53.48           C  
+ATOM   2798  C   GLN C  59      -1.963  39.892  29.795  1.00 52.46           C  
+ATOM   2799  O   GLN C  59      -2.179  39.059  28.913  1.00 49.97           O  
+ATOM   2800  CB  GLN C  59       0.047  41.318  29.950  1.00 55.88           C  
+ATOM   2801  CG  GLN C  59       1.568  41.350  29.933  1.00 59.93           C  
+ATOM   2802  CD  GLN C  59       2.105  42.552  29.166  1.00 62.48           C  
+ATOM   2803  OE1 GLN C  59       1.984  43.698  29.612  1.00 65.92           O  
+ATOM   2804  NE2 GLN C  59       2.689  42.297  27.999  1.00 61.89           N  
+ATOM   2805  N   GLY C  60      -2.891  40.736  30.235  1.00 51.31           N  
+ATOM   2806  CA  GLY C  60      -4.221  40.741  29.660  1.00 50.39           C  
+ATOM   2807  C   GLY C  60      -5.223  39.745  30.199  1.00 50.00           C  
+ATOM   2808  O   GLY C  60      -4.931  38.946  31.080  1.00 49.68           O  
+ATOM   2809  N   LYS C  61      -6.424  39.795  29.639  1.00 50.45           N  
+ATOM   2810  CA  LYS C  61      -7.508  38.921  30.055  1.00 50.10           C  
+ATOM   2811  C   LYS C  61      -8.302  38.411  28.849  1.00 48.35           C  
+ATOM   2812  O   LYS C  61      -8.396  39.078  27.814  1.00 46.31           O  
+ATOM   2813  CB  LYS C  61      -8.439  39.694  31.000  1.00 52.53           C  
+ATOM   2814  CG  LYS C  61      -9.676  38.940  31.447  1.00 57.70           C  
+ATOM   2815  CD  LYS C  61     -10.609  39.825  32.276  1.00 61.85           C  
+ATOM   2816  CE  LYS C  61     -11.157  40.997  31.462  1.00 65.05           C  
+ATOM   2817  NZ  LYS C  61     -12.126  41.826  32.242  1.00 66.53           N  
+ATOM   2818  N   ILE C  62      -8.864  37.219  28.996  1.00 46.25           N  
+ATOM   2819  CA  ILE C  62      -9.678  36.617  27.957  1.00 46.19           C  
+ATOM   2820  C   ILE C  62     -10.992  36.211  28.599  1.00 46.31           C  
+ATOM   2821  O   ILE C  62     -10.997  35.456  29.565  1.00 47.53           O  
+ATOM   2822  CB  ILE C  62      -9.031  35.332  27.361  1.00 44.08           C  
+ATOM   2823  CG1 ILE C  62      -7.744  35.675  26.609  1.00 42.71           C  
+ATOM   2824  CG2 ILE C  62     -10.024  34.646  26.427  1.00 42.24           C  
+ATOM   2825  CD1 ILE C  62      -7.021  34.470  26.043  0.00 43.32           C  
+ATOM   2826  N   GLU C  63     -12.104  36.706  28.069  1.00 47.45           N  
+ATOM   2827  CA  GLU C  63     -13.409  36.346  28.608  1.00 48.44           C  
+ATOM   2828  C   GLU C  63     -14.276  35.749  27.500  1.00 47.37           C  
+ATOM   2829  O   GLU C  63     -14.484  36.382  26.463  1.00 46.03           O  
+ATOM   2830  CB  GLU C  63     -14.100  37.578  29.202  1.00 52.66           C  
+ATOM   2831  CG  GLU C  63     -15.406  37.257  29.925  1.00 60.11           C  
+ATOM   2832  CD  GLU C  63     -15.188  36.679  31.321  1.00 64.95           C  
+ATOM   2833  OE1 GLU C  63     -14.189  35.951  31.521  1.00 67.41           O  
+ATOM   2834  OE2 GLU C  63     -16.027  36.943  32.214  1.00 67.29           O  
+ATOM   2835  N   VAL C  64     -14.765  34.529  27.704  1.00 46.38           N  
+ATOM   2836  CA  VAL C  64     -15.613  33.892  26.702  1.00 46.97           C  
+ATOM   2837  C   VAL C  64     -17.018  33.772  27.285  1.00 47.40           C  
+ATOM   2838  O   VAL C  64     -17.214  33.231  28.370  1.00 48.26           O  
+ATOM   2839  CB  VAL C  64     -15.041  32.502  26.260  1.00 46.30           C  
+ATOM   2840  CG1 VAL C  64     -13.595  32.376  26.704  1.00 44.82           C  
+ATOM   2841  CG2 VAL C  64     -15.885  31.365  26.790  1.00 46.86           C  
+ATOM   2842  N   TYR C  65     -17.992  34.293  26.548  1.00 47.82           N  
+ATOM   2843  CA  TYR C  65     -19.381  34.328  26.987  1.00 47.11           C  
+ATOM   2844  C   TYR C  65     -20.284  33.226  26.462  1.00 46.70           C  
+ATOM   2845  O   TYR C  65     -21.461  33.173  26.808  1.00 45.78           O  
+ATOM   2846  CB  TYR C  65     -19.972  35.680  26.599  1.00 48.29           C  
+ATOM   2847  CG  TYR C  65     -19.148  36.848  27.084  1.00 51.75           C  
+ATOM   2848  CD1 TYR C  65     -19.232  37.285  28.409  1.00 52.41           C  
+ATOM   2849  CD2 TYR C  65     -18.275  37.515  26.224  1.00 50.77           C  
+ATOM   2850  CE1 TYR C  65     -18.468  38.359  28.861  1.00 54.16           C  
+ATOM   2851  CE2 TYR C  65     -17.507  38.589  26.669  1.00 52.47           C  
+ATOM   2852  CZ  TYR C  65     -17.610  39.007  27.987  1.00 53.72           C  
+ATOM   2853  OH  TYR C  65     -16.867  40.078  28.432  1.00 56.28           O  
+ATOM   2854  N   GLN C  66     -19.744  32.357  25.618  1.00 47.32           N  
+ATOM   2855  CA  GLN C  66     -20.530  31.264  25.050  1.00 47.30           C  
+ATOM   2856  C   GLN C  66     -19.807  29.943  25.290  1.00 45.54           C  
+ATOM   2857  O   GLN C  66     -18.593  29.928  25.492  1.00 45.22           O  
+ATOM   2858  CB  GLN C  66     -20.703  31.459  23.536  1.00 49.54           C  
+ATOM   2859  CG  GLN C  66     -21.502  32.687  23.101  1.00 53.85           C  
+ATOM   2860  CD  GLN C  66     -21.742  32.713  21.584  1.00 57.32           C  
+ATOM   2861  OE1 GLN C  66     -20.822  32.953  20.795  1.00 57.26           O  
+ATOM   2862  NE2 GLN C  66     -22.980  32.449  21.177  1.00 58.66           N  
+ATOM   2863  N   SER C  67     -20.544  28.837  25.279  1.00 43.65           N  
+ATOM   2864  CA  SER C  67     -19.910  27.539  25.459  1.00 43.64           C  
+ATOM   2865  C   SER C  67     -18.970  27.397  24.256  1.00 42.61           C  
+ATOM   2866  O   SER C  67     -19.348  27.686  23.119  1.00 41.01           O  
+ATOM   2867  CB  SER C  67     -20.955  26.427  25.470  1.00 42.44           C  
+ATOM   2868  OG  SER C  67     -21.751  26.476  24.303  1.00 49.20           O  
+ATOM   2869  N   ILE C  68     -17.746  26.958  24.514  1.00 41.29           N  
+ATOM   2870  CA  ILE C  68     -16.745  26.843  23.470  1.00 40.99           C  
+ATOM   2871  C   ILE C  68     -16.451  25.420  23.000  1.00 40.48           C  
+ATOM   2872  O   ILE C  68     -16.343  24.492  23.801  1.00 42.24           O  
+ATOM   2873  CB  ILE C  68     -15.433  27.499  23.945  1.00 41.66           C  
+ATOM   2874  CG1 ILE C  68     -14.435  27.589  22.791  1.00 42.70           C  
+ATOM   2875  CG2 ILE C  68     -14.849  26.692  25.100  1.00 43.21           C  
+ATOM   2876  CD1 ILE C  68     -13.170  28.349  23.131  0.00 42.27           C  
+ATOM   2877  N   GLY C  69     -16.334  25.271  21.684  1.00 39.13           N  
+ATOM   2878  CA  GLY C  69     -16.025  23.995  21.066  1.00 33.88           C  
+ATOM   2879  C   GLY C  69     -14.732  24.182  20.283  1.00 33.35           C  
+ATOM   2880  O   GLY C  69     -14.375  25.308  19.936  1.00 31.68           O  
+ATOM   2881  N   PHE C  70     -14.022  23.095  20.002  1.00 30.39           N  
+ATOM   2882  CA  PHE C  70     -12.767  23.187  19.279  1.00 28.52           C  
+ATOM   2883  C   PHE C  70     -12.679  22.108  18.221  1.00 28.72           C  
+ATOM   2884  O   PHE C  70     -13.228  21.021  18.388  1.00 28.96           O  
+ATOM   2885  CB  PHE C  70     -11.589  23.063  20.258  1.00 30.27           C  
+ATOM   2886  CG  PHE C  70     -10.233  22.991  19.593  1.00 30.38           C  
+ATOM   2887  CD1 PHE C  70      -9.542  21.784  19.519  1.00 30.10           C  
+ATOM   2888  CD2 PHE C  70      -9.656  24.124  19.031  1.00 28.84           C  
+ATOM   2889  CE1 PHE C  70      -8.291  21.705  18.888  1.00 30.07           C  
+ATOM   2890  CE2 PHE C  70      -8.409  24.062  18.398  1.00 31.23           C  
+ATOM   2891  CZ  PHE C  70      -7.724  22.846  18.325  1.00 28.77           C  
+ATOM   2892  N   VAL C  71     -12.013  22.429  17.114  1.00 27.16           N  
+ATOM   2893  CA  VAL C  71     -11.822  21.477  16.033  1.00 25.28           C  
+ATOM   2894  C   VAL C  71     -10.361  21.508  15.604  1.00 27.36           C  
+ATOM   2895  O   VAL C  71      -9.885  22.498  15.053  1.00 27.93           O  
+ATOM   2896  CB  VAL C  71     -12.688  21.806  14.797  1.00 25.67           C  
+ATOM   2897  CG1 VAL C  71     -12.659  20.620  13.827  1.00 20.69           C  
+ATOM   2898  CG2 VAL C  71     -14.128  22.127  15.218  1.00 21.53           C  
+ATOM   2899  N   PRO C  72      -9.618  20.430  15.876  1.00 26.43           N  
+ATOM   2900  CA  PRO C  72      -8.210  20.414  15.475  1.00 25.89           C  
+ATOM   2901  C   PRO C  72      -8.163  20.075  13.994  1.00 26.07           C  
+ATOM   2902  O   PRO C  72      -9.168  19.674  13.408  1.00 25.45           O  
+ATOM   2903  CB  PRO C  72      -7.619  19.299  16.337  1.00 26.88           C  
+ATOM   2904  CG  PRO C  72      -8.749  18.300  16.355  1.00 26.97           C  
+ATOM   2905  CD  PRO C  72      -9.980  19.196  16.595  1.00 27.28           C  
+ATOM   2906  N   GLN C  73      -6.997  20.228  13.393  1.00 28.01           N  
+ATOM   2907  CA  GLN C  73      -6.854  19.934  11.984  1.00 32.59           C  
+ATOM   2908  C   GLN C  73      -6.899  18.428  11.730  1.00 35.15           C  
+ATOM   2909  O   GLN C  73      -7.385  17.980  10.688  1.00 36.40           O  
+ATOM   2910  CB  GLN C  73      -5.535  20.509  11.465  1.00 31.62           C  
+ATOM   2911  CG  GLN C  73      -5.464  20.547   9.964  1.00 35.79           C  
+ATOM   2912  CD  GLN C  73      -4.128  21.039   9.446  1.00 36.64           C  
+ATOM   2913  OE1 GLN C  73      -3.914  21.105   8.236  1.00 38.55           O  
+ATOM   2914  NE2 GLN C  73      -3.225  21.385  10.355  1.00 33.41           N  
+ATOM   2915  N   PHE C  74      -6.414  17.648  12.694  1.00 36.48           N  
+ATOM   2916  CA  PHE C  74      -6.375  16.196  12.547  1.00 36.38           C  
+ATOM   2917  C   PHE C  74      -6.698  15.445  13.826  1.00 36.78           C  
+ATOM   2918  O   PHE C  74      -6.592  15.982  14.922  1.00 36.58           O  
+ATOM   2919  CB  PHE C  74      -4.975  15.756  12.106  1.00 33.87           C  
+ATOM   2920  CG  PHE C  74      -4.479  16.444  10.877  1.00 34.86           C  
+ATOM   2921  CD1 PHE C  74      -5.118  16.253   9.649  1.00 34.19           C  
+ATOM   2922  CD2 PHE C  74      -3.356  17.269  10.935  1.00 32.57           C  
+ATOM   2923  CE1 PHE C  74      -4.642  16.874   8.493  1.00 33.25           C  
+ATOM   2924  CE2 PHE C  74      -2.869  17.895   9.789  1.00 32.59           C  
+ATOM   2925  CZ  PHE C  74      -3.511  17.698   8.562  1.00 34.15           C  
+ATOM   2926  N   PHE C  75      -7.097  14.191  13.669  1.00 38.96           N  
+ATOM   2927  CA  PHE C  75      -7.351  13.325  14.809  1.00 41.06           C  
+ATOM   2928  C   PHE C  75      -6.553  12.074  14.492  1.00 42.82           C  
+ATOM   2929  O   PHE C  75      -6.831  11.383  13.513  1.00 41.74           O  
+ATOM   2930  CB  PHE C  75      -8.824  12.948  14.955  1.00 41.37           C  
+ATOM   2931  CG  PHE C  75      -9.069  11.911  16.020  1.00 40.38           C  
+ATOM   2932  CD1 PHE C  75      -8.993  12.249  17.370  1.00 41.24           C  
+ATOM   2933  CD2 PHE C  75      -9.313  10.584  15.675  1.00 40.52           C  
+ATOM   2934  CE1 PHE C  75      -9.154  11.281  18.367  1.00 41.93           C  
+ATOM   2935  CE2 PHE C  75      -9.477   9.602  16.660  1.00 41.64           C  
+ATOM   2936  CZ  PHE C  75      -9.398   9.950  18.011  1.00 40.50           C  
+ATOM   2937  N   SER C  76      -5.552  11.790  15.311  1.00 45.45           N  
+ATOM   2938  CA  SER C  76      -4.713  10.620  15.090  1.00 48.29           C  
+ATOM   2939  C   SER C  76      -4.864   9.627  16.226  1.00 47.07           C  
+ATOM   2940  O   SER C  76      -4.733   9.985  17.394  1.00 47.74           O  
+ATOM   2941  CB  SER C  76      -3.245  11.043  14.969  1.00 50.67           C  
+ATOM   2942  OG  SER C  76      -2.412   9.931  14.707  1.00 56.45           O  
+ATOM   2943  N   SER C  77      -5.149   8.379  15.878  1.00 46.48           N  
+ATOM   2944  CA  SER C  77      -5.301   7.335  16.878  1.00 45.79           C  
+ATOM   2945  C   SER C  77      -5.032   5.969  16.271  1.00 45.98           C  
+ATOM   2946  O   SER C  77      -5.516   5.661  15.184  1.00 44.42           O  
+ATOM   2947  CB  SER C  77      -6.707   7.358  17.467  1.00 45.80           C  
+ATOM   2948  OG  SER C  77      -6.878   6.301  18.391  1.00 48.42           O  
+ATOM   2949  N   PRO C  78      -4.233   5.139  16.959  1.00 46.53           N  
+ATOM   2950  CA  PRO C  78      -3.925   3.799  16.452  1.00 46.91           C  
+ATOM   2951  C   PRO C  78      -5.133   2.866  16.553  1.00 46.89           C  
+ATOM   2952  O   PRO C  78      -5.118   1.760  16.013  1.00 49.47           O  
+ATOM   2953  CB  PRO C  78      -2.765   3.352  17.341  1.00 46.04           C  
+ATOM   2954  CG  PRO C  78      -3.040   4.071  18.639  1.00 46.76           C  
+ATOM   2955  CD  PRO C  78      -3.432   5.446  18.158  1.00 46.02           C  
+ATOM   2956  N   PHE C  79      -6.185   3.328  17.223  1.00 44.87           N  
+ATOM   2957  CA  PHE C  79      -7.393   2.526  17.405  1.00 44.22           C  
+ATOM   2958  C   PHE C  79      -8.463   2.795  16.350  1.00 44.50           C  
+ATOM   2959  O   PHE C  79      -8.729   3.943  15.993  1.00 45.70           O  
+ATOM   2960  CB  PHE C  79      -7.959   2.779  18.800  1.00 42.68           C  
+ATOM   2961  CG  PHE C  79      -6.956   2.576  19.892  1.00 39.24           C  
+ATOM   2962  CD1 PHE C  79      -6.837   3.500  20.924  1.00 39.55           C  
+ATOM   2963  CD2 PHE C  79      -6.120   1.465  19.883  1.00 37.58           C  
+ATOM   2964  CE1 PHE C  79      -5.889   3.318  21.934  1.00 38.83           C  
+ATOM   2965  CE2 PHE C  79      -5.176   1.275  20.881  1.00 38.42           C  
+ATOM   2966  CZ  PHE C  79      -5.059   2.203  21.909  1.00 39.20           C  
+ATOM   2967  N   ALA C  80      -9.083   1.722  15.873  1.00 43.46           N  
+ATOM   2968  CA  ALA C  80     -10.107   1.804  14.840  1.00 42.11           C  
+ATOM   2969  C   ALA C  80     -11.437   2.404  15.272  1.00 40.83           C  
+ATOM   2970  O   ALA C  80     -12.488   1.802  15.051  1.00 42.12           O  
+ATOM   2971  CB  ALA C  80     -10.342   0.415  14.242  1.00 43.33           C  
+ATOM   2972  N   TYR C  81     -11.406   3.591  15.867  1.00 39.64           N  
+ATOM   2973  CA  TYR C  81     -12.643   4.237  16.284  1.00 39.77           C  
+ATOM   2974  C   TYR C  81     -13.563   4.487  15.095  1.00 40.10           C  
+ATOM   2975  O   TYR C  81     -13.107   4.755  13.987  1.00 39.66           O  
+ATOM   2976  CB  TYR C  81     -12.360   5.570  16.969  1.00 40.17           C  
+ATOM   2977  CG  TYR C  81     -11.810   5.453  18.366  1.00 40.17           C  
+ATOM   2978  CD1 TYR C  81     -10.523   5.899  18.665  1.00 39.56           C  
+ATOM   2979  CD2 TYR C  81     -12.588   4.932  19.399  1.00 39.45           C  
+ATOM   2980  CE1 TYR C  81     -10.023   5.834  19.962  1.00 41.05           C  
+ATOM   2981  CE2 TYR C  81     -12.099   4.860  20.701  1.00 40.44           C  
+ATOM   2982  CZ  TYR C  81     -10.815   5.313  20.975  1.00 41.51           C  
+ATOM   2983  OH  TYR C  81     -10.319   5.247  22.258  1.00 42.15           O  
+ATOM   2984  N   SER C  82     -14.867   4.397  15.332  1.00 41.07           N  
+ATOM   2985  CA  SER C  82     -15.840   4.634  14.274  1.00 40.57           C  
+ATOM   2986  C   SER C  82     -16.251   6.105  14.292  1.00 39.69           C  
+ATOM   2987  O   SER C  82     -15.988   6.826  15.259  1.00 38.63           O  
+ATOM   2988  CB  SER C  82     -17.082   3.772  14.491  1.00 38.98           C  
+ATOM   2989  OG  SER C  82     -17.797   4.223  15.630  1.00 41.69           O  
+ATOM   2990  N   VAL C  83     -16.905   6.534  13.218  1.00 38.09           N  
+ATOM   2991  CA  VAL C  83     -17.377   7.902  13.099  1.00 38.17           C  
+ATOM   2992  C   VAL C  83     -18.211   8.266  14.311  1.00 38.56           C  
+ATOM   2993  O   VAL C  83     -17.951   9.276  14.963  1.00 41.28           O  
+ATOM   2994  CB  VAL C  83     -18.216   8.082  11.803  1.00 37.97           C  
+ATOM   2995  CG1 VAL C  83     -18.968   9.403  11.826  1.00 34.38           C  
+ATOM   2996  CG2 VAL C  83     -17.295   8.026  10.601  1.00 34.62           C  
+ATOM   2997  N   LEU C  84     -19.203   7.438  14.622  1.00 39.92           N  
+ATOM   2998  CA  LEU C  84     -20.068   7.684  15.776  1.00 40.92           C  
+ATOM   2999  C   LEU C  84     -19.269   7.785  17.074  1.00 40.66           C  
+ATOM   3000  O   LEU C  84     -19.567   8.623  17.923  1.00 43.34           O  
+ATOM   3001  CB  LEU C  84     -21.108   6.570  15.918  1.00 42.01           C  
+ATOM   3002  CG  LEU C  84     -22.551   7.021  16.148  1.00 43.38           C  
+ATOM   3003  CD1 LEU C  84     -23.376   5.827  16.606  1.00 44.59           C  
+ATOM   3004  CD2 LEU C  84     -22.610   8.134  17.184  1.00 44.09           C  
+ATOM   3005  N   ASP C  85     -18.264   6.925  17.231  1.00 40.27           N  
+ATOM   3006  CA  ASP C  85     -17.421   6.935  18.430  1.00 39.70           C  
+ATOM   3007  C   ASP C  85     -16.745   8.296  18.580  1.00 38.03           C  
+ATOM   3008  O   ASP C  85     -16.657   8.852  19.679  1.00 35.15           O  
+ATOM   3009  CB  ASP C  85     -16.330   5.853  18.338  1.00 43.73           C  
+ATOM   3010  CG  ASP C  85     -16.869   4.441  18.519  1.00 47.11           C  
+ATOM   3011  OD1 ASP C  85     -16.174   3.482  18.106  1.00 49.07           O  
+ATOM   3012  OD2 ASP C  85     -17.973   4.285  19.083  1.00 49.99           O  
+ATOM   3013  N   ILE C  86     -16.251   8.826  17.467  1.00 36.13           N  
+ATOM   3014  CA  ILE C  86     -15.584  10.115  17.498  1.00 33.55           C  
+ATOM   3015  C   ILE C  86     -16.556  11.248  17.819  1.00 33.70           C  
+ATOM   3016  O   ILE C  86     -16.299  12.065  18.698  1.00 31.56           O  
+ATOM   3017  CB  ILE C  86     -14.860  10.390  16.157  1.00 34.91           C  
+ATOM   3018  CG1 ILE C  86     -13.655   9.440  16.037  1.00 30.36           C  
+ATOM   3019  CG2 ILE C  86     -14.469  11.874  16.057  1.00 28.94           C  
+ATOM   3020  CD1 ILE C  86     -12.575   9.915  15.108  0.00 32.01           C  
+ATOM   3021  N   VAL C  87     -17.688  11.281  17.129  1.00 35.16           N  
+ATOM   3022  CA  VAL C  87     -18.663  12.340  17.363  1.00 34.94           C  
+ATOM   3023  C   VAL C  87     -19.225  12.279  18.779  1.00 36.42           C  
+ATOM   3024  O   VAL C  87     -19.338  13.301  19.455  1.00 37.81           O  
+ATOM   3025  CB  VAL C  87     -19.818  12.263  16.336  1.00 34.17           C  
+ATOM   3026  CG1 VAL C  87     -20.866  13.314  16.652  1.00 30.00           C  
+ATOM   3027  CG2 VAL C  87     -19.267  12.463  14.916  1.00 28.79           C  
+ATOM   3028  N   LEU C  88     -19.557  11.076  19.232  1.00 37.10           N  
+ATOM   3029  CA  LEU C  88     -20.117  10.884  20.565  1.00 36.93           C  
+ATOM   3030  C   LEU C  88     -19.229  11.473  21.659  1.00 37.38           C  
+ATOM   3031  O   LEU C  88     -19.722  11.951  22.684  1.00 41.14           O  
+ATOM   3032  CB  LEU C  88     -20.346   9.395  20.819  1.00 38.13           C  
+ATOM   3033  CG  LEU C  88     -21.259   9.018  21.987  1.00 41.13           C  
+ATOM   3034  CD1 LEU C  88     -22.679   9.556  21.762  1.00 35.29           C  
+ATOM   3035  CD2 LEU C  88     -21.275   7.494  22.110  1.00 42.48           C  
+ATOM   3036  N   MET C  89     -17.920  11.453  21.450  1.00 35.62           N  
+ATOM   3037  CA  MET C  89     -17.015  12.019  22.437  1.00 36.90           C  
+ATOM   3038  C   MET C  89     -17.380  13.475  22.704  1.00 37.18           C  
+ATOM   3039  O   MET C  89     -17.044  14.032  23.753  1.00 37.10           O  
+ATOM   3040  CB  MET C  89     -15.563  11.918  21.955  1.00 38.62           C  
+ATOM   3041  CG  MET C  89     -15.057  10.482  21.828  1.00 39.96           C  
+ATOM   3042  SD  MET C  89     -13.252  10.356  21.692  1.00 45.27           S  
+ATOM   3043  CE  MET C  89     -13.083   8.772  20.757  1.00 40.24           C  
+ATOM   3044  N   GLY C  90     -18.067  14.091  21.745  1.00 37.70           N  
+ATOM   3045  CA  GLY C  90     -18.482  15.474  21.904  1.00 38.04           C  
+ATOM   3046  C   GLY C  90     -19.518  15.634  23.004  1.00 40.86           C  
+ATOM   3047  O   GLY C  90     -19.778  16.746  23.463  1.00 39.98           O  
+ATOM   3048  N   ARG C  91     -20.109  14.521  23.436  1.00 42.25           N  
+ATOM   3049  CA  ARG C  91     -21.115  14.544  24.494  1.00 43.86           C  
+ATOM   3050  C   ARG C  91     -20.445  14.512  25.863  1.00 45.40           C  
+ATOM   3051  O   ARG C  91     -21.106  14.451  26.902  1.00 46.01           O  
+ATOM   3052  CB  ARG C  91     -22.060  13.350  24.340  1.00 43.88           C  
+ATOM   3053  CG  ARG C  91     -22.847  13.372  23.037  1.00 44.66           C  
+ATOM   3054  CD  ARG C  91     -23.647  14.665  22.920  1.00 45.58           C  
+ATOM   3055  NE  ARG C  91     -24.693  14.763  23.936  1.00 47.34           N  
+ATOM   3056  CZ  ARG C  91     -25.369  15.876  24.211  1.00 48.43           C  
+ATOM   3057  NH1 ARG C  91     -26.308  15.875  25.146  1.00 44.94           N  
+ATOM   3058  NH2 ARG C  91     -25.094  16.998  23.560  1.00 48.47           N  
+ATOM   3059  N   SER C  92     -19.121  14.566  25.845  1.00 46.14           N  
+ATOM   3060  CA  SER C  92     -18.313  14.544  27.048  1.00 47.35           C  
+ATOM   3061  C   SER C  92     -18.914  15.302  28.231  1.00 48.97           C  
+ATOM   3062  O   SER C  92     -19.107  14.727  29.304  1.00 47.93           O  
+ATOM   3063  CB  SER C  92     -16.923  15.099  26.728  1.00 48.34           C  
+ATOM   3064  OG  SER C  92     -16.139  15.224  27.898  1.00 53.39           O  
+ATOM   3065  N   THR C  93     -19.213  16.586  28.040  1.00 50.39           N  
+ATOM   3066  CA  THR C  93     -19.760  17.412  29.122  1.00 51.64           C  
+ATOM   3067  C   THR C  93     -21.212  17.141  29.488  1.00 52.24           C  
+ATOM   3068  O   THR C  93     -21.729  17.727  30.432  1.00 54.00           O  
+ATOM   3069  CB  THR C  93     -19.613  18.918  28.808  1.00 52.36           C  
+ATOM   3070  OG1 THR C  93     -20.155  19.196  27.507  1.00 52.72           O  
+ATOM   3071  CG2 THR C  93     -18.142  19.326  28.851  1.00 51.74           C  
+ATOM   3072  N   HIS C  94     -21.870  16.256  28.753  1.00 53.58           N  
+ATOM   3073  CA  HIS C  94     -23.261  15.932  29.046  1.00 55.53           C  
+ATOM   3074  C   HIS C  94     -23.388  14.557  29.695  1.00 55.78           C  
+ATOM   3075  O   HIS C  94     -24.493  14.035  29.886  1.00 56.54           O  
+ATOM   3076  CB  HIS C  94     -24.099  16.002  27.769  1.00 56.98           C  
+ATOM   3077  CG  HIS C  94     -24.279  17.395  27.251  1.00 60.45           C  
+ATOM   3078  ND1 HIS C  94     -23.244  18.131  26.716  1.00 61.89           N  
+ATOM   3079  CD2 HIS C  94     -25.366  18.201  27.225  1.00 60.78           C  
+ATOM   3080  CE1 HIS C  94     -23.685  19.330  26.382  1.00 60.71           C  
+ATOM   3081  NE2 HIS C  94     -24.970  19.399  26.681  1.00 61.60           N  
+ATOM   3082  N   ILE C  95     -22.241  13.983  30.042  1.00 54.13           N  
+ATOM   3083  CA  ILE C  95     -22.185  12.675  30.674  1.00 52.07           C  
+ATOM   3084  C   ILE C  95     -21.304  12.791  31.911  1.00 52.93           C  
+ATOM   3085  O   ILE C  95     -20.232  13.396  31.866  1.00 51.78           O  
+ATOM   3086  CB  ILE C  95     -21.584  11.629  29.717  1.00 51.91           C  
+ATOM   3087  CG1 ILE C  95     -22.388  11.595  28.415  1.00 49.95           C  
+ATOM   3088  CG2 ILE C  95     -21.579  10.259  30.375  1.00 50.10           C  
+ATOM   3089  CD1 ILE C  95     -21.788  10.707  27.348  0.00 50.80           C  
+ATOM   3090  N   ASN C  96     -21.764  12.231  33.025  1.00 54.82           N  
+ATOM   3091  CA  ASN C  96     -20.986  12.287  34.255  1.00 56.07           C  
+ATOM   3092  C   ASN C  96     -19.784  11.347  34.187  1.00 54.88           C  
+ATOM   3093  O   ASN C  96     -19.819  10.316  33.515  1.00 53.22           O  
+ATOM   3094  CB  ASN C  96     -21.865  11.945  35.459  1.00 59.26           C  
+ATOM   3095  CG  ASN C  96     -22.775  13.094  35.858  1.00 63.10           C  
+ATOM   3096  OD1 ASN C  96     -23.559  12.983  36.802  1.00 65.14           O  
+ATOM   3097  ND2 ASN C  96     -22.670  14.209  35.141  1.00 63.69           N  
+ATOM   3098  N   THR C  97     -18.724  11.720  34.891  1.00 54.57           N  
+ATOM   3099  CA  THR C  97     -17.486  10.959  34.916  1.00 55.45           C  
+ATOM   3100  C   THR C  97     -17.631   9.441  34.920  1.00 55.38           C  
+ATOM   3101  O   THR C  97     -17.002   8.757  34.115  1.00 56.25           O  
+ATOM   3102  CB  THR C  97     -16.632  11.361  36.125  1.00 56.97           C  
+ATOM   3103  OG1 THR C  97     -16.425  12.780  36.105  1.00 58.65           O  
+ATOM   3104  CG2 THR C  97     -15.281  10.651  36.083  1.00 56.70           C  
+ATOM   3105  N   PHE C  98     -18.454   8.904  35.813  1.00 53.16           N  
+ATOM   3106  CA  PHE C  98     -18.598   7.459  35.877  1.00 51.05           C  
+ATOM   3107  C   PHE C  98     -19.876   6.953  35.248  1.00 51.12           C  
+ATOM   3108  O   PHE C  98     -20.347   5.859  35.567  1.00 52.40           O  
+ATOM   3109  CB  PHE C  98     -18.503   6.992  37.328  1.00 49.23           C  
+ATOM   3110  CG  PHE C  98     -17.250   7.439  38.015  1.00 48.59           C  
+ATOM   3111  CD1 PHE C  98     -17.232   8.611  38.760  1.00 47.90           C  
+ATOM   3112  CD2 PHE C  98     -16.070   6.715  37.875  1.00 49.03           C  
+ATOM   3113  CE1 PHE C  98     -16.056   9.061  39.354  1.00 48.47           C  
+ATOM   3114  CE2 PHE C  98     -14.886   7.154  38.464  1.00 48.75           C  
+ATOM   3115  CZ  PHE C  98     -14.879   8.331  39.206  1.00 48.28           C  
+ATOM   3116  N   ALA C  99     -20.432   7.740  34.338  1.00 49.07           N  
+ATOM   3117  CA  ALA C  99     -21.663   7.347  33.679  1.00 48.01           C  
+ATOM   3118  C   ALA C  99     -21.429   6.966  32.226  1.00 48.24           C  
+ATOM   3119  O   ALA C  99     -20.340   7.142  31.684  1.00 47.75           O  
+ATOM   3120  CB  ALA C  99     -22.676   8.470  33.769  1.00 48.26           C  
+ATOM   3121  N   LYS C 100     -22.467   6.434  31.602  1.00 49.10           N  
+ATOM   3122  CA  LYS C 100     -22.394   6.028  30.211  1.00 51.27           C  
+ATOM   3123  C   LYS C 100     -23.301   6.936  29.390  1.00 51.51           C  
+ATOM   3124  O   LYS C 100     -24.261   7.503  29.913  1.00 50.83           O  
+ATOM   3125  CB  LYS C 100     -22.857   4.575  30.063  1.00 51.22           C  
+ATOM   3126  CG  LYS C 100     -22.019   3.563  30.831  1.00 54.71           C  
+ATOM   3127  CD  LYS C 100     -20.584   3.524  30.316  1.00 56.89           C  
+ATOM   3128  CE  LYS C 100     -19.834   2.294  30.812  1.00 57.38           C  
+ATOM   3129  NZ  LYS C 100     -19.573   2.324  32.271  1.00 58.53           N  
+ATOM   3130  N   PRO C 101     -22.996   7.104  28.096  1.00 52.00           N  
+ATOM   3131  CA  PRO C 101     -23.854   7.962  27.282  1.00 52.36           C  
+ATOM   3132  C   PRO C 101     -25.259   7.367  27.227  1.00 53.75           C  
+ATOM   3133  O   PRO C 101     -25.425   6.146  27.285  1.00 52.83           O  
+ATOM   3134  CB  PRO C 101     -23.153   7.958  25.920  1.00 52.94           C  
+ATOM   3135  CG  PRO C 101     -22.436   6.640  25.899  1.00 51.66           C  
+ATOM   3136  CD  PRO C 101     -21.886   6.557  27.297  1.00 51.83           C  
+ATOM   3137  N   LYS C 102     -26.263   8.233  27.130  1.00 54.99           N  
+ATOM   3138  CA  LYS C 102     -27.653   7.794  27.067  1.00 56.44           C  
+ATOM   3139  C   LYS C 102     -28.188   7.930  25.651  1.00 56.39           C  
+ATOM   3140  O   LYS C 102     -27.532   8.510  24.787  1.00 56.35           O  
+ATOM   3141  CB  LYS C 102     -28.515   8.617  28.032  1.00 57.94           C  
+ATOM   3142  CG  LYS C 102     -28.262   8.302  29.496  1.00 60.06           C  
+ATOM   3143  CD  LYS C 102     -29.135   9.148  30.407  1.00 63.57           C  
+ATOM   3144  CE  LYS C 102     -29.079   8.634  31.840  1.00 65.76           C  
+ATOM   3145  NZ  LYS C 102     -27.681   8.545  32.362  1.00 66.31           N  
+ATOM   3146  N   SER C 103     -29.384   7.397  25.419  1.00 56.35           N  
+ATOM   3147  CA  SER C 103     -29.997   7.456  24.099  1.00 56.18           C  
+ATOM   3148  C   SER C 103     -30.020   8.885  23.564  1.00 55.62           C  
+ATOM   3149  O   SER C 103     -29.881   9.096  22.363  1.00 56.23           O  
+ATOM   3150  CB  SER C 103     -31.420   6.894  24.145  1.00 56.29           C  
+ATOM   3151  OG  SER C 103     -32.248   7.680  24.983  1.00 58.12           O  
+ATOM   3152  N   HIS C 104     -30.194   9.860  24.454  1.00 54.81           N  
+ATOM   3153  CA  HIS C 104     -30.219  11.262  24.050  1.00 55.25           C  
+ATOM   3154  C   HIS C 104     -28.873  11.648  23.438  1.00 55.43           C  
+ATOM   3155  O   HIS C 104     -28.820  12.300  22.394  1.00 55.16           O  
+ATOM   3156  CB  HIS C 104     -30.511  12.168  25.252  1.00 55.08           C  
+ATOM   3157  CG  HIS C 104     -30.563  13.629  24.913  1.00 55.31           C  
+ATOM   3158  ND1 HIS C 104     -31.387  14.139  23.932  1.00 55.17           N  
+ATOM   3159  CD2 HIS C 104     -29.909  14.691  25.442  1.00 55.51           C  
+ATOM   3160  CE1 HIS C 104     -31.239  15.451  23.871  1.00 54.61           C  
+ATOM   3161  NE2 HIS C 104     -30.348  15.812  24.777  1.00 54.72           N  
+ATOM   3162  N   ASP C 105     -27.791  11.242  24.097  1.00 54.01           N  
+ATOM   3163  CA  ASP C 105     -26.451  11.535  23.610  1.00 52.15           C  
+ATOM   3164  C   ASP C 105     -26.264  10.982  22.201  1.00 51.50           C  
+ATOM   3165  O   ASP C 105     -25.679  11.644  21.346  1.00 50.62           O  
+ATOM   3166  CB  ASP C 105     -25.408  10.954  24.565  1.00 50.06           C  
+ATOM   3167  CG  ASP C 105     -25.408  11.655  25.911  1.00 51.10           C  
+ATOM   3168  OD1 ASP C 105     -25.598  10.972  26.945  1.00 52.47           O  
+ATOM   3169  OD2 ASP C 105     -25.222  12.893  25.935  1.00 47.12           O  
+ATOM   3170  N   TYR C 106     -26.763   9.774  21.952  1.00 51.23           N  
+ATOM   3171  CA  TYR C 106     -26.652   9.194  20.619  1.00 51.63           C  
+ATOM   3172  C   TYR C 106     -27.557   9.964  19.659  1.00 51.96           C  
+ATOM   3173  O   TYR C 106     -27.292  10.045  18.457  1.00 52.36           O  
+ATOM   3174  CB  TYR C 106     -27.064   7.720  20.620  1.00 52.81           C  
+ATOM   3175  CG  TYR C 106     -26.119   6.804  21.362  1.00 54.64           C  
+ATOM   3176  CD1 TYR C 106     -26.197   6.662  22.749  1.00 55.53           C  
+ATOM   3177  CD2 TYR C 106     -25.131   6.090  20.681  1.00 54.37           C  
+ATOM   3178  CE1 TYR C 106     -25.314   5.829  23.440  1.00 56.71           C  
+ATOM   3179  CE2 TYR C 106     -24.242   5.256  21.364  1.00 56.26           C  
+ATOM   3180  CZ  TYR C 106     -24.340   5.131  22.742  1.00 56.28           C  
+ATOM   3181  OH  TYR C 106     -23.469   4.311  23.424  1.00 57.70           O  
+ATOM   3182  N   GLN C 107     -28.633  10.525  20.194  1.00 50.84           N  
+ATOM   3183  CA  GLN C 107     -29.562  11.287  19.377  1.00 51.78           C  
+ATOM   3184  C   GLN C 107     -28.883  12.552  18.845  1.00 49.61           C  
+ATOM   3185  O   GLN C 107     -28.894  12.815  17.644  1.00 48.43           O  
+ATOM   3186  CB  GLN C 107     -30.803  11.662  20.197  1.00 54.07           C  
+ATOM   3187  CG  GLN C 107     -31.806  12.531  19.441  1.00 58.99           C  
+ATOM   3188  CD  GLN C 107     -33.085  12.776  20.224  1.00 62.35           C  
+ATOM   3189  OE1 GLN C 107     -33.061  13.338  21.324  1.00 64.28           O  
+ATOM   3190  NE2 GLN C 107     -34.212  12.353  19.659  1.00 63.76           N  
+ATOM   3191  N   VAL C 108     -28.288  13.325  19.748  1.00 47.68           N  
+ATOM   3192  CA  VAL C 108     -27.609  14.554  19.368  1.00 47.48           C  
+ATOM   3193  C   VAL C 108     -26.486  14.307  18.363  1.00 48.40           C  
+ATOM   3194  O   VAL C 108     -26.353  15.039  17.378  1.00 47.80           O  
+ATOM   3195  CB  VAL C 108     -27.020  15.267  20.599  1.00 47.29           C  
+ATOM   3196  CG1 VAL C 108     -26.182  16.461  20.155  1.00 45.09           C  
+ATOM   3197  CG2 VAL C 108     -28.147  15.717  21.523  1.00 44.16           C  
+ATOM   3198  N   ALA C 109     -25.678  13.280  18.617  1.00 46.91           N  
+ATOM   3199  CA  ALA C 109     -24.575  12.951  17.724  1.00 46.77           C  
+ATOM   3200  C   ALA C 109     -25.124  12.645  16.346  1.00 46.90           C  
+ATOM   3201  O   ALA C 109     -24.592  13.108  15.337  1.00 46.94           O  
+ATOM   3202  CB  ALA C 109     -23.800  11.751  18.255  1.00 45.78           C  
+ATOM   3203  N   MET C 110     -26.200  11.865  16.313  1.00 47.45           N  
+ATOM   3204  CA  MET C 110     -26.832  11.489  15.058  1.00 47.91           C  
+ATOM   3205  C   MET C 110     -27.406  12.690  14.321  1.00 46.71           C  
+ATOM   3206  O   MET C 110     -27.320  12.766  13.094  1.00 45.21           O  
+ATOM   3207  CB  MET C 110     -27.938  10.457  15.303  1.00 50.05           C  
+ATOM   3208  CG  MET C 110     -27.423   9.058  15.595  1.00 51.94           C  
+ATOM   3209  SD  MET C 110     -26.508   8.343  14.206  1.00 55.54           S  
+ATOM   3210  CE  MET C 110     -24.904   8.542  14.791  1.00 56.22           C  
+ATOM   3211  N   GLN C 111     -28.004  13.627  15.046  1.00 46.14           N  
+ATOM   3212  CA  GLN C 111     -28.542  14.784  14.355  1.00 48.66           C  
+ATOM   3213  C   GLN C 111     -27.413  15.706  13.903  1.00 49.19           C  
+ATOM   3214  O   GLN C 111     -27.577  16.474  12.954  1.00 50.09           O  
+ATOM   3215  CB  GLN C 111     -29.574  15.528  15.215  1.00 50.02           C  
+ATOM   3216  CG  GLN C 111     -29.275  15.637  16.689  1.00 54.09           C  
+ATOM   3217  CD  GLN C 111     -30.505  16.065  17.487  1.00 55.35           C  
+ATOM   3218  OE1 GLN C 111     -31.572  15.461  17.372  1.00 53.35           O  
+ATOM   3219  NE2 GLN C 111     -30.356  17.103  18.300  1.00 56.34           N  
+ATOM   3220  N   ALA C 112     -26.259  15.607  14.561  1.00 47.79           N  
+ATOM   3221  CA  ALA C 112     -25.104  16.415  14.181  1.00 47.89           C  
+ATOM   3222  C   ALA C 112     -24.631  15.919  12.822  1.00 47.60           C  
+ATOM   3223  O   ALA C 112     -24.324  16.710  11.931  1.00 47.35           O  
+ATOM   3224  CB  ALA C 112     -23.989  16.273  15.202  1.00 45.95           C  
+ATOM   3225  N   LEU C 113     -24.581  14.597  12.676  1.00 47.28           N  
+ATOM   3226  CA  LEU C 113     -24.166  13.962  11.431  1.00 46.32           C  
+ATOM   3227  C   LEU C 113     -25.189  14.245  10.342  1.00 46.52           C  
+ATOM   3228  O   LEU C 113     -24.845  14.479   9.183  1.00 48.22           O  
+ATOM   3229  CB  LEU C 113     -24.053  12.450  11.624  1.00 45.02           C  
+ATOM   3230  CG  LEU C 113     -22.875  11.946  12.457  1.00 46.66           C  
+ATOM   3231  CD1 LEU C 113     -22.993  10.435  12.661  1.00 44.05           C  
+ATOM   3232  CD2 LEU C 113     -21.574  12.304  11.745  1.00 40.94           C  
+ATOM   3233  N   ASP C 114     -26.455  14.214  10.731  1.00 46.68           N  
+ATOM   3234  CA  ASP C 114     -27.553  14.454   9.810  1.00 46.66           C  
+ATOM   3235  C   ASP C 114     -27.472  15.869   9.263  1.00 45.22           C  
+ATOM   3236  O   ASP C 114     -27.621  16.093   8.063  1.00 42.13           O  
+ATOM   3237  CB  ASP C 114     -28.884  14.239  10.531  1.00 49.20           C  
+ATOM   3238  CG  ASP C 114     -30.071  14.449   9.629  1.00 53.47           C  
+ATOM   3239  OD1 ASP C 114     -30.041  13.943   8.485  1.00 54.66           O  
+ATOM   3240  OD2 ASP C 114     -31.034  15.114  10.069  1.00 56.37           O  
+ATOM   3241  N   TYR C 115     -27.232  16.820  10.158  1.00 44.76           N  
+ATOM   3242  CA  TYR C 115     -27.117  18.208   9.770  1.00 44.62           C  
+ATOM   3243  C   TYR C 115     -26.087  18.372   8.656  1.00 44.28           C  
+ATOM   3244  O   TYR C 115     -26.269  19.190   7.765  1.00 44.35           O  
+ATOM   3245  CB  TYR C 115     -26.720  19.051  10.974  1.00 45.94           C  
+ATOM   3246  CG  TYR C 115     -26.336  20.459  10.617  1.00 46.64           C  
+ATOM   3247  CD1 TYR C 115     -27.289  21.375  10.166  1.00 47.71           C  
+ATOM   3248  CD2 TYR C 115     -25.013  20.880  10.724  1.00 49.34           C  
+ATOM   3249  CE1 TYR C 115     -26.930  22.681   9.833  1.00 47.81           C  
+ATOM   3250  CE2 TYR C 115     -24.642  22.180  10.395  1.00 49.87           C  
+ATOM   3251  CZ  TYR C 115     -25.605  23.073   9.953  1.00 49.29           C  
+ATOM   3252  OH  TYR C 115     -25.229  24.356   9.651  1.00 51.75           O  
+ATOM   3253  N   LEU C 116     -25.017  17.585   8.701  1.00 43.83           N  
+ATOM   3254  CA  LEU C 116     -23.970  17.661   7.681  1.00 43.74           C  
+ATOM   3255  C   LEU C 116     -24.174  16.632   6.557  1.00 44.76           C  
+ATOM   3256  O   LEU C 116     -23.321  16.485   5.665  1.00 41.73           O  
+ATOM   3257  CB  LEU C 116     -22.598  17.442   8.325  1.00 43.65           C  
+ATOM   3258  CG  LEU C 116     -22.228  18.383   9.470  1.00 44.31           C  
+ATOM   3259  CD1 LEU C 116     -20.905  17.968  10.082  1.00 42.44           C  
+ATOM   3260  CD2 LEU C 116     -22.159  19.800   8.945  1.00 46.07           C  
+ATOM   3261  N   ASN C 117     -25.299  15.922   6.613  1.00 43.68           N  
+ATOM   3262  CA  ASN C 117     -25.633  14.904   5.620  1.00 45.16           C  
+ATOM   3263  C   ASN C 117     -24.574  13.814   5.565  1.00 45.01           C  
+ATOM   3264  O   ASN C 117     -24.137  13.419   4.483  1.00 43.41           O  
+ATOM   3265  CB  ASN C 117     -25.783  15.535   4.231  1.00 46.27           C  
+ATOM   3266  CG  ASN C 117     -26.824  16.632   4.201  1.00 48.81           C  
+ATOM   3267  OD1 ASN C 117     -26.517  17.782   3.883  1.00 51.83           O  
+ATOM   3268  ND2 ASN C 117     -28.063  16.287   4.540  1.00 48.13           N  
+ATOM   3269  N   LEU C 118     -24.163  13.332   6.733  1.00 46.08           N  
+ATOM   3270  CA  LEU C 118     -23.146  12.286   6.811  1.00 48.21           C  
+ATOM   3271  C   LEU C 118     -23.631  11.099   7.638  1.00 47.75           C  
+ATOM   3272  O   LEU C 118     -22.832  10.298   8.122  1.00 46.07           O  
+ATOM   3273  CB  LEU C 118     -21.855  12.847   7.423  1.00 48.25           C  
+ATOM   3274  CG  LEU C 118     -21.206  14.010   6.668  1.00 49.90           C  
+ATOM   3275  CD1 LEU C 118     -20.025  14.534   7.465  1.00 48.36           C  
+ATOM   3276  CD2 LEU C 118     -20.770  13.544   5.272  1.00 48.63           C  
+ATOM   3277  N   THR C 119     -24.945  10.999   7.801  1.00 49.03           N  
+ATOM   3278  CA  THR C 119     -25.539   9.911   8.563  1.00 50.64           C  
+ATOM   3279  C   THR C 119     -25.029   8.565   8.065  1.00 50.13           C  
+ATOM   3280  O   THR C 119     -24.750   7.667   8.860  1.00 51.13           O  
+ATOM   3281  CB  THR C 119     -27.074   9.940   8.456  1.00 52.23           C  
+ATOM   3282  OG1 THR C 119     -27.576  11.088   9.149  1.00 54.18           O  
+ATOM   3283  CG2 THR C 119     -27.680   8.688   9.067  1.00 54.70           C  
+ATOM   3284  N   HIS C 120     -24.891   8.443   6.750  1.00 48.94           N  
+ATOM   3285  CA  HIS C 120     -24.424   7.209   6.127  1.00 49.21           C  
+ATOM   3286  C   HIS C 120     -22.945   6.935   6.382  1.00 50.68           C  
+ATOM   3287  O   HIS C 120     -22.316   6.176   5.645  1.00 52.71           O  
+ATOM   3288  CB  HIS C 120     -24.648   7.268   4.619  1.00 48.04           C  
+ATOM   3289  CG  HIS C 120     -23.696   8.177   3.905  1.00 49.92           C  
+ATOM   3290  ND1 HIS C 120     -23.728   9.550   4.041  1.00 50.55           N  
+ATOM   3291  CD2 HIS C 120     -22.669   7.907   3.065  1.00 48.40           C  
+ATOM   3292  CE1 HIS C 120     -22.763  10.086   3.314  1.00 48.53           C  
+ATOM   3293  NE2 HIS C 120     -22.105   9.110   2.713  1.00 50.33           N  
+ATOM   3294  N   LEU C 121     -22.385   7.550   7.415  1.00 50.61           N  
+ATOM   3295  CA  LEU C 121     -20.974   7.357   7.733  1.00 49.16           C  
+ATOM   3296  C   LEU C 121     -20.812   6.891   9.171  1.00 48.16           C  
+ATOM   3297  O   LEU C 121     -19.742   6.442   9.569  1.00 49.49           O  
+ATOM   3298  CB  LEU C 121     -20.214   8.672   7.534  1.00 48.30           C  
+ATOM   3299  CG  LEU C 121     -19.279   8.845   6.335  1.00 49.44           C  
+ATOM   3300  CD1 LEU C 121     -19.893   8.277   5.075  1.00 50.39           C  
+ATOM   3301  CD2 LEU C 121     -18.972  10.327   6.164  1.00 49.23           C  
+ATOM   3302  N   ALA C 122     -21.889   6.997   9.940  1.00 48.25           N  
+ATOM   3303  CA  ALA C 122     -21.890   6.629  11.351  1.00 50.52           C  
+ATOM   3304  C   ALA C 122     -21.094   5.381  11.735  1.00 51.43           C  
+ATOM   3305  O   ALA C 122     -20.310   5.414  12.685  1.00 52.67           O  
+ATOM   3306  CB  ALA C 122     -23.332   6.496  11.846  1.00 48.59           C  
+ATOM   3307  N   LYS C 123     -21.288   4.290  11.001  1.00 52.71           N  
+ATOM   3308  CA  LYS C 123     -20.608   3.031  11.309  1.00 53.38           C  
+ATOM   3309  C   LYS C 123     -19.243   2.853  10.658  1.00 51.54           C  
+ATOM   3310  O   LYS C 123     -18.529   1.901  10.962  1.00 52.43           O  
+ATOM   3311  CB  LYS C 123     -21.502   1.848  10.918  1.00 55.12           C  
+ATOM   3312  CG  LYS C 123     -22.873   1.846  11.577  1.00 59.59           C  
+ATOM   3313  CD  LYS C 123     -22.754   1.801  13.091  1.00 63.76           C  
+ATOM   3314  CE  LYS C 123     -24.119   1.686  13.754  1.00 66.68           C  
+ATOM   3315  NZ  LYS C 123     -24.011   1.626  15.245  1.00 69.77           N  
+ATOM   3316  N   ARG C 124     -18.880   3.757   9.760  1.00 49.97           N  
+ATOM   3317  CA  ARG C 124     -17.597   3.661   9.073  1.00 49.19           C  
+ATOM   3318  C   ARG C 124     -16.406   3.858  10.009  1.00 48.63           C  
+ATOM   3319  O   ARG C 124     -16.518   4.491  11.061  1.00 48.70           O  
+ATOM   3320  CB  ARG C 124     -17.534   4.693   7.941  1.00 49.42           C  
+ATOM   3321  CG  ARG C 124     -18.444   4.388   6.762  1.00 50.51           C  
+ATOM   3322  CD  ARG C 124     -17.875   3.257   5.921  1.00 50.96           C  
+ATOM   3323  NE  ARG C 124     -16.633   3.647   5.260  1.00 51.67           N  
+ATOM   3324  CZ  ARG C 124     -16.555   4.564   4.299  1.00 53.22           C  
+ATOM   3325  NH1 ARG C 124     -15.383   4.857   3.756  1.00 53.12           N  
+ATOM   3326  NH2 ARG C 124     -17.650   5.182   3.874  1.00 52.85           N  
+ATOM   3327  N   GLU C 125     -15.264   3.303   9.627  1.00 47.33           N  
+ATOM   3328  CA  GLU C 125     -14.060   3.458  10.422  1.00 47.66           C  
+ATOM   3329  C   GLU C 125     -13.470   4.820  10.069  1.00 46.03           C  
+ATOM   3330  O   GLU C 125     -13.118   5.075   8.913  1.00 45.89           O  
+ATOM   3331  CB  GLU C 125     -13.057   2.359  10.092  1.00 51.50           C  
+ATOM   3332  CG  GLU C 125     -11.772   2.447  10.891  1.00 57.85           C  
+ATOM   3333  CD  GLU C 125     -10.879   1.235  10.685  1.00 62.44           C  
+ATOM   3334  OE1 GLU C 125     -11.404   0.098  10.763  1.00 63.54           O  
+ATOM   3335  OE2 GLU C 125      -9.660   1.419  10.459  1.00 64.33           O  
+ATOM   3336  N   PHE C 126     -13.362   5.688  11.068  1.00 42.19           N  
+ATOM   3337  CA  PHE C 126     -12.838   7.031  10.866  1.00 39.85           C  
+ATOM   3338  C   PHE C 126     -11.671   7.156   9.889  1.00 39.70           C  
+ATOM   3339  O   PHE C 126     -11.698   8.023   9.018  1.00 38.77           O  
+ATOM   3340  CB  PHE C 126     -12.425   7.643  12.200  1.00 36.74           C  
+ATOM   3341  CG  PHE C 126     -12.016   9.082  12.097  1.00 35.60           C  
+ATOM   3342  CD1 PHE C 126     -12.974  10.080  11.958  1.00 33.35           C  
+ATOM   3343  CD2 PHE C 126     -10.672   9.443  12.144  1.00 35.51           C  
+ATOM   3344  CE1 PHE C 126     -12.604  11.420  11.873  1.00 35.30           C  
+ATOM   3345  CE2 PHE C 126     -10.290  10.786  12.056  1.00 35.68           C  
+ATOM   3346  CZ  PHE C 126     -11.261  11.774  11.921  1.00 34.64           C  
+ATOM   3347  N   THR C 127     -10.653   6.307  10.032  1.00 40.09           N  
+ATOM   3348  CA  THR C 127      -9.473   6.376   9.159  1.00 42.28           C  
+ATOM   3349  C   THR C 127      -9.694   5.913   7.732  1.00 42.40           C  
+ATOM   3350  O   THR C 127      -8.791   6.014   6.909  1.00 44.99           O  
+ATOM   3351  CB  THR C 127      -8.276   5.555   9.712  1.00 42.49           C  
+ATOM   3352  OG1 THR C 127      -8.683   4.197   9.924  1.00 45.09           O  
+ATOM   3353  CG2 THR C 127      -7.759   6.156  11.016  1.00 38.78           C  
+ATOM   3354  N   SER C 128     -10.880   5.401   7.430  1.00 42.82           N  
+ATOM   3355  CA  SER C 128     -11.162   4.937   6.074  1.00 43.55           C  
+ATOM   3356  C   SER C 128     -11.800   6.055   5.260  1.00 43.64           C  
+ATOM   3357  O   SER C 128     -12.061   5.894   4.071  1.00 42.97           O  
+ATOM   3358  CB  SER C 128     -12.112   3.740   6.100  1.00 41.49           C  
+ATOM   3359  OG  SER C 128     -13.420   4.141   6.478  1.00 41.98           O  
+ATOM   3360  N   LEU C 129     -12.060   7.182   5.914  1.00 43.21           N  
+ATOM   3361  CA  LEU C 129     -12.676   8.321   5.251  1.00 42.91           C  
+ATOM   3362  C   LEU C 129     -11.627   9.209   4.614  1.00 42.24           C  
+ATOM   3363  O   LEU C 129     -10.435   9.084   4.901  1.00 41.46           O  
+ATOM   3364  CB  LEU C 129     -13.485   9.137   6.254  1.00 43.25           C  
+ATOM   3365  CG  LEU C 129     -14.537   8.332   7.018  1.00 45.92           C  
+ATOM   3366  CD1 LEU C 129     -15.144   9.208   8.071  1.00 47.96           C  
+ATOM   3367  CD2 LEU C 129     -15.601   7.810   6.078  1.00 44.46           C  
+ATOM   3368  N   SER C 130     -12.075  10.101   3.736  1.00 42.27           N  
+ATOM   3369  CA  SER C 130     -11.170  11.034   3.067  1.00 40.11           C  
+ATOM   3370  C   SER C 130     -10.835  12.159   4.050  1.00 37.98           C  
+ATOM   3371  O   SER C 130     -11.444  12.261   5.114  1.00 34.78           O  
+ATOM   3372  CB  SER C 130     -11.850  11.625   1.827  1.00 40.35           C  
+ATOM   3373  OG  SER C 130     -13.011  12.370   2.190  1.00 42.33           O  
+ATOM   3374  N   GLY C 131      -9.869  12.999   3.689  1.00 38.51           N  
+ATOM   3375  CA  GLY C 131      -9.496  14.106   4.550  1.00 35.62           C  
+ATOM   3376  C   GLY C 131     -10.669  15.038   4.790  1.00 35.56           C  
+ATOM   3377  O   GLY C 131     -10.886  15.485   5.911  1.00 36.07           O  
+ATOM   3378  N   GLY C 132     -11.434  15.315   3.737  1.00 35.78           N  
+ATOM   3379  CA  GLY C 132     -12.582  16.200   3.846  1.00 35.74           C  
+ATOM   3380  C   GLY C 132     -13.667  15.671   4.759  1.00 35.39           C  
+ATOM   3381  O   GLY C 132     -14.236  16.425   5.548  1.00 37.91           O  
+ATOM   3382  N   GLN C 133     -13.965  14.379   4.658  1.00 35.34           N  
+ATOM   3383  CA  GLN C 133     -14.986  13.768   5.506  1.00 35.72           C  
+ATOM   3384  C   GLN C 133     -14.499  13.731   6.954  1.00 33.93           C  
+ATOM   3385  O   GLN C 133     -15.284  13.908   7.888  1.00 33.13           O  
+ATOM   3386  CB  GLN C 133     -15.292  12.343   5.039  1.00 37.80           C  
+ATOM   3387  CG  GLN C 133     -15.888  12.243   3.641  1.00 39.11           C  
+ATOM   3388  CD  GLN C 133     -16.046  10.796   3.178  1.00 41.34           C  
+ATOM   3389  OE1 GLN C 133     -15.079  10.023   3.157  1.00 40.70           O  
+ATOM   3390  NE2 GLN C 133     -17.267  10.427   2.804  1.00 40.40           N  
+ATOM   3391  N   ARG C 134     -13.202  13.490   7.136  1.00 31.56           N  
+ATOM   3392  CA  ARG C 134     -12.621  13.448   8.474  1.00 33.99           C  
+ATOM   3393  C   ARG C 134     -12.774  14.800   9.154  1.00 31.69           C  
+ATOM   3394  O   ARG C 134     -13.236  14.888  10.296  1.00 32.62           O  
+ATOM   3395  CB  ARG C 134     -11.138  13.105   8.418  1.00 35.24           C  
+ATOM   3396  CG  ARG C 134     -10.793  11.667   8.086  1.00 40.55           C  
+ATOM   3397  CD  ARG C 134      -9.406  11.423   8.642  1.00 44.59           C  
+ATOM   3398  NE  ARG C 134      -8.740  10.251   8.110  1.00 51.55           N  
+ATOM   3399  CZ  ARG C 134      -7.637   9.730   8.644  1.00 55.27           C  
+ATOM   3400  NH1 ARG C 134      -7.075   8.656   8.100  1.00 55.92           N  
+ATOM   3401  NH2 ARG C 134      -7.105  10.275   9.734  1.00 55.02           N  
+ATOM   3402  N   GLN C 135     -12.371  15.852   8.445  1.00 30.37           N  
+ATOM   3403  CA  GLN C 135     -12.470  17.205   8.973  1.00 31.46           C  
+ATOM   3404  C   GLN C 135     -13.937  17.507   9.293  1.00 29.72           C  
+ATOM   3405  O   GLN C 135     -14.239  18.064  10.338  1.00 31.55           O  
+ATOM   3406  CB  GLN C 135     -11.891  18.208   7.954  1.00 31.25           C  
+ATOM   3407  CG  GLN C 135     -12.101  19.697   8.269  1.00 31.62           C  
+ATOM   3408  CD  GLN C 135     -11.478  20.133   9.583  1.00 35.09           C  
+ATOM   3409  OE1 GLN C 135     -10.336  19.795   9.888  1.00 38.66           O  
+ATOM   3410  NE2 GLN C 135     -12.227  20.898  10.365  1.00 32.88           N  
+ATOM   3411  N   LEU C 136     -14.853  17.124   8.409  1.00 30.55           N  
+ATOM   3412  CA  LEU C 136     -16.267  17.376   8.668  1.00 31.57           C  
+ATOM   3413  C   LEU C 136     -16.734  16.601   9.904  1.00 30.99           C  
+ATOM   3414  O   LEU C 136     -17.489  17.121  10.732  1.00 31.06           O  
+ATOM   3415  CB  LEU C 136     -17.120  16.997   7.449  1.00 31.99           C  
+ATOM   3416  CG  LEU C 136     -17.005  17.917   6.225  1.00 34.78           C  
+ATOM   3417  CD1 LEU C 136     -17.869  17.385   5.094  1.00 36.34           C  
+ATOM   3418  CD2 LEU C 136     -17.435  19.325   6.590  1.00 31.99           C  
+ATOM   3419  N   ILE C 137     -16.284  15.360  10.043  1.00 29.59           N  
+ATOM   3420  CA  ILE C 137     -16.685  14.590  11.208  1.00 29.52           C  
+ATOM   3421  C   ILE C 137     -16.177  15.254  12.486  1.00 30.30           C  
+ATOM   3422  O   ILE C 137     -16.850  15.205  13.514  1.00 28.62           O  
+ATOM   3423  CB  ILE C 137     -16.194  13.130  11.108  1.00 30.97           C  
+ATOM   3424  CG1 ILE C 137     -17.072  12.391  10.095  1.00 29.38           C  
+ATOM   3425  CG2 ILE C 137     -16.237  12.437  12.487  1.00 30.13           C  
+ATOM   3426  CD1 ILE C 137     -16.721  10.966   9.931  0.00 29.88           C  
+ATOM   3427  N   LEU C 138     -15.006  15.893  12.423  1.00 29.16           N  
+ATOM   3428  CA  LEU C 138     -14.470  16.561  13.601  1.00 28.90           C  
+ATOM   3429  C   LEU C 138     -15.291  17.805  13.927  1.00 30.30           C  
+ATOM   3430  O   LEU C 138     -15.388  18.209  15.093  1.00 29.24           O  
+ATOM   3431  CB  LEU C 138     -12.995  16.927  13.406  1.00 27.85           C  
+ATOM   3432  CG  LEU C 138     -12.028  15.738  13.319  1.00 30.12           C  
+ATOM   3433  CD1 LEU C 138     -10.582  16.239  13.192  1.00 23.31           C  
+ATOM   3434  CD2 LEU C 138     -12.201  14.845  14.575  1.00 27.50           C  
+ATOM   3435  N   ILE C 139     -15.884  18.425  12.908  1.00 30.59           N  
+ATOM   3436  CA  ILE C 139     -16.715  19.597  13.172  1.00 30.21           C  
+ATOM   3437  C   ILE C 139     -18.003  19.084  13.835  1.00 30.99           C  
+ATOM   3438  O   ILE C 139     -18.550  19.716  14.743  1.00 31.15           O  
+ATOM   3439  CB  ILE C 139     -17.077  20.379  11.879  1.00 29.19           C  
+ATOM   3440  CG1 ILE C 139     -15.813  20.967  11.230  1.00 27.83           C  
+ATOM   3441  CG2 ILE C 139     -18.060  21.519  12.225  1.00 28.59           C  
+ATOM   3442  CD1 ILE C 139     -16.073  21.700   9.930  0.00 28.40           C  
+ATOM   3443  N   ALA C 140     -18.477  17.928  13.380  1.00 29.71           N  
+ATOM   3444  CA  ALA C 140     -19.679  17.320  13.946  1.00 32.39           C  
+ATOM   3445  C   ALA C 140     -19.506  17.028  15.442  1.00 32.91           C  
+ATOM   3446  O   ALA C 140     -20.400  17.312  16.243  1.00 34.47           O  
+ATOM   3447  CB  ALA C 140     -20.023  16.027  13.198  1.00 30.18           C  
+ATOM   3448  N   ARG C 141     -18.361  16.481  15.839  1.00 34.07           N  
+ATOM   3449  CA  ARG C 141     -18.182  16.184  17.254  1.00 34.51           C  
+ATOM   3450  C   ARG C 141     -18.241  17.467  18.084  1.00 35.07           C  
+ATOM   3451  O   ARG C 141     -18.767  17.455  19.197  1.00 33.42           O  
+ATOM   3452  CB  ARG C 141     -16.880  15.420  17.496  1.00 34.56           C  
+ATOM   3453  CG  ARG C 141     -15.669  16.267  17.692  1.00 40.33           C  
+ATOM   3454  CD  ARG C 141     -15.049  15.961  19.032  1.00 39.30           C  
+ATOM   3455  NE  ARG C 141     -14.011  14.942  18.966  1.00 38.72           N  
+ATOM   3456  CZ  ARG C 141     -12.756  15.155  18.573  1.00 36.18           C  
+ATOM   3457  NH1 ARG C 141     -11.893  14.152  18.560  1.00 36.82           N  
+ATOM   3458  NH2 ARG C 141     -12.359  16.354  18.194  1.00 32.17           N  
+ATOM   3459  N   ALA C 142     -17.724  18.576  17.549  1.00 34.08           N  
+ATOM   3460  CA  ALA C 142     -17.786  19.850  18.274  1.00 34.99           C  
+ATOM   3461  C   ALA C 142     -19.248  20.303  18.321  1.00 35.82           C  
+ATOM   3462  O   ALA C 142     -19.714  20.833  19.326  1.00 35.43           O  
+ATOM   3463  CB  ALA C 142     -16.935  20.916  17.579  1.00 34.59           C  
+ATOM   3464  N   ILE C 143     -19.964  20.091  17.221  1.00 37.18           N  
+ATOM   3465  CA  ILE C 143     -21.374  20.457  17.136  1.00 39.72           C  
+ATOM   3466  C   ILE C 143     -22.195  19.655  18.146  1.00 40.45           C  
+ATOM   3467  O   ILE C 143     -23.045  20.206  18.837  1.00 40.85           O  
+ATOM   3468  CB  ILE C 143     -21.933  20.203  15.709  1.00 40.89           C  
+ATOM   3469  CG1 ILE C 143     -21.533  21.359  14.784  1.00 40.66           C  
+ATOM   3470  CG2 ILE C 143     -23.448  20.020  15.754  1.00 39.63           C  
+ATOM   3471  CD1 ILE C 143     -21.994  21.189  13.350  0.00 40.70           C  
+ATOM   3472  N   ALA C 144     -21.942  18.351  18.222  1.00 40.89           N  
+ATOM   3473  CA  ALA C 144     -22.660  17.495  19.159  1.00 39.93           C  
+ATOM   3474  C   ALA C 144     -22.457  17.966  20.598  1.00 39.47           C  
+ATOM   3475  O   ALA C 144     -23.253  17.645  21.475  1.00 41.13           O  
+ATOM   3476  CB  ALA C 144     -22.194  16.047  19.013  1.00 39.86           C  
+ATOM   3477  N   SER C 145     -21.395  18.725  20.846  1.00 38.21           N  
+ATOM   3478  CA  SER C 145     -21.128  19.213  22.195  1.00 39.73           C  
+ATOM   3479  C   SER C 145     -22.077  20.362  22.517  1.00 40.58           C  
+ATOM   3480  O   SER C 145     -22.196  20.781  23.668  1.00 38.63           O  
+ATOM   3481  CB  SER C 145     -19.678  19.695  22.324  1.00 38.62           C  
+ATOM   3482  OG  SER C 145     -19.524  21.017  21.833  1.00 41.39           O  
+ATOM   3483  N   GLU C 146     -22.736  20.868  21.477  1.00 41.56           N  
+ATOM   3484  CA  GLU C 146     -23.688  21.967  21.602  1.00 44.47           C  
+ATOM   3485  C   GLU C 146     -23.056  23.316  21.948  1.00 42.42           C  
+ATOM   3486  O   GLU C 146     -23.677  24.151  22.597  1.00 43.43           O  
+ATOM   3487  CB  GLU C 146     -24.763  21.610  22.633  1.00 47.38           C  
+ATOM   3488  CG  GLU C 146     -25.636  20.441  22.208  1.00 53.27           C  
+ATOM   3489  CD  GLU C 146     -26.650  20.049  23.267  1.00 57.89           C  
+ATOM   3490  OE1 GLU C 146     -27.557  19.242  22.959  1.00 59.22           O  
+ATOM   3491  OE2 GLU C 146     -26.537  20.541  24.412  1.00 61.78           O  
+ATOM   3492  N   CYS C 147     -21.824  23.527  21.500  1.00 40.73           N  
+ATOM   3493  CA  CYS C 147     -21.123  24.783  21.743  1.00 39.28           C  
+ATOM   3494  C   CYS C 147     -21.754  25.882  20.888  1.00 38.88           C  
+ATOM   3495  O   CYS C 147     -22.481  25.594  19.939  1.00 37.50           O  
+ATOM   3496  CB  CYS C 147     -19.652  24.638  21.363  1.00 41.28           C  
+ATOM   3497  SG  CYS C 147     -19.378  24.252  19.598  1.00 44.15           S  
+ATOM   3498  N   LYS C 148     -21.475  27.136  21.227  1.00 38.08           N  
+ATOM   3499  CA  LYS C 148     -22.007  28.270  20.479  1.00 39.34           C  
+ATOM   3500  C   LYS C 148     -20.852  29.027  19.825  1.00 38.33           C  
+ATOM   3501  O   LYS C 148     -21.032  29.735  18.836  1.00 38.19           O  
+ATOM   3502  CB  LYS C 148     -22.804  29.194  21.408  1.00 42.69           C  
+ATOM   3503  CG  LYS C 148     -24.068  28.551  21.974  1.00 47.27           C  
+ATOM   3504  CD  LYS C 148     -24.987  28.079  20.859  1.00 51.90           C  
+ATOM   3505  CE  LYS C 148     -26.292  27.486  21.391  1.00 56.83           C  
+ATOM   3506  NZ  LYS C 148     -26.102  26.204  22.140  1.00 60.77           N  
+ATOM   3507  N   LEU C 149     -19.664  28.861  20.396  1.00 36.52           N  
+ATOM   3508  CA  LEU C 149     -18.440  29.474  19.889  1.00 34.46           C  
+ATOM   3509  C   LEU C 149     -17.562  28.316  19.424  1.00 34.57           C  
+ATOM   3510  O   LEU C 149     -17.107  27.508  20.242  1.00 33.94           O  
+ATOM   3511  CB  LEU C 149     -17.734  30.241  21.003  1.00 31.63           C  
+ATOM   3512  CG  LEU C 149     -16.337  30.770  20.687  1.00 34.57           C  
+ATOM   3513  CD1 LEU C 149     -16.363  31.645  19.431  1.00 33.12           C  
+ATOM   3514  CD2 LEU C 149     -15.832  31.557  21.890  1.00 34.75           C  
+ATOM   3515  N   ILE C 150     -17.339  28.220  18.116  1.00 32.48           N  
+ATOM   3516  CA  ILE C 150     -16.536  27.134  17.580  1.00 30.78           C  
+ATOM   3517  C   ILE C 150     -15.191  27.627  17.021  1.00 31.37           C  
+ATOM   3518  O   ILE C 150     -15.139  28.488  16.140  1.00 29.55           O  
+ATOM   3519  CB  ILE C 150     -17.331  26.353  16.488  1.00 31.53           C  
+ATOM   3520  CG1 ILE C 150     -16.586  25.069  16.090  1.00 30.89           C  
+ATOM   3521  CG2 ILE C 150     -17.553  27.240  15.270  1.00 33.18           C  
+ATOM   3522  CD1 ILE C 150     -17.317  24.224  15.069  0.00 31.06           C  
+ATOM   3523  N   LEU C 151     -14.110  27.080  17.573  1.00 29.01           N  
+ATOM   3524  CA  LEU C 151     -12.753  27.405  17.158  1.00 30.08           C  
+ATOM   3525  C   LEU C 151     -12.187  26.292  16.267  1.00 29.75           C  
+ATOM   3526  O   LEU C 151     -12.144  25.122  16.668  1.00 28.30           O  
+ATOM   3527  CB  LEU C 151     -11.854  27.570  18.382  1.00 32.44           C  
+ATOM   3528  CG  LEU C 151     -11.855  28.902  19.133  1.00 35.48           C  
+ATOM   3529  CD1 LEU C 151     -13.251  29.280  19.577  1.00 35.67           C  
+ATOM   3530  CD2 LEU C 151     -10.920  28.771  20.331  1.00 37.86           C  
+ATOM   3531  N   LEU C 152     -11.763  26.652  15.061  1.00 28.56           N  
+ATOM   3532  CA  LEU C 152     -11.202  25.664  14.140  1.00 28.87           C  
+ATOM   3533  C   LEU C 152      -9.769  25.983  13.757  1.00 28.72           C  
+ATOM   3534  O   LEU C 152      -9.450  27.109  13.346  1.00 26.98           O  
+ATOM   3535  CB  LEU C 152     -12.038  25.557  12.863  1.00 26.53           C  
+ATOM   3536  CG  LEU C 152     -13.508  25.168  13.041  1.00 26.38           C  
+ATOM   3537  CD1 LEU C 152     -14.337  26.430  13.257  1.00 26.53           C  
+ATOM   3538  CD2 LEU C 152     -13.995  24.414  11.803  1.00 23.34           C  
+ATOM   3539  N   ASP C 153      -8.909  24.982  13.906  1.00 27.37           N  
+ATOM   3540  CA  ASP C 153      -7.511  25.127  13.559  1.00 29.26           C  
+ATOM   3541  C   ASP C 153      -7.284  24.662  12.117  1.00 29.60           C  
+ATOM   3542  O   ASP C 153      -7.457  23.473  11.808  1.00 24.97           O  
+ATOM   3543  CB  ASP C 153      -6.646  24.291  14.493  1.00 33.24           C  
+ATOM   3544  CG  ASP C 153      -5.171  24.498  14.243  1.00 38.98           C  
+ATOM   3545  OD1 ASP C 153      -4.370  23.633  14.645  1.00 43.58           O  
+ATOM   3546  OD2 ASP C 153      -4.807  25.540  13.654  1.00 43.86           O  
+ATOM   3547  N   GLU C 154      -6.910  25.603  11.246  1.00 27.13           N  
+ATOM   3548  CA  GLU C 154      -6.642  25.311   9.834  1.00 28.66           C  
+ATOM   3549  C   GLU C 154      -7.652  24.342   9.217  1.00 28.10           C  
+ATOM   3550  O   GLU C 154      -7.268  23.347   8.612  1.00 27.20           O  
+ATOM   3551  CB  GLU C 154      -5.232  24.726   9.688  1.00 31.10           C  
+ATOM   3552  CG  GLU C 154      -4.130  25.613  10.258  1.00 36.92           C  
+ATOM   3553  CD  GLU C 154      -3.916  26.880   9.457  1.00 42.73           C  
+ATOM   3554  OE1 GLU C 154      -3.497  27.896  10.054  1.00 48.73           O  
+ATOM   3555  OE2 GLU C 154      -4.150  26.868   8.229  1.00 46.67           O  
+ATOM   3556  N   PRO C 155      -8.956  24.644   9.327  1.00 29.83           N  
+ATOM   3557  CA  PRO C 155      -9.978  23.749   8.769  1.00 30.25           C  
+ATOM   3558  C   PRO C 155      -9.921  23.400   7.282  1.00 31.23           C  
+ATOM   3559  O   PRO C 155     -10.434  22.355   6.872  1.00 33.16           O  
+ATOM   3560  CB  PRO C 155     -11.294  24.434   9.159  1.00 29.15           C  
+ATOM   3561  CG  PRO C 155     -10.918  25.895   9.213  1.00 27.57           C  
+ATOM   3562  CD  PRO C 155      -9.567  25.870   9.881  1.00 27.79           C  
+ATOM   3563  N   THR C 156      -9.287  24.236   6.473  1.00 29.39           N  
+ATOM   3564  CA  THR C 156      -9.248  23.961   5.040  1.00 29.13           C  
+ATOM   3565  C   THR C 156      -7.898  23.596   4.441  1.00 29.73           C  
+ATOM   3566  O   THR C 156      -7.847  23.019   3.364  1.00 28.59           O  
+ATOM   3567  CB  THR C 156      -9.711  25.172   4.236  1.00 29.83           C  
+ATOM   3568  OG1 THR C 156      -8.796  26.248   4.470  1.00 26.78           O  
+ATOM   3569  CG2 THR C 156     -11.119  25.586   4.623  1.00 30.59           C  
+ATOM   3570  N   SER C 157      -6.821  23.944   5.134  1.00 31.70           N  
+ATOM   3571  CA  SER C 157      -5.459  23.742   4.640  1.00 34.95           C  
+ATOM   3572  C   SER C 157      -5.092  22.446   3.948  1.00 35.25           C  
+ATOM   3573  O   SER C 157      -4.383  22.477   2.942  1.00 38.51           O  
+ATOM   3574  CB  SER C 157      -4.454  24.004   5.768  1.00 35.41           C  
+ATOM   3575  OG  SER C 157      -4.708  25.272   6.350  1.00 40.28           O  
+ATOM   3576  N   ALA C 158      -5.566  21.316   4.460  1.00 32.73           N  
+ATOM   3577  CA  ALA C 158      -5.209  20.028   3.875  1.00 33.60           C  
+ATOM   3578  C   ALA C 158      -6.274  19.370   3.009  1.00 34.47           C  
+ATOM   3579  O   ALA C 158      -6.110  18.216   2.605  1.00 37.31           O  
+ATOM   3580  CB  ALA C 158      -4.787  19.055   4.994  1.00 31.37           C  
+ATOM   3581  N   LEU C 159      -7.350  20.082   2.701  1.00 32.25           N  
+ATOM   3582  CA  LEU C 159      -8.411  19.478   1.906  1.00 33.06           C  
+ATOM   3583  C   LEU C 159      -8.329  19.808   0.422  1.00 35.00           C  
+ATOM   3584  O   LEU C 159      -7.684  20.780   0.027  1.00 37.44           O  
+ATOM   3585  CB  LEU C 159      -9.778  19.910   2.453  1.00 30.71           C  
+ATOM   3586  CG  LEU C 159      -9.950  19.956   3.981  1.00 31.65           C  
+ATOM   3587  CD1 LEU C 159     -11.405  20.215   4.308  1.00 28.17           C  
+ATOM   3588  CD2 LEU C 159      -9.491  18.650   4.621  1.00 27.99           C  
+ATOM   3589  N   ASP C 160      -8.962  18.987  -0.413  1.00 36.73           N  
+ATOM   3590  CA  ASP C 160      -8.973  19.281  -1.837  1.00 36.93           C  
+ATOM   3591  C   ASP C 160      -9.914  20.475  -1.983  1.00 34.91           C  
+ATOM   3592  O   ASP C 160     -10.688  20.767  -1.066  1.00 33.64           O  
+ATOM   3593  CB  ASP C 160      -9.471  18.083  -2.653  1.00 41.98           C  
+ATOM   3594  CG  ASP C 160     -10.829  17.583  -2.207  1.00 47.95           C  
+ATOM   3595  OD1 ASP C 160     -11.695  18.401  -1.829  1.00 52.46           O  
+ATOM   3596  OD2 ASP C 160     -11.041  16.354  -2.257  1.00 54.74           O  
+ATOM   3597  N   LEU C 161      -9.846  21.167  -3.117  1.00 32.50           N  
+ATOM   3598  CA  LEU C 161     -10.673  22.350  -3.343  1.00 31.17           C  
+ATOM   3599  C   LEU C 161     -12.175  22.161  -3.136  1.00 30.02           C  
+ATOM   3600  O   LEU C 161     -12.821  22.994  -2.491  1.00 27.15           O  
+ATOM   3601  CB  LEU C 161     -10.409  22.930  -4.743  1.00 30.05           C  
+ATOM   3602  CG  LEU C 161      -8.998  23.495  -4.955  1.00 33.51           C  
+ATOM   3603  CD1 LEU C 161      -8.910  24.202  -6.310  1.00 32.61           C  
+ATOM   3604  CD2 LEU C 161      -8.664  24.477  -3.829  1.00 33.68           C  
+ATOM   3605  N   ALA C 162     -12.732  21.080  -3.677  1.00 27.99           N  
+ATOM   3606  CA  ALA C 162     -14.164  20.830  -3.528  1.00 30.13           C  
+ATOM   3607  C   ALA C 162     -14.581  20.753  -2.052  1.00 29.27           C  
+ATOM   3608  O   ALA C 162     -15.638  21.258  -1.676  1.00 28.48           O  
+ATOM   3609  CB  ALA C 162     -14.555  19.540  -4.262  1.00 26.88           C  
+ATOM   3610  N   ASN C 163     -13.739  20.137  -1.222  1.00 29.33           N  
+ATOM   3611  CA  ASN C 163     -14.029  20.003   0.212  1.00 31.95           C  
+ATOM   3612  C   ASN C 163     -13.813  21.289   0.987  1.00 29.81           C  
+ATOM   3613  O   ASN C 163     -14.493  21.550   1.972  1.00 31.00           O  
+ATOM   3614  CB  ASN C 163     -13.197  18.878   0.837  1.00 32.17           C  
+ATOM   3615  CG  ASN C 163     -13.658  17.514   0.391  1.00 36.15           C  
+ATOM   3616  OD1 ASN C 163     -14.857  17.241   0.357  1.00 39.06           O  
+ATOM   3617  ND2 ASN C 163     -12.716  16.645   0.050  1.00 38.44           N  
+ATOM   3618  N   GLN C 164     -12.853  22.088   0.549  1.00 29.94           N  
+ATOM   3619  CA  GLN C 164     -12.605  23.365   1.192  1.00 30.46           C  
+ATOM   3620  C   GLN C 164     -13.870  24.188   0.966  1.00 29.27           C  
+ATOM   3621  O   GLN C 164     -14.334  24.902   1.857  1.00 29.16           O  
+ATOM   3622  CB  GLN C 164     -11.403  24.058   0.553  1.00 30.82           C  
+ATOM   3623  CG  GLN C 164     -10.083  23.385   0.848  1.00 35.43           C  
+ATOM   3624  CD  GLN C 164      -8.921  24.061   0.151  1.00 38.13           C  
+ATOM   3625  OE1 GLN C 164      -8.703  25.259   0.308  1.00 36.61           O  
+ATOM   3626  NE2 GLN C 164      -8.169  23.291  -0.628  1.00 39.38           N  
+ATOM   3627  N   ASP C 165     -14.428  24.065  -0.235  1.00 29.81           N  
+ATOM   3628  CA  ASP C 165     -15.645  24.780  -0.587  1.00 30.00           C  
+ATOM   3629  C   ASP C 165     -16.790  24.377   0.344  1.00 28.64           C  
+ATOM   3630  O   ASP C 165     -17.521  25.227   0.836  1.00 28.06           O  
+ATOM   3631  CB  ASP C 165     -16.030  24.484  -2.034  1.00 32.21           C  
+ATOM   3632  CG  ASP C 165     -17.240  25.275  -2.486  1.00 34.99           C  
+ATOM   3633  OD1 ASP C 165     -18.141  24.668  -3.090  1.00 39.77           O  
+ATOM   3634  OD2 ASP C 165     -17.295  26.502  -2.244  1.00 35.93           O  
+ATOM   3635  N   ILE C 166     -16.938  23.078   0.589  1.00 28.59           N  
+ATOM   3636  CA  ILE C 166     -17.996  22.596   1.465  1.00 28.15           C  
+ATOM   3637  C   ILE C 166     -17.812  23.156   2.878  1.00 28.19           C  
+ATOM   3638  O   ILE C 166     -18.778  23.572   3.523  1.00 28.97           O  
+ATOM   3639  CB  ILE C 166     -18.022  21.037   1.509  1.00 31.35           C  
+ATOM   3640  CG1 ILE C 166     -18.525  20.483   0.162  1.00 32.35           C  
+ATOM   3641  CG2 ILE C 166     -18.924  20.538   2.650  1.00 27.38           C  
+ATOM   3642  CD1 ILE C 166     -18.536  18.970   0.081  0.00 31.85           C  
+ATOM   3643  N   VAL C 167     -16.570  23.194   3.345  1.00 27.46           N  
+ATOM   3644  CA  VAL C 167     -16.288  23.687   4.681  1.00 27.12           C  
+ATOM   3645  C   VAL C 167     -16.591  25.174   4.826  1.00 25.58           C  
+ATOM   3646  O   VAL C 167     -17.160  25.596   5.838  1.00 23.90           O  
+ATOM   3647  CB  VAL C 167     -14.808  23.399   5.087  1.00 27.92           C  
+ATOM   3648  CG1 VAL C 167     -14.464  24.115   6.395  1.00 26.11           C  
+ATOM   3649  CG2 VAL C 167     -14.613  21.918   5.267  1.00 24.31           C  
+ATOM   3650  N   LEU C 168     -16.216  25.968   3.825  1.00 24.46           N  
+ATOM   3651  CA  LEU C 168     -16.481  27.408   3.880  1.00 24.85           C  
+ATOM   3652  C   LEU C 168     -17.987  27.666   3.947  1.00 24.07           C  
+ATOM   3653  O   LEU C 168     -18.447  28.481   4.744  1.00 22.94           O  
+ATOM   3654  CB  LEU C 168     -15.888  28.129   2.659  1.00 22.03           C  
+ATOM   3655  CG  LEU C 168     -14.359  28.133   2.569  1.00 23.08           C  
+ATOM   3656  CD1 LEU C 168     -13.929  28.690   1.202  1.00 22.45           C  
+ATOM   3657  CD2 LEU C 168     -13.766  28.941   3.725  1.00 16.85           C  
+ATOM   3658  N   SER C 169     -18.749  26.966   3.116  1.00 25.48           N  
+ATOM   3659  CA  SER C 169     -20.206  27.123   3.109  1.00 28.15           C  
+ATOM   3660  C   SER C 169     -20.795  26.723   4.457  1.00 28.37           C  
+ATOM   3661  O   SER C 169     -21.690  27.397   4.972  1.00 26.18           O  
+ATOM   3662  CB  SER C 169     -20.839  26.267   2.010  1.00 24.17           C  
+ATOM   3663  OG  SER C 169     -20.430  26.733   0.742  1.00 30.75           O  
+ATOM   3664  N   LEU C 170     -20.275  25.634   5.025  1.00 28.26           N  
+ATOM   3665  CA  LEU C 170     -20.748  25.147   6.315  1.00 28.42           C  
+ATOM   3666  C   LEU C 170     -20.546  26.181   7.426  1.00 29.55           C  
+ATOM   3667  O   LEU C 170     -21.461  26.441   8.203  1.00 31.26           O  
+ATOM   3668  CB  LEU C 170     -20.029  23.842   6.680  1.00 28.15           C  
+ATOM   3669  CG  LEU C 170     -20.226  23.298   8.102  1.00 29.94           C  
+ATOM   3670  CD1 LEU C 170     -21.711  23.032   8.357  1.00 27.17           C  
+ATOM   3671  CD2 LEU C 170     -19.402  22.014   8.279  1.00 28.47           C  
+ATOM   3672  N   LEU C 171     -19.356  26.776   7.492  1.00 29.33           N  
+ATOM   3673  CA  LEU C 171     -19.059  27.761   8.530  1.00 31.78           C  
+ATOM   3674  C   LEU C 171     -19.968  28.987   8.451  1.00 32.75           C  
+ATOM   3675  O   LEU C 171     -20.336  29.557   9.481  1.00 30.15           O  
+ATOM   3676  CB  LEU C 171     -17.577  28.193   8.469  1.00 29.67           C  
+ATOM   3677  CG  LEU C 171     -16.528  27.086   8.685  1.00 30.03           C  
+ATOM   3678  CD1 LEU C 171     -15.135  27.690   8.729  1.00 29.74           C  
+ATOM   3679  CD2 LEU C 171     -16.810  26.342   9.985  1.00 28.85           C  
+ATOM   3680  N   ILE C 172     -20.321  29.392   7.233  1.00 33.81           N  
+ATOM   3681  CA  ILE C 172     -21.201  30.534   7.045  1.00 34.93           C  
+ATOM   3682  C   ILE C 172     -22.594  30.164   7.546  1.00 35.83           C  
+ATOM   3683  O   ILE C 172     -23.268  30.965   8.188  1.00 36.20           O  
+ATOM   3684  CB  ILE C 172     -21.267  30.969   5.544  1.00 36.32           C  
+ATOM   3685  CG1 ILE C 172     -20.408  32.231   5.335  1.00 35.17           C  
+ATOM   3686  CG2 ILE C 172     -22.720  31.235   5.133  1.00 34.97           C  
+ATOM   3687  CD1 ILE C 172     -20.391  32.738   3.908  0.00 35.57           C  
+ATOM   3688  N   ASP C 173     -23.010  28.936   7.262  1.00 36.43           N  
+ATOM   3689  CA  ASP C 173     -24.310  28.456   7.692  1.00 37.07           C  
+ATOM   3690  C   ASP C 173     -24.398  28.324   9.219  1.00 37.32           C  
+ATOM   3691  O   ASP C 173     -25.457  28.553   9.808  1.00 39.16           O  
+ATOM   3692  CB  ASP C 173     -24.616  27.111   7.023  1.00 38.96           C  
+ATOM   3693  CG  ASP C 173     -26.055  26.669   7.238  1.00 44.32           C  
+ATOM   3694  OD1 ASP C 173     -26.307  25.850   8.142  1.00 43.97           O  
+ATOM   3695  OD2 ASP C 173     -26.946  27.157   6.507  1.00 49.96           O  
+ATOM   3696  N   LEU C 174     -23.293  27.964   9.864  1.00 34.54           N  
+ATOM   3697  CA  LEU C 174     -23.289  27.819  11.315  1.00 33.51           C  
+ATOM   3698  C   LEU C 174     -23.450  29.171  11.992  1.00 35.15           C  
+ATOM   3699  O   LEU C 174     -24.118  29.287  13.016  1.00 33.62           O  
+ATOM   3700  CB  LEU C 174     -21.985  27.172  11.797  1.00 31.30           C  
+ATOM   3701  CG  LEU C 174     -21.710  25.718  11.414  1.00 31.46           C  
+ATOM   3702  CD1 LEU C 174     -20.360  25.270  11.992  1.00 32.16           C  
+ATOM   3703  CD2 LEU C 174     -22.837  24.837  11.941  1.00 32.38           C  
+ATOM   3704  N   ALA C 175     -22.832  30.195  11.416  1.00 36.86           N  
+ATOM   3705  CA  ALA C 175     -22.899  31.536  11.982  1.00 39.32           C  
+ATOM   3706  C   ALA C 175     -24.187  32.276  11.636  1.00 41.31           C  
+ATOM   3707  O   ALA C 175     -24.754  32.967  12.478  1.00 42.66           O  
+ATOM   3708  CB  ALA C 175     -21.684  32.360  11.525  1.00 36.70           C  
+ATOM   3709  N   GLN C 176     -24.655  32.128  10.403  1.00 45.22           N  
+ATOM   3710  CA  GLN C 176     -25.864  32.824   9.976  1.00 49.68           C  
+ATOM   3711  C   GLN C 176     -27.167  32.117  10.316  1.00 50.73           C  
+ATOM   3712  O   GLN C 176     -28.150  32.765  10.646  1.00 53.06           O  
+ATOM   3713  CB  GLN C 176     -25.812  33.104   8.468  1.00 50.66           C  
+ATOM   3714  CG  GLN C 176     -24.701  34.069   8.052  1.00 54.61           C  
+ATOM   3715  CD  GLN C 176     -24.708  34.385   6.557  1.00 57.21           C  
+ATOM   3716  OE1 GLN C 176     -23.908  35.196   6.076  1.00 56.58           O  
+ATOM   3717  NE2 GLN C 176     -25.613  33.745   5.817  1.00 58.71           N  
+ATOM   3718  N   SER C 177     -27.180  30.793  10.256  1.00 53.27           N  
+ATOM   3719  CA  SER C 177     -28.404  30.051  10.540  1.00 54.35           C  
+ATOM   3720  C   SER C 177     -28.536  29.511  11.955  1.00 54.14           C  
+ATOM   3721  O   SER C 177     -29.636  29.482  12.501  1.00 56.73           O  
+ATOM   3722  CB  SER C 177     -28.551  28.890   9.555  1.00 55.42           C  
+ATOM   3723  OG  SER C 177     -28.502  29.359   8.219  1.00 60.11           O  
+ATOM   3724  N   GLN C 178     -27.429  29.082  12.552  1.00 53.23           N  
+ATOM   3725  CA  GLN C 178     -27.478  28.516  13.896  1.00 51.94           C  
+ATOM   3726  C   GLN C 178     -26.944  29.465  14.953  1.00 52.01           C  
+ATOM   3727  O   GLN C 178     -26.690  29.061  16.081  1.00 53.91           O  
+ATOM   3728  CB  GLN C 178     -26.687  27.210  13.927  1.00 51.65           C  
+ATOM   3729  CG  GLN C 178     -26.925  26.335  12.697  1.00 55.06           C  
+ATOM   3730  CD  GLN C 178     -28.381  25.912  12.530  1.00 57.63           C  
+ATOM   3731  OE1 GLN C 178     -28.789  25.462  11.456  1.00 58.44           O  
+ATOM   3732  NE2 GLN C 178     -29.166  26.042  13.597  1.00 57.31           N  
+ATOM   3733  N   ASN C 179     -26.791  30.729  14.580  1.00 52.74           N  
+ATOM   3734  CA  ASN C 179     -26.270  31.768  15.467  1.00 54.48           C  
+ATOM   3735  C   ASN C 179     -25.064  31.330  16.292  1.00 53.06           C  
+ATOM   3736  O   ASN C 179     -25.030  31.519  17.508  1.00 54.53           O  
+ATOM   3737  CB  ASN C 179     -27.353  32.299  16.418  1.00 58.46           C  
+ATOM   3738  CG  ASN C 179     -27.004  33.687  16.983  1.00 62.84           C  
+ATOM   3739  OD1 ASN C 179     -27.482  34.085  18.051  1.00 64.37           O  
+ATOM   3740  ND2 ASN C 179     -26.178  34.431  16.251  1.00 63.43           N  
+ATOM   3741  N   MET C 180     -24.085  30.725  15.628  1.00 49.47           N  
+ATOM   3742  CA  MET C 180     -22.857  30.314  16.289  1.00 44.15           C  
+ATOM   3743  C   MET C 180     -21.812  31.373  15.970  1.00 41.60           C  
+ATOM   3744  O   MET C 180     -21.984  32.155  15.035  1.00 40.64           O  
+ATOM   3745  CB  MET C 180     -22.375  28.971  15.754  1.00 47.24           C  
+ATOM   3746  CG  MET C 180     -23.112  27.766  16.305  1.00 49.64           C  
+ATOM   3747  SD  MET C 180     -22.173  26.270  15.990  1.00 52.55           S  
+ATOM   3748  CE  MET C 180     -23.240  25.460  14.887  1.00 53.80           C  
+ATOM   3749  N   THR C 181     -20.745  31.422  16.760  1.00 37.54           N  
+ATOM   3750  CA  THR C 181     -19.667  32.361  16.512  1.00 34.14           C  
+ATOM   3751  C   THR C 181     -18.496  31.494  16.058  1.00 34.61           C  
+ATOM   3752  O   THR C 181     -18.189  30.478  16.684  1.00 34.63           O  
+ATOM   3753  CB  THR C 181     -19.308  33.151  17.774  1.00 35.19           C  
+ATOM   3754  OG1 THR C 181     -20.452  33.907  18.190  1.00 37.90           O  
+ATOM   3755  CG2 THR C 181     -18.156  34.118  17.501  1.00 31.38           C  
+ATOM   3756  N   VAL C 182     -17.856  31.887  14.961  1.00 32.57           N  
+ATOM   3757  CA  VAL C 182     -16.765  31.107  14.399  1.00 29.88           C  
+ATOM   3758  C   VAL C 182     -15.408  31.785  14.369  1.00 29.28           C  
+ATOM   3759  O   VAL C 182     -15.298  32.958  14.011  1.00 31.56           O  
+ATOM   3760  CB  VAL C 182     -17.111  30.674  12.952  1.00 30.39           C  
+ATOM   3761  CG1 VAL C 182     -15.939  29.929  12.321  1.00 26.29           C  
+ATOM   3762  CG2 VAL C 182     -18.362  29.806  12.960  1.00 27.83           C  
+ATOM   3763  N   VAL C 183     -14.380  31.029  14.753  1.00 27.86           N  
+ATOM   3764  CA  VAL C 183     -12.993  31.494  14.727  1.00 26.64           C  
+ATOM   3765  C   VAL C 183     -12.172  30.367  14.070  1.00 28.72           C  
+ATOM   3766  O   VAL C 183     -12.136  29.238  14.575  1.00 27.53           O  
+ATOM   3767  CB  VAL C 183     -12.412  31.733  16.138  1.00 27.75           C  
+ATOM   3768  CG1 VAL C 183     -10.990  32.269  16.020  1.00 24.40           C  
+ATOM   3769  CG2 VAL C 183     -13.295  32.702  16.933  1.00 25.76           C  
+ATOM   3770  N   PHE C 184     -11.538  30.669  12.937  1.00 26.43           N  
+ATOM   3771  CA  PHE C 184     -10.719  29.686  12.243  1.00 26.70           C  
+ATOM   3772  C   PHE C 184      -9.406  30.320  11.806  1.00 25.53           C  
+ATOM   3773  O   PHE C 184      -9.344  31.521  11.563  1.00 25.90           O  
+ATOM   3774  CB  PHE C 184     -11.468  29.084  11.034  1.00 25.54           C  
+ATOM   3775  CG  PHE C 184     -11.616  30.019   9.859  1.00 29.09           C  
+ATOM   3776  CD1 PHE C 184     -12.475  31.121   9.920  1.00 28.67           C  
+ATOM   3777  CD2 PHE C 184     -10.908  29.786   8.675  1.00 27.23           C  
+ATOM   3778  CE1 PHE C 184     -12.627  31.977   8.812  1.00 28.48           C  
+ATOM   3779  CE2 PHE C 184     -11.053  30.634   7.562  1.00 25.81           C  
+ATOM   3780  CZ  PHE C 184     -11.910  31.727   7.631  1.00 27.24           C  
+ATOM   3781  N   THR C 185      -8.355  29.506  11.738  1.00 26.66           N  
+ATOM   3782  CA  THR C 185      -7.031  29.972  11.332  1.00 26.48           C  
+ATOM   3783  C   THR C 185      -6.859  29.604   9.865  1.00 27.68           C  
+ATOM   3784  O   THR C 185      -7.415  28.608   9.404  1.00 26.46           O  
+ATOM   3785  CB  THR C 185      -5.891  29.323  12.198  1.00 27.44           C  
+ATOM   3786  OG1 THR C 185      -5.895  27.898  12.050  1.00 30.38           O  
+ATOM   3787  CG2 THR C 185      -6.097  29.646  13.668  1.00 25.94           C  
+ATOM   3788  N   THR C 186      -6.103  30.419   9.133  1.00 29.10           N  
+ATOM   3789  CA  THR C 186      -5.885  30.204   7.709  1.00 27.61           C  
+ATOM   3790  C   THR C 186      -4.701  31.038   7.210  1.00 28.40           C  
+ATOM   3791  O   THR C 186      -4.247  31.961   7.891  1.00 27.41           O  
+ATOM   3792  CB  THR C 186      -7.156  30.623   6.907  1.00 31.65           C  
+ATOM   3793  OG1 THR C 186      -6.966  30.379   5.507  1.00 36.64           O  
+ATOM   3794  CG2 THR C 186      -7.435  32.103   7.101  1.00 30.64           C  
+ATOM   3795  N   HIS C 187      -4.201  30.702   6.022  1.00 28.08           N  
+ATOM   3796  CA  HIS C 187      -3.108  31.451   5.414  1.00 30.75           C  
+ATOM   3797  C   HIS C 187      -3.586  31.907   4.037  1.00 30.23           C  
+ATOM   3798  O   HIS C 187      -2.812  32.454   3.256  1.00 30.13           O  
+ATOM   3799  CB  HIS C 187      -1.844  30.590   5.254  1.00 30.97           C  
+ATOM   3800  CG  HIS C 187      -2.064  29.324   4.485  1.00 36.15           C  
+ATOM   3801  ND1 HIS C 187      -2.334  28.119   5.097  1.00 39.25           N  
+ATOM   3802  CD2 HIS C 187      -2.096  29.083   3.152  1.00 36.15           C  
+ATOM   3803  CE1 HIS C 187      -2.526  27.191   4.175  1.00 37.70           C  
+ATOM   3804  NE2 HIS C 187      -2.388  27.750   2.987  1.00 38.95           N  
+ATOM   3805  N   GLN C 188      -4.874  31.702   3.771  1.00 27.97           N  
+ATOM   3806  CA  GLN C 188      -5.471  32.035   2.483  1.00 32.14           C  
+ATOM   3807  C   GLN C 188      -6.434  33.233   2.478  1.00 30.83           C  
+ATOM   3808  O   GLN C 188      -7.609  33.106   2.825  1.00 31.92           O  
+ATOM   3809  CB  GLN C 188      -6.181  30.788   1.935  1.00 33.48           C  
+ATOM   3810  CG  GLN C 188      -5.224  29.670   1.504  1.00 40.25           C  
+ATOM   3811  CD  GLN C 188      -5.917  28.323   1.323  1.00 45.61           C  
+ATOM   3812  OE1 GLN C 188      -6.042  27.540   2.270  1.00 49.20           O  
+ATOM   3813  NE2 GLN C 188      -6.381  28.052   0.102  1.00 49.36           N  
+ATOM   3814  N   PRO C 189      -5.951  34.407   2.049  1.00 28.92           N  
+ATOM   3815  CA  PRO C 189      -6.795  35.605   2.011  1.00 29.35           C  
+ATOM   3816  C   PRO C 189      -8.119  35.509   1.244  1.00 28.40           C  
+ATOM   3817  O   PRO C 189      -9.101  36.139   1.636  1.00 29.97           O  
+ATOM   3818  CB  PRO C 189      -5.853  36.685   1.455  1.00 30.34           C  
+ATOM   3819  CG  PRO C 189      -4.818  35.913   0.696  1.00 31.93           C  
+ATOM   3820  CD  PRO C 189      -4.589  34.704   1.573  1.00 30.88           C  
+ATOM   3821  N   ASN C 190      -8.166  34.739   0.162  1.00 25.71           N  
+ATOM   3822  CA  ASN C 190      -9.420  34.616  -0.588  1.00 27.15           C  
+ATOM   3823  C   ASN C 190     -10.508  33.954   0.268  1.00 27.93           C  
+ATOM   3824  O   ASN C 190     -11.689  34.274   0.139  1.00 28.63           O  
+ATOM   3825  CB  ASN C 190      -9.225  33.796  -1.876  1.00 26.69           C  
+ATOM   3826  CG  ASN C 190      -8.400  34.528  -2.935  1.00 25.55           C  
+ATOM   3827  OD1 ASN C 190      -8.140  33.985  -4.012  1.00 27.43           O  
+ATOM   3828  ND2 ASN C 190      -7.983  35.749  -2.635  1.00 21.51           N  
+ATOM   3829  N   GLN C 191     -10.108  33.026   1.138  1.00 26.09           N  
+ATOM   3830  CA  GLN C 191     -11.067  32.346   2.000  1.00 28.77           C  
+ATOM   3831  C   GLN C 191     -11.544  33.291   3.094  1.00 28.07           C  
+ATOM   3832  O   GLN C 191     -12.661  33.164   3.592  1.00 28.38           O  
+ATOM   3833  CB  GLN C 191     -10.447  31.073   2.603  1.00 27.56           C  
+ATOM   3834  CG  GLN C 191     -10.113  30.049   1.525  1.00 29.17           C  
+ATOM   3835  CD  GLN C 191      -9.634  28.718   2.067  1.00 33.19           C  
+ATOM   3836  OE1 GLN C 191      -9.403  28.561   3.268  1.00 33.01           O  
+ATOM   3837  NE2 GLN C 191      -9.473  27.750   1.173  1.00 31.15           N  
+ATOM   3838  N   VAL C 192     -10.698  34.254   3.440  1.00 27.05           N  
+ATOM   3839  CA  VAL C 192     -11.031  35.239   4.460  1.00 26.67           C  
+ATOM   3840  C   VAL C 192     -12.109  36.191   3.932  1.00 29.64           C  
+ATOM   3841  O   VAL C 192     -13.117  36.420   4.592  1.00 28.77           O  
+ATOM   3842  CB  VAL C 192      -9.780  36.044   4.868  1.00 26.68           C  
+ATOM   3843  CG1 VAL C 192     -10.155  37.145   5.822  1.00 22.44           C  
+ATOM   3844  CG2 VAL C 192      -8.741  35.098   5.510  1.00 23.24           C  
+ATOM   3845  N   VAL C 193     -11.911  36.725   2.730  1.00 30.44           N  
+ATOM   3846  CA  VAL C 193     -12.894  37.636   2.165  1.00 30.39           C  
+ATOM   3847  C   VAL C 193     -14.181  36.873   1.849  1.00 30.35           C  
+ATOM   3848  O   VAL C 193     -15.269  37.439   1.853  1.00 31.84           O  
+ATOM   3849  CB  VAL C 193     -12.355  38.329   0.875  1.00 32.92           C  
+ATOM   3850  CG1 VAL C 193     -12.518  37.409  -0.345  1.00 29.27           C  
+ATOM   3851  CG2 VAL C 193     -13.079  39.656   0.660  1.00 32.14           C  
+ATOM   3852  N   ALA C 194     -14.059  35.577   1.591  1.00 31.17           N  
+ATOM   3853  CA  ALA C 194     -15.232  34.761   1.278  1.00 28.70           C  
+ATOM   3854  C   ALA C 194     -16.217  34.584   2.435  1.00 29.97           C  
+ATOM   3855  O   ALA C 194     -17.428  34.602   2.218  1.00 31.73           O  
+ATOM   3856  CB  ALA C 194     -14.795  33.394   0.786  1.00 27.81           C  
+ATOM   3857  N   ILE C 195     -15.723  34.426   3.664  1.00 28.30           N  
+ATOM   3858  CA  ILE C 195     -16.645  34.183   4.770  1.00 27.63           C  
+ATOM   3859  C   ILE C 195     -16.437  34.913   6.096  1.00 27.47           C  
+ATOM   3860  O   ILE C 195     -17.278  34.822   6.982  1.00 28.24           O  
+ATOM   3861  CB  ILE C 195     -16.690  32.665   5.099  1.00 28.00           C  
+ATOM   3862  CG1 ILE C 195     -15.394  32.236   5.812  1.00 25.76           C  
+ATOM   3863  CG2 ILE C 195     -16.867  31.855   3.813  1.00 23.91           C  
+ATOM   3864  CD1 ILE C 195     -15.376  30.782   6.237  0.00 26.57           C  
+ATOM   3865  N   ALA C 196     -15.333  35.627   6.249  1.00 25.27           N  
+ATOM   3866  CA  ALA C 196     -15.066  36.294   7.515  1.00 26.77           C  
+ATOM   3867  C   ALA C 196     -15.357  37.792   7.535  1.00 27.67           C  
+ATOM   3868  O   ALA C 196     -14.739  38.554   6.796  1.00 27.22           O  
+ATOM   3869  CB  ALA C 196     -13.608  36.048   7.927  1.00 21.13           C  
+ATOM   3870  N   ASN C 197     -16.275  38.213   8.400  1.00 26.34           N  
+ATOM   3871  CA  ASN C 197     -16.595  39.632   8.515  1.00 28.52           C  
+ATOM   3872  C   ASN C 197     -15.541  40.336   9.373  1.00 28.61           C  
+ATOM   3873  O   ASN C 197     -15.409  41.551   9.315  1.00 32.04           O  
+ATOM   3874  CB  ASN C 197     -18.014  39.840   9.093  1.00 27.96           C  
+ATOM   3875  CG  ASN C 197     -18.186  39.257  10.490  1.00 31.54           C  
+ATOM   3876  OD1 ASN C 197     -17.883  38.084  10.737  1.00 33.67           O  
+ATOM   3877  ND2 ASN C 197     -18.691  40.075  11.412  1.00 32.12           N  
+ATOM   3878  N   LYS C 198     -14.783  39.566  10.153  1.00 30.84           N  
+ATOM   3879  CA  LYS C 198     -13.708  40.107  11.000  1.00 29.65           C  
+ATOM   3880  C   LYS C 198     -12.430  39.311  10.733  1.00 29.79           C  
+ATOM   3881  O   LYS C 198     -12.495  38.105  10.486  1.00 29.71           O  
+ATOM   3882  CB  LYS C 198     -14.044  39.966  12.493  1.00 29.30           C  
+ATOM   3883  CG  LYS C 198     -15.327  40.645  12.965  1.00 34.09           C  
+ATOM   3884  CD  LYS C 198     -15.233  42.154  12.914  1.00 36.25           C  
+ATOM   3885  CE  LYS C 198     -16.555  42.804  13.332  1.00 38.42           C  
+ATOM   3886  NZ  LYS C 198     -16.972  42.450  14.719  1.00 38.38           N  
+ATOM   3887  N   THR C 199     -11.273  39.971  10.763  1.00 29.50           N  
+ATOM   3888  CA  THR C 199     -10.015  39.253  10.571  1.00 30.47           C  
+ATOM   3889  C   THR C 199      -8.887  39.799  11.444  1.00 31.44           C  
+ATOM   3890  O   THR C 199      -8.827  40.991  11.751  1.00 31.59           O  
+ATOM   3891  CB  THR C 199      -9.537  39.200   9.058  1.00 32.68           C  
+ATOM   3892  OG1 THR C 199      -8.303  39.908   8.896  1.00 36.32           O  
+ATOM   3893  CG2 THR C 199     -10.551  39.779   8.136  1.00 30.19           C  
+ATOM   3894  N   LEU C 200      -8.000  38.896  11.850  1.00 31.15           N  
+ATOM   3895  CA  LEU C 200      -6.861  39.230  12.689  1.00 31.52           C  
+ATOM   3896  C   LEU C 200      -5.625  38.798  11.917  1.00 32.65           C  
+ATOM   3897  O   LEU C 200      -5.493  37.620  11.575  1.00 32.84           O  
+ATOM   3898  CB  LEU C 200      -6.937  38.441  14.005  1.00 33.43           C  
+ATOM   3899  CG  LEU C 200      -6.013  38.762  15.187  1.00 34.52           C  
+ATOM   3900  CD1 LEU C 200      -6.115  37.644  16.201  1.00 35.27           C  
+ATOM   3901  CD2 LEU C 200      -4.587  38.909  14.737  1.00 37.71           C  
+ATOM   3902  N   LEU C 201      -4.730  39.740  11.638  1.00 33.16           N  
+ATOM   3903  CA  LEU C 201      -3.500  39.438  10.915  1.00 36.52           C  
+ATOM   3904  C   LEU C 201      -2.350  39.290  11.899  1.00 40.15           C  
+ATOM   3905  O   LEU C 201      -2.098  40.196  12.699  1.00 39.49           O  
+ATOM   3906  CB  LEU C 201      -3.153  40.558   9.927  1.00 38.42           C  
+ATOM   3907  CG  LEU C 201      -4.085  40.882   8.761  1.00 38.26           C  
+ATOM   3908  CD1 LEU C 201      -3.404  41.910   7.864  1.00 37.61           C  
+ATOM   3909  CD2 LEU C 201      -4.395  39.626   7.970  1.00 38.33           C  
+ATOM   3910  N   LEU C 202      -1.656  38.155  11.842  1.00 42.64           N  
+ATOM   3911  CA  LEU C 202      -0.523  37.903  12.729  1.00 47.03           C  
+ATOM   3912  C   LEU C 202       0.797  37.957  11.965  1.00 50.17           C  
+ATOM   3913  O   LEU C 202       1.087  37.079  11.156  1.00 50.18           O  
+ATOM   3914  CB  LEU C 202      -0.651  36.534  13.393  1.00 48.30           C  
+ATOM   3915  CG  LEU C 202      -1.771  36.274  14.400  1.00 49.67           C  
+ATOM   3916  CD1 LEU C 202      -1.563  34.879  14.992  1.00 48.98           C  
+ATOM   3917  CD2 LEU C 202      -1.758  37.326  15.506  1.00 49.14           C  
+ATOM   3918  N   ASN C 203       1.598  38.981  12.239  1.00 54.30           N  
+ATOM   3919  CA  ASN C 203       2.885  39.157  11.575  1.00 59.01           C  
+ATOM   3920  C   ASN C 203       3.987  39.577  12.545  1.00 62.17           C  
+ATOM   3921  O   ASN C 203       3.975  40.702  13.041  1.00 62.35           O  
+ATOM   3922  CB  ASN C 203       2.760  40.227  10.493  1.00 60.54           C  
+ATOM   3923  CG  ASN C 203       4.076  40.499   9.786  1.00 60.82           C  
+ATOM   3924  OD1 ASN C 203       4.382  41.641   9.444  1.00 59.93           O  
+ATOM   3925  ND2 ASN C 203       4.855  39.445   9.549  1.00 60.48           N  
+ATOM   3926  N   LYS C 204       4.934  38.675  12.804  1.00 66.50           N  
+ATOM   3927  CA  LYS C 204       6.069  38.944  13.699  1.00 70.06           C  
+ATOM   3928  C   LYS C 204       5.744  39.899  14.855  1.00 71.56           C  
+ATOM   3929  O   LYS C 204       5.911  41.117  14.730  1.00 71.70           O  
+ATOM   3930  CB  LYS C 204       7.239  39.530  12.896  1.00 72.18           C  
+ATOM   3931  CG  LYS C 204       7.859  38.589  11.867  1.00 75.06           C  
+ATOM   3932  CD  LYS C 204       8.938  37.703  12.484  1.00 78.17           C  
+ATOM   3933  CE  LYS C 204      10.158  38.517  12.923  1.00 78.52           C  
+ATOM   3934  NZ  LYS C 204      11.217  37.673  13.559  1.00 78.69           N  
+ATOM   3935  N   GLN C 205       5.293  39.346  15.978  1.00 72.01           N  
+ATOM   3936  CA  GLN C 205       4.953  40.149  17.154  1.00 72.62           C  
+ATOM   3937  C   GLN C 205       3.964  41.287  16.887  1.00 71.81           C  
+ATOM   3938  O   GLN C 205       3.503  41.941  17.825  1.00 73.46           O  
+ATOM   3939  CB  GLN C 205       6.222  40.723  17.795  1.00 72.97           C  
+ATOM   3940  CG  GLN C 205       7.121  39.674  18.421  1.00 74.43           C  
+ATOM   3941  CD  GLN C 205       8.294  40.270  19.180  1.00 75.25           C  
+ATOM   3942  OE1 GLN C 205       9.108  39.545  19.755  1.00 75.62           O  
+ATOM   3943  NE2 GLN C 205       8.383  41.595  19.189  1.00 76.03           N  
+ATOM   3944  N   ASN C 206       3.644  41.529  15.618  1.00 70.27           N  
+ATOM   3945  CA  ASN C 206       2.701  42.584  15.257  1.00 68.84           C  
+ATOM   3946  C   ASN C 206       1.394  41.980  14.769  1.00 65.79           C  
+ATOM   3947  O   ASN C 206       1.342  40.808  14.398  1.00 64.49           O  
+ATOM   3948  CB  ASN C 206       3.281  43.493  14.169  1.00 71.54           C  
+ATOM   3949  CG  ASN C 206       4.477  44.286  14.652  1.00 74.34           C  
+ATOM   3950  OD1 ASN C 206       5.559  43.736  14.860  1.00 75.86           O  
+ATOM   3951  ND2 ASN C 206       4.285  45.587  14.843  1.00 75.29           N  
+ATOM   3952  N   PHE C 207       0.342  42.792  14.763  1.00 62.89           N  
+ATOM   3953  CA  PHE C 207      -0.967  42.324  14.340  1.00 59.12           C  
+ATOM   3954  C   PHE C 207      -1.903  43.462  13.961  1.00 56.45           C  
+ATOM   3955  O   PHE C 207      -1.579  44.635  14.125  1.00 56.83           O  
+ATOM   3956  CB  PHE C 207      -1.599  41.498  15.460  1.00 59.02           C  
+ATOM   3957  CG  PHE C 207      -1.727  42.239  16.756  1.00 59.88           C  
+ATOM   3958  CD1 PHE C 207      -2.629  43.292  16.887  1.00 60.96           C  
+ATOM   3959  CD2 PHE C 207      -0.933  41.898  17.847  1.00 61.34           C  
+ATOM   3960  CE1 PHE C 207      -2.740  43.996  18.084  1.00 59.84           C  
+ATOM   3961  CE2 PHE C 207      -1.035  42.595  19.050  1.00 60.70           C  
+ATOM   3962  CZ  PHE C 207      -1.941  43.646  19.166  1.00 60.57           C  
+ATOM   3963  N   LYS C 208      -3.068  43.088  13.447  1.00 52.23           N  
+ATOM   3964  CA  LYS C 208      -4.098  44.034  13.046  1.00 48.88           C  
+ATOM   3965  C   LYS C 208      -5.445  43.331  13.130  1.00 45.29           C  
+ATOM   3966  O   LYS C 208      -5.605  42.207  12.653  1.00 44.00           O  
+ATOM   3967  CB  LYS C 208      -3.871  44.528  11.614  1.00 49.83           C  
+ATOM   3968  CG  LYS C 208      -2.734  45.509  11.457  1.00 51.23           C  
+ATOM   3969  CD  LYS C 208      -2.710  46.080  10.049  1.00 54.18           C  
+ATOM   3970  CE  LYS C 208      -1.613  47.125   9.889  1.00 55.93           C  
+ATOM   3971  NZ  LYS C 208      -1.829  48.297  10.784  1.00 57.29           N  
+ATOM   3972  N   PHE C 209      -6.408  43.998  13.747  1.00 40.89           N  
+ATOM   3973  CA  PHE C 209      -7.738  43.445  13.905  1.00 38.58           C  
+ATOM   3974  C   PHE C 209      -8.781  44.476  13.505  1.00 38.90           C  
+ATOM   3975  O   PHE C 209      -8.587  45.671  13.710  1.00 40.23           O  
+ATOM   3976  CB  PHE C 209      -7.976  43.052  15.359  1.00 35.07           C  
+ATOM   3977  CG  PHE C 209      -9.391  42.651  15.642  1.00 33.35           C  
+ATOM   3978  CD1 PHE C 209      -9.846  41.379  15.318  1.00 32.15           C  
+ATOM   3979  CD2 PHE C 209     -10.282  43.561  16.190  1.00 31.92           C  
+ATOM   3980  CE1 PHE C 209     -11.177  41.015  15.538  1.00 33.15           C  
+ATOM   3981  CE2 PHE C 209     -11.607  43.213  16.412  1.00 33.04           C  
+ATOM   3982  CZ  PHE C 209     -12.060  41.934  16.085  1.00 34.08           C  
+ATOM   3983  N   GLY C 210      -9.891  44.002  12.950  1.00 38.56           N  
+ATOM   3984  CA  GLY C 210     -10.957  44.892  12.544  1.00 37.51           C  
+ATOM   3985  C   GLY C 210     -11.844  44.269  11.487  1.00 37.85           C  
+ATOM   3986  O   GLY C 210     -11.824  43.052  11.282  1.00 38.34           O  
+ATOM   3987  N   GLU C 211     -12.635  45.109  10.828  1.00 36.22           N  
+ATOM   3988  CA  GLU C 211     -13.522  44.659   9.765  1.00 36.25           C  
+ATOM   3989  C   GLU C 211     -12.636  44.134   8.653  1.00 33.40           C  
+ATOM   3990  O   GLU C 211     -11.617  44.739   8.322  1.00 33.32           O  
+ATOM   3991  CB  GLU C 211     -14.366  45.823   9.238  1.00 40.35           C  
+ATOM   3992  CG  GLU C 211     -15.171  46.524  10.309  1.00 45.99           C  
+ATOM   3993  CD  GLU C 211     -16.000  45.547  11.100  1.00 50.10           C  
+ATOM   3994  OE1 GLU C 211     -16.751  44.770  10.472  1.00 55.17           O  
+ATOM   3995  OE2 GLU C 211     -15.898  45.545  12.345  1.00 55.16           O  
+ATOM   3996  N   THR C 212     -13.027  43.003   8.085  1.00 30.38           N  
+ATOM   3997  CA  THR C 212     -12.267  42.385   7.014  1.00 27.78           C  
+ATOM   3998  C   THR C 212     -11.906  43.336   5.871  1.00 28.29           C  
+ATOM   3999  O   THR C 212     -10.746  43.393   5.472  1.00 31.21           O  
+ATOM   4000  CB  THR C 212     -13.027  41.168   6.466  1.00 26.33           C  
+ATOM   4001  OG1 THR C 212     -13.135  40.184   7.508  1.00 24.89           O  
+ATOM   4002  CG2 THR C 212     -12.301  40.564   5.264  1.00 24.62           C  
+ATOM   4003  N   ARG C 213     -12.878  44.079   5.347  1.00 27.97           N  
+ATOM   4004  CA  ARG C 213     -12.609  45.013   4.247  1.00 29.23           C  
+ATOM   4005  C   ARG C 213     -11.617  46.115   4.627  1.00 30.34           C  
+ATOM   4006  O   ARG C 213     -10.990  46.712   3.756  1.00 29.84           O  
+ATOM   4007  CB  ARG C 213     -13.907  45.659   3.748  1.00 29.91           C  
+ATOM   4008  CG  ARG C 213     -14.907  44.697   3.103  1.00 27.37           C  
+ATOM   4009  CD  ARG C 213     -14.463  44.252   1.718  1.00 28.93           C  
+ATOM   4010  NE  ARG C 213     -15.410  43.298   1.140  1.00 29.04           N  
+ATOM   4011  CZ  ARG C 213     -15.251  42.681  -0.028  1.00 27.79           C  
+ATOM   4012  NH1 ARG C 213     -16.174  41.827  -0.460  1.00 30.00           N  
+ATOM   4013  NH2 ARG C 213     -14.179  42.912  -0.764  1.00 26.86           N  
+ATOM   4014  N   ASN C 214     -11.486  46.395   5.921  1.00 32.14           N  
+ATOM   4015  CA  ASN C 214     -10.553  47.420   6.386  1.00 33.71           C  
+ATOM   4016  C   ASN C 214      -9.138  46.834   6.531  1.00 34.33           C  
+ATOM   4017  O   ASN C 214      -8.139  47.529   6.336  1.00 35.12           O  
+ATOM   4018  CB  ASN C 214     -10.991  47.969   7.754  1.00 35.29           C  
+ATOM   4019  CG  ASN C 214     -12.322  48.704   7.707  1.00 40.05           C  
+ATOM   4020  OD1 ASN C 214     -12.988  48.847   8.737  1.00 40.90           O  
+ATOM   4021  ND2 ASN C 214     -12.709  49.188   6.523  1.00 38.67           N  
+ATOM   4022  N   ILE C 215      -9.065  45.552   6.872  1.00 32.58           N  
+ATOM   4023  CA  ILE C 215      -7.788  44.885   7.095  1.00 32.94           C  
+ATOM   4024  C   ILE C 215      -7.165  44.195   5.896  1.00 31.25           C  
+ATOM   4025  O   ILE C 215      -5.945  44.246   5.715  1.00 32.66           O  
+ATOM   4026  CB  ILE C 215      -7.916  43.840   8.229  1.00 33.85           C  
+ATOM   4027  CG1 ILE C 215      -8.383  44.522   9.507  1.00 31.95           C  
+ATOM   4028  CG2 ILE C 215      -6.577  43.158   8.473  1.00 31.91           C  
+ATOM   4029  CD1 ILE C 215      -8.526  43.565  10.638  0.00 32.61           C  
+ATOM   4030  N   LEU C 216      -7.990  43.525   5.101  1.00 30.27           N  
+ATOM   4031  CA  LEU C 216      -7.502  42.824   3.919  1.00 30.50           C  
+ATOM   4032  C   LEU C 216      -7.222  43.775   2.791  1.00 29.80           C  
+ATOM   4033  O   LEU C 216      -8.033  43.905   1.887  1.00 32.76           O  
+ATOM   4034  CB  LEU C 216      -8.519  41.817   3.403  1.00 31.21           C  
+ATOM   4035  CG  LEU C 216      -8.634  40.464   4.076  1.00 32.03           C  
+ATOM   4036  CD1 LEU C 216      -9.459  39.551   3.166  1.00 27.35           C  
+ATOM   4037  CD2 LEU C 216      -7.249  39.893   4.318  1.00 29.23           C  
+ATOM   4038  N   THR C 217      -6.075  44.426   2.827  1.00 30.11           N  
+ATOM   4039  CA  THR C 217      -5.723  45.368   1.778  1.00 30.68           C  
+ATOM   4040  C   THR C 217      -4.371  44.974   1.205  1.00 31.01           C  
+ATOM   4041  O   THR C 217      -3.615  44.245   1.841  1.00 30.23           O  
+ATOM   4042  CB  THR C 217      -5.637  46.794   2.349  1.00 31.72           C  
+ATOM   4043  OG1 THR C 217      -4.568  46.854   3.306  1.00 33.25           O  
+ATOM   4044  CG2 THR C 217      -6.950  47.161   3.053  1.00 30.78           C  
+ATOM   4045  N   SER C 218      -4.076  45.455   0.003  1.00 32.85           N  
+ATOM   4046  CA  SER C 218      -2.811  45.167  -0.653  1.00 35.39           C  
+ATOM   4047  C   SER C 218      -1.660  45.523   0.269  1.00 34.82           C  
+ATOM   4048  O   SER C 218      -0.722  44.745   0.429  1.00 36.14           O  
+ATOM   4049  CB  SER C 218      -2.696  45.967  -1.958  1.00 36.41           C  
+ATOM   4050  OG  SER C 218      -3.698  45.563  -2.877  1.00 40.17           O  
+ATOM   4051  N   GLU C 219      -1.743  46.698   0.883  1.00 35.31           N  
+ATOM   4052  CA  GLU C 219      -0.695  47.163   1.786  1.00 37.14           C  
+ATOM   4053  C   GLU C 219      -0.495  46.259   3.006  1.00 33.78           C  
+ATOM   4054  O   GLU C 219       0.628  45.929   3.361  1.00 31.68           O  
+ATOM   4055  CB  GLU C 219      -0.995  48.599   2.242  1.00 40.73           C  
+ATOM   4056  CG  GLU C 219      -0.054  49.122   3.314  1.00 49.60           C  
+ATOM   4057  CD  GLU C 219      -0.232  50.609   3.586  1.00 56.19           C  
+ATOM   4058  OE1 GLU C 219       0.384  51.120   4.552  1.00 58.02           O  
+ATOM   4059  OE2 GLU C 219      -0.982  51.266   2.830  1.00 59.20           O  
+ATOM   4060  N   ASN C 220      -1.582  45.860   3.652  1.00 33.07           N  
+ATOM   4061  CA  ASN C 220      -1.459  45.005   4.821  1.00 32.09           C  
+ATOM   4062  C   ASN C 220      -0.976  43.603   4.447  1.00 30.87           C  
+ATOM   4063  O   ASN C 220      -0.131  43.033   5.123  1.00 28.81           O  
+ATOM   4064  CB  ASN C 220      -2.799  44.937   5.562  1.00 33.31           C  
+ATOM   4065  CG  ASN C 220      -3.058  46.177   6.427  1.00 35.08           C  
+ATOM   4066  OD1 ASN C 220      -4.172  46.387   6.913  1.00 37.27           O  
+ATOM   4067  ND2 ASN C 220      -2.028  46.987   6.630  1.00 31.69           N  
+ATOM   4068  N   LEU C 221      -1.486  43.059   3.350  1.00 29.47           N  
+ATOM   4069  CA  LEU C 221      -1.079  41.720   2.946  1.00 30.90           C  
+ATOM   4070  C   LEU C 221       0.367  41.685   2.464  1.00 30.76           C  
+ATOM   4071  O   LEU C 221       1.102  40.739   2.758  1.00 28.42           O  
+ATOM   4072  CB  LEU C 221      -2.029  41.176   1.878  1.00 27.86           C  
+ATOM   4073  CG  LEU C 221      -3.431  40.902   2.441  1.00 29.86           C  
+ATOM   4074  CD1 LEU C 221      -4.375  40.453   1.331  1.00 26.22           C  
+ATOM   4075  CD2 LEU C 221      -3.337  39.839   3.534  1.00 27.00           C  
+ATOM   4076  N   THR C 222       0.783  42.725   1.749  1.00 30.24           N  
+ATOM   4077  CA  THR C 222       2.150  42.796   1.256  1.00 28.80           C  
+ATOM   4078  C   THR C 222       3.129  42.831   2.435  1.00 30.63           C  
+ATOM   4079  O   THR C 222       4.186  42.208   2.381  1.00 31.03           O  
+ATOM   4080  CB  THR C 222       2.353  44.044   0.364  1.00 30.77           C  
+ATOM   4081  OG1 THR C 222       1.527  43.932  -0.804  1.00 27.94           O  
+ATOM   4082  CG2 THR C 222       3.817  44.176  -0.061  1.00 26.14           C  
+ATOM   4083  N   ALA C 223       2.773  43.548   3.499  1.00 28.64           N  
+ATOM   4084  CA  ALA C 223       3.631  43.621   4.682  1.00 31.39           C  
+ATOM   4085  C   ALA C 223       3.628  42.281   5.427  1.00 31.91           C  
+ATOM   4086  O   ALA C 223       4.649  41.851   5.955  1.00 34.22           O  
+ATOM   4087  CB  ALA C 223       3.159  44.745   5.624  1.00 28.82           C  
+ATOM   4088  N   LEU C 224       2.476  41.630   5.470  1.00 32.12           N  
+ATOM   4089  CA  LEU C 224       2.356  40.341   6.137  1.00 35.33           C  
+ATOM   4090  C   LEU C 224       3.114  39.218   5.411  1.00 35.27           C  
+ATOM   4091  O   LEU C 224       3.815  38.425   6.043  1.00 35.91           O  
+ATOM   4092  CB  LEU C 224       0.880  39.950   6.253  1.00 37.68           C  
+ATOM   4093  CG  LEU C 224       0.604  38.528   6.760  1.00 40.09           C  
+ATOM   4094  CD1 LEU C 224       1.236  38.357   8.128  1.00 41.73           C  
+ATOM   4095  CD2 LEU C 224      -0.897  38.286   6.849  1.00 39.60           C  
+ATOM   4096  N   PHE C 225       2.980  39.163   4.088  1.00 32.81           N  
+ATOM   4097  CA  PHE C 225       3.620  38.112   3.296  1.00 32.84           C  
+ATOM   4098  C   PHE C 225       5.024  38.404   2.771  1.00 33.17           C  
+ATOM   4099  O   PHE C 225       5.661  37.528   2.186  1.00 32.46           O  
+ATOM   4100  CB  PHE C 225       2.703  37.719   2.128  1.00 30.15           C  
+ATOM   4101  CG  PHE C 225       1.440  37.017   2.566  1.00 32.23           C  
+ATOM   4102  CD1 PHE C 225       0.188  37.573   2.314  1.00 29.11           C  
+ATOM   4103  CD2 PHE C 225       1.507  35.815   3.263  1.00 31.69           C  
+ATOM   4104  CE1 PHE C 225      -0.969  36.947   2.751  1.00 30.72           C  
+ATOM   4105  CE2 PHE C 225       0.351  35.180   3.703  1.00 32.63           C  
+ATOM   4106  CZ  PHE C 225      -0.891  35.747   3.447  1.00 31.61           C  
+ATOM   4107  N   HIS C 226       5.508  39.624   2.983  1.00 33.74           N  
+ATOM   4108  CA  HIS C 226       6.846  40.004   2.525  1.00 36.86           C  
+ATOM   4109  C   HIS C 226       7.022  39.693   1.039  1.00 35.38           C  
+ATOM   4110  O   HIS C 226       8.102  39.347   0.574  1.00 36.84           O  
+ATOM   4111  CB  HIS C 226       7.899  39.280   3.367  1.00 37.65           C  
+ATOM   4112  CG  HIS C 226       7.687  39.446   4.836  1.00 42.44           C  
+ATOM   4113  ND1 HIS C 226       7.784  40.669   5.466  1.00 44.09           N  
+ATOM   4114  CD2 HIS C 226       7.300  38.562   5.787  1.00 44.95           C  
+ATOM   4115  CE1 HIS C 226       7.462  40.532   6.740  1.00 44.54           C  
+ATOM   4116  NE2 HIS C 226       7.163  39.263   6.961  1.00 44.82           N  
+ATOM   4117  N   LEU C 227       5.928  39.847   0.310  1.00 34.76           N  
+ATOM   4118  CA  LEU C 227       5.869  39.619  -1.122  1.00 33.14           C  
+ATOM   4119  C   LEU C 227       4.746  40.545  -1.574  1.00 34.22           C  
+ATOM   4120  O   LEU C 227       3.753  40.696  -0.863  1.00 33.32           O  
+ATOM   4121  CB  LEU C 227       5.470  38.166  -1.401  1.00 33.37           C  
+ATOM   4122  CG  LEU C 227       5.525  37.725  -2.862  1.00 32.95           C  
+ATOM   4123  CD1 LEU C 227       6.965  37.707  -3.311  1.00 33.02           C  
+ATOM   4124  CD2 LEU C 227       4.914  36.355  -3.020  1.00 33.95           C  
+ATOM   4125  N   PRO C 228       4.885  41.193  -2.741  1.00 34.25           N  
+ATOM   4126  CA  PRO C 228       3.770  42.064  -3.128  1.00 33.12           C  
+ATOM   4127  C   PRO C 228       2.469  41.291  -3.343  1.00 33.90           C  
+ATOM   4128  O   PRO C 228       2.440  40.245  -3.996  1.00 32.16           O  
+ATOM   4129  CB  PRO C 228       4.275  42.757  -4.403  1.00 33.40           C  
+ATOM   4130  CG  PRO C 228       5.387  41.881  -4.894  1.00 33.83           C  
+ATOM   4131  CD  PRO C 228       6.037  41.354  -3.646  1.00 34.37           C  
+ATOM   4132  N   MET C 229       1.398  41.803  -2.753  1.00 34.82           N  
+ATOM   4133  CA  MET C 229       0.083  41.188  -2.863  1.00 36.56           C  
+ATOM   4134  C   MET C 229      -0.864  42.288  -3.302  1.00 35.75           C  
+ATOM   4135  O   MET C 229      -0.819  43.400  -2.768  1.00 33.94           O  
+ATOM   4136  CB  MET C 229      -0.387  40.661  -1.504  1.00 38.34           C  
+ATOM   4137  CG  MET C 229       0.496  39.600  -0.876  1.00 42.19           C  
+ATOM   4138  SD  MET C 229       0.159  37.945  -1.502  1.00 48.12           S  
+ATOM   4139  CE  MET C 229      -1.616  37.760  -1.035  1.00 36.62           C  
+ATOM   4140  N   PHE C 230      -1.718  41.996  -4.272  1.00 35.14           N  
+ATOM   4141  CA  PHE C 230      -2.656  43.013  -4.702  1.00 38.64           C  
+ATOM   4142  C   PHE C 230      -4.067  42.503  -4.859  1.00 36.18           C  
+ATOM   4143  O   PHE C 230      -4.295  41.373  -5.278  1.00 35.90           O  
+ATOM   4144  CB  PHE C 230      -2.189  43.694  -5.994  1.00 39.81           C  
+ATOM   4145  CG  PHE C 230      -1.929  42.755  -7.130  1.00 44.46           C  
+ATOM   4146  CD1 PHE C 230      -0.783  41.971  -7.155  1.00 47.51           C  
+ATOM   4147  CD2 PHE C 230      -2.808  42.694  -8.211  1.00 46.23           C  
+ATOM   4148  CE1 PHE C 230      -0.507  41.136  -8.250  1.00 48.52           C  
+ATOM   4149  CE2 PHE C 230      -2.543  41.865  -9.311  1.00 47.43           C  
+ATOM   4150  CZ  PHE C 230      -1.391  41.088  -9.328  1.00 48.13           C  
+ATOM   4151  N   GLU C 231      -5.015  43.351  -4.492  1.00 35.76           N  
+ATOM   4152  CA  GLU C 231      -6.420  43.019  -4.595  1.00 36.00           C  
+ATOM   4153  C   GLU C 231      -6.826  43.127  -6.061  1.00 35.64           C  
+ATOM   4154  O   GLU C 231      -6.392  44.028  -6.768  1.00 35.56           O  
+ATOM   4155  CB  GLU C 231      -7.237  43.985  -3.745  1.00 36.14           C  
+ATOM   4156  CG  GLU C 231      -8.725  43.692  -3.723  1.00 43.14           C  
+ATOM   4157  CD  GLU C 231      -9.499  44.703  -2.896  1.00 46.97           C  
+ATOM   4158  OE1 GLU C 231     -10.745  44.635  -2.882  1.00 51.51           O  
+ATOM   4159  OE2 GLU C 231      -8.862  45.567  -2.255  1.00 52.10           O  
+ATOM   4160  N   GLN C 232      -7.649  42.194  -6.514  1.00 36.29           N  
+ATOM   4161  CA  GLN C 232      -8.114  42.186  -7.891  1.00 39.20           C  
+ATOM   4162  C   GLN C 232      -9.622  42.019  -7.949  1.00 38.79           C  
+ATOM   4163  O   GLN C 232     -10.195  41.221  -7.213  1.00 38.82           O  
+ATOM   4164  CB  GLN C 232      -7.456  41.045  -8.670  1.00 42.33           C  
+ATOM   4165  CG  GLN C 232      -6.101  41.393  -9.266  1.00 51.15           C  
+ATOM   4166  CD  GLN C 232      -6.185  41.717 -10.747  1.00 52.96           C  
+ATOM   4167  OE1 GLN C 232      -5.210  42.150 -11.353  1.00 58.04           O  
+ATOM   4168  NE2 GLN C 232      -7.355  41.501 -11.336  1.00 57.01           N  
+ATOM   4169  N   GLN C 233     -10.261  42.785  -8.822  1.00 39.40           N  
+ATOM   4170  CA  GLN C 233     -11.702  42.697  -8.998  1.00 38.36           C  
+ATOM   4171  C   GLN C 233     -11.971  41.729 -10.137  1.00 37.56           C  
+ATOM   4172  O   GLN C 233     -11.124  41.506 -11.005  1.00 36.60           O  
+ATOM   4173  CB  GLN C 233     -12.284  44.055  -9.360  1.00 41.26           C  
+ATOM   4174  CG  GLN C 233     -12.114  45.120  -8.304  1.00 47.51           C  
+ATOM   4175  CD  GLN C 233     -12.449  46.495  -8.845  1.00 51.94           C  
+ATOM   4176  OE1 GLN C 233     -13.528  46.708  -9.398  1.00 55.29           O  
+ATOM   4177  NE2 GLN C 233     -11.521  47.436  -8.697  1.00 55.17           N  
+ATOM   4178  N   ALA C 234     -13.154  41.144 -10.136  1.00 35.72           N  
+ATOM   4179  CA  ALA C 234     -13.499  40.220 -11.188  1.00 34.43           C  
+ATOM   4180  C   ALA C 234     -15.003  40.059 -11.243  1.00 34.65           C  
+ATOM   4181  O   ALA C 234     -15.719  40.417 -10.304  1.00 34.94           O  
+ATOM   4182  CB  ALA C 234     -12.823  38.868 -10.947  1.00 32.88           C  
+ATOM   4183  N   GLN C 235     -15.469  39.539 -12.366  1.00 36.34           N  
+ATOM   4184  CA  GLN C 235     -16.881  39.279 -12.578  1.00 39.49           C  
+ATOM   4185  C   GLN C 235     -17.004  37.960 -13.302  1.00 38.66           C  
+ATOM   4186  O   GLN C 235     -16.374  37.742 -14.332  1.00 40.32           O  
+ATOM   4187  CB  GLN C 235     -17.535  40.390 -13.400  1.00 41.51           C  
+ATOM   4188  CG  GLN C 235     -18.141  41.492 -12.546  1.00 44.71           C  
+ATOM   4189  CD  GLN C 235     -18.898  42.513 -13.367  1.00 48.50           C  
+ATOM   4190  OE1 GLN C 235     -18.306  43.435 -13.944  1.00 48.45           O  
+ATOM   4191  NE2 GLN C 235     -20.220  42.348 -13.438  1.00 48.88           N  
+ATOM   4192  N   TYR C 236     -17.807  37.076 -12.734  1.00 39.01           N  
+ATOM   4193  CA  TYR C 236     -18.046  35.763 -13.288  1.00 36.38           C  
+ATOM   4194  C   TYR C 236     -19.554  35.626 -13.452  1.00 38.50           C  
+ATOM   4195  O   TYR C 236     -20.293  35.599 -12.463  1.00 37.86           O  
+ATOM   4196  CB  TYR C 236     -17.509  34.706 -12.322  1.00 35.47           C  
+ATOM   4197  CG  TYR C 236     -17.919  33.301 -12.660  1.00 34.21           C  
+ATOM   4198  CD1 TYR C 236     -18.836  32.615 -11.869  1.00 32.76           C  
+ATOM   4199  CD2 TYR C 236     -17.384  32.651 -13.771  1.00 34.19           C  
+ATOM   4200  CE1 TYR C 236     -19.209  31.306 -12.174  1.00 35.78           C  
+ATOM   4201  CE2 TYR C 236     -17.747  31.348 -14.087  1.00 36.00           C  
+ATOM   4202  CZ  TYR C 236     -18.655  30.679 -13.284  1.00 38.31           C  
+ATOM   4203  OH  TYR C 236     -18.978  29.369 -13.574  1.00 41.75           O  
+ATOM   4204  N   LYS C 237     -20.003  35.550 -14.703  1.00 41.68           N  
+ATOM   4205  CA  LYS C 237     -21.425  35.434 -15.017  1.00 43.06           C  
+ATOM   4206  C   LYS C 237     -22.233  36.490 -14.267  1.00 43.63           C  
+ATOM   4207  O   LYS C 237     -23.196  36.163 -13.568  1.00 43.50           O  
+ATOM   4208  CB  LYS C 237     -21.948  34.045 -14.645  1.00 44.41           C  
+ATOM   4209  CG  LYS C 237     -21.296  32.891 -15.395  1.00 49.95           C  
+ATOM   4210  CD  LYS C 237     -22.018  31.580 -15.091  1.00 53.23           C  
+ATOM   4211  CE  LYS C 237     -21.261  30.370 -15.621  1.00 55.63           C  
+ATOM   4212  NZ  LYS C 237     -21.030  30.435 -17.096  1.00 58.49           N  
+ATOM   4213  N   GLU C 238     -21.834  37.753 -14.403  1.00 43.79           N  
+ATOM   4214  CA  GLU C 238     -22.528  38.856 -13.730  1.00 45.92           C  
+ATOM   4215  C   GLU C 238     -22.264  38.976 -12.221  1.00 42.65           C  
+ATOM   4216  O   GLU C 238     -22.690  39.940 -11.596  1.00 41.74           O  
+ATOM   4217  CB  GLU C 238     -24.040  38.757 -13.956  1.00 50.38           C  
+ATOM   4218  CG  GLU C 238     -24.568  39.605 -15.097  1.00 60.42           C  
+ATOM   4219  CD  GLU C 238     -26.086  39.755 -15.054  1.00 65.07           C  
+ATOM   4220  OE1 GLU C 238     -26.625  40.594 -15.811  1.00 67.48           O  
+ATOM   4221  OE2 GLU C 238     -26.740  39.033 -14.263  1.00 67.95           O  
+ATOM   4222  N   SER C 239     -21.587  37.996 -11.632  1.00 39.61           N  
+ATOM   4223  CA  SER C 239     -21.279  38.053 -10.210  1.00 37.14           C  
+ATOM   4224  C   SER C 239     -19.931  38.714  -9.954  1.00 34.13           C  
+ATOM   4225  O   SER C 239     -18.887  38.206 -10.362  1.00 32.57           O  
+ATOM   4226  CB  SER C 239     -21.277  36.650  -9.588  1.00 38.73           C  
+ATOM   4227  OG  SER C 239     -22.584  36.269  -9.195  1.00 43.17           O  
+ATOM   4228  N   PHE C 240     -19.967  39.852  -9.272  1.00 32.13           N  
+ATOM   4229  CA  PHE C 240     -18.758  40.590  -8.927  1.00 30.12           C  
+ATOM   4230  C   PHE C 240     -18.119  39.976  -7.687  1.00 28.66           C  
+ATOM   4231  O   PHE C 240     -18.820  39.449  -6.831  1.00 26.11           O  
+ATOM   4232  CB  PHE C 240     -19.112  42.042  -8.625  1.00 28.20           C  
+ATOM   4233  CG  PHE C 240     -17.976  42.838  -8.053  1.00 32.57           C  
+ATOM   4234  CD1 PHE C 240     -17.028  43.429  -8.887  1.00 32.54           C  
+ATOM   4235  CD2 PHE C 240     -17.851  43.004  -6.676  1.00 31.65           C  
+ATOM   4236  CE1 PHE C 240     -15.977  44.177  -8.355  1.00 28.95           C  
+ATOM   4237  CE2 PHE C 240     -16.800  43.751  -6.140  1.00 33.70           C  
+ATOM   4238  CZ  PHE C 240     -15.865  44.338  -6.983  1.00 31.44           C  
+ATOM   4239  N   PHE C 241     -16.792  40.030  -7.603  1.00 29.69           N  
+ATOM   4240  CA  PHE C 241     -16.080  39.528  -6.434  1.00 29.62           C  
+ATOM   4241  C   PHE C 241     -14.645  40.024  -6.438  1.00 31.03           C  
+ATOM   4242  O   PHE C 241     -14.140  40.464  -7.471  1.00 31.44           O  
+ATOM   4243  CB  PHE C 241     -16.144  37.987  -6.357  1.00 30.42           C  
+ATOM   4244  CG  PHE C 241     -15.340  37.264  -7.415  1.00 33.56           C  
+ATOM   4245  CD1 PHE C 241     -14.018  36.877  -7.166  1.00 31.54           C  
+ATOM   4246  CD2 PHE C 241     -15.914  36.932  -8.642  1.00 33.06           C  
+ATOM   4247  CE1 PHE C 241     -13.283  36.167  -8.121  1.00 32.84           C  
+ATOM   4248  CE2 PHE C 241     -15.188  36.222  -9.610  1.00 33.45           C  
+ATOM   4249  CZ  PHE C 241     -13.871  35.838  -9.349  1.00 33.61           C  
+ATOM   4250  N   THR C 242     -14.012  40.008  -5.270  1.00 31.70           N  
+ATOM   4251  CA  THR C 242     -12.624  40.423  -5.146  1.00 34.00           C  
+ATOM   4252  C   THR C 242     -11.793  39.233  -4.649  1.00 33.86           C  
+ATOM   4253  O   THR C 242     -12.310  38.326  -3.988  1.00 31.41           O  
+ATOM   4254  CB  THR C 242     -12.455  41.615  -4.159  1.00 38.26           C  
+ATOM   4255  OG1 THR C 242     -12.749  41.199  -2.822  1.00 38.95           O  
+ATOM   4256  CG2 THR C 242     -13.392  42.744  -4.529  1.00 44.01           C  
+ATOM   4257  N   HIS C 243     -10.513  39.228  -5.005  1.00 33.30           N  
+ATOM   4258  CA  HIS C 243      -9.591  38.174  -4.591  1.00 31.98           C  
+ATOM   4259  C   HIS C 243      -8.208  38.797  -4.568  1.00 30.83           C  
+ATOM   4260  O   HIS C 243      -8.018  39.906  -5.080  1.00 29.89           O  
+ATOM   4261  CB  HIS C 243      -9.654  36.959  -5.546  1.00 30.59           C  
+ATOM   4262  CG  HIS C 243      -9.302  37.275  -6.964  1.00 33.51           C  
+ATOM   4263  ND1 HIS C 243      -8.029  37.122  -7.468  1.00 32.14           N  
+ATOM   4264  CD2 HIS C 243     -10.047  37.786  -7.975  1.00 34.80           C  
+ATOM   4265  CE1 HIS C 243      -8.003  37.528  -8.725  1.00 32.85           C  
+ATOM   4266  NE2 HIS C 243      -9.215  37.936  -9.058  1.00 32.81           N  
+ATOM   4267  N   PHE C 244      -7.249  38.097  -3.969  1.00 30.24           N  
+ATOM   4268  CA  PHE C 244      -5.900  38.624  -3.850  1.00 30.07           C  
+ATOM   4269  C   PHE C 244      -4.850  37.784  -4.545  1.00 30.60           C  
+ATOM   4270  O   PHE C 244      -4.837  36.559  -4.417  1.00 29.89           O  
+ATOM   4271  CB  PHE C 244      -5.556  38.784  -2.375  1.00 31.23           C  
+ATOM   4272  CG  PHE C 244      -6.533  39.641  -1.634  1.00 33.58           C  
+ATOM   4273  CD1 PHE C 244      -7.709  39.100  -1.131  1.00 34.20           C  
+ATOM   4274  CD2 PHE C 244      -6.317  41.012  -1.509  1.00 35.55           C  
+ATOM   4275  CE1 PHE C 244      -8.660  39.911  -0.520  1.00 34.76           C  
+ATOM   4276  CE2 PHE C 244      -7.265  41.830  -0.899  1.00 35.33           C  
+ATOM   4277  CZ  PHE C 244      -8.440  41.274  -0.405  1.00 34.20           C  
+ATOM   4278  N   VAL C 245      -3.961  38.438  -5.286  1.00 28.24           N  
+ATOM   4279  CA  VAL C 245      -2.940  37.684  -5.979  1.00 30.87           C  
+ATOM   4280  C   VAL C 245      -1.507  38.008  -5.546  1.00 31.56           C  
+ATOM   4281  O   VAL C 245      -1.095  39.167  -5.473  1.00 31.50           O  
+ATOM   4282  CB  VAL C 245      -3.111  37.787  -7.545  1.00 31.66           C  
+ATOM   4283  CG1 VAL C 245      -4.150  38.821  -7.907  1.00 34.41           C  
+ATOM   4284  CG2 VAL C 245      -1.791  38.088  -8.210  1.00 31.79           C  
+ATOM   4285  N   PRO C 246      -0.741  36.962  -5.212  1.00 30.33           N  
+ATOM   4286  CA  PRO C 246       0.655  37.105  -4.785  1.00 31.64           C  
+ATOM   4287  C   PRO C 246       1.495  37.304  -6.051  1.00 33.13           C  
+ATOM   4288  O   PRO C 246       1.328  36.586  -7.033  1.00 32.87           O  
+ATOM   4289  CB  PRO C 246       0.939  35.780  -4.075  1.00 31.48           C  
+ATOM   4290  CG  PRO C 246       0.109  34.795  -4.865  1.00 31.16           C  
+ATOM   4291  CD  PRO C 246      -1.185  35.555  -5.176  1.00 27.97           C  
+ATOM   4292  N   LEU C 247       2.384  38.287  -6.030  1.00 34.35           N  
+ATOM   4293  CA  LEU C 247       3.204  38.588  -7.194  1.00 37.50           C  
+ATOM   4294  C   LEU C 247       4.573  37.910  -7.166  1.00 37.38           C  
+ATOM   4295  O   LEU C 247       5.546  38.489  -6.680  1.00 37.94           O  
+ATOM   4296  CB  LEU C 247       3.368  40.110  -7.303  1.00 39.63           C  
+ATOM   4297  CG  LEU C 247       3.730  40.745  -8.647  1.00 44.23           C  
+ATOM   4298  CD1 LEU C 247       5.169  40.441  -8.982  1.00 48.37           C  
+ATOM   4299  CD2 LEU C 247       2.795  40.239  -9.728  1.00 43.97           C  
+ATOM   4300  N   TYR C 248       4.646  36.685  -7.683  1.00 36.01           N  
+ATOM   4301  CA  TYR C 248       5.917  35.961  -7.724  1.00 36.63           C  
+ATOM   4302  C   TYR C 248       6.819  36.623  -8.744  1.00 37.68           C  
+ATOM   4303  O   TYR C 248       6.379  36.965  -9.837  1.00 39.91           O  
+ATOM   4304  CB  TYR C 248       5.717  34.505  -8.130  1.00 33.75           C  
+ATOM   4305  CG  TYR C 248       4.869  33.717  -7.176  1.00 32.99           C  
+ATOM   4306  CD1 TYR C 248       3.676  33.137  -7.604  1.00 31.06           C  
+ATOM   4307  CD2 TYR C 248       5.262  33.534  -5.847  1.00 31.92           C  
+ATOM   4308  CE1 TYR C 248       2.899  32.392  -6.743  1.00 32.38           C  
+ATOM   4309  CE2 TYR C 248       4.486  32.785  -4.968  1.00 32.66           C  
+ATOM   4310  CZ  TYR C 248       3.306  32.217  -5.429  1.00 32.85           C  
+ATOM   4311  OH  TYR C 248       2.535  31.454  -4.598  1.00 35.24           O  
+ATOM   4312  N   LYS C 249       8.083  36.791  -8.387  1.00 38.77           N  
+ATOM   4313  CA  LYS C 249       9.042  37.423  -9.269  1.00 41.30           C  
+ATOM   4314  C   LYS C 249       9.038  36.783 -10.662  1.00 42.43           C  
+ATOM   4315  O   LYS C 249       9.195  37.473 -11.666  1.00 43.62           O  
+ATOM   4316  CB  LYS C 249      10.433  37.343  -8.640  1.00 44.09           C  
+ATOM   4317  CG  LYS C 249      11.429  38.330  -9.203  1.00 49.41           C  
+ATOM   4318  CD  LYS C 249      12.772  38.217  -8.494  1.00 54.67           C  
+ATOM   4319  CE  LYS C 249      12.643  38.495  -6.998  1.00 57.69           C  
+ATOM   4320  NZ  LYS C 249      13.969  38.448  -6.308  1.00 60.80           N  
+ATOM   4321  N   THR C 250       8.833  35.470 -10.719  1.00 41.04           N  
+ATOM   4322  CA  THR C 250       8.816  34.745 -11.988  1.00 41.83           C  
+ATOM   4323  C   THR C 250       7.584  35.000 -12.871  1.00 43.75           C  
+ATOM   4324  O   THR C 250       7.578  34.646 -14.054  1.00 41.53           O  
+ATOM   4325  CB  THR C 250       8.932  33.222 -11.753  1.00 40.73           C  
+ATOM   4326  OG1 THR C 250       8.022  32.832 -10.717  1.00 38.49           O  
+ATOM   4327  CG2 THR C 250      10.354  32.841 -11.363  1.00 36.43           C  
+ATOM   4328  N   LEU C 251       6.536  35.589 -12.301  1.00 45.22           N  
+ATOM   4329  CA  LEU C 251       5.337  35.879 -13.083  1.00 46.90           C  
+ATOM   4330  C   LEU C 251       5.662  37.018 -14.044  1.00 49.10           C  
+ATOM   4331  O   LEU C 251       5.136  37.079 -15.154  1.00 51.41           O  
+ATOM   4332  CB  LEU C 251       4.173  36.280 -12.169  1.00 44.77           C  
+ATOM   4333  CG  LEU C 251       3.496  35.154 -11.375  1.00 45.07           C  
+ATOM   4334  CD1 LEU C 251       2.566  35.730 -10.311  1.00 38.42           C  
+ATOM   4335  CD2 LEU C 251       2.735  34.253 -12.332  1.00 43.24           C  
+ATOM   4336  N   LEU C 252       6.545  37.908 -13.607  1.00 51.44           N  
+ATOM   4337  CA  LEU C 252       6.972  39.054 -14.400  1.00 53.87           C  
+ATOM   4338  C   LEU C 252       7.736  38.627 -15.651  1.00 55.23           C  
+ATOM   4339  O   LEU C 252       7.325  39.037 -16.757  0.00 55.44           O  
+ATOM   4340  CB  LEU C 252       7.845  39.973 -13.541  1.00 53.81           C  
+ATOM   4341  CG  LEU C 252       7.135  41.059 -12.718  1.00 55.90           C  
+ATOM   4342  CD1 LEU C 252       5.804  40.557 -12.189  1.00 55.94           C  
+ATOM   4343  CD2 LEU C 252       8.047  41.499 -11.580  1.00 55.82           C  
+TER    4344      LEU C 252                                                      
+ATOM   4345  N   SER B   5      37.342  21.962  18.520  1.00 73.14           N  
+ATOM   4346  CA  SER B   5      38.282  21.216  17.637  1.00 73.31           C  
+ATOM   4347  C   SER B   5      38.216  19.716  17.919  1.00 73.52           C  
+ATOM   4348  O   SER B   5      38.547  19.261  19.015  1.00 73.42           O  
+ATOM   4349  CB  SER B   5      39.709  21.723  17.847  1.00 73.31           C  
+ATOM   4350  OG  SER B   5      40.624  21.025  17.023  1.00 73.48           O  
+ATOM   4351  N   TYR B   6      37.791  18.956  16.915  1.00 74.08           N  
+ATOM   4352  CA  TYR B   6      37.657  17.508  17.038  1.00 74.03           C  
+ATOM   4353  C   TYR B   6      38.907  16.817  17.587  1.00 74.45           C  
+ATOM   4354  O   TYR B   6      38.825  16.069  18.563  1.00 74.32           O  
+ATOM   4355  CB  TYR B   6      37.277  16.902  15.681  1.00 72.87           C  
+ATOM   4356  CG  TYR B   6      37.054  15.408  15.724  1.00 72.29           C  
+ATOM   4357  CD1 TYR B   6      36.045  14.856  16.515  1.00 71.71           C  
+ATOM   4358  CD2 TYR B   6      37.865  14.543  14.990  1.00 72.33           C  
+ATOM   4359  CE1 TYR B   6      35.852  13.480  16.575  1.00 71.28           C  
+ATOM   4360  CE2 TYR B   6      37.679  13.163  15.042  1.00 71.42           C  
+ATOM   4361  CZ  TYR B   6      36.674  12.640  15.836  1.00 71.00           C  
+ATOM   4362  OH  TYR B   6      36.493  11.280  15.893  1.00 70.50           O  
+ATOM   4363  N   PRO B   7      40.078  17.052  16.966  1.00 75.44           N  
+ATOM   4364  CA  PRO B   7      41.331  16.434  17.421  1.00 75.49           C  
+ATOM   4365  C   PRO B   7      41.619  16.662  18.907  1.00 74.90           C  
+ATOM   4366  O   PRO B   7      42.052  15.751  19.610  1.00 74.15           O  
+ATOM   4367  CB  PRO B   7      42.379  17.088  16.525  1.00 76.10           C  
+ATOM   4368  CG  PRO B   7      41.625  17.304  15.248  1.00 75.95           C  
+ATOM   4369  CD  PRO B   7      40.311  17.855  15.750  1.00 75.80           C  
+ATOM   4370  N   LYS B   8      41.378  17.881  19.380  1.00 74.94           N  
+ATOM   4371  CA  LYS B   8      41.622  18.206  20.780  1.00 74.69           C  
+ATOM   4372  C   LYS B   8      40.779  17.326  21.689  1.00 73.47           C  
+ATOM   4373  O   LYS B   8      41.266  16.819  22.700  1.00 73.68           O  
+ATOM   4374  CB  LYS B   8      41.305  19.679  21.051  1.00 75.96           C  
+ATOM   4375  CG  LYS B   8      42.080  20.643  20.167  1.00 76.85           C  
+ATOM   4376  CD  LYS B   8      41.840  22.091  20.562  1.00 77.26           C  
+ATOM   4377  CE  LYS B   8      42.571  23.034  19.619  1.00 77.88           C  
+ATOM   4378  NZ  LYS B   8      44.026  22.708  19.533  1.00 78.39           N  
+ATOM   4379  N   ILE B   9      39.513  17.149  21.322  1.00 72.32           N  
+ATOM   4380  CA  ILE B   9      38.594  16.328  22.101  1.00 69.38           C  
+ATOM   4381  C   ILE B   9      39.122  14.903  22.213  1.00 67.89           C  
+ATOM   4382  O   ILE B   9      39.177  14.345  23.307  1.00 66.50           O  
+ATOM   4383  CB  ILE B   9      37.192  16.287  21.458  1.00 69.64           C  
+ATOM   4384  CG1 ILE B   9      36.673  17.711  21.240  1.00 69.31           C  
+ATOM   4385  CG2 ILE B   9      36.232  15.514  22.356  1.00 67.88           C  
+ATOM   4386  CD1 ILE B   9      35.323  17.778  20.556  0.00 69.42           C  
+ATOM   4387  N   LEU B  10      39.512  14.319  21.082  1.00 67.47           N  
+ATOM   4388  CA  LEU B  10      40.038  12.956  21.075  1.00 68.47           C  
+ATOM   4389  C   LEU B  10      41.267  12.798  21.972  1.00 69.08           C  
+ATOM   4390  O   LEU B  10      41.410  11.785  22.655  1.00 69.00           O  
+ATOM   4391  CB  LEU B  10      40.380  12.519  19.649  1.00 67.72           C  
+ATOM   4392  CG  LEU B  10      39.202  12.323  18.693  1.00 67.34           C  
+ATOM   4393  CD1 LEU B  10      39.729  11.816  17.366  1.00 67.72           C  
+ATOM   4394  CD2 LEU B  10      38.207  11.330  19.270  1.00 66.83           C  
+ATOM   4395  N   PHE B  11      42.154  13.791  21.963  1.00 70.03           N  
+ATOM   4396  CA  PHE B  11      43.350  13.753  22.805  1.00 70.86           C  
+ATOM   4397  C   PHE B  11      42.923  13.753  24.263  1.00 69.13           C  
+ATOM   4398  O   PHE B  11      43.327  12.892  25.044  1.00 69.15           O  
+ATOM   4399  CB  PHE B  11      44.236  14.977  22.552  1.00 74.81           C  
+ATOM   4400  CG  PHE B  11      45.261  14.782  21.468  1.00 78.57           C  
+ATOM   4401  CD1 PHE B  11      44.875  14.458  20.168  1.00 80.53           C  
+ATOM   4402  CD2 PHE B  11      46.617  14.944  21.745  1.00 80.55           C  
+ATOM   4403  CE1 PHE B  11      45.829  14.301  19.154  1.00 82.19           C  
+ATOM   4404  CE2 PHE B  11      47.580  14.790  20.741  1.00 82.20           C  
+ATOM   4405  CZ  PHE B  11      47.185  14.469  19.443  1.00 82.29           C  
+ATOM   4406  N   GLY B  12      42.101  14.733  24.621  1.00 67.23           N  
+ATOM   4407  CA  GLY B  12      41.625  14.838  25.986  1.00 65.83           C  
+ATOM   4408  C   GLY B  12      40.990  13.552  26.473  1.00 65.14           C  
+ATOM   4409  O   GLY B  12      41.204  13.137  27.613  1.00 64.79           O  
+ATOM   4410  N   LEU B  13      40.204  12.918  25.607  1.00 64.20           N  
+ATOM   4411  CA  LEU B  13      39.534  11.674  25.956  1.00 62.68           C  
+ATOM   4412  C   LEU B  13      40.526  10.535  26.124  1.00 62.28           C  
+ATOM   4413  O   LEU B  13      40.450   9.776  27.090  1.00 61.74           O  
+ATOM   4414  CB  LEU B  13      38.495  11.312  24.889  1.00 60.98           C  
+ATOM   4415  CG  LEU B  13      37.197  12.126  24.915  1.00 58.60           C  
+ATOM   4416  CD1 LEU B  13      36.357  11.776  23.709  1.00 58.16           C  
+ATOM   4417  CD2 LEU B  13      36.431  11.844  26.198  1.00 57.39           C  
+ATOM   4418  N   THR B  14      41.458  10.421  25.184  1.00 63.06           N  
+ATOM   4419  CA  THR B  14      42.470   9.370  25.232  1.00 63.74           C  
+ATOM   4420  C   THR B  14      43.326   9.519  26.483  1.00 64.58           C  
+ATOM   4421  O   THR B  14      43.708   8.532  27.115  1.00 64.87           O  
+ATOM   4422  CB  THR B  14      43.388   9.426  24.009  1.00 62.70           C  
+ATOM   4423  OG1 THR B  14      42.600   9.339  22.817  1.00 62.27           O  
+ATOM   4424  CG2 THR B  14      44.377   8.271  24.040  1.00 63.82           C  
+ATOM   4425  N   LEU B  15      43.620  10.764  26.833  1.00 65.14           N  
+ATOM   4426  CA  LEU B  15      44.422  11.060  28.008  1.00 65.77           C  
+ATOM   4427  C   LEU B  15      43.647  10.605  29.237  1.00 64.91           C  
+ATOM   4428  O   LEU B  15      44.175   9.909  30.105  1.00 65.50           O  
+ATOM   4429  CB  LEU B  15      44.690  12.565  28.080  1.00 67.81           C  
+ATOM   4430  CG  LEU B  15      45.918  13.043  28.861  1.00 69.20           C  
+ATOM   4431  CD1 LEU B  15      46.011  14.557  28.744  1.00 69.99           C  
+ATOM   4432  CD2 LEU B  15      45.827  12.617  30.318  1.00 69.48           C  
+ATOM   4433  N   LEU B  16      42.382  11.007  29.295  1.00 64.17           N  
+ATOM   4434  CA  LEU B  16      41.497  10.656  30.397  1.00 62.74           C  
+ATOM   4435  C   LEU B  16      41.389   9.139  30.531  1.00 62.12           C  
+ATOM   4436  O   LEU B  16      41.303   8.597  31.635  1.00 60.66           O  
+ATOM   4437  CB  LEU B  16      40.112  11.244  30.144  1.00 62.89           C  
+ATOM   4438  CG  LEU B  16      39.050  10.984  31.209  1.00 62.62           C  
+ATOM   4439  CD1 LEU B  16      39.420  11.719  32.490  1.00 61.01           C  
+ATOM   4440  CD2 LEU B  16      37.697  11.447  30.689  1.00 62.20           C  
+ATOM   4441  N   LEU B  17      41.383   8.457  29.394  1.00 61.39           N  
+ATOM   4442  CA  LEU B  17      41.287   7.010  29.394  1.00 61.22           C  
+ATOM   4443  C   LEU B  17      42.489   6.457  30.149  1.00 62.61           C  
+ATOM   4444  O   LEU B  17      42.344   5.602  31.019  1.00 62.40           O  
+ATOM   4445  CB  LEU B  17      41.249   6.485  27.951  1.00 58.28           C  
+ATOM   4446  CG  LEU B  17      41.112   4.975  27.727  1.00 56.38           C  
+ATOM   4447  CD1 LEU B  17      40.610   4.706  26.325  1.00 54.45           C  
+ATOM   4448  CD2 LEU B  17      42.450   4.288  27.964  1.00 56.15           C  
+ATOM   4449  N   VAL B  18      43.674   6.968  29.829  1.00 65.16           N  
+ATOM   4450  CA  VAL B  18      44.902   6.516  30.478  1.00 66.54           C  
+ATOM   4451  C   VAL B  18      44.966   6.897  31.957  1.00 66.98           C  
+ATOM   4452  O   VAL B  18      45.362   6.085  32.794  1.00 67.09           O  
+ATOM   4453  CB  VAL B  18      46.146   7.071  29.758  1.00 67.38           C  
+ATOM   4454  CG1 VAL B  18      47.407   6.555  30.435  1.00 68.29           C  
+ATOM   4455  CG2 VAL B  18      46.123   6.657  28.286  1.00 66.68           C  
+ATOM   4456  N   ILE B  19      44.583   8.127  32.284  1.00 67.43           N  
+ATOM   4457  CA  ILE B  19      44.597   8.551  33.677  1.00 68.17           C  
+ATOM   4458  C   ILE B  19      43.723   7.587  34.471  1.00 69.32           C  
+ATOM   4459  O   ILE B  19      44.053   7.209  35.596  1.00 70.60           O  
+ATOM   4460  CB  ILE B  19      44.036   9.981  33.857  1.00 69.01           C  
+ATOM   4461  CG1 ILE B  19      44.946  10.998  33.165  1.00 68.71           C  
+ATOM   4462  CG2 ILE B  19      43.912  10.307  35.346  1.00 68.23           C  
+ATOM   4463  CD1 ILE B  19      44.481  12.435  33.314  0.00 68.99           C  
+ATOM   4464  N   THR B  20      42.608   7.187  33.871  1.00 68.92           N  
+ATOM   4465  CA  THR B  20      41.680   6.264  34.515  1.00 68.10           C  
+ATOM   4466  C   THR B  20      42.307   4.877  34.671  1.00 67.83           C  
+ATOM   4467  O   THR B  20      42.042   4.172  35.645  1.00 65.75           O  
+ATOM   4468  CB  THR B  20      40.371   6.145  33.696  1.00 67.91           C  
+ATOM   4469  OG1 THR B  20      39.776   7.442  33.557  1.00 67.16           O  
+ATOM   4470  CG2 THR B  20      39.381   5.219  34.393  1.00 67.78           C  
+ATOM   4471  N   ALA B  21      43.139   4.493  33.707  1.00 68.67           N  
+ATOM   4472  CA  ALA B  21      43.800   3.193  33.735  1.00 70.57           C  
+ATOM   4473  C   ALA B  21      44.788   3.108  34.894  1.00 71.94           C  
+ATOM   4474  O   ALA B  21      44.866   2.090  35.583  1.00 71.70           O  
+ATOM   4475  CB  ALA B  21      44.518   2.944  32.417  1.00 70.26           C  
+ATOM   4476  N   VAL B  22      45.542   4.184  35.102  1.00 72.91           N  
+ATOM   4477  CA  VAL B  22      46.520   4.233  36.182  1.00 73.57           C  
+ATOM   4478  C   VAL B  22      45.830   4.248  37.540  1.00 74.46           C  
+ATOM   4479  O   VAL B  22      46.156   3.450  38.418  1.00 75.58           O  
+ATOM   4480  CB  VAL B  22      47.413   5.474  36.061  1.00 73.79           C  
+ATOM   4481  CG1 VAL B  22      48.337   5.568  37.266  1.00 73.48           C  
+ATOM   4482  CG2 VAL B  22      48.217   5.402  34.767  1.00 72.51           C  
+ATOM   4483  N   ILE B  23      44.879   5.158  37.718  1.00 74.87           N  
+ATOM   4484  CA  ILE B  23      44.148   5.229  38.978  1.00 75.40           C  
+ATOM   4485  C   ILE B  23      43.575   3.843  39.254  1.00 75.74           C  
+ATOM   4486  O   ILE B  23      43.277   3.490  40.395  1.00 76.69           O  
+ATOM   4487  CB  ILE B  23      42.987   6.251  38.901  1.00 75.27           C  
+ATOM   4488  CG1 ILE B  23      43.546   7.659  38.685  1.00 75.90           C  
+ATOM   4489  CG2 ILE B  23      42.162   6.207  40.178  1.00 75.31           C  
+ATOM   4490  CD1 ILE B  23      42.483   8.729  38.540  0.00 75.79           C  
+ATOM   4491  N   SER B  24      43.435   3.059  38.190  1.00 75.60           N  
+ATOM   4492  CA  SER B  24      42.899   1.712  38.286  1.00 75.68           C  
+ATOM   4493  C   SER B  24      43.881   0.796  39.010  1.00 75.69           C  
+ATOM   4494  O   SER B  24      43.478  -0.162  39.673  1.00 75.37           O  
+ATOM   4495  CB  SER B  24      42.608   1.172  36.881  1.00 75.09           C  
+ATOM   4496  OG  SER B  24      42.007  -0.109  36.932  1.00 77.23           O  
+ATOM   4497  N   LEU B  25      45.169   1.100  38.881  1.00 75.55           N  
+ATOM   4498  CA  LEU B  25      46.217   0.309  39.518  1.00 75.30           C  
+ATOM   4499  C   LEU B  25      46.346   0.626  41.004  1.00 75.62           C  
+ATOM   4500  O   LEU B  25      46.998  -0.105  41.743  1.00 76.19           O  
+ATOM   4501  CB  LEU B  25      47.560   0.551  38.821  1.00 73.74           C  
+ATOM   4502  CG  LEU B  25      47.643   0.115  37.354  1.00 73.40           C  
+ATOM   4503  CD1 LEU B  25      48.997   0.495  36.784  1.00 72.71           C  
+ATOM   4504  CD2 LEU B  25      47.419  -1.388  37.244  1.00 71.59           C  
+ATOM   4505  N   GLY B  26      45.717   1.714  41.437  1.00 75.89           N  
+ATOM   4506  CA  GLY B  26      45.779   2.097  42.834  1.00 75.22           C  
+ATOM   4507  C   GLY B  26      44.605   1.580  43.647  1.00 75.65           C  
+ATOM   4508  O   GLY B  26      44.324   2.089  44.732  1.00 74.34           O  
+ATOM   4509  N   ILE B  27      43.918   0.568  43.127  1.00 76.33           N  
+ATOM   4510  CA  ILE B  27      42.769  -0.011  43.817  1.00 78.37           C  
+ATOM   4511  C   ILE B  27      42.931  -1.523  43.938  1.00 80.72           C  
+ATOM   4512  O   ILE B  27      43.420  -2.178  43.018  1.00 80.90           O  
+ATOM   4513  CB  ILE B  27      41.447   0.278  43.060  1.00 77.54           C  
+ATOM   4514  CG1 ILE B  27      41.259   1.787  42.888  1.00 77.51           C  
+ATOM   4515  CG2 ILE B  27      40.270  -0.312  43.822  1.00 75.86           C  
+ATOM   4516  CD1 ILE B  27      40.019   2.168  42.105  0.00 77.37           C  
+ATOM   4517  N   GLY B  28      42.524  -2.075  45.076  1.00 83.46           N  
+ATOM   4518  CA  GLY B  28      42.633  -3.510  45.266  1.00 87.65           C  
+ATOM   4519  C   GLY B  28      43.751  -3.967  46.185  1.00 90.11           C  
+ATOM   4520  O   GLY B  28      44.530  -3.161  46.694  1.00 89.67           O  
+ATOM   4521  N   ARG B  29      43.827  -5.282  46.375  1.00 93.10           N  
+ATOM   4522  CA  ARG B  29      44.816  -5.921  47.238  1.00 95.84           C  
+ATOM   4523  C   ARG B  29      46.212  -5.303  47.225  1.00 97.51           C  
+ATOM   4524  O   ARG B  29      46.618  -4.661  48.196  1.00 98.73           O  
+ATOM   4525  CB  ARG B  29      44.912  -7.408  46.889  1.00 95.86           C  
+ATOM   4526  CG  ARG B  29      43.583  -8.140  46.976  0.00 96.21           C  
+ATOM   4527  CD  ARG B  29      43.721  -9.605  46.601  0.00 96.48           C  
+ATOM   4528  NE  ARG B  29      42.427 -10.283  46.592  0.00 96.83           N  
+ATOM   4529  CZ  ARG B  29      42.258 -11.568  46.297  0.00 97.01           C  
+ATOM   4530  NH1 ARG B  29      41.042 -12.098  46.313  0.00 97.16           N  
+ATOM   4531  NH2 ARG B  29      43.302 -12.324  45.987  0.00 97.16           N  
+ATOM   4532  N   TYR B  30      46.950  -5.499  46.138  1.00 98.59           N  
+ATOM   4533  CA  TYR B  30      48.302  -4.963  46.046  1.00 99.99           C  
+ATOM   4534  C   TYR B  30      48.366  -3.742  45.142  1.00101.25           C  
+ATOM   4535  O   TYR B  30      48.896  -3.801  44.032  1.00101.71           O  
+ATOM   4536  CB  TYR B  30      49.260  -6.047  45.544  1.00100.42           C  
+ATOM   4537  CG  TYR B  30      49.262  -7.290  46.410  1.00101.23           C  
+ATOM   4538  CD1 TYR B  30      48.152  -8.137  46.453  1.00101.34           C  
+ATOM   4539  CD2 TYR B  30      50.361  -7.605  47.210  1.00101.25           C  
+ATOM   4540  CE1 TYR B  30      48.134  -9.264  47.273  1.00101.93           C  
+ATOM   4541  CE2 TYR B  30      50.353  -8.731  48.035  1.00101.75           C  
+ATOM   4542  CZ  TYR B  30      49.237  -9.555  48.061  1.00102.18           C  
+ATOM   4543  OH  TYR B  30      49.222 -10.664  48.877  1.00102.44           O  
+ATOM   4544  N   SER B  31      47.830  -2.633  45.640  1.00102.25           N  
+ATOM   4545  CA  SER B  31      47.795  -1.374  44.905  1.00103.58           C  
+ATOM   4546  C   SER B  31      49.186  -0.815  44.626  1.00104.51           C  
+ATOM   4547  O   SER B  31      50.183  -1.527  44.721  1.00105.18           O  
+ATOM   4548  CB  SER B  31      46.986  -0.343  45.691  1.00103.88           C  
+ATOM   4549  OG  SER B  31      45.716  -0.861  46.043  1.00104.42           O  
+ATOM   4550  N   LEU B  32      49.236   0.467  44.275  1.00105.58           N  
+ATOM   4551  CA  LEU B  32      50.491   1.151  43.982  1.00106.75           C  
+ATOM   4552  C   LEU B  32      50.656   2.378  44.875  1.00108.26           C  
+ATOM   4553  O   LEU B  32      49.880   2.590  45.809  1.00108.69           O  
+ATOM   4554  CB  LEU B  32      50.538   1.580  42.512  1.00105.65           C  
+ATOM   4555  CG  LEU B  32      50.983   0.565  41.454  1.00105.29           C  
+ATOM   4556  CD1 LEU B  32      52.469   0.308  41.603  1.00105.36           C  
+ATOM   4557  CD2 LEU B  32      50.191  -0.725  41.584  1.00105.37           C  
+ATOM   4558  N   SER B  33      51.670   3.185  44.578  1.00109.63           N  
+ATOM   4559  CA  SER B  33      51.948   4.391  45.350  1.00110.29           C  
+ATOM   4560  C   SER B  33      51.023   5.535  44.949  1.00110.67           C  
+ATOM   4561  O   SER B  33      50.942   5.901  43.775  1.00110.41           O  
+ATOM   4562  CB  SER B  33      53.403   4.815  45.148  1.00110.02           C  
+ATOM   4563  OG  SER B  33      54.283   3.758  45.482  1.00110.93           O  
+ATOM   4564  N   VAL B  34      50.329   6.094  45.936  1.00111.03           N  
+ATOM   4565  CA  VAL B  34      49.407   7.198  45.702  1.00111.18           C  
+ATOM   4566  C   VAL B  34      50.160   8.472  45.333  1.00111.29           C  
+ATOM   4567  O   VAL B  34      50.810   8.539  44.291  1.00111.64           O  
+ATOM   4568  CB  VAL B  34      48.548   7.475  46.954  1.00111.20           C  
+ATOM   4569  CG1 VAL B  34      49.445   7.772  48.146  1.00111.04           C  
+ATOM   4570  CG2 VAL B  34      47.608   8.640  46.690  1.00111.11           C  
+ATOM   4571  N   GLN B  54      57.638  -4.847  44.318  1.00 93.35           N  
+ATOM   4572  CA  GLN B  54      58.037  -5.913  43.405  1.00 94.00           C  
+ATOM   4573  C   GLN B  54      57.214  -7.176  43.651  1.00 94.46           C  
+ATOM   4574  O   GLN B  54      56.878  -7.904  42.712  1.00 94.03           O  
+ATOM   4575  CB  GLN B  54      59.520  -6.214  43.571  1.00 93.82           C  
+ATOM   4576  N   GLN B  55      56.898  -7.433  44.918  1.00 94.97           N  
+ATOM   4577  CA  GLN B  55      56.105  -8.602  45.287  1.00 95.05           C  
+ATOM   4578  C   GLN B  55      54.682  -8.420  44.768  1.00 94.75           C  
+ATOM   4579  O   GLN B  55      53.895  -9.370  44.717  1.00 94.01           O  
+ATOM   4580  CB  GLN B  55      56.095  -8.772  46.806  1.00 95.14           C  
+ATOM   4581  N   GLN B  56      54.366  -7.186  44.384  1.00 94.50           N  
+ATOM   4582  CA  GLN B  56      53.049  -6.842  43.859  1.00 93.73           C  
+ATOM   4583  C   GLN B  56      53.085  -6.773  42.333  1.00 93.08           C  
+ATOM   4584  O   GLN B  56      53.071  -5.689  41.746  1.00 92.65           O  
+ATOM   4585  CB  GLN B  56      52.589  -5.503  44.436  1.00 93.47           C  
+ATOM   4586  N   VAL B  57      53.149  -7.940  41.699  1.00 92.13           N  
+ATOM   4587  CA  VAL B  57      53.173  -8.023  40.244  1.00 91.46           C  
+ATOM   4588  C   VAL B  57      51.813  -8.532  39.782  1.00 90.81           C  
+ATOM   4589  O   VAL B  57      51.683  -9.111  38.701  1.00 90.06           O  
+ATOM   4590  CB  VAL B  57      54.278  -8.970  39.787  1.00 91.37           C  
+ATOM   4591  N   ILE B  58      50.803  -8.307  40.622  1.00 89.90           N  
+ATOM   4592  CA  ILE B  58      49.434  -8.725  40.340  1.00 89.31           C  
+ATOM   4593  C   ILE B  58      48.925  -8.097  39.045  1.00 88.81           C  
+ATOM   4594  O   ILE B  58      47.816  -8.392  38.597  1.00 88.53           O  
+ATOM   4595  CB  ILE B  58      48.520  -8.340  41.502  1.00 88.62           C  
+ATOM   4596  N   PHE B  59      49.743  -7.234  38.449  1.00 87.59           N  
+ATOM   4597  CA  PHE B  59      49.389  -6.565  37.207  1.00 87.06           C  
+ATOM   4598  C   PHE B  59      49.201  -7.562  36.063  1.00 87.11           C  
+ATOM   4599  O   PHE B  59      49.077  -7.167  34.903  1.00 87.93           O  
+ATOM   4600  CB  PHE B  59      50.458  -5.543  36.844  1.00 86.34           C  
+ATOM   4601  N   GLN B  60      49.190  -8.852  36.390  1.00 86.01           N  
+ATOM   4602  CA  GLN B  60      48.994  -9.899  35.390  1.00 84.54           C  
+ATOM   4603  C   GLN B  60      47.627 -10.537  35.609  1.00 83.14           C  
+ATOM   4604  O   GLN B  60      47.339 -11.623  35.112  1.00 82.89           O  
+ATOM   4605  CB  GLN B  60      50.088 -10.961  35.497  1.00 86.49           C  
+ATOM   4606  CG  GLN B  60      51.510 -10.417  35.374  1.00 87.87           C  
+ATOM   4607  CD  GLN B  60      51.673  -9.418  34.236  1.00 88.73           C  
+ATOM   4608  OE1 GLN B  60      51.308  -8.247  34.363  1.00 87.39           O  
+ATOM   4609  NE2 GLN B  60      52.218  -9.882  33.114  1.00 88.33           N  
+ATOM   4610  N   VAL B  61      46.797  -9.836  36.374  1.00 81.30           N  
+ATOM   4611  CA  VAL B  61      45.436 -10.257  36.688  1.00 79.00           C  
+ATOM   4612  C   VAL B  61      44.573  -8.998  36.623  1.00 77.51           C  
+ATOM   4613  O   VAL B  61      43.360  -9.058  36.406  1.00 76.68           O  
+ATOM   4614  CB  VAL B  61      45.345 -10.832  38.115  1.00 79.03           C  
+ATOM   4615  CG1 VAL B  61      43.915 -11.238  38.425  1.00 78.41           C  
+ATOM   4616  CG2 VAL B  61      46.282 -12.016  38.256  1.00 79.61           C  
+ATOM   4617  N   ARG B  62      45.233  -7.857  36.801  1.00 75.11           N  
+ATOM   4618  CA  ARG B  62      44.589  -6.551  36.797  1.00 73.57           C  
+ATOM   4619  C   ARG B  62      44.631  -5.896  35.414  1.00 72.05           C  
+ATOM   4620  O   ARG B  62      43.611  -5.415  34.914  1.00 71.32           O  
+ATOM   4621  CB  ARG B  62      45.280  -5.650  37.827  1.00 74.06           C  
+ATOM   4622  CG  ARG B  62      44.552  -4.360  38.123  1.00 75.32           C  
+ATOM   4623  CD  ARG B  62      45.264  -3.539  39.190  1.00 76.01           C  
+ATOM   4624  NE  ARG B  62      45.468  -4.257  40.452  1.00 77.41           N  
+ATOM   4625  CZ  ARG B  62      44.519  -4.913  41.120  1.00 77.77           C  
+ATOM   4626  NH1 ARG B  62      44.812  -5.523  42.262  1.00 76.34           N  
+ATOM   4627  NH2 ARG B  62      43.282  -4.980  40.644  1.00 78.41           N  
+ATOM   4628  N   LEU B  63      45.814  -5.880  34.803  1.00 69.95           N  
+ATOM   4629  CA  LEU B  63      45.994  -5.287  33.482  1.00 67.58           C  
+ATOM   4630  C   LEU B  63      45.035  -5.930  32.484  1.00 65.65           C  
+ATOM   4631  O   LEU B  63      44.383  -5.238  31.707  1.00 65.66           O  
+ATOM   4632  CB  LEU B  63      47.442  -5.469  33.009  1.00 67.61           C  
+ATOM   4633  CG  LEU B  63      48.027  -4.396  32.082  1.00 67.79           C  
+ATOM   4634  CD1 LEU B  63      49.465  -4.740  31.753  1.00 67.19           C  
+ATOM   4635  CD2 LEU B  63      47.209  -4.288  30.813  1.00 68.67           C  
+ATOM   4636  N   PRO B  64      44.938  -7.268  32.488  1.00 64.11           N  
+ATOM   4637  CA  PRO B  64      44.022  -7.916  31.546  1.00 62.48           C  
+ATOM   4638  C   PRO B  64      42.569  -7.545  31.845  1.00 61.11           C  
+ATOM   4639  O   PRO B  64      41.688  -7.692  30.992  1.00 58.69           O  
+ATOM   4640  CB  PRO B  64      44.304  -9.402  31.761  1.00 62.64           C  
+ATOM   4641  CG  PRO B  64      44.697  -9.459  33.203  1.00 62.51           C  
+ATOM   4642  CD  PRO B  64      45.622  -8.273  33.320  1.00 63.48           C  
+ATOM   4643  N   ARG B  65      42.322  -7.070  33.063  1.00 58.74           N  
+ATOM   4644  CA  ARG B  65      40.977  -6.679  33.451  1.00 56.79           C  
+ATOM   4645  C   ARG B  65      40.707  -5.243  33.014  1.00 55.64           C  
+ATOM   4646  O   ARG B  65      39.606  -4.914  32.576  1.00 55.34           O  
+ATOM   4647  CB  ARG B  65      40.786  -6.813  34.962  1.00 56.42           C  
+ATOM   4648  CG  ARG B  65      39.459  -6.253  35.441  1.00 55.67           C  
+ATOM   4649  CD  ARG B  65      39.056  -6.808  36.775  1.00 54.04           C  
+ATOM   4650  NE  ARG B  65      37.848  -6.163  37.274  1.00 54.16           N  
+ATOM   4651  CZ  ARG B  65      37.126  -6.621  38.290  1.00 53.41           C  
+ATOM   4652  NH1 ARG B  65      37.490  -7.734  38.912  1.00 56.05           N  
+ATOM   4653  NH2 ARG B  65      36.047  -5.966  38.688  1.00 52.02           N  
+ATOM   4654  N   ILE B  66      41.718  -4.393  33.140  1.00 53.49           N  
+ATOM   4655  CA  ILE B  66      41.592  -3.004  32.733  1.00 52.37           C  
+ATOM   4656  C   ILE B  66      41.325  -2.986  31.230  1.00 52.51           C  
+ATOM   4657  O   ILE B  66      40.453  -2.257  30.747  1.00 52.68           O  
+ATOM   4658  CB  ILE B  66      42.889  -2.215  33.039  1.00 51.55           C  
+ATOM   4659  CG1 ILE B  66      43.027  -2.014  34.550  1.00 51.08           C  
+ATOM   4660  CG2 ILE B  66      42.880  -0.875  32.313  1.00 50.05           C  
+ATOM   4661  CD1 ILE B  66      44.299  -1.302  34.963  0.00 51.39           C  
+ATOM   4662  N   LEU B  67      42.076  -3.812  30.505  1.00 50.27           N  
+ATOM   4663  CA  LEU B  67      41.958  -3.917  29.057  1.00 49.01           C  
+ATOM   4664  C   LEU B  67      40.624  -4.504  28.608  1.00 48.07           C  
+ATOM   4665  O   LEU B  67      40.102  -4.131  27.554  1.00 48.11           O  
+ATOM   4666  CB  LEU B  67      43.110  -4.761  28.505  1.00 48.90           C  
+ATOM   4667  CG  LEU B  67      44.376  -4.054  28.002  1.00 51.19           C  
+ATOM   4668  CD1 LEU B  67      44.732  -2.856  28.864  1.00 52.78           C  
+ATOM   4669  CD2 LEU B  67      45.512  -5.059  27.979  1.00 51.13           C  
+ATOM   4670  N   THR B  68      40.077  -5.417  29.405  1.00 44.17           N  
+ATOM   4671  CA  THR B  68      38.804  -6.042  29.073  1.00 42.63           C  
+ATOM   4672  C   THR B  68      37.660  -5.041  29.220  1.00 41.74           C  
+ATOM   4673  O   THR B  68      36.771  -4.971  28.371  1.00 42.69           O  
+ATOM   4674  CB  THR B  68      38.514  -7.264  29.981  1.00 40.67           C  
+ATOM   4675  OG1 THR B  68      39.564  -8.230  29.838  1.00 43.75           O  
+ATOM   4676  CG2 THR B  68      37.191  -7.920  29.590  1.00 36.93           C  
+ATOM   4677  N   ALA B  69      37.693  -4.273  30.303  1.00 40.70           N  
+ATOM   4678  CA  ALA B  69      36.671  -3.276  30.576  1.00 41.42           C  
+ATOM   4679  C   ALA B  69      36.675  -2.207  29.481  1.00 41.86           C  
+ATOM   4680  O   ALA B  69      35.615  -1.773  29.023  1.00 40.31           O  
+ATOM   4681  CB  ALA B  69      36.917  -2.634  31.936  1.00 39.55           C  
+ATOM   4682  N   LEU B  70      37.871  -1.793  29.073  1.00 42.45           N  
+ATOM   4683  CA  LEU B  70      38.034  -0.784  28.032  1.00 42.54           C  
+ATOM   4684  C   LEU B  70      37.433  -1.260  26.713  1.00 41.93           C  
+ATOM   4685  O   LEU B  70      36.592  -0.582  26.122  1.00 40.42           O  
+ATOM   4686  CB  LEU B  70      39.521  -0.462  27.834  1.00 43.08           C  
+ATOM   4687  CG  LEU B  70      40.242   0.217  29.003  1.00 43.52           C  
+ATOM   4688  CD1 LEU B  70      41.726   0.294  28.707  1.00 44.36           C  
+ATOM   4689  CD2 LEU B  70      39.671   1.618  29.230  1.00 44.55           C  
+ATOM   4690  N   CYS B  71      37.854  -2.437  26.267  1.00 41.10           N  
+ATOM   4691  CA  CYS B  71      37.363  -2.989  25.015  1.00 41.95           C  
+ATOM   4692  C   CYS B  71      35.869  -3.268  25.035  1.00 42.24           C  
+ATOM   4693  O   CYS B  71      35.174  -3.030  24.041  1.00 41.60           O  
+ATOM   4694  CB  CYS B  71      38.114  -4.278  24.675  1.00 43.19           C  
+ATOM   4695  SG  CYS B  71      39.870  -4.033  24.304  1.00 50.88           S  
+ATOM   4696  N   VAL B  72      35.374  -3.784  26.158  1.00 40.51           N  
+ATOM   4697  CA  VAL B  72      33.954  -4.100  26.277  1.00 37.85           C  
+ATOM   4698  C   VAL B  72      33.112  -2.826  26.295  1.00 36.24           C  
+ATOM   4699  O   VAL B  72      32.029  -2.783  25.719  1.00 34.71           O  
+ATOM   4700  CB  VAL B  72      33.674  -4.948  27.556  1.00 38.66           C  
+ATOM   4701  CG1 VAL B  72      32.173  -4.958  27.885  1.00 33.72           C  
+ATOM   4702  CG2 VAL B  72      34.166  -6.384  27.333  1.00 35.38           C  
+ATOM   4703  N   GLY B  73      33.616  -1.791  26.957  1.00 34.66           N  
+ATOM   4704  CA  GLY B  73      32.890  -0.539  27.013  1.00 34.46           C  
+ATOM   4705  C   GLY B  73      32.798   0.056  25.620  1.00 34.21           C  
+ATOM   4706  O   GLY B  73      31.725   0.448  25.171  1.00 33.65           O  
+ATOM   4707  N   ALA B  74      33.936   0.097  24.936  1.00 33.38           N  
+ATOM   4708  CA  ALA B  74      34.022   0.626  23.586  1.00 34.47           C  
+ATOM   4709  C   ALA B  74      33.108  -0.140  22.635  1.00 35.49           C  
+ATOM   4710  O   ALA B  74      32.434   0.456  21.798  1.00 37.05           O  
+ATOM   4711  CB  ALA B  74      35.467   0.548  23.096  1.00 31.93           C  
+ATOM   4712  N   GLY B  75      33.086  -1.463  22.780  1.00 35.56           N  
+ATOM   4713  CA  GLY B  75      32.278  -2.304  21.919  1.00 34.21           C  
+ATOM   4714  C   GLY B  75      30.787  -2.185  22.143  1.00 34.03           C  
+ATOM   4715  O   GLY B  75      30.008  -2.274  21.194  1.00 34.67           O  
+ATOM   4716  N   LEU B  76      30.381  -1.999  23.394  1.00 33.57           N  
+ATOM   4717  CA  LEU B  76      28.964  -1.864  23.703  1.00 33.91           C  
+ATOM   4718  C   LEU B  76      28.477  -0.495  23.260  1.00 33.84           C  
+ATOM   4719  O   LEU B  76      27.371  -0.355  22.743  1.00 32.79           O  
+ATOM   4720  CB  LEU B  76      28.702  -2.042  25.205  1.00 33.57           C  
+ATOM   4721  CG  LEU B  76      28.631  -3.471  25.760  1.00 35.85           C  
+ATOM   4722  CD1 LEU B  76      28.396  -3.438  27.275  1.00 33.05           C  
+ATOM   4723  CD2 LEU B  76      27.503  -4.217  25.066  1.00 35.28           C  
+ATOM   4724  N   ALA B  77      29.306   0.518  23.472  1.00 33.40           N  
+ATOM   4725  CA  ALA B  77      28.940   1.866  23.078  1.00 35.63           C  
+ATOM   4726  C   ALA B  77      28.820   1.922  21.551  1.00 34.37           C  
+ATOM   4727  O   ALA B  77      27.902   2.536  21.017  1.00 33.22           O  
+ATOM   4728  CB  ALA B  77      29.991   2.863  23.568  1.00 34.12           C  
+ATOM   4729  N   LEU B  78      29.747   1.262  20.865  1.00 33.97           N  
+ATOM   4730  CA  LEU B  78      29.777   1.234  19.401  1.00 34.82           C  
+ATOM   4731  C   LEU B  78      28.499   0.623  18.827  1.00 33.44           C  
+ATOM   4732  O   LEU B  78      27.900   1.164  17.883  1.00 31.78           O  
+ATOM   4733  CB  LEU B  78      30.978   0.417  18.916  1.00 34.60           C  
+ATOM   4734  CG  LEU B  78      31.778   0.849  17.683  1.00 35.90           C  
+ATOM   4735  CD1 LEU B  78      32.364  -0.395  17.033  1.00 36.66           C  
+ATOM   4736  CD2 LEU B  78      30.913   1.591  16.685  1.00 36.85           C  
+ATOM   4737  N   SER B  79      28.101  -0.514  19.390  1.00 32.49           N  
+ATOM   4738  CA  SER B  79      26.895  -1.214  18.953  1.00 33.66           C  
+ATOM   4739  C   SER B  79      25.684  -0.333  19.169  1.00 29.03           C  
+ATOM   4740  O   SER B  79      24.784  -0.277  18.336  1.00 29.97           O  
+ATOM   4741  CB  SER B  79      26.708  -2.515  19.741  1.00 35.30           C  
+ATOM   4742  OG  SER B  79      27.785  -3.400  19.506  1.00 44.04           O  
+ATOM   4743  N   GLY B  80      25.671   0.346  20.304  1.00 26.59           N  
+ATOM   4744  CA  GLY B  80      24.569   1.224  20.628  1.00 29.45           C  
+ATOM   4745  C   GLY B  80      24.407   2.353  19.622  1.00 30.28           C  
+ATOM   4746  O   GLY B  80      23.317   2.556  19.092  1.00 30.47           O  
+ATOM   4747  N   VAL B  81      25.487   3.080  19.346  1.00 29.29           N  
+ATOM   4748  CA  VAL B  81      25.413   4.192  18.415  1.00 30.34           C  
+ATOM   4749  C   VAL B  81      25.068   3.770  16.974  1.00 31.44           C  
+ATOM   4750  O   VAL B  81      24.285   4.452  16.304  1.00 31.77           O  
+ATOM   4751  CB  VAL B  81      26.733   5.026  18.441  1.00 30.81           C  
+ATOM   4752  CG1 VAL B  81      27.889   4.218  17.878  1.00 33.14           C  
+ATOM   4753  CG2 VAL B  81      26.551   6.321  17.656  1.00 31.11           C  
+ATOM   4754  N   VAL B  82      25.615   2.651  16.497  1.00 30.20           N  
+ATOM   4755  CA  VAL B  82      25.315   2.230  15.129  1.00 32.19           C  
+ATOM   4756  C   VAL B  82      23.878   1.748  15.007  1.00 32.58           C  
+ATOM   4757  O   VAL B  82      23.246   1.932  13.962  1.00 34.48           O  
+ATOM   4758  CB  VAL B  82      26.283   1.119  14.596  1.00 32.90           C  
+ATOM   4759  CG1 VAL B  82      27.731   1.600  14.676  1.00 31.09           C  
+ATOM   4760  CG2 VAL B  82      26.089  -0.174  15.370  1.00 36.47           C  
+ATOM   4761  N   LEU B  83      23.354   1.147  16.071  1.00 30.90           N  
+ATOM   4762  CA  LEU B  83      21.973   0.681  16.051  1.00 31.10           C  
+ATOM   4763  C   LEU B  83      21.016   1.866  16.115  1.00 29.20           C  
+ATOM   4764  O   LEU B  83      19.947   1.846  15.508  1.00 30.02           O  
+ATOM   4765  CB  LEU B  83      21.703  -0.291  17.209  1.00 31.17           C  
+ATOM   4766  CG  LEU B  83      22.400  -1.649  17.046  1.00 33.34           C  
+ATOM   4767  CD1 LEU B  83      22.018  -2.582  18.198  1.00 32.86           C  
+ATOM   4768  CD2 LEU B  83      22.004  -2.258  15.702  1.00 30.02           C  
+ATOM   4769  N   GLN B  84      21.394   2.896  16.859  1.00 26.68           N  
+ATOM   4770  CA  GLN B  84      20.565   4.084  16.944  1.00 30.55           C  
+ATOM   4771  C   GLN B  84      20.514   4.744  15.558  1.00 32.03           C  
+ATOM   4772  O   GLN B  84      19.502   5.327  15.181  1.00 31.44           O  
+ATOM   4773  CB  GLN B  84      21.128   5.049  17.983  1.00 27.92           C  
+ATOM   4774  CG  GLN B  84      21.086   4.478  19.369  1.00 31.44           C  
+ATOM   4775  CD  GLN B  84      21.582   5.436  20.422  1.00 32.52           C  
+ATOM   4776  OE1 GLN B  84      21.597   5.105  21.603  1.00 37.55           O  
+ATOM   4777  NE2 GLN B  84      21.990   6.624  20.008  1.00 30.26           N  
+ATOM   4778  N   GLY B  85      21.613   4.631  14.808  1.00 33.43           N  
+ATOM   4779  CA  GLY B  85      21.665   5.177  13.463  1.00 33.59           C  
+ATOM   4780  C   GLY B  85      20.792   4.375  12.506  1.00 34.41           C  
+ATOM   4781  O   GLY B  85      20.079   4.956  11.689  1.00 33.33           O  
+ATOM   4782  N   ILE B  86      20.842   3.045  12.602  1.00 34.91           N  
+ATOM   4783  CA  ILE B  86      20.028   2.183  11.740  1.00 36.49           C  
+ATOM   4784  C   ILE B  86      18.546   2.427  11.992  1.00 35.40           C  
+ATOM   4785  O   ILE B  86      17.765   2.607  11.056  1.00 34.93           O  
+ATOM   4786  CB  ILE B  86      20.291   0.666  11.989  1.00 40.23           C  
+ATOM   4787  CG1 ILE B  86      21.653   0.256  11.422  1.00 40.19           C  
+ATOM   4788  CG2 ILE B  86      19.188  -0.166  11.343  1.00 40.03           C  
+ATOM   4789  CD1 ILE B  86      21.976  -1.212  11.615  0.00 40.14           C  
+ATOM   4790  N   PHE B  87      18.162   2.447  13.262  1.00 33.92           N  
+ATOM   4791  CA  PHE B  87      16.766   2.647  13.612  1.00 35.30           C  
+ATOM   4792  C   PHE B  87      16.330   4.096  13.721  1.00 35.19           C  
+ATOM   4793  O   PHE B  87      15.194   4.376  14.083  1.00 35.55           O  
+ATOM   4794  CB  PHE B  87      16.436   1.885  14.902  1.00 34.31           C  
+ATOM   4795  CG  PHE B  87      16.454   0.394  14.726  1.00 35.25           C  
+ATOM   4796  CD1 PHE B  87      17.628  -0.331  14.917  1.00 34.87           C  
+ATOM   4797  CD2 PHE B  87      15.315  -0.278  14.277  1.00 36.48           C  
+ATOM   4798  CE1 PHE B  87      17.674  -1.705  14.656  1.00 36.80           C  
+ATOM   4799  CE2 PHE B  87      15.346  -1.653  14.012  1.00 37.37           C  
+ATOM   4800  CZ  PHE B  87      16.529  -2.367  14.200  1.00 37.56           C  
+ATOM   4801  N   ARG B  88      17.231   5.017  13.397  1.00 37.61           N  
+ATOM   4802  CA  ARG B  88      16.911   6.438  13.440  1.00 39.27           C  
+ATOM   4803  C   ARG B  88      16.216   6.782  14.756  1.00 41.00           C  
+ATOM   4804  O   ARG B  88      15.299   7.604  14.797  1.00 41.67           O  
+ATOM   4805  CB  ARG B  88      16.004   6.803  12.255  1.00 37.62           C  
+ATOM   4806  CG  ARG B  88      16.485   6.251  10.920  1.00 41.35           C  
+ATOM   4807  CD  ARG B  88      15.927   7.052   9.754  1.00 47.53           C  
+ATOM   4808  NE  ARG B  88      14.805   6.391   9.100  1.00 50.94           N  
+ATOM   4809  CZ  ARG B  88      14.884   5.795   7.915  1.00 54.16           C  
+ATOM   4810  NH1 ARG B  88      13.812   5.210   7.394  1.00 57.24           N  
+ATOM   4811  NH2 ARG B  88      16.029   5.790   7.243  1.00 54.11           N  
+ATOM   4812  N   ASN B  89      16.665   6.156  15.837  1.00 42.98           N  
+ATOM   4813  CA  ASN B  89      16.071   6.395  17.146  1.00 44.23           C  
+ATOM   4814  C   ASN B  89      17.149   6.386  18.224  1.00 43.90           C  
+ATOM   4815  O   ASN B  89      17.934   5.447  18.324  1.00 41.90           O  
+ATOM   4816  CB  ASN B  89      15.019   5.321  17.431  1.00 46.49           C  
+ATOM   4817  CG  ASN B  89      14.224   5.594  18.697  1.00 50.92           C  
+ATOM   4818  OD1 ASN B  89      13.333   4.820  19.059  1.00 54.52           O  
+ATOM   4819  ND2 ASN B  89      14.537   6.692  19.378  1.00 50.75           N  
+ATOM   4820  N   PRO B  90      17.211   7.450  19.037  1.00 45.84           N  
+ATOM   4821  CA  PRO B  90      18.210   7.545  20.107  1.00 46.74           C  
+ATOM   4822  C   PRO B  90      17.908   6.702  21.349  1.00 47.92           C  
+ATOM   4823  O   PRO B  90      18.739   6.608  22.248  1.00 48.01           O  
+ATOM   4824  CB  PRO B  90      18.243   9.040  20.413  1.00 46.94           C  
+ATOM   4825  CG  PRO B  90      16.823   9.460  20.151  1.00 47.97           C  
+ATOM   4826  CD  PRO B  90      16.504   8.734  18.858  1.00 47.04           C  
+ATOM   4827  N   LEU B  91      16.730   6.086  21.394  1.00 49.62           N  
+ATOM   4828  CA  LEU B  91      16.353   5.265  22.541  1.00 51.13           C  
+ATOM   4829  C   LEU B  91      16.558   3.785  22.281  1.00 51.28           C  
+ATOM   4830  O   LEU B  91      16.079   2.939  23.027  1.00 53.39           O  
+ATOM   4831  CB  LEU B  91      14.900   5.531  22.934  1.00 50.95           C  
+ATOM   4832  CG  LEU B  91      14.685   6.977  23.389  1.00 52.67           C  
+ATOM   4833  CD1 LEU B  91      13.224   7.205  23.737  1.00 53.46           C  
+ATOM   4834  CD2 LEU B  91      15.580   7.272  24.585  1.00 52.69           C  
+ATOM   4835  N   VAL B  92      17.285   3.483  21.217  1.00 51.09           N  
+ATOM   4836  CA  VAL B  92      17.585   2.109  20.847  1.00 50.44           C  
+ATOM   4837  C   VAL B  92      18.912   1.721  21.493  1.00 51.13           C  
+ATOM   4838  O   VAL B  92      19.757   2.575  21.748  1.00 52.24           O  
+ATOM   4839  CB  VAL B  92      17.676   1.974  19.298  1.00 48.55           C  
+ATOM   4840  CG1 VAL B  92      18.599   0.839  18.901  1.00 47.18           C  
+ATOM   4841  CG2 VAL B  92      16.294   1.742  18.730  1.00 47.84           C  
+ATOM   4842  N   ASN B  93      19.085   0.436  21.774  1.00 51.16           N  
+ATOM   4843  CA  ASN B  93      20.319  -0.047  22.375  1.00 52.01           C  
+ATOM   4844  C   ASN B  93      20.672  -1.385  21.754  1.00 52.03           C  
+ATOM   4845  O   ASN B  93      19.888  -1.942  20.989  1.00 51.74           O  
+ATOM   4846  CB  ASN B  93      20.170  -0.170  23.895  1.00 52.33           C  
+ATOM   4847  CG  ASN B  93      18.962  -0.984  24.304  1.00 53.79           C  
+ATOM   4848  OD1 ASN B  93      18.912  -2.198  24.106  1.00 51.72           O  
+ATOM   4849  ND2 ASN B  93      17.973  -0.312  24.879  1.00 56.21           N  
+ATOM   4850  N   PRO B  94      21.860  -1.920  22.068  1.00 53.23           N  
+ATOM   4851  CA  PRO B  94      22.265  -3.207  21.495  1.00 54.00           C  
+ATOM   4852  C   PRO B  94      21.383  -4.413  21.805  1.00 54.85           C  
+ATOM   4853  O   PRO B  94      21.658  -5.508  21.330  1.00 56.36           O  
+ATOM   4854  CB  PRO B  94      23.694  -3.379  22.010  1.00 52.89           C  
+ATOM   4855  CG  PRO B  94      23.701  -2.606  23.289  1.00 53.22           C  
+ATOM   4856  CD  PRO B  94      22.915  -1.375  22.942  1.00 52.57           C  
+ATOM   4857  N   HIS B  95      20.307  -4.217  22.560  1.00 56.48           N  
+ATOM   4858  CA  HIS B  95      19.441  -5.336  22.923  1.00 57.12           C  
+ATOM   4859  C   HIS B  95      18.027  -5.312  22.339  1.00 57.74           C  
+ATOM   4860  O   HIS B  95      17.132  -5.965  22.874  1.00 58.25           O  
+ATOM   4861  CB  HIS B  95      19.335  -5.437  24.450  1.00 59.47           C  
+ATOM   4862  CG  HIS B  95      20.595  -5.067  25.173  1.00 61.88           C  
+ATOM   4863  ND1 HIS B  95      21.828  -5.584  24.838  1.00 63.09           N  
+ATOM   4864  CD2 HIS B  95      20.812  -4.221  26.208  1.00 62.11           C  
+ATOM   4865  CE1 HIS B  95      22.750  -5.072  25.633  1.00 63.08           C  
+ATOM   4866  NE2 HIS B  95      22.160  -4.241  26.474  1.00 62.41           N  
+ATOM   4867  N   ILE B  96      17.808  -4.575  21.255  1.00 57.16           N  
+ATOM   4868  CA  ILE B  96      16.467  -4.527  20.671  1.00 57.52           C  
+ATOM   4869  C   ILE B  96      16.341  -5.495  19.503  1.00 55.96           C  
+ATOM   4870  O   ILE B  96      15.244  -5.756  19.011  1.00 55.98           O  
+ATOM   4871  CB  ILE B  96      16.099  -3.112  20.156  1.00 59.11           C  
+ATOM   4872  CG1 ILE B  96      16.965  -2.752  18.946  1.00 59.30           C  
+ATOM   4873  CG2 ILE B  96      16.263  -2.092  21.278  1.00 60.18           C  
+ATOM   4874  CD1 ILE B  96      16.475  -1.545  18.184  0.00 59.17           C  
+ATOM   4875  N   ILE B  97      17.475  -6.023  19.065  1.00 54.19           N  
+ATOM   4876  CA  ILE B  97      17.498  -6.951  17.950  1.00 54.35           C  
+ATOM   4877  C   ILE B  97      17.426  -8.404  18.450  1.00 53.21           C  
+ATOM   4878  O   ILE B  97      17.352  -9.344  17.660  1.00 51.88           O  
+ATOM   4879  CB  ILE B  97      18.771  -6.705  17.093  1.00 55.53           C  
+ATOM   4880  CG1 ILE B  97      18.766  -7.610  15.860  1.00 56.77           C  
+ATOM   4881  CG2 ILE B  97      20.019  -6.902  17.946  1.00 55.98           C  
+ATOM   4882  CD1 ILE B  97      17.614  -7.351  14.914  0.00 56.19           C  
+ATOM   4883  N   GLY B  98      17.443  -8.569  19.771  1.00 52.39           N  
+ATOM   4884  CA  GLY B  98      17.353  -9.889  20.376  1.00 51.31           C  
+ATOM   4885  C   GLY B  98      18.626 -10.712  20.504  1.00 50.90           C  
+ATOM   4886  O   GLY B  98      18.577 -11.829  21.011  1.00 51.46           O  
+ATOM   4887  N   VAL B  99      19.761 -10.171  20.067  1.00 49.69           N  
+ATOM   4888  CA  VAL B  99      21.034 -10.893  20.118  1.00 48.94           C  
+ATOM   4889  C   VAL B  99      21.554 -11.194  21.518  1.00 49.70           C  
+ATOM   4890  O   VAL B  99      22.204 -12.215  21.740  1.00 50.58           O  
+ATOM   4891  CB  VAL B  99      22.133 -10.132  19.356  1.00 47.72           C  
+ATOM   4892  CG1 VAL B  99      23.429 -10.917  19.378  1.00 46.29           C  
+ATOM   4893  CG2 VAL B  99      21.694  -9.905  17.927  1.00 50.23           C  
+ATOM   4894  N   THR B 100      21.285 -10.303  22.461  1.00 49.52           N  
+ATOM   4895  CA  THR B 100      21.742 -10.506  23.825  1.00 49.32           C  
+ATOM   4896  C   THR B 100      20.976 -11.648  24.489  1.00 49.11           C  
+ATOM   4897  O   THR B 100      21.538 -12.399  25.287  1.00 49.24           O  
+ATOM   4898  CB  THR B 100      21.597  -9.215  24.650  1.00 49.63           C  
+ATOM   4899  OG1 THR B 100      20.265  -8.700  24.522  1.00 53.04           O  
+ATOM   4900  CG2 THR B 100      22.571  -8.177  24.152  1.00 51.79           C  
+ATOM   4901  N   SER B 101      19.696 -11.781  24.160  1.00 47.84           N  
+ATOM   4902  CA  SER B 101      18.891 -12.857  24.717  1.00 48.53           C  
+ATOM   4903  C   SER B 101      19.350 -14.197  24.149  1.00 48.15           C  
+ATOM   4904  O   SER B 101      19.592 -15.139  24.895  1.00 49.27           O  
+ATOM   4905  CB  SER B 101      17.412 -12.639  24.404  1.00 46.57           C  
+ATOM   4906  OG  SER B 101      16.885 -11.627  25.239  1.00 49.74           O  
+ATOM   4907  N   GLY B 102      19.473 -14.272  22.828  1.00 47.27           N  
+ATOM   4908  CA  GLY B 102      19.917 -15.500  22.199  1.00 48.54           C  
+ATOM   4909  C   GLY B 102      21.270 -15.918  22.746  1.00 49.89           C  
+ATOM   4910  O   GLY B 102      21.477 -17.082  23.092  1.00 49.15           O  
+ATOM   4911  N   SER B 103      22.195 -14.965  22.828  1.00 49.19           N  
+ATOM   4912  CA  SER B 103      23.528 -15.248  23.346  1.00 49.30           C  
+ATOM   4913  C   SER B 103      23.426 -15.750  24.773  1.00 49.35           C  
+ATOM   4914  O   SER B 103      24.096 -16.711  25.146  1.00 48.37           O  
+ATOM   4915  CB  SER B 103      24.405 -13.992  23.313  1.00 49.29           C  
+ATOM   4916  OG  SER B 103      24.677 -13.582  21.983  1.00 51.42           O  
+ATOM   4917  N   ALA B 104      22.588 -15.088  25.568  1.00 49.30           N  
+ATOM   4918  CA  ALA B 104      22.398 -15.464  26.961  1.00 49.69           C  
+ATOM   4919  C   ALA B 104      21.949 -16.916  27.026  1.00 50.82           C  
+ATOM   4920  O   ALA B 104      22.425 -17.682  27.857  1.00 49.00           O  
+ATOM   4921  CB  ALA B 104      21.361 -14.562  27.616  1.00 49.95           C  
+ATOM   4922  N   PHE B 105      21.031 -17.288  26.141  1.00 51.22           N  
+ATOM   4923  CA  PHE B 105      20.543 -18.656  26.100  1.00 54.26           C  
+ATOM   4924  C   PHE B 105      21.665 -19.629  25.726  1.00 55.31           C  
+ATOM   4925  O   PHE B 105      21.834 -20.666  26.366  1.00 56.59           O  
+ATOM   4926  CB  PHE B 105      19.402 -18.793  25.094  1.00 53.51           C  
+ATOM   4927  CG  PHE B 105      18.963 -20.213  24.882  1.00 55.55           C  
+ATOM   4928  CD1 PHE B 105      18.434 -20.956  25.936  1.00 55.59           C  
+ATOM   4929  CD2 PHE B 105      19.104 -20.820  23.639  1.00 55.73           C  
+ATOM   4930  CE1 PHE B 105      18.051 -22.285  25.753  1.00 54.56           C  
+ATOM   4931  CE2 PHE B 105      18.724 -22.151  23.445  1.00 56.16           C  
+ATOM   4932  CZ  PHE B 105      18.197 -22.883  24.503  1.00 55.13           C  
+ATOM   4933  N   GLY B 106      22.421 -19.290  24.685  1.00 55.92           N  
+ATOM   4934  CA  GLY B 106      23.513 -20.139  24.246  1.00 55.68           C  
+ATOM   4935  C   GLY B 106      24.502 -20.410  25.363  1.00 56.75           C  
+ATOM   4936  O   GLY B 106      24.956 -21.542  25.545  1.00 56.30           O  
+ATOM   4937  N   GLY B 107      24.838 -19.369  26.115  1.00 55.90           N  
+ATOM   4938  CA  GLY B 107      25.771 -19.529  27.211  1.00 57.28           C  
+ATOM   4939  C   GLY B 107      25.141 -20.264  28.377  1.00 58.70           C  
+ATOM   4940  O   GLY B 107      25.840 -20.915  29.154  1.00 60.35           O  
+ATOM   4941  N   THR B 108      23.822 -20.149  28.513  1.00 58.27           N  
+ATOM   4942  CA  THR B 108      23.102 -20.825  29.586  1.00 58.06           C  
+ATOM   4943  C   THR B 108      22.974 -22.302  29.225  1.00 58.51           C  
+ATOM   4944  O   THR B 108      23.151 -23.175  30.071  1.00 58.23           O  
+ATOM   4945  CB  THR B 108      21.686 -20.236  29.790  1.00 57.07           C  
+ATOM   4946  OG1 THR B 108      21.790 -18.910  30.321  1.00 58.37           O  
+ATOM   4947  CG2 THR B 108      20.884 -21.093  30.765  1.00 56.84           C  
+ATOM   4948  N   LEU B 109      22.672 -22.570  27.959  1.00 58.20           N  
+ATOM   4949  CA  LEU B 109      22.528 -23.933  27.478  1.00 59.06           C  
+ATOM   4950  C   LEU B 109      23.849 -24.666  27.686  1.00 60.45           C  
+ATOM   4951  O   LEU B 109      23.865 -25.863  27.964  1.00 60.94           O  
+ATOM   4952  CB  LEU B 109      22.168 -23.929  25.991  1.00 59.44           C  
+ATOM   4953  CG  LEU B 109      21.720 -25.245  25.347  1.00 60.03           C  
+ATOM   4954  CD1 LEU B 109      20.388 -25.682  25.940  1.00 60.16           C  
+ATOM   4955  CD2 LEU B 109      21.585 -25.058  23.838  1.00 59.77           C  
+ATOM   4956  N   ALA B 110      24.953 -23.934  27.563  1.00 60.23           N  
+ATOM   4957  CA  ALA B 110      26.284 -24.507  27.731  1.00 61.52           C  
+ATOM   4958  C   ALA B 110      26.603 -24.842  29.188  1.00 62.37           C  
+ATOM   4959  O   ALA B 110      27.199 -25.879  29.471  1.00 63.38           O  
+ATOM   4960  CB  ALA B 110      27.340 -23.556  27.170  1.00 59.45           C  
+ATOM   4961  N   ILE B 111      26.221 -23.965  30.110  1.00 62.92           N  
+ATOM   4962  CA  ILE B 111      26.478 -24.211  31.526  1.00 63.90           C  
+ATOM   4963  C   ILE B 111      25.658 -25.411  31.986  1.00 65.44           C  
+ATOM   4964  O   ILE B 111      26.143 -26.271  32.724  1.00 65.89           O  
+ATOM   4965  CB  ILE B 111      26.092 -22.993  32.390  1.00 64.10           C  
+ATOM   4966  CG1 ILE B 111      27.038 -21.823  32.094  1.00 64.02           C  
+ATOM   4967  CG2 ILE B 111      26.129 -23.369  33.868  1.00 62.18           C  
+ATOM   4968  CD1 ILE B 111      26.708 -20.558  32.859  0.00 64.14           C  
+ATOM   4969  N   PHE B 112      24.410 -25.454  31.538  1.00 66.23           N  
+ATOM   4970  CA  PHE B 112      23.495 -26.530  31.883  1.00 66.75           C  
+ATOM   4971  C   PHE B 112      24.099 -27.881  31.507  1.00 67.65           C  
+ATOM   4972  O   PHE B 112      23.926 -28.864  32.222  1.00 67.53           O  
+ATOM   4973  CB  PHE B 112      22.161 -26.304  31.163  1.00 66.33           C  
+ATOM   4974  CG  PHE B 112      21.134 -27.362  31.424  1.00 65.27           C  
+ATOM   4975  CD1 PHE B 112      20.982 -28.431  30.549  1.00 65.92           C  
+ATOM   4976  CD2 PHE B 112      20.306 -27.284  32.537  1.00 66.21           C  
+ATOM   4977  CE1 PHE B 112      20.016 -29.408  30.777  1.00 65.86           C  
+ATOM   4978  CE2 PHE B 112      19.336 -28.257  32.777  1.00 66.65           C  
+ATOM   4979  CZ  PHE B 112      19.191 -29.320  31.893  1.00 66.42           C  
+ATOM   4980  N   PHE B 113      24.819 -27.922  30.391  1.00 68.29           N  
+ATOM   4981  CA  PHE B 113      25.445 -29.160  29.941  1.00 69.34           C  
+ATOM   4982  C   PHE B 113      26.931 -29.220  30.306  1.00 69.69           C  
+ATOM   4983  O   PHE B 113      27.681 -30.035  29.769  1.00 69.84           O  
+ATOM   4984  CB  PHE B 113      25.268 -29.325  28.430  1.00 69.49           C  
+ATOM   4985  CG  PHE B 113      23.846 -29.577  28.009  1.00 70.81           C  
+ATOM   4986  CD1 PHE B 113      23.125 -30.637  28.548  1.00 71.83           C  
+ATOM   4987  CD2 PHE B 113      23.231 -28.763  27.064  1.00 71.71           C  
+ATOM   4988  CE1 PHE B 113      21.812 -30.883  28.152  1.00 72.39           C  
+ATOM   4989  CE2 PHE B 113      21.919 -28.999  26.661  1.00 72.13           C  
+ATOM   4990  CZ  PHE B 113      21.208 -30.061  27.206  1.00 72.89           C  
+ATOM   4991  N   GLY B 114      27.343 -28.349  31.221  1.00 69.71           N  
+ATOM   4992  CA  GLY B 114      28.725 -28.317  31.666  1.00 69.59           C  
+ATOM   4993  C   GLY B 114      29.811 -28.258  30.606  1.00 70.23           C  
+ATOM   4994  O   GLY B 114      30.870 -28.857  30.783  1.00 71.23           O  
+ATOM   4995  N   PHE B 115      29.570 -27.545  29.509  1.00 69.99           N  
+ATOM   4996  CA  PHE B 115      30.577 -27.422  28.454  1.00 69.99           C  
+ATOM   4997  C   PHE B 115      31.842 -26.764  29.002  1.00 69.67           C  
+ATOM   4998  O   PHE B 115      31.854 -26.239  30.117  1.00 68.02           O  
+ATOM   4999  CB  PHE B 115      30.060 -26.558  27.297  1.00 71.25           C  
+ATOM   5000  CG  PHE B 115      28.949 -27.181  26.504  1.00 72.78           C  
+ATOM   5001  CD1 PHE B 115      28.317 -26.452  25.497  1.00 73.15           C  
+ATOM   5002  CD2 PHE B 115      28.537 -28.489  26.746  1.00 72.76           C  
+ATOM   5003  CE1 PHE B 115      27.292 -27.013  24.740  1.00 74.06           C  
+ATOM   5004  CE2 PHE B 115      27.509 -29.064  25.993  1.00 73.88           C  
+ATOM   5005  CZ  PHE B 115      26.886 -28.324  24.988  1.00 74.50           C  
+ATOM   5006  N   SER B 116      32.905 -26.791  28.204  1.00 70.33           N  
+ATOM   5007  CA  SER B 116      34.168 -26.172  28.587  1.00 71.53           C  
+ATOM   5008  C   SER B 116      34.076 -24.670  28.303  1.00 72.64           C  
+ATOM   5009  O   SER B 116      33.136 -24.216  27.650  1.00 72.39           O  
+ATOM   5010  CB  SER B 116      35.314 -26.783  27.783  1.00 70.97           C  
+ATOM   5011  OG  SER B 116      35.023 -26.751  26.396  1.00 71.60           O  
+ATOM   5012  N   LEU B 117      35.051 -23.907  28.788  1.00 73.26           N  
+ATOM   5013  CA  LEU B 117      35.060 -22.462  28.586  1.00 73.32           C  
+ATOM   5014  C   LEU B 117      34.866 -22.114  27.112  1.00 73.36           C  
+ATOM   5015  O   LEU B 117      34.132 -21.182  26.774  1.00 73.56           O  
+ATOM   5016  CB  LEU B 117      36.380 -21.862  29.077  1.00 74.52           C  
+ATOM   5017  CG  LEU B 117      36.300 -20.519  29.816  1.00 75.67           C  
+ATOM   5018  CD1 LEU B 117      37.703 -19.947  30.000  1.00 75.29           C  
+ATOM   5019  CD2 LEU B 117      35.437 -19.548  29.040  1.00 74.92           C  
+ATOM   5020  N   TYR B 118      35.522 -22.868  26.236  1.00 72.78           N  
+ATOM   5021  CA  TYR B 118      35.414 -22.626  24.803  1.00 72.57           C  
+ATOM   5022  C   TYR B 118      34.089 -23.136  24.259  1.00 70.35           C  
+ATOM   5023  O   TYR B 118      33.613 -22.671  23.224  1.00 70.29           O  
+ATOM   5024  CB  TYR B 118      36.581 -23.283  24.061  1.00 75.96           C  
+ATOM   5025  CG  TYR B 118      37.933 -22.752  24.488  1.00 80.26           C  
+ATOM   5026  CD1 TYR B 118      38.517 -23.155  25.692  1.00 82.25           C  
+ATOM   5027  CD2 TYR B 118      38.616 -21.821  23.705  1.00 82.29           C  
+ATOM   5028  CE1 TYR B 118      39.750 -22.643  26.106  1.00 83.62           C  
+ATOM   5029  CE2 TYR B 118      39.848 -21.301  24.109  1.00 84.45           C  
+ATOM   5030  CZ  TYR B 118      40.410 -21.716  25.309  1.00 84.29           C  
+ATOM   5031  OH  TYR B 118      41.627 -21.206  25.708  1.00 84.69           O  
+ATOM   5032  N   GLY B 119      33.498 -24.098  24.958  1.00 68.09           N  
+ATOM   5033  CA  GLY B 119      32.217 -24.626  24.534  1.00 64.87           C  
+ATOM   5034  C   GLY B 119      31.175 -23.555  24.794  1.00 62.71           C  
+ATOM   5035  O   GLY B 119      30.184 -23.436  24.073  1.00 61.91           O  
+ATOM   5036  N   LEU B 120      31.413 -22.771  25.841  1.00 60.81           N  
+ATOM   5037  CA  LEU B 120      30.521 -21.685  26.216  1.00 59.27           C  
+ATOM   5038  C   LEU B 120      30.637 -20.580  25.168  1.00 58.69           C  
+ATOM   5039  O   LEU B 120      29.628 -20.061  24.691  1.00 58.04           O  
+ATOM   5040  CB  LEU B 120      30.895 -21.159  27.605  1.00 58.45           C  
+ATOM   5041  CG  LEU B 120      30.103 -19.962  28.136  1.00 58.70           C  
+ATOM   5042  CD1 LEU B 120      30.115 -19.963  29.655  1.00 56.61           C  
+ATOM   5043  CD2 LEU B 120      30.697 -18.675  27.584  1.00 57.48           C  
+ATOM   5044  N   PHE B 121      31.871 -20.238  24.810  1.00 57.40           N  
+ATOM   5045  CA  PHE B 121      32.134 -19.216  23.802  1.00 56.79           C  
+ATOM   5046  C   PHE B 121      31.398 -19.533  22.508  1.00 58.12           C  
+ATOM   5047  O   PHE B 121      30.622 -18.724  21.997  1.00 58.37           O  
+ATOM   5048  CB  PHE B 121      33.626 -19.151  23.475  1.00 55.65           C  
+ATOM   5049  CG  PHE B 121      34.475 -18.582  24.568  1.00 55.00           C  
+ATOM   5050  CD1 PHE B 121      35.860 -18.618  24.463  1.00 55.59           C  
+ATOM   5051  CD2 PHE B 121      33.903 -17.990  25.685  1.00 55.36           C  
+ATOM   5052  CE1 PHE B 121      36.666 -18.072  25.455  1.00 55.18           C  
+ATOM   5053  CE2 PHE B 121      34.700 -17.439  26.683  1.00 55.58           C  
+ATOM   5054  CZ  PHE B 121      36.085 -17.481  26.566  1.00 55.45           C  
+ATOM   5055  N   THR B 122      31.664 -20.721  21.978  1.00 58.58           N  
+ATOM   5056  CA  THR B 122      31.066 -21.153  20.725  1.00 58.07           C  
+ATOM   5057  C   THR B 122      29.540 -21.234  20.764  1.00 56.27           C  
+ATOM   5058  O   THR B 122      28.874 -20.897  19.782  1.00 55.00           O  
+ATOM   5059  CB  THR B 122      31.666 -22.517  20.279  1.00 59.14           C  
+ATOM   5060  OG1 THR B 122      30.968 -22.999  19.124  1.00 60.77           O  
+ATOM   5061  CG2 THR B 122      31.562 -23.539  21.394  1.00 61.47           C  
+ATOM   5062  N   SER B 123      28.985 -21.665  21.893  1.00 55.12           N  
+ATOM   5063  CA  SER B 123      27.534 -21.776  22.019  1.00 54.09           C  
+ATOM   5064  C   SER B 123      26.886 -20.393  22.085  1.00 53.07           C  
+ATOM   5065  O   SER B 123      25.883 -20.135  21.422  1.00 53.11           O  
+ATOM   5066  CB  SER B 123      27.162 -22.582  23.268  1.00 54.31           C  
+ATOM   5067  OG  SER B 123      25.765 -22.843  23.302  1.00 52.72           O  
+ATOM   5068  N   THR B 124      27.463 -19.512  22.894  1.00 52.03           N  
+ATOM   5069  CA  THR B 124      26.960 -18.152  23.038  1.00 51.87           C  
+ATOM   5070  C   THR B 124      26.923 -17.483  21.667  1.00 53.06           C  
+ATOM   5071  O   THR B 124      25.880 -16.999  21.215  1.00 50.92           O  
+ATOM   5072  CB  THR B 124      27.880 -17.315  23.948  1.00 52.10           C  
+ATOM   5073  OG1 THR B 124      27.974 -17.933  25.237  1.00 48.90           O  
+ATOM   5074  CG2 THR B 124      27.335 -15.892  24.096  1.00 50.58           C  
+ATOM   5075  N   ILE B 125      28.081 -17.470  21.016  1.00 53.52           N  
+ATOM   5076  CA  ILE B 125      28.238 -16.873  19.700  1.00 54.74           C  
+ATOM   5077  C   ILE B 125      27.331 -17.520  18.659  1.00 55.94           C  
+ATOM   5078  O   ILE B 125      26.726 -16.830  17.839  1.00 55.80           O  
+ATOM   5079  CB  ILE B 125      29.709 -16.980  19.228  1.00 55.79           C  
+ATOM   5080  CG1 ILE B 125      30.604 -16.107  20.115  1.00 55.68           C  
+ATOM   5081  CG2 ILE B 125      29.825 -16.569  17.768  1.00 56.18           C  
+ATOM   5082  CD1 ILE B 125      32.078 -16.185  19.769  0.00 55.88           C  
+ATOM   5083  N   LEU B 126      27.234 -18.844  18.696  1.00 57.13           N  
+ATOM   5084  CA  LEU B 126      26.407 -19.567  17.740  1.00 58.19           C  
+ATOM   5085  C   LEU B 126      24.949 -19.134  17.829  1.00 58.55           C  
+ATOM   5086  O   LEU B 126      24.314 -18.865  16.811  1.00 59.20           O  
+ATOM   5087  CB  LEU B 126      26.521 -21.075  17.979  1.00 60.91           C  
+ATOM   5088  CG  LEU B 126      26.038 -22.042  16.887  1.00 63.80           C  
+ATOM   5089  CD1 LEU B 126      24.524 -21.966  16.729  1.00 64.05           C  
+ATOM   5090  CD2 LEU B 126      26.744 -21.715  15.573  1.00 64.09           C  
+ATOM   5091  N   PHE B 127      24.410 -19.072  19.040  1.00 58.80           N  
+ATOM   5092  CA  PHE B 127      23.023 -18.657  19.196  1.00 58.39           C  
+ATOM   5093  C   PHE B 127      22.873 -17.155  18.999  1.00 57.80           C  
+ATOM   5094  O   PHE B 127      21.795 -16.668  18.660  1.00 55.72           O  
+ATOM   5095  CB  PHE B 127      22.481 -19.082  20.559  1.00 58.46           C  
+ATOM   5096  CG  PHE B 127      22.039 -20.511  20.602  1.00 61.53           C  
+ATOM   5097  CD1 PHE B 127      22.934 -21.523  20.928  1.00 62.16           C  
+ATOM   5098  CD2 PHE B 127      20.731 -20.854  20.266  1.00 62.20           C  
+ATOM   5099  CE1 PHE B 127      22.534 -22.857  20.918  1.00 61.93           C  
+ATOM   5100  CE2 PHE B 127      20.322 -22.182  20.252  1.00 62.62           C  
+ATOM   5101  CZ  PHE B 127      21.226 -23.186  20.578  1.00 62.86           C  
+ATOM   5102  N   GLY B 128      23.960 -16.424  19.218  1.00 58.29           N  
+ATOM   5103  CA  GLY B 128      23.922 -14.991  19.011  1.00 59.48           C  
+ATOM   5104  C   GLY B 128      23.736 -14.789  17.519  1.00 61.09           C  
+ATOM   5105  O   GLY B 128      22.773 -14.156  17.083  1.00 60.33           O  
+ATOM   5106  N   PHE B 129      24.655 -15.351  16.737  1.00 62.26           N  
+ATOM   5107  CA  PHE B 129      24.600 -15.264  15.281  1.00 64.49           C  
+ATOM   5108  C   PHE B 129      23.262 -15.792  14.786  1.00 64.06           C  
+ATOM   5109  O   PHE B 129      22.598 -15.163  13.961  1.00 64.94           O  
+ATOM   5110  CB  PHE B 129      25.728 -16.091  14.650  1.00 67.97           C  
+ATOM   5111  CG  PHE B 129      27.058 -15.385  14.600  1.00 71.92           C  
+ATOM   5112  CD1 PHE B 129      27.649 -14.887  15.756  1.00 73.19           C  
+ATOM   5113  CD2 PHE B 129      27.729 -15.232  13.389  1.00 74.72           C  
+ATOM   5114  CE1 PHE B 129      28.894 -14.245  15.708  1.00 74.76           C  
+ATOM   5115  CE2 PHE B 129      28.973 -14.593  13.331  1.00 75.52           C  
+ATOM   5116  CZ  PHE B 129      29.555 -14.099  14.495  1.00 73.94           C  
+ATOM   5117  N   GLY B 130      22.875 -16.955  15.299  1.00 63.54           N  
+ATOM   5118  CA  GLY B 130      21.622 -17.570  14.902  1.00 62.14           C  
+ATOM   5119  C   GLY B 130      20.429 -16.650  15.052  1.00 61.75           C  
+ATOM   5120  O   GLY B 130      19.545 -16.622  14.193  1.00 61.73           O  
+ATOM   5121  N   THR B 131      20.390 -15.896  16.146  1.00 60.77           N  
+ATOM   5122  CA  THR B 131      19.283 -14.980  16.367  1.00 59.24           C  
+ATOM   5123  C   THR B 131      19.269 -13.961  15.234  1.00 58.92           C  
+ATOM   5124  O   THR B 131      18.201 -13.605  14.730  1.00 58.49           O  
+ATOM   5125  CB  THR B 131      19.414 -14.257  17.712  1.00 59.28           C  
+ATOM   5126  OG1 THR B 131      19.577 -15.226  18.754  1.00 58.07           O  
+ATOM   5127  CG2 THR B 131      18.162 -13.429  17.992  1.00 58.02           C  
+ATOM   5128  N   LEU B 132      20.455 -13.500  14.835  1.00 58.18           N  
+ATOM   5129  CA  LEU B 132      20.569 -12.545  13.738  1.00 57.41           C  
+ATOM   5130  C   LEU B 132      19.972 -13.177  12.483  1.00 56.76           C  
+ATOM   5131  O   LEU B 132      19.166 -12.561  11.783  1.00 55.47           O  
+ATOM   5132  CB  LEU B 132      22.034 -12.184  13.460  1.00 59.31           C  
+ATOM   5133  CG  LEU B 132      22.821 -11.216  14.355  1.00 60.56           C  
+ATOM   5134  CD1 LEU B 132      21.942 -10.031  14.721  1.00 60.27           C  
+ATOM   5135  CD2 LEU B 132      23.300 -11.920  15.599  1.00 61.66           C  
+ATOM   5136  N   ALA B 133      20.374 -14.413  12.206  1.00 55.71           N  
+ATOM   5137  CA  ALA B 133      19.874 -15.129  11.039  1.00 56.35           C  
+ATOM   5138  C   ALA B 133      18.347 -15.192  11.056  1.00 56.53           C  
+ATOM   5139  O   ALA B 133      17.695 -14.927  10.047  1.00 55.97           O  
+ATOM   5140  CB  ALA B 133      20.459 -16.537  11.000  1.00 56.54           C  
+ATOM   5141  N   LEU B 134      17.780 -15.538  12.208  1.00 56.18           N  
+ATOM   5142  CA  LEU B 134      16.333 -15.631  12.335  1.00 57.74           C  
+ATOM   5143  C   LEU B 134      15.662 -14.303  12.044  1.00 58.73           C  
+ATOM   5144  O   LEU B 134      14.679 -14.246  11.299  1.00 58.55           O  
+ATOM   5145  CB  LEU B 134      15.940 -16.105  13.737  1.00 58.20           C  
+ATOM   5146  CG  LEU B 134      16.223 -17.577  14.042  1.00 58.30           C  
+ATOM   5147  CD1 LEU B 134      15.719 -17.923  15.435  1.00 56.51           C  
+ATOM   5148  CD2 LEU B 134      15.540 -18.449  12.995  1.00 57.81           C  
+ATOM   5149  N   VAL B 135      16.185 -13.236  12.641  1.00 59.27           N  
+ATOM   5150  CA  VAL B 135      15.622 -11.910  12.424  1.00 60.57           C  
+ATOM   5151  C   VAL B 135      15.686 -11.602  10.938  1.00 60.59           C  
+ATOM   5152  O   VAL B 135      14.780 -10.983  10.379  1.00 60.27           O  
+ATOM   5153  CB  VAL B 135      16.401 -10.824  13.193  1.00 61.18           C  
+ATOM   5154  CG1 VAL B 135      15.852  -9.450  12.835  1.00 59.87           C  
+ATOM   5155  CG2 VAL B 135      16.285 -11.067  14.695  1.00 58.52           C  
+ATOM   5156  N   PHE B 136      16.764 -12.049  10.305  1.00 61.49           N  
+ATOM   5157  CA  PHE B 136      16.949 -11.839   8.880  1.00 63.52           C  
+ATOM   5158  C   PHE B 136      15.885 -12.625   8.116  1.00 64.77           C  
+ATOM   5159  O   PHE B 136      15.137 -12.057   7.322  1.00 63.93           O  
+ATOM   5160  CB  PHE B 136      18.341 -12.304   8.447  1.00 63.44           C  
+ATOM   5161  CG  PHE B 136      18.646 -12.030   7.003  1.00 64.03           C  
+ATOM   5162  CD1 PHE B 136      18.815 -10.724   6.551  1.00 64.20           C  
+ATOM   5163  CD2 PHE B 136      18.747 -13.073   6.089  1.00 65.02           C  
+ATOM   5164  CE1 PHE B 136      19.081 -10.457   5.212  1.00 64.56           C  
+ATOM   5165  CE2 PHE B 136      19.013 -12.818   4.741  1.00 65.33           C  
+ATOM   5166  CZ  PHE B 136      19.180 -11.505   4.304  1.00 65.51           C  
+ATOM   5167  N   LEU B 137      15.818 -13.930   8.367  1.00 66.25           N  
+ATOM   5168  CA  LEU B 137      14.846 -14.784   7.691  1.00 68.66           C  
+ATOM   5169  C   LEU B 137      13.418 -14.274   7.838  1.00 69.34           C  
+ATOM   5170  O   LEU B 137      12.724 -14.059   6.847  1.00 69.42           O  
+ATOM   5171  CB  LEU B 137      14.930 -16.222   8.220  1.00 69.43           C  
+ATOM   5172  CG  LEU B 137      15.984 -17.168   7.624  1.00 70.86           C  
+ATOM   5173  CD1 LEU B 137      15.706 -17.362   6.140  1.00 71.83           C  
+ATOM   5174  CD2 LEU B 137      17.382 -16.615   7.829  1.00 71.48           C  
+ATOM   5175  N   PHE B 138      12.986 -14.076   9.078  1.00 71.15           N  
+ATOM   5176  CA  PHE B 138      11.633 -13.604   9.355  1.00 72.87           C  
+ATOM   5177  C   PHE B 138      11.264 -12.266   8.708  1.00 73.36           C  
+ATOM   5178  O   PHE B 138      10.136 -11.798   8.856  1.00 73.53           O  
+ATOM   5179  CB  PHE B 138      11.412 -13.529  10.871  1.00 73.70           C  
+ATOM   5180  CG  PHE B 138      11.238 -14.874  11.528  1.00 75.69           C  
+ATOM   5181  CD1 PHE B 138      11.350 -15.007  12.909  1.00 76.70           C  
+ATOM   5182  CD2 PHE B 138      10.938 -16.007  10.771  1.00 76.43           C  
+ATOM   5183  CE1 PHE B 138      11.167 -16.248  13.527  1.00 77.32           C  
+ATOM   5184  CE2 PHE B 138      10.753 -17.250  11.379  1.00 76.41           C  
+ATOM   5185  CZ  PHE B 138      10.867 -17.371  12.758  1.00 76.32           C  
+ATOM   5186  N   SER B 139      12.201 -11.651   7.993  1.00 73.81           N  
+ATOM   5187  CA  SER B 139      11.917 -10.377   7.336  1.00 74.44           C  
+ATOM   5188  C   SER B 139      11.726 -10.565   5.831  1.00 74.95           C  
+ATOM   5189  O   SER B 139      12.538 -11.209   5.161  1.00 75.57           O  
+ATOM   5190  CB  SER B 139      13.047  -9.374   7.588  1.00 74.29           C  
+ATOM   5191  OG  SER B 139      14.226  -9.736   6.892  1.00 74.73           O  
+ATOM   5192  N   LEU B 147      11.381  -1.730   9.472  1.00 44.58           N  
+ATOM   5193  CA  LEU B 147      12.237  -1.317  10.582  1.00 47.10           C  
+ATOM   5194  C   LEU B 147      11.560  -1.648  11.905  1.00 47.51           C  
+ATOM   5195  O   LEU B 147      12.164  -2.259  12.793  1.00 46.19           O  
+ATOM   5196  CB  LEU B 147      12.522   0.183  10.505  1.00 47.50           C  
+ATOM   5197  CG  LEU B 147      13.960   0.673  10.705  1.00 46.20           C  
+ATOM   5198  CD1 LEU B 147      14.954  -0.187   9.929  1.00 44.35           C  
+ATOM   5199  CD2 LEU B 147      14.036   2.114  10.241  1.00 44.73           C  
+ATOM   5200  N   LEU B 148      10.303  -1.242  12.034  1.00 48.22           N  
+ATOM   5201  CA  LEU B 148       9.540  -1.523  13.243  1.00 50.13           C  
+ATOM   5202  C   LEU B 148       9.379  -3.043  13.351  1.00 49.71           C  
+ATOM   5203  O   LEU B 148       9.387  -3.605  14.449  1.00 48.79           O  
+ATOM   5204  CB  LEU B 148       8.172  -0.828  13.175  1.00 50.98           C  
+ATOM   5205  CG  LEU B 148       7.214  -0.920  14.372  1.00 53.73           C  
+ATOM   5206  CD1 LEU B 148       6.483  -2.247  14.358  1.00 54.76           C  
+ATOM   5207  CD2 LEU B 148       7.983  -0.733  15.672  1.00 53.40           C  
+ATOM   5208  N   MET B 149       9.250  -3.699  12.200  1.00 49.24           N  
+ATOM   5209  CA  MET B 149       9.107  -5.149  12.144  1.00 50.75           C  
+ATOM   5210  C   MET B 149      10.314  -5.871  12.732  1.00 50.68           C  
+ATOM   5211  O   MET B 149      10.170  -6.917  13.367  1.00 51.35           O  
+ATOM   5212  CB  MET B 149       8.900  -5.608  10.702  1.00 54.39           C  
+ATOM   5213  CG  MET B 149       7.463  -5.509  10.223  1.00 60.15           C  
+ATOM   5214  SD  MET B 149       6.344  -6.538  11.221  1.00 66.17           S  
+ATOM   5215  CE  MET B 149       5.463  -5.250  12.137  1.00 64.03           C  
+ATOM   5216  N   LEU B 150      11.505  -5.325  12.511  1.00 48.82           N  
+ATOM   5217  CA  LEU B 150      12.704  -5.939  13.054  1.00 48.76           C  
+ATOM   5218  C   LEU B 150      12.632  -5.875  14.572  1.00 48.53           C  
+ATOM   5219  O   LEU B 150      13.024  -6.813  15.260  1.00 48.32           O  
+ATOM   5220  CB  LEU B 150      13.955  -5.213  12.562  1.00 48.71           C  
+ATOM   5221  CG  LEU B 150      14.175  -5.214  11.051  1.00 50.12           C  
+ATOM   5222  CD1 LEU B 150      15.552  -4.640  10.740  1.00 48.62           C  
+ATOM   5223  CD2 LEU B 150      14.047  -6.638  10.516  1.00 50.68           C  
+ATOM   5224  N   ILE B 151      12.122  -4.760  15.084  1.00 47.71           N  
+ATOM   5225  CA  ILE B 151      11.985  -4.570  16.521  1.00 47.49           C  
+ATOM   5226  C   ILE B 151      10.967  -5.559  17.098  1.00 47.20           C  
+ATOM   5227  O   ILE B 151      11.203  -6.169  18.143  1.00 46.29           O  
+ATOM   5228  CB  ILE B 151      11.535  -3.131  16.852  1.00 45.81           C  
+ATOM   5229  CG1 ILE B 151      12.606  -2.134  16.403  1.00 46.19           C  
+ATOM   5230  CG2 ILE B 151      11.281  -2.998  18.341  1.00 45.70           C  
+ATOM   5231  CD1 ILE B 151      12.234  -0.683  16.637  0.00 46.09           C  
+ATOM   5232  N   LEU B 152       9.834  -5.709  16.422  1.00 46.44           N  
+ATOM   5233  CA  LEU B 152       8.812  -6.636  16.884  1.00 47.57           C  
+ATOM   5234  C   LEU B 152       9.338  -8.076  16.823  1.00 48.30           C  
+ATOM   5235  O   LEU B 152       9.097  -8.868  17.737  1.00 44.78           O  
+ATOM   5236  CB  LEU B 152       7.540  -6.476  16.046  1.00 48.19           C  
+ATOM   5237  CG  LEU B 152       6.464  -5.544  16.626  1.00 50.33           C  
+ATOM   5238  CD1 LEU B 152       7.089  -4.306  17.246  1.00 49.61           C  
+ATOM   5239  CD2 LEU B 152       5.484  -5.164  15.525  1.00 50.84           C  
+ATOM   5240  N   ILE B 153      10.066  -8.401  15.753  1.00 46.87           N  
+ATOM   5241  CA  ILE B 153      10.639  -9.732  15.608  1.00 48.06           C  
+ATOM   5242  C   ILE B 153      11.638  -9.973  16.742  1.00 48.53           C  
+ATOM   5243  O   ILE B 153      11.612 -11.018  17.390  1.00 47.26           O  
+ATOM   5244  CB  ILE B 153      11.386  -9.898  14.263  1.00 48.74           C  
+ATOM   5245  CG1 ILE B 153      10.388  -9.943  13.100  1.00 48.41           C  
+ATOM   5246  CG2 ILE B 153      12.233 -11.163  14.299  1.00 46.50           C  
+ATOM   5247  CD1 ILE B 153      11.036 -10.052  11.734  0.00 48.61           C  
+ATOM   5248  N   GLY B 154      12.517  -9.001  16.969  1.00 48.57           N  
+ATOM   5249  CA  GLY B 154      13.508  -9.124  18.021  1.00 49.61           C  
+ATOM   5250  C   GLY B 154      12.866  -9.256  19.391  1.00 51.23           C  
+ATOM   5251  O   GLY B 154      13.446  -9.829  20.314  1.00 50.57           O  
+ATOM   5252  N   MET B 155      11.661  -8.714  19.517  1.00 52.33           N  
+ATOM   5253  CA  MET B 155      10.906  -8.751  20.760  1.00 52.13           C  
+ATOM   5254  C   MET B 155      10.406 -10.175  21.008  1.00 51.68           C  
+ATOM   5255  O   MET B 155      10.457 -10.678  22.130  1.00 50.13           O  
+ATOM   5256  CB  MET B 155       9.727  -7.789  20.644  1.00 56.20           C  
+ATOM   5257  CG  MET B 155       8.904  -7.610  21.896  1.00 60.81           C  
+ATOM   5258  SD  MET B 155       7.600  -6.401  21.585  1.00 67.63           S  
+ATOM   5259  CE  MET B 155       8.588  -4.906  21.393  1.00 66.25           C  
+ATOM   5260  N   ILE B 156       9.918 -10.808  19.948  1.00 50.33           N  
+ATOM   5261  CA  ILE B 156       9.415 -12.171  20.010  1.00 51.04           C  
+ATOM   5262  C   ILE B 156      10.558 -13.118  20.388  1.00 51.39           C  
+ATOM   5263  O   ILE B 156      10.458 -13.877  21.356  1.00 49.57           O  
+ATOM   5264  CB  ILE B 156       8.822 -12.591  18.645  1.00 51.34           C  
+ATOM   5265  CG1 ILE B 156       7.571 -11.760  18.347  1.00 50.85           C  
+ATOM   5266  CG2 ILE B 156       8.498 -14.081  18.642  1.00 52.88           C  
+ATOM   5267  CD1 ILE B 156       6.966 -12.029  16.985  0.00 51.13           C  
+ATOM   5268  N   LEU B 157      11.643 -13.057  19.619  1.00 50.68           N  
+ATOM   5269  CA  LEU B 157      12.814 -13.892  19.856  1.00 50.70           C  
+ATOM   5270  C   LEU B 157      13.366 -13.669  21.257  1.00 51.36           C  
+ATOM   5271  O   LEU B 157      13.733 -14.615  21.951  1.00 51.53           O  
+ATOM   5272  CB  LEU B 157      13.898 -13.585  18.821  1.00 50.86           C  
+ATOM   5273  CG  LEU B 157      13.978 -14.459  17.565  1.00 51.57           C  
+ATOM   5274  CD1 LEU B 157      12.612 -14.630  16.955  1.00 52.86           C  
+ATOM   5275  CD2 LEU B 157      14.932 -13.818  16.570  1.00 51.05           C  
+ATOM   5276  N   SER B 158      13.427 -12.411  21.669  1.00 50.79           N  
+ATOM   5277  CA  SER B 158      13.928 -12.073  22.992  1.00 51.44           C  
+ATOM   5278  C   SER B 158      13.047 -12.750  24.045  1.00 51.56           C  
+ATOM   5279  O   SER B 158      13.529 -13.172  25.096  1.00 52.21           O  
+ATOM   5280  CB  SER B 158      13.908 -10.552  23.181  1.00 52.25           C  
+ATOM   5281  OG  SER B 158      14.597 -10.161  24.356  1.00 55.86           O  
+ATOM   5282  N   GLY B 159      11.756 -12.859  23.746  1.00 50.50           N  
+ATOM   5283  CA  GLY B 159      10.823 -13.484  24.665  1.00 49.83           C  
+ATOM   5284  C   GLY B 159      10.981 -14.993  24.762  1.00 49.45           C  
+ATOM   5285  O   GLY B 159      11.001 -15.545  25.858  1.00 47.85           O  
+ATOM   5286  N   LEU B 160      11.079 -15.666  23.620  1.00 49.39           N  
+ATOM   5287  CA  LEU B 160      11.251 -17.115  23.616  1.00 50.08           C  
+ATOM   5288  C   LEU B 160      12.533 -17.485  24.364  1.00 50.16           C  
+ATOM   5289  O   LEU B 160      12.514 -18.316  25.269  1.00 50.90           O  
+ATOM   5290  CB  LEU B 160      11.318 -17.646  22.179  1.00 48.03           C  
+ATOM   5291  CG  LEU B 160      10.034 -17.527  21.356  1.00 50.03           C  
+ATOM   5292  CD1 LEU B 160      10.275 -18.031  19.936  1.00 49.26           C  
+ATOM   5293  CD2 LEU B 160       8.929 -18.327  22.025  1.00 49.72           C  
+ATOM   5294  N   PHE B 161      13.643 -16.850  23.996  1.00 49.75           N  
+ATOM   5295  CA  PHE B 161      14.920 -17.133  24.636  1.00 50.46           C  
+ATOM   5296  C   PHE B 161      14.908 -16.904  26.143  1.00 50.69           C  
+ATOM   5297  O   PHE B 161      15.534 -17.659  26.886  1.00 50.41           O  
+ATOM   5298  CB  PHE B 161      16.045 -16.317  23.985  1.00 49.45           C  
+ATOM   5299  CG  PHE B 161      16.455 -16.830  22.635  1.00 51.27           C  
+ATOM   5300  CD1 PHE B 161      16.118 -16.138  21.475  1.00 52.70           C  
+ATOM   5301  CD2 PHE B 161      17.148 -18.031  22.518  1.00 52.60           C  
+ATOM   5302  CE1 PHE B 161      16.461 -16.637  20.219  1.00 54.25           C  
+ATOM   5303  CE2 PHE B 161      17.496 -18.539  21.265  1.00 52.99           C  
+ATOM   5304  CZ  PHE B 161      17.150 -17.839  20.114  1.00 52.26           C  
+ATOM   5305  N   SER B 162      14.207 -15.868  26.596  1.00 50.67           N  
+ATOM   5306  CA  SER B 162      14.131 -15.591  28.023  1.00 51.28           C  
+ATOM   5307  C   SER B 162      13.342 -16.709  28.688  1.00 51.50           C  
+ATOM   5308  O   SER B 162      13.652 -17.136  29.801  1.00 51.09           O  
+ATOM   5309  CB  SER B 162      13.448 -14.245  28.284  1.00 52.16           C  
+ATOM   5310  OG  SER B 162      14.333 -13.171  28.025  1.00 57.28           O  
+ATOM   5311  N   ALA B 163      12.315 -17.181  27.993  1.00 50.79           N  
+ATOM   5312  CA  ALA B 163      11.499 -18.261  28.512  1.00 51.64           C  
+ATOM   5313  C   ALA B 163      12.377 -19.509  28.625  1.00 52.07           C  
+ATOM   5314  O   ALA B 163      12.349 -20.199  29.647  1.00 52.41           O  
+ATOM   5315  CB  ALA B 163      10.318 -18.520  27.588  1.00 50.33           C  
+ATOM   5316  N   LEU B 164      13.168 -19.781  27.586  1.00 50.85           N  
+ATOM   5317  CA  LEU B 164      14.049 -20.948  27.585  1.00 51.21           C  
+ATOM   5318  C   LEU B 164      15.097 -20.874  28.689  1.00 51.59           C  
+ATOM   5319  O   LEU B 164      15.379 -21.876  29.345  1.00 52.56           O  
+ATOM   5320  CB  LEU B 164      14.739 -21.113  26.229  1.00 50.18           C  
+ATOM   5321  CG  LEU B 164      13.810 -21.341  25.034  1.00 50.39           C  
+ATOM   5322  CD1 LEU B 164      14.632 -21.702  23.809  1.00 51.82           C  
+ATOM   5323  CD2 LEU B 164      12.824 -22.455  25.352  1.00 52.60           C  
+ATOM   5324  N   VAL B 165      15.674 -19.694  28.896  1.00 50.45           N  
+ATOM   5325  CA  VAL B 165      16.669 -19.529  29.949  1.00 49.81           C  
+ATOM   5326  C   VAL B 165      16.027 -19.818  31.309  1.00 50.70           C  
+ATOM   5327  O   VAL B 165      16.652 -20.414  32.189  1.00 49.59           O  
+ATOM   5328  CB  VAL B 165      17.249 -18.095  29.960  1.00 48.66           C  
+ATOM   5329  CG1 VAL B 165      18.059 -17.862  31.228  1.00 47.87           C  
+ATOM   5330  CG2 VAL B 165      18.134 -17.889  28.747  1.00 48.43           C  
+ATOM   5331  N   SER B 166      14.776 -19.394  31.472  1.00 51.99           N  
+ATOM   5332  CA  SER B 166      14.051 -19.609  32.720  1.00 53.57           C  
+ATOM   5333  C   SER B 166      13.758 -21.081  32.926  1.00 53.79           C  
+ATOM   5334  O   SER B 166      13.838 -21.578  34.043  1.00 53.63           O  
+ATOM   5335  CB  SER B 166      12.731 -18.833  32.723  1.00 53.80           C  
+ATOM   5336  OG  SER B 166      12.964 -17.442  32.796  1.00 54.62           O  
+ATOM   5337  N   LEU B 167      13.413 -21.772  31.845  1.00 55.28           N  
+ATOM   5338  CA  LEU B 167      13.111 -23.193  31.915  1.00 57.35           C  
+ATOM   5339  C   LEU B 167      14.327 -23.982  32.400  1.00 58.72           C  
+ATOM   5340  O   LEU B 167      14.265 -24.649  33.433  1.00 59.17           O  
+ATOM   5341  CB  LEU B 167      12.671 -23.712  30.542  1.00 57.54           C  
+ATOM   5342  CG  LEU B 167      12.237 -25.181  30.482  1.00 58.03           C  
+ATOM   5343  CD1 LEU B 167      11.016 -25.389  31.376  1.00 57.82           C  
+ATOM   5344  CD2 LEU B 167      11.921 -25.569  29.043  1.00 57.66           C  
+ATOM   5345  N   LEU B 168      15.427 -23.896  31.652  1.00 59.60           N  
+ATOM   5346  CA  LEU B 168      16.663 -24.601  31.994  1.00 60.30           C  
+ATOM   5347  C   LEU B 168      17.117 -24.250  33.399  1.00 60.75           C  
+ATOM   5348  O   LEU B 168      17.762 -25.043  34.081  1.00 61.70           O  
+ATOM   5349  CB  LEU B 168      17.773 -24.237  31.008  1.00 59.03           C  
+ATOM   5350  CG  LEU B 168      17.571 -24.638  29.545  1.00 60.65           C  
+ATOM   5351  CD1 LEU B 168      18.757 -24.158  28.719  1.00 61.01           C  
+ATOM   5352  CD2 LEU B 168      17.422 -26.145  29.437  1.00 59.82           C  
+ATOM   5353  N   GLN B 169      16.772 -23.045  33.821  1.00 61.30           N  
+ATOM   5354  CA  GLN B 169      17.133 -22.545  35.133  1.00 62.09           C  
+ATOM   5355  C   GLN B 169      16.244 -23.203  36.189  1.00 63.65           C  
+ATOM   5356  O   GLN B 169      16.673 -23.460  37.316  1.00 63.52           O  
+ATOM   5357  CB  GLN B 169      16.950 -21.029  35.131  1.00 61.52           C  
+ATOM   5358  CG  GLN B 169      17.503 -20.282  36.313  1.00 60.78           C  
+ATOM   5359  CD  GLN B 169      17.530 -18.785  36.056  1.00 59.77           C  
+ATOM   5360  OE1 GLN B 169      16.509 -18.183  35.735  1.00 60.16           O  
+ATOM   5361  NE2 GLN B 169      18.700 -18.181  36.189  1.00 60.32           N  
+ATOM   5362  N   TYR B 170      15.008 -23.495  35.805  1.00 64.46           N  
+ATOM   5363  CA  TYR B 170      14.051 -24.108  36.711  1.00 65.84           C  
+ATOM   5364  C   TYR B 170      14.196 -25.628  36.808  1.00 66.64           C  
+ATOM   5365  O   TYR B 170      13.850 -26.224  37.828  1.00 65.52           O  
+ATOM   5366  CB  TYR B 170      12.629 -23.734  36.277  1.00 65.17           C  
+ATOM   5367  CG  TYR B 170      11.534 -24.367  37.107  1.00 64.55           C  
+ATOM   5368  CD1 TYR B 170      10.959 -25.580  36.730  1.00 64.60           C  
+ATOM   5369  CD2 TYR B 170      11.080 -23.758  38.276  1.00 64.24           C  
+ATOM   5370  CE1 TYR B 170       9.957 -26.172  37.498  1.00 65.21           C  
+ATOM   5371  CE2 TYR B 170      10.080 -24.340  39.052  1.00 65.02           C  
+ATOM   5372  CZ  TYR B 170       9.524 -25.546  38.657  1.00 65.81           C  
+ATOM   5373  OH  TYR B 170       8.534 -26.126  39.417  1.00 68.71           O  
+ATOM   5374  N   ILE B 171      14.716 -26.249  35.754  1.00 67.96           N  
+ATOM   5375  CA  ILE B 171      14.883 -27.696  35.734  1.00 69.07           C  
+ATOM   5376  C   ILE B 171      16.336 -28.133  35.891  1.00 70.75           C  
+ATOM   5377  O   ILE B 171      16.797 -29.038  35.194  1.00 71.40           O  
+ATOM   5378  CB  ILE B 171      14.327 -28.301  34.424  1.00 68.62           C  
+ATOM   5379  CG1 ILE B 171      15.126 -27.791  33.222  1.00 68.73           C  
+ATOM   5380  CG2 ILE B 171      12.862 -27.939  34.275  1.00 69.02           C  
+ATOM   5381  CD1 ILE B 171      14.684 -28.375  31.895  0.00 68.62           C  
+ATOM   5382  N   SER B 172      17.055 -27.497  36.810  1.00 71.50           N  
+ATOM   5383  CA  SER B 172      18.453 -27.844  37.041  1.00 73.21           C  
+ATOM   5384  C   SER B 172      18.754 -27.873  38.535  1.00 74.45           C  
+ATOM   5385  O   SER B 172      17.978 -27.349  39.331  1.00 75.58           O  
+ATOM   5386  CB  SER B 172      19.370 -26.837  36.334  1.00 72.48           C  
+ATOM   5387  OG  SER B 172      19.195 -25.526  36.843  1.00 70.83           O  
+ATOM   5388  N   ASP B 173      19.871 -28.494  38.913  1.00 75.92           N  
+ATOM   5389  CA  ASP B 173      20.268 -28.580  40.321  1.00 78.14           C  
+ATOM   5390  C   ASP B 173      20.382 -27.187  40.929  1.00 78.21           C  
+ATOM   5391  O   ASP B 173      21.111 -26.341  40.413  1.00 78.55           O  
+ATOM   5392  CB  ASP B 173      21.613 -29.309  40.456  1.00 80.10           C  
+ATOM   5393  CG  ASP B 173      22.184 -29.235  41.869  1.00 82.44           C  
+ATOM   5394  OD1 ASP B 173      21.510 -29.688  42.820  1.00 83.60           O  
+ATOM   5395  OD2 ASP B 173      23.311 -28.721  42.029  1.00 83.05           O  
+ATOM   5396  N   THR B 174      19.671 -26.959  42.031  1.00 78.34           N  
+ATOM   5397  CA  THR B 174      19.677 -25.658  42.698  1.00 79.10           C  
+ATOM   5398  C   THR B 174      20.834 -25.487  43.674  1.00 79.67           C  
+ATOM   5399  O   THR B 174      20.814 -24.593  44.520  0.00 79.94           O  
+ATOM   5400  CB  THR B 174      18.369 -25.426  43.476  1.00 78.15           C  
+ATOM   5401  OG1 THR B 174      18.310 -26.325  44.589  1.00 77.37           O  
+ATOM   5402  CG2 THR B 174      17.167 -25.665  42.576  1.00 77.73           C  
+ATOM   5403  N   GLU B 175      21.842 -26.342  43.555  1.00 81.41           N  
+ATOM   5404  CA  GLU B 175      22.990 -26.270  44.445  1.00 83.74           C  
+ATOM   5405  C   GLU B 175      24.305 -26.098  43.694  1.00 83.66           C  
+ATOM   5406  O   GLU B 175      25.295 -25.629  44.259  1.00 83.50           O  
+ATOM   5407  CB  GLU B 175      23.049 -27.527  45.316  1.00 86.24           C  
+ATOM   5408  CG  GLU B 175      21.808 -27.733  46.173  1.00 89.94           C  
+ATOM   5409  CD  GLU B 175      21.452 -26.496  46.986  1.00 91.91           C  
+ATOM   5410  OE1 GLU B 175      22.296 -26.050  47.791  1.00 92.93           O  
+ATOM   5411  OE2 GLU B 175      20.330 -25.969  46.817  1.00 92.69           O  
+ATOM   5412  N   GLU B 176      24.309 -26.465  42.417  1.00 83.53           N  
+ATOM   5413  CA  GLU B 176      25.513 -26.356  41.606  1.00 82.81           C  
+ATOM   5414  C   GLU B 176      25.283 -25.550  40.329  1.00 80.87           C  
+ATOM   5415  O   GLU B 176      25.904 -24.508  40.119  1.00 81.12           O  
+ATOM   5416  CB  GLU B 176      26.016 -27.756  41.243  1.00 85.03           C  
+ATOM   5417  CG  GLU B 176      27.521 -27.850  41.056  1.00 88.73           C  
+ATOM   5418  CD  GLU B 176      28.282 -27.548  42.337  1.00 91.08           C  
+ATOM   5419  OE1 GLU B 176      28.197 -26.399  42.828  1.00 92.64           O  
+ATOM   5420  OE2 GLU B 176      28.962 -28.461  42.857  1.00 91.63           O  
+ATOM   5421  N   LYS B 177      24.380 -26.034  39.482  1.00 78.22           N  
+ATOM   5422  CA  LYS B 177      24.086 -25.375  38.217  1.00 75.08           C  
+ATOM   5423  C   LYS B 177      23.278 -24.078  38.314  1.00 72.49           C  
+ATOM   5424  O   LYS B 177      23.585 -23.113  37.617  1.00 73.19           O  
+ATOM   5425  CB  LYS B 177      23.369 -26.348  37.271  1.00 75.34           C  
+ATOM   5426  CG  LYS B 177      24.185 -27.570  36.880  1.00 76.29           C  
+ATOM   5427  CD  LYS B 177      25.456 -27.188  36.135  1.00 77.32           C  
+ATOM   5428  CE  LYS B 177      26.263 -28.422  35.745  1.00 77.48           C  
+ATOM   5429  NZ  LYS B 177      26.670 -29.218  36.936  0.00 77.53           N  
+ATOM   5430  N   LEU B 178      22.257 -24.042  39.167  1.00 68.58           N  
+ATOM   5431  CA  LEU B 178      21.435 -22.838  39.279  1.00 65.29           C  
+ATOM   5432  C   LEU B 178      22.226 -21.554  39.529  1.00 63.03           C  
+ATOM   5433  O   LEU B 178      22.166 -20.628  38.724  1.00 62.32           O  
+ATOM   5434  CB  LEU B 178      20.359 -22.993  40.362  1.00 63.99           C  
+ATOM   5435  CG  LEU B 178      19.456 -21.758  40.511  1.00 63.31           C  
+ATOM   5436  CD1 LEU B 178      18.745 -21.496  39.193  1.00 61.19           C  
+ATOM   5437  CD2 LEU B 178      18.444 -21.960  41.632  1.00 62.52           C  
+ATOM   5438  N   PRO B 179      22.978 -21.476  40.643  1.00 61.41           N  
+ATOM   5439  CA  PRO B 179      23.750 -20.255  40.913  1.00 60.14           C  
+ATOM   5440  C   PRO B 179      24.835 -19.991  39.873  1.00 59.21           C  
+ATOM   5441  O   PRO B 179      25.304 -18.864  39.718  1.00 58.43           O  
+ATOM   5442  CB  PRO B 179      24.325 -20.509  42.303  1.00 58.84           C  
+ATOM   5443  CG  PRO B 179      24.507 -21.982  42.315  1.00 60.84           C  
+ATOM   5444  CD  PRO B 179      23.223 -22.484  41.688  1.00 60.88           C  
+ATOM   5445  N   SER B 180      25.228 -21.037  39.158  1.00 58.01           N  
+ATOM   5446  CA  SER B 180      26.250 -20.903  38.137  1.00 57.36           C  
+ATOM   5447  C   SER B 180      25.644 -20.224  36.909  1.00 56.49           C  
+ATOM   5448  O   SER B 180      26.299 -19.421  36.243  1.00 56.01           O  
+ATOM   5449  CB  SER B 180      26.803 -22.279  37.767  1.00 58.43           C  
+ATOM   5450  OG  SER B 180      28.043 -22.159  37.094  1.00 60.29           O  
+ATOM   5451  N   ILE B 181      24.393 -20.555  36.610  1.00 55.19           N  
+ATOM   5452  CA  ILE B 181      23.699 -19.956  35.475  1.00 54.37           C  
+ATOM   5453  C   ILE B 181      23.410 -18.501  35.834  1.00 54.00           C  
+ATOM   5454  O   ILE B 181      23.834 -17.576  35.143  1.00 53.56           O  
+ATOM   5455  CB  ILE B 181      22.356 -20.674  35.188  1.00 53.37           C  
+ATOM   5456  CG1 ILE B 181      22.615 -22.123  34.767  1.00 52.07           C  
+ATOM   5457  CG2 ILE B 181      21.588 -19.931  34.103  1.00 52.73           C  
+ATOM   5458  CD1 ILE B 181      21.355 -22.925  34.511  0.00 52.68           C  
+ATOM   5459  N   VAL B 182      22.701 -18.324  36.942  1.00 53.41           N  
+ATOM   5460  CA  VAL B 182      22.317 -17.017  37.448  1.00 53.68           C  
+ATOM   5461  C   VAL B 182      23.424 -15.973  37.460  1.00 54.95           C  
+ATOM   5462  O   VAL B 182      23.219 -14.843  37.022  1.00 56.25           O  
+ATOM   5463  CB  VAL B 182      21.760 -17.135  38.882  1.00 52.81           C  
+ATOM   5464  CG1 VAL B 182      21.520 -15.752  39.474  1.00 51.11           C  
+ATOM   5465  CG2 VAL B 182      20.472 -17.943  38.865  1.00 53.91           C  
+ATOM   5466  N   PHE B 183      24.597 -16.334  37.961  1.00 55.83           N  
+ATOM   5467  CA  PHE B 183      25.674 -15.364  38.030  1.00 55.90           C  
+ATOM   5468  C   PHE B 183      26.500 -15.197  36.766  1.00 54.40           C  
+ATOM   5469  O   PHE B 183      27.320 -14.285  36.677  1.00 54.53           O  
+ATOM   5470  CB  PHE B 183      26.549 -15.655  39.247  1.00 57.93           C  
+ATOM   5471  CG  PHE B 183      25.805 -15.518  40.543  1.00 62.35           C  
+ATOM   5472  CD1 PHE B 183      25.100 -14.348  40.828  1.00 62.95           C  
+ATOM   5473  CD2 PHE B 183      25.759 -16.567  41.458  1.00 63.58           C  
+ATOM   5474  CE1 PHE B 183      24.357 -14.226  42.002  1.00 63.92           C  
+ATOM   5475  CE2 PHE B 183      25.018 -16.454  42.635  1.00 64.88           C  
+ATOM   5476  CZ  PHE B 183      24.315 -15.281  42.906  1.00 64.98           C  
+ATOM   5477  N   TRP B 184      26.296 -16.071  35.789  1.00 53.13           N  
+ATOM   5478  CA  TRP B 184      26.998 -15.909  34.527  1.00 52.65           C  
+ATOM   5479  C   TRP B 184      26.158 -14.882  33.772  1.00 53.04           C  
+ATOM   5480  O   TRP B 184      26.685 -14.006  33.094  1.00 52.59           O  
+ATOM   5481  CB  TRP B 184      27.035 -17.198  33.713  1.00 50.85           C  
+ATOM   5482  CG  TRP B 184      27.565 -16.943  32.332  1.00 49.83           C  
+ATOM   5483  CD1 TRP B 184      28.859 -16.673  31.990  1.00 49.83           C  
+ATOM   5484  CD2 TRP B 184      26.801 -16.833  31.126  1.00 47.43           C  
+ATOM   5485  NE1 TRP B 184      28.947 -16.397  30.647  1.00 50.53           N  
+ATOM   5486  CE2 TRP B 184      27.699 -16.488  30.092  1.00 47.99           C  
+ATOM   5487  CE3 TRP B 184      25.443 -16.988  30.819  1.00 47.03           C  
+ATOM   5488  CZ2 TRP B 184      27.287 -16.295  28.773  1.00 46.33           C  
+ATOM   5489  CZ3 TRP B 184      25.031 -16.796  29.506  1.00 48.27           C  
+ATOM   5490  CH2 TRP B 184      25.953 -16.452  28.499  1.00 48.85           C  
+ATOM   5491  N   LEU B 185      24.841 -15.009  33.913  1.00 53.19           N  
+ATOM   5492  CA  LEU B 185      23.891 -14.111  33.274  1.00 53.75           C  
+ATOM   5493  C   LEU B 185      24.117 -12.660  33.661  1.00 54.77           C  
+ATOM   5494  O   LEU B 185      23.999 -11.773  32.817  1.00 55.74           O  
+ATOM   5495  CB  LEU B 185      22.459 -14.503  33.625  1.00 52.74           C  
+ATOM   5496  CG  LEU B 185      21.873 -15.730  32.925  1.00 52.62           C  
+ATOM   5497  CD1 LEU B 185      20.479 -15.999  33.480  1.00 54.04           C  
+ATOM   5498  CD2 LEU B 185      21.812 -15.499  31.423  1.00 52.86           C  
+ATOM   5499  N   MET B 186      24.428 -12.393  34.925  1.00 54.16           N  
+ATOM   5500  CA  MET B 186      24.660 -11.006  35.291  1.00 54.93           C  
+ATOM   5501  C   MET B 186      26.123 -10.629  35.095  1.00 54.00           C  
+ATOM   5502  O   MET B 186      26.982 -10.952  35.911  1.00 55.39           O  
+ATOM   5503  CB  MET B 186      24.166 -10.701  36.720  1.00 54.79           C  
+ATOM   5504  CG  MET B 186      24.698 -11.543  37.858  1.00 56.96           C  
+ATOM   5505  SD  MET B 186      24.089 -10.867  39.448  1.00 56.48           S  
+ATOM   5506  CE  MET B 186      22.651 -11.879  39.765  1.00 56.99           C  
+ATOM   5507  N   GLY B 187      26.372  -9.949  33.976  1.00 53.33           N  
+ATOM   5508  CA  GLY B 187      27.700  -9.506  33.575  1.00 51.01           C  
+ATOM   5509  C   GLY B 187      28.674  -9.106  34.659  1.00 51.07           C  
+ATOM   5510  O   GLY B 187      28.305  -8.429  35.620  1.00 51.13           O  
+ATOM   5511  N   SER B 188      29.934  -9.498  34.477  1.00 50.77           N  
+ATOM   5512  CA  SER B 188      30.984  -9.220  35.451  1.00 51.35           C  
+ATOM   5513  C   SER B 188      32.391  -9.346  34.857  1.00 50.92           C  
+ATOM   5514  O   SER B 188      32.619 -10.118  33.932  1.00 51.81           O  
+ATOM   5515  CB  SER B 188      30.835 -10.193  36.634  1.00 53.22           C  
+ATOM   5516  OG  SER B 188      31.843  -9.997  37.613  1.00 55.43           O  
+ATOM   5517  N   PHE B 189      33.333  -8.582  35.396  1.00 51.27           N  
+ATOM   5518  CA  PHE B 189      34.719  -8.625  34.938  1.00 52.88           C  
+ATOM   5519  C   PHE B 189      35.580  -9.353  35.976  1.00 54.71           C  
+ATOM   5520  O   PHE B 189      36.800  -9.437  35.840  1.00 54.51           O  
+ATOM   5521  CB  PHE B 189      35.251  -7.201  34.739  1.00 53.21           C  
+ATOM   5522  CG  PHE B 189      34.611  -6.465  33.590  1.00 53.55           C  
+ATOM   5523  CD1 PHE B 189      34.462  -5.083  33.633  1.00 52.41           C  
+ATOM   5524  CD2 PHE B 189      34.157  -7.153  32.464  1.00 53.80           C  
+ATOM   5525  CE1 PHE B 189      33.868  -4.398  32.574  1.00 52.76           C  
+ATOM   5526  CE2 PHE B 189      33.564  -6.476  31.402  1.00 53.23           C  
+ATOM   5527  CZ  PHE B 189      33.419  -5.096  31.459  1.00 52.32           C  
+ATOM   5528  N   ALA B 190      34.926  -9.882  37.008  1.00 56.49           N  
+ATOM   5529  CA  ALA B 190      35.601 -10.592  38.095  1.00 59.97           C  
+ATOM   5530  C   ALA B 190      36.618 -11.621  37.616  1.00 60.68           C  
+ATOM   5531  O   ALA B 190      37.770 -11.615  38.050  1.00 60.95           O  
+ATOM   5532  CB  ALA B 190      34.565 -11.275  38.991  1.00 59.88           C  
+ATOM   5533  N   THR B 191      36.186 -12.499  36.719  1.00 62.21           N  
+ATOM   5534  CA  THR B 191      37.049 -13.547  36.192  1.00 62.88           C  
+ATOM   5535  C   THR B 191      37.667 -13.207  34.840  1.00 63.71           C  
+ATOM   5536  O   THR B 191      37.531 -13.970  33.883  1.00 64.94           O  
+ATOM   5537  CB  THR B 191      36.269 -14.856  36.052  1.00 62.68           C  
+ATOM   5538  OG1 THR B 191      35.221 -14.687  35.091  1.00 63.37           O  
+ATOM   5539  CG2 THR B 191      35.659 -15.251  37.386  1.00 61.37           C  
+ATOM   5540  N   SER B 192      38.358 -12.073  34.766  1.00 63.99           N  
+ATOM   5541  CA  SER B 192      38.993 -11.640  33.522  1.00 64.30           C  
+ATOM   5542  C   SER B 192      40.448 -12.101  33.412  1.00 64.66           C  
+ATOM   5543  O   SER B 192      41.245 -11.906  34.334  1.00 64.77           O  
+ATOM   5544  CB  SER B 192      38.941 -10.113  33.410  1.00 64.53           C  
+ATOM   5545  OG  SER B 192      37.606  -9.643  33.441  1.00 66.28           O  
+ATOM   5546  N   ASN B 193      40.790 -12.703  32.277  1.00 64.47           N  
+ATOM   5547  CA  ASN B 193      42.147 -13.185  32.033  1.00 64.32           C  
+ATOM   5548  C   ASN B 193      42.535 -12.932  30.581  1.00 64.44           C  
+ATOM   5549  O   ASN B 193      41.679 -12.651  29.744  1.00 64.07           O  
+ATOM   5550  CB  ASN B 193      42.245 -14.678  32.355  1.00 63.74           C  
+ATOM   5551  CG  ASN B 193      41.267 -15.512  31.557  1.00 64.48           C  
+ATOM   5552  OD1 ASN B 193      40.499 -16.293  32.119  1.00 63.98           O  
+ATOM   5553  ND2 ASN B 193      41.292 -15.356  30.239  1.00 64.89           N  
+ATOM   5554  N   TRP B 194      43.825 -13.036  30.282  1.00 65.21           N  
+ATOM   5555  CA  TRP B 194      44.302 -12.793  28.925  1.00 65.74           C  
+ATOM   5556  C   TRP B 194      43.656 -13.701  27.888  1.00 65.78           C  
+ATOM   5557  O   TRP B 194      43.490 -13.311  26.731  1.00 65.97           O  
+ATOM   5558  CB  TRP B 194      45.825 -12.934  28.857  1.00 66.04           C  
+ATOM   5559  CG  TRP B 194      46.558 -11.916  29.679  1.00 65.72           C  
+ATOM   5560  CD1 TRP B 194      46.988 -12.055  30.968  1.00 65.50           C  
+ATOM   5561  CD2 TRP B 194      46.929 -10.592  29.273  1.00 65.63           C  
+ATOM   5562  NE1 TRP B 194      47.607 -10.901  31.390  1.00 65.14           N  
+ATOM   5563  CE2 TRP B 194      47.585  -9.987  30.370  1.00 65.55           C  
+ATOM   5564  CE3 TRP B 194      46.771  -9.858  28.089  1.00 64.83           C  
+ATOM   5565  CZ2 TRP B 194      48.085  -8.680  30.318  1.00 64.67           C  
+ATOM   5566  CZ3 TRP B 194      47.268  -8.558  28.036  1.00 64.74           C  
+ATOM   5567  CH2 TRP B 194      47.917  -7.984  29.146  1.00 64.89           C  
+ATOM   5568  N   GLU B 195      43.289 -14.910  28.295  1.00 65.31           N  
+ATOM   5569  CA  GLU B 195      42.658 -15.840  27.369  1.00 65.39           C  
+ATOM   5570  C   GLU B 195      41.405 -15.190  26.797  1.00 64.02           C  
+ATOM   5571  O   GLU B 195      41.254 -15.063  25.582  1.00 63.87           O  
+ATOM   5572  CB  GLU B 195      42.274 -17.133  28.086  1.00 67.15           C  
+ATOM   5573  CG  GLU B 195      41.733 -18.213  27.167  1.00 69.55           C  
+ATOM   5574  CD  GLU B 195      41.131 -19.369  27.937  1.00 72.47           C  
+ATOM   5575  OE1 GLU B 195      41.790 -19.857  28.881  1.00 73.48           O  
+ATOM   5576  OE2 GLU B 195      40.003 -19.790  27.598  1.00 73.08           O  
+ATOM   5577  N   LYS B 196      40.511 -14.780  27.691  1.00 62.36           N  
+ATOM   5578  CA  LYS B 196      39.264 -14.138  27.302  1.00 60.33           C  
+ATOM   5579  C   LYS B 196      39.524 -12.846  26.527  1.00 58.27           C  
+ATOM   5580  O   LYS B 196      39.005 -12.659  25.429  1.00 56.62           O  
+ATOM   5581  CB  LYS B 196      38.423 -13.854  28.550  1.00 61.03           C  
+ATOM   5582  CG  LYS B 196      38.009 -15.115  29.300  1.00 62.03           C  
+ATOM   5583  CD  LYS B 196      37.123 -14.798  30.498  1.00 64.33           C  
+ATOM   5584  CE  LYS B 196      36.631 -16.073  31.179  1.00 66.30           C  
+ATOM   5585  NZ  LYS B 196      35.775 -15.793  32.368  1.00 68.10           N  
+ATOM   5586  N   LEU B 197      40.341 -11.967  27.100  1.00 56.05           N  
+ATOM   5587  CA  LEU B 197      40.680 -10.702  26.468  1.00 54.65           C  
+ATOM   5588  C   LEU B 197      41.122 -10.856  25.012  1.00 56.48           C  
+ATOM   5589  O   LEU B 197      40.586 -10.195  24.120  1.00 56.45           O  
+ATOM   5590  CB  LEU B 197      41.782 -10.001  27.263  1.00 52.81           C  
+ATOM   5591  CG  LEU B 197      42.379  -8.733  26.645  1.00 51.83           C  
+ATOM   5592  CD1 LEU B 197      41.274  -7.729  26.330  1.00 52.30           C  
+ATOM   5593  CD2 LEU B 197      43.387  -8.138  27.598  1.00 48.99           C  
+ATOM   5594  N   LEU B 198      42.098 -11.726  24.768  1.00 57.67           N  
+ATOM   5595  CA  LEU B 198      42.589 -11.933  23.412  1.00 57.71           C  
+ATOM   5596  C   LEU B 198      41.537 -12.590  22.528  1.00 56.25           C  
+ATOM   5597  O   LEU B 198      41.523 -12.388  21.312  1.00 56.94           O  
+ATOM   5598  CB  LEU B 198      43.875 -12.768  23.427  1.00 59.02           C  
+ATOM   5599  CG  LEU B 198      45.057 -12.118  24.160  1.00 61.31           C  
+ATOM   5600  CD1 LEU B 198      46.283 -13.013  24.047  1.00 62.36           C  
+ATOM   5601  CD2 LEU B 198      45.356 -10.743  23.570  1.00 61.03           C  
+ATOM   5602  N   PHE B 199      40.650 -13.372  23.130  1.00 53.72           N  
+ATOM   5603  CA  PHE B 199      39.599 -14.014  22.351  1.00 53.36           C  
+ATOM   5604  C   PHE B 199      38.620 -12.944  21.860  1.00 53.09           C  
+ATOM   5605  O   PHE B 199      38.160 -12.980  20.715  1.00 52.96           O  
+ATOM   5606  CB  PHE B 199      38.839 -15.037  23.194  1.00 52.71           C  
+ATOM   5607  CG  PHE B 199      37.617 -15.584  22.512  1.00 54.10           C  
+ATOM   5608  CD1 PHE B 199      37.733 -16.530  21.501  1.00 54.62           C  
+ATOM   5609  CD2 PHE B 199      36.351 -15.114  22.847  1.00 54.57           C  
+ATOM   5610  CE1 PHE B 199      36.601 -17.001  20.828  1.00 55.85           C  
+ATOM   5611  CE2 PHE B 199      35.215 -15.575  22.182  1.00 54.99           C  
+ATOM   5612  CZ  PHE B 199      35.341 -16.521  21.170  1.00 56.01           C  
+ATOM   5613  N   PHE B 200      38.308 -11.995  22.739  1.00 51.12           N  
+ATOM   5614  CA  PHE B 200      37.384 -10.916  22.418  1.00 49.54           C  
+ATOM   5615  C   PHE B 200      38.005  -9.871  21.503  1.00 48.10           C  
+ATOM   5616  O   PHE B 200      37.368  -9.406  20.564  1.00 45.62           O  
+ATOM   5617  CB  PHE B 200      36.902 -10.240  23.703  1.00 48.71           C  
+ATOM   5618  CG  PHE B 200      36.027  -9.040  23.469  1.00 46.81           C  
+ATOM   5619  CD1 PHE B 200      36.521  -7.754  23.664  1.00 46.30           C  
+ATOM   5620  CD2 PHE B 200      34.713  -9.195  23.044  1.00 45.24           C  
+ATOM   5621  CE1 PHE B 200      35.715  -6.637  23.439  1.00 45.47           C  
+ATOM   5622  CE2 PHE B 200      33.901  -8.086  22.816  1.00 44.43           C  
+ATOM   5623  CZ  PHE B 200      34.402  -6.806  23.014  1.00 42.62           C  
+ATOM   5624  N   PHE B 201      39.254  -9.520  21.786  1.00 48.35           N  
+ATOM   5625  CA  PHE B 201      39.972  -8.510  21.023  1.00 49.46           C  
+ATOM   5626  C   PHE B 201      39.998  -8.749  19.520  1.00 49.57           C  
+ATOM   5627  O   PHE B 201      39.910  -7.802  18.746  1.00 49.45           O  
+ATOM   5628  CB  PHE B 201      41.407  -8.380  21.539  1.00 50.68           C  
+ATOM   5629  CG  PHE B 201      42.109  -7.137  21.069  1.00 52.05           C  
+ATOM   5630  CD1 PHE B 201      41.666  -5.879  21.474  1.00 52.73           C  
+ATOM   5631  CD2 PHE B 201      43.207  -7.221  20.219  1.00 53.11           C  
+ATOM   5632  CE1 PHE B 201      42.307  -4.720  21.040  1.00 52.99           C  
+ATOM   5633  CE2 PHE B 201      43.859  -6.068  19.777  1.00 53.80           C  
+ATOM   5634  CZ  PHE B 201      43.407  -4.813  20.189  1.00 54.15           C  
+ATOM   5635  N   VAL B 202      40.123 -10.001  19.096  1.00 50.21           N  
+ATOM   5636  CA  VAL B 202      40.163 -10.278  17.666  1.00 50.75           C  
+ATOM   5637  C   VAL B 202      38.877  -9.820  16.976  1.00 52.05           C  
+ATOM   5638  O   VAL B 202      38.925  -9.016  16.044  1.00 52.25           O  
+ATOM   5639  CB  VAL B 202      40.416 -11.779  17.389  1.00 51.80           C  
+ATOM   5640  CG1 VAL B 202      40.284 -12.074  15.900  1.00 48.33           C  
+ATOM   5641  CG2 VAL B 202      41.810 -12.157  17.873  1.00 51.13           C  
+ATOM   5642  N   PRO B 203      37.709 -10.321  17.418  1.00 52.78           N  
+ATOM   5643  CA  PRO B 203      36.465  -9.887  16.770  1.00 51.25           C  
+ATOM   5644  C   PRO B 203      36.259  -8.391  16.998  1.00 50.38           C  
+ATOM   5645  O   PRO B 203      35.796  -7.669  16.116  1.00 50.21           O  
+ATOM   5646  CB  PRO B 203      35.392 -10.717  17.478  1.00 51.82           C  
+ATOM   5647  CG  PRO B 203      36.129 -11.937  17.926  1.00 53.27           C  
+ATOM   5648  CD  PRO B 203      37.434 -11.357  18.427  1.00 53.26           C  
+ATOM   5649  N   PHE B 204      36.613  -7.932  18.193  1.00 47.83           N  
+ATOM   5650  CA  PHE B 204      36.459  -6.532  18.542  1.00 47.25           C  
+ATOM   5651  C   PHE B 204      37.165  -5.624  17.542  1.00 48.32           C  
+ATOM   5652  O   PHE B 204      36.554  -4.711  16.989  1.00 48.32           O  
+ATOM   5653  CB  PHE B 204      36.990  -6.284  19.955  1.00 44.81           C  
+ATOM   5654  CG  PHE B 204      37.112  -4.831  20.310  1.00 43.77           C  
+ATOM   5655  CD1 PHE B 204      38.358  -4.210  20.336  1.00 42.23           C  
+ATOM   5656  CD2 PHE B 204      35.981  -4.075  20.605  1.00 41.34           C  
+ATOM   5657  CE1 PHE B 204      38.474  -2.853  20.653  1.00 40.66           C  
+ATOM   5658  CE2 PHE B 204      36.090  -2.720  20.921  1.00 39.13           C  
+ATOM   5659  CZ  PHE B 204      37.336  -2.110  20.946  1.00 36.54           C  
+ATOM   5660  N   LEU B 205      38.447  -5.886  17.310  1.00 48.87           N  
+ATOM   5661  CA  LEU B 205      39.253  -5.101  16.381  1.00 50.01           C  
+ATOM   5662  C   LEU B 205      38.716  -5.203  14.959  1.00 50.14           C  
+ATOM   5663  O   LEU B 205      38.611  -4.205  14.252  1.00 50.33           O  
+ATOM   5664  CB  LEU B 205      40.703  -5.583  16.429  1.00 51.94           C  
+ATOM   5665  CG  LEU B 205      41.772  -4.866  15.605  1.00 53.68           C  
+ATOM   5666  CD1 LEU B 205      43.143  -5.238  16.150  1.00 53.59           C  
+ATOM   5667  CD2 LEU B 205      41.656  -5.246  14.136  1.00 54.85           C  
+ATOM   5668  N   LEU B 206      38.367  -6.416  14.552  1.00 49.81           N  
+ATOM   5669  CA  LEU B 206      37.846  -6.661  13.217  1.00 48.74           C  
+ATOM   5670  C   LEU B 206      36.522  -5.924  12.991  1.00 48.97           C  
+ATOM   5671  O   LEU B 206      36.355  -5.228  11.989  1.00 48.14           O  
+ATOM   5672  CB  LEU B 206      37.674  -8.173  13.012  1.00 50.67           C  
+ATOM   5673  CG  LEU B 206      37.320  -8.767  11.644  1.00 51.93           C  
+ATOM   5674  CD1 LEU B 206      35.836  -8.613  11.369  1.00 53.54           C  
+ATOM   5675  CD2 LEU B 206      38.158  -8.096  10.564  1.00 54.86           C  
+ATOM   5676  N   CYS B 207      35.586  -6.066  13.924  1.00 48.35           N  
+ATOM   5677  CA  CYS B 207      34.284  -5.413  13.797  1.00 47.61           C  
+ATOM   5678  C   CYS B 207      34.362  -3.889  13.873  1.00 45.90           C  
+ATOM   5679  O   CYS B 207      33.713  -3.190  13.092  1.00 45.17           O  
+ATOM   5680  CB  CYS B 207      33.322  -5.943  14.864  1.00 47.31           C  
+ATOM   5681  SG  CYS B 207      32.711  -7.610  14.506  1.00 53.04           S  
+ATOM   5682  N   SER B 208      35.159  -3.380  14.808  1.00 42.74           N  
+ATOM   5683  CA  SER B 208      35.322  -1.946  14.969  1.00 42.41           C  
+ATOM   5684  C   SER B 208      35.923  -1.303  13.723  1.00 43.75           C  
+ATOM   5685  O   SER B 208      35.506  -0.218  13.316  1.00 43.88           O  
+ATOM   5686  CB  SER B 208      36.213  -1.644  16.170  1.00 41.09           C  
+ATOM   5687  OG  SER B 208      35.591  -2.050  17.374  1.00 45.22           O  
+ATOM   5688  N   SER B 209      36.905  -1.973  13.124  1.00 43.01           N  
+ATOM   5689  CA  SER B 209      37.564  -1.455  11.929  1.00 42.28           C  
+ATOM   5690  C   SER B 209      36.600  -1.286  10.768  1.00 39.69           C  
+ATOM   5691  O   SER B 209      36.600  -0.251  10.106  1.00 40.69           O  
+ATOM   5692  CB  SER B 209      38.710  -2.375  11.504  1.00 43.85           C  
+ATOM   5693  OG  SER B 209      39.748  -2.354  12.464  1.00 49.38           O  
+ATOM   5694  N   ILE B 210      35.788  -2.304  10.518  1.00 37.32           N  
+ATOM   5695  CA  ILE B 210      34.825  -2.245   9.433  1.00 37.67           C  
+ATOM   5696  C   ILE B 210      33.793  -1.147   9.696  1.00 38.49           C  
+ATOM   5697  O   ILE B 210      33.474  -0.368   8.802  1.00 37.22           O  
+ATOM   5698  CB  ILE B 210      34.093  -3.593   9.249  1.00 37.23           C  
+ATOM   5699  CG1 ILE B 210      35.095  -4.690   8.864  1.00 37.75           C  
+ATOM   5700  CG2 ILE B 210      33.031  -3.466   8.154  1.00 37.26           C  
+ATOM   5701  CD1 ILE B 210      34.477  -6.066   8.718  0.00 37.50           C  
+ATOM   5702  N   LEU B 211      33.271  -1.082  10.921  1.00 38.64           N  
+ATOM   5703  CA  LEU B 211      32.284  -0.060  11.252  1.00 36.66           C  
+ATOM   5704  C   LEU B 211      32.887   1.330  11.117  1.00 35.72           C  
+ATOM   5705  O   LEU B 211      32.245   2.243  10.595  1.00 34.00           O  
+ATOM   5706  CB  LEU B 211      31.732  -0.269  12.667  1.00 35.30           C  
+ATOM   5707  CG  LEU B 211      30.839  -1.511  12.798  1.00 37.55           C  
+ATOM   5708  CD1 LEU B 211      30.470  -1.744  14.256  1.00 35.81           C  
+ATOM   5709  CD2 LEU B 211      29.587  -1.333  11.941  1.00 36.03           C  
+ATOM   5710  N   LEU B 212      34.122   1.490  11.576  1.00 35.76           N  
+ATOM   5711  CA  LEU B 212      34.790   2.782  11.483  1.00 36.98           C  
+ATOM   5712  C   LEU B 212      35.012   3.195  10.034  1.00 36.83           C  
+ATOM   5713  O   LEU B 212      34.982   4.379   9.716  1.00 38.59           O  
+ATOM   5714  CB  LEU B 212      36.126   2.757  12.222  1.00 36.33           C  
+ATOM   5715  CG  LEU B 212      36.008   2.838  13.745  1.00 38.53           C  
+ATOM   5716  CD1 LEU B 212      37.374   2.630  14.385  1.00 38.94           C  
+ATOM   5717  CD2 LEU B 212      35.425   4.180  14.140  1.00 35.48           C  
+ATOM   5718  N   SER B 213      35.216   2.222   9.152  1.00 34.97           N  
+ATOM   5719  CA  SER B 213      35.435   2.537   7.750  1.00 34.21           C  
+ATOM   5720  C   SER B 213      34.114   2.866   7.062  1.00 34.99           C  
+ATOM   5721  O   SER B 213      34.117   3.411   5.959  1.00 35.26           O  
+ATOM   5722  CB  SER B 213      36.128   1.378   7.032  1.00 33.09           C  
+ATOM   5723  OG  SER B 213      35.231   0.301   6.826  1.00 39.83           O  
+ATOM   5724  N   LEU B 214      32.997   2.524   7.714  1.00 34.06           N  
+ATOM   5725  CA  LEU B 214      31.643   2.809   7.213  1.00 32.93           C  
+ATOM   5726  C   LEU B 214      31.109   4.016   7.982  1.00 33.31           C  
+ATOM   5727  O   LEU B 214      29.930   4.361   7.902  1.00 33.99           O  
+ATOM   5728  CB  LEU B 214      30.697   1.630   7.463  1.00 33.85           C  
+ATOM   5729  CG  LEU B 214      30.775   0.395   6.573  1.00 36.46           C  
+ATOM   5730  CD1 LEU B 214      29.898  -0.694   7.159  1.00 38.28           C  
+ATOM   5731  CD2 LEU B 214      30.332   0.747   5.152  1.00 37.62           C  
+ATOM   5732  N   SER B 215      31.999   4.631   8.747  1.00 31.61           N  
+ATOM   5733  CA  SER B 215      31.686   5.790   9.565  1.00 33.82           C  
+ATOM   5734  C   SER B 215      30.758   6.809   8.918  1.00 33.68           C  
+ATOM   5735  O   SER B 215      29.675   7.096   9.430  1.00 32.64           O  
+ATOM   5736  CB  SER B 215      32.979   6.501   9.945  1.00 32.80           C  
+ATOM   5737  OG  SER B 215      33.099   6.539  11.340  1.00 41.51           O  
+ATOM   5738  N   TRP B 216      31.206   7.369   7.800  1.00 32.16           N  
+ATOM   5739  CA  TRP B 216      30.440   8.387   7.105  1.00 31.18           C  
+ATOM   5740  C   TRP B 216      29.210   7.813   6.428  1.00 31.11           C  
+ATOM   5741  O   TRP B 216      28.165   8.456   6.377  1.00 29.11           O  
+ATOM   5742  CB  TRP B 216      31.318   9.092   6.067  1.00 28.73           C  
+ATOM   5743  CG  TRP B 216      30.601  10.189   5.353  1.00 28.20           C  
+ATOM   5744  CD1 TRP B 216      30.374  11.461   5.811  1.00 25.25           C  
+ATOM   5745  CD2 TRP B 216      29.966  10.100   4.073  1.00 24.05           C  
+ATOM   5746  NE1 TRP B 216      29.634  12.164   4.890  1.00 29.80           N  
+ATOM   5747  CE2 TRP B 216      29.369  11.354   3.815  1.00 27.26           C  
+ATOM   5748  CE3 TRP B 216      29.841   9.079   3.122  1.00 25.28           C  
+ATOM   5749  CZ2 TRP B 216      28.652  11.619   2.636  1.00 23.92           C  
+ATOM   5750  CZ3 TRP B 216      29.127   9.337   1.950  1.00 25.36           C  
+ATOM   5751  CH2 TRP B 216      28.541  10.603   1.720  1.00 24.03           C  
+ATOM   5752  N   ARG B 217      29.330   6.601   5.909  1.00 31.78           N  
+ATOM   5753  CA  ARG B 217      28.205   5.986   5.229  1.00 33.55           C  
+ATOM   5754  C   ARG B 217      27.022   5.772   6.177  1.00 33.66           C  
+ATOM   5755  O   ARG B 217      25.876   5.713   5.735  1.00 31.47           O  
+ATOM   5756  CB  ARG B 217      28.621   4.658   4.603  1.00 33.67           C  
+ATOM   5757  CG  ARG B 217      27.728   4.252   3.444  1.00 37.49           C  
+ATOM   5758  CD  ARG B 217      28.555   4.080   2.194  1.00 39.11           C  
+ATOM   5759  NE  ARG B 217      27.871   4.603   1.020  1.00 43.10           N  
+ATOM   5760  CZ  ARG B 217      28.415   5.462   0.164  1.00 41.60           C  
+ATOM   5761  NH1 ARG B 217      27.716   5.883  -0.880  1.00 44.40           N  
+ATOM   5762  NH2 ARG B 217      29.654   5.904   0.353  1.00 41.42           N  
+ATOM   5763  N   LEU B 218      27.295   5.666   7.476  1.00 33.67           N  
+ATOM   5764  CA  LEU B 218      26.223   5.478   8.450  1.00 34.45           C  
+ATOM   5765  C   LEU B 218      25.259   6.653   8.408  1.00 31.62           C  
+ATOM   5766  O   LEU B 218      24.073   6.494   8.673  1.00 30.77           O  
+ATOM   5767  CB  LEU B 218      26.781   5.334   9.873  1.00 39.37           C  
+ATOM   5768  CG  LEU B 218      27.503   4.026  10.210  1.00 45.28           C  
+ATOM   5769  CD1 LEU B 218      27.900   4.041  11.682  1.00 48.56           C  
+ATOM   5770  CD2 LEU B 218      26.594   2.826   9.917  1.00 46.98           C  
+ATOM   5771  N   ASN B 219      25.768   7.835   8.080  1.00 29.69           N  
+ATOM   5772  CA  ASN B 219      24.914   9.013   8.003  1.00 28.98           C  
+ATOM   5773  C   ASN B 219      23.779   8.783   7.019  1.00 27.87           C  
+ATOM   5774  O   ASN B 219      22.669   9.259   7.223  1.00 27.50           O  
+ATOM   5775  CB  ASN B 219      25.710  10.246   7.566  1.00 27.96           C  
+ATOM   5776  CG  ASN B 219      26.677  10.726   8.628  1.00 31.82           C  
+ATOM   5777  OD1 ASN B 219      26.408  10.622   9.820  1.00 33.19           O  
+ATOM   5778  ND2 ASN B 219      27.805  11.275   8.196  1.00 33.49           N  
+ATOM   5779  N   LEU B 220      24.069   8.040   5.957  1.00 29.74           N  
+ATOM   5780  CA  LEU B 220      23.102   7.741   4.907  1.00 31.58           C  
+ATOM   5781  C   LEU B 220      21.958   6.820   5.322  1.00 33.32           C  
+ATOM   5782  O   LEU B 220      20.922   6.786   4.655  1.00 29.49           O  
+ATOM   5783  CB  LEU B 220      23.829   7.149   3.706  1.00 33.00           C  
+ATOM   5784  CG  LEU B 220      24.943   8.066   3.206  1.00 33.14           C  
+ATOM   5785  CD1 LEU B 220      25.728   7.352   2.128  1.00 35.02           C  
+ATOM   5786  CD2 LEU B 220      24.345   9.377   2.687  1.00 34.42           C  
+ATOM   5787  N   LEU B 221      22.141   6.067   6.405  1.00 36.42           N  
+ATOM   5788  CA  LEU B 221      21.075   5.192   6.893  1.00 41.29           C  
+ATOM   5789  C   LEU B 221      19.918   6.031   7.442  1.00 42.22           C  
+ATOM   5790  O   LEU B 221      18.855   5.500   7.757  1.00 44.73           O  
+ATOM   5791  CB  LEU B 221      21.582   4.272   8.006  1.00 43.90           C  
+ATOM   5792  CG  LEU B 221      22.369   3.019   7.616  1.00 47.17           C  
+ATOM   5793  CD1 LEU B 221      22.762   2.259   8.874  1.00 49.66           C  
+ATOM   5794  CD2 LEU B 221      21.519   2.137   6.722  1.00 48.66           C  
+ATOM   5795  N   SER B 222      20.136   7.337   7.553  1.00 41.41           N  
+ATOM   5796  CA  SER B 222      19.130   8.264   8.067  1.00 44.28           C  
+ATOM   5797  C   SER B 222      18.234   8.815   6.946  1.00 45.20           C  
+ATOM   5798  O   SER B 222      17.308   9.581   7.196  1.00 44.73           O  
+ATOM   5799  CB  SER B 222      19.828   9.427   8.788  1.00 47.28           C  
+ATOM   5800  OG  SER B 222      20.829   8.953   9.694  1.00 51.49           O  
+ATOM   5801  N   LEU B 223      18.516   8.420   5.711  1.00 46.50           N  
+ATOM   5802  CA  LEU B 223      17.743   8.873   4.558  1.00 47.93           C  
+ATOM   5803  C   LEU B 223      16.450   8.083   4.332  1.00 49.38           C  
+ATOM   5804  O   LEU B 223      16.254   7.011   4.899  1.00 48.66           O  
+ATOM   5805  CB  LEU B 223      18.610   8.788   3.299  1.00 47.16           C  
+ATOM   5806  CG  LEU B 223      19.490   9.979   2.895  1.00 48.05           C  
+ATOM   5807  CD1 LEU B 223      19.676  10.941   4.044  1.00 50.09           C  
+ATOM   5808  CD2 LEU B 223      20.822   9.455   2.401  1.00 48.70           C  
+ATOM   5809  N   ASP B 224      15.557   8.635   3.515  1.00 50.85           N  
+ATOM   5810  CA  ASP B 224      14.316   7.947   3.194  1.00 52.01           C  
+ATOM   5811  C   ASP B 224      14.507   7.253   1.846  1.00 52.65           C  
+ATOM   5812  O   ASP B 224      15.373   7.634   1.045  1.00 49.95           O  
+ATOM   5813  CB  ASP B 224      13.136   8.922   3.116  1.00 54.76           C  
+ATOM   5814  CG  ASP B 224      12.064   8.634   4.169  1.00 59.82           C  
+ATOM   5815  OD1 ASP B 224      10.952   9.202   4.065  1.00 61.16           O  
+ATOM   5816  OD2 ASP B 224      12.332   7.845   5.109  1.00 61.94           O  
+ATOM   5817  N   GLU B 225      13.690   6.233   1.613  1.00 52.49           N  
+ATOM   5818  CA  GLU B 225      13.739   5.436   0.400  1.00 51.58           C  
+ATOM   5819  C   GLU B 225      14.064   6.220  -0.876  1.00 50.74           C  
+ATOM   5820  O   GLU B 225      15.040   5.919  -1.566  1.00 49.91           O  
+ATOM   5821  CB  GLU B 225      12.407   4.700   0.236  1.00 53.82           C  
+ATOM   5822  CG  GLU B 225      12.412   3.602  -0.821  1.00 60.04           C  
+ATOM   5823  CD  GLU B 225      11.110   2.805  -0.844  1.00 63.50           C  
+ATOM   5824  OE1 GLU B 225      11.035   1.795  -1.578  1.00 65.71           O  
+ATOM   5825  OE2 GLU B 225      10.161   3.189  -0.130  1.00 65.12           O  
+ATOM   5826  N   LYS B 226      13.258   7.228  -1.185  1.00 49.87           N  
+ATOM   5827  CA  LYS B 226      13.463   7.999  -2.406  1.00 49.61           C  
+ATOM   5828  C   LYS B 226      14.840   8.638  -2.555  1.00 47.86           C  
+ATOM   5829  O   LYS B 226      15.448   8.550  -3.627  1.00 47.02           O  
+ATOM   5830  CB  LYS B 226      12.372   9.064  -2.557  1.00 51.78           C  
+ATOM   5831  CG  LYS B 226      10.956   8.513  -2.441  1.00 56.10           C  
+ATOM   5832  CD  LYS B 226       9.925   9.495  -2.976  1.00 58.90           C  
+ATOM   5833  CE  LYS B 226       8.599   9.364  -2.239  1.00 61.08           C  
+ATOM   5834  NZ  LYS B 226       8.091   7.966  -2.228  1.00 62.76           N  
+ATOM   5835  N   GLU B 227      15.341   9.279  -1.501  1.00 46.54           N  
+ATOM   5836  CA  GLU B 227      16.656   9.908  -1.590  1.00 44.57           C  
+ATOM   5837  C   GLU B 227      17.737   8.835  -1.686  1.00 43.45           C  
+ATOM   5838  O   GLU B 227      18.682   8.955  -2.477  1.00 39.26           O  
+ATOM   5839  CB  GLU B 227      16.925  10.814  -0.384  1.00 44.92           C  
+ATOM   5840  CG  GLU B 227      18.190  11.664  -0.545  1.00 44.12           C  
+ATOM   5841  CD  GLU B 227      18.112  12.593  -1.743  1.00 45.78           C  
+ATOM   5842  OE1 GLU B 227      19.147  13.185  -2.124  1.00 46.88           O  
+ATOM   5843  OE2 GLU B 227      17.008  12.739  -2.305  1.00 46.28           O  
+ATOM   5844  N   ALA B 228      17.587   7.785  -0.881  1.00 43.96           N  
+ATOM   5845  CA  ALA B 228      18.535   6.674  -0.889  1.00 45.11           C  
+ATOM   5846  C   ALA B 228      18.653   6.123  -2.309  1.00 46.71           C  
+ATOM   5847  O   ALA B 228      19.755   5.884  -2.808  1.00 47.88           O  
+ATOM   5848  CB  ALA B 228      18.065   5.582   0.057  1.00 43.76           C  
+ATOM   5849  N   LYS B 229      17.513   5.942  -2.963  1.00 46.94           N  
+ATOM   5850  CA  LYS B 229      17.493   5.425  -4.324  1.00 49.26           C  
+ATOM   5851  C   LYS B 229      18.204   6.402  -5.251  1.00 50.21           C  
+ATOM   5852  O   LYS B 229      19.019   6.002  -6.088  1.00 51.02           O  
+ATOM   5853  CB  LYS B 229      16.044   5.233  -4.793  1.00 51.65           C  
+ATOM   5854  CG  LYS B 229      15.856   4.181  -5.880  1.00 53.66           C  
+ATOM   5855  CD  LYS B 229      16.518   4.581  -7.181  1.00 56.69           C  
+ATOM   5856  CE  LYS B 229      16.370   3.479  -8.220  1.00 59.04           C  
+ATOM   5857  NZ  LYS B 229      16.910   2.183  -7.713  1.00 60.51           N  
+ATOM   5858  N   ALA B 230      17.882   7.684  -5.107  1.00 49.06           N  
+ATOM   5859  CA  ALA B 230      18.497   8.710  -5.934  1.00 48.43           C  
+ATOM   5860  C   ALA B 230      19.997   8.747  -5.675  1.00 46.12           C  
+ATOM   5861  O   ALA B 230      20.795   8.799  -6.604  1.00 45.11           O  
+ATOM   5862  CB  ALA B 230      17.875  10.076  -5.633  1.00 50.06           C  
+ATOM   5863  N   LEU B 231      20.373   8.702  -4.404  1.00 46.64           N  
+ATOM   5864  CA  LEU B 231      21.782   8.743  -4.026  1.00 47.39           C  
+ATOM   5865  C   LEU B 231      22.484   7.402  -4.224  1.00 48.24           C  
+ATOM   5866  O   LEU B 231      23.634   7.227  -3.809  1.00 50.07           O  
+ATOM   5867  CB  LEU B 231      21.917   9.207  -2.572  1.00 44.73           C  
+ATOM   5868  CG  LEU B 231      21.415  10.639  -2.339  1.00 43.80           C  
+ATOM   5869  CD1 LEU B 231      21.640  11.048  -0.888  1.00 41.07           C  
+ATOM   5870  CD2 LEU B 231      22.141  11.585  -3.282  1.00 39.84           C  
+ATOM   5871  N   GLY B 232      21.780   6.466  -4.861  1.00 48.44           N  
+ATOM   5872  CA  GLY B 232      22.331   5.151  -5.138  1.00 45.78           C  
+ATOM   5873  C   GLY B 232      22.788   4.373  -3.919  1.00 45.09           C  
+ATOM   5874  O   GLY B 232      23.725   3.582  -4.004  1.00 45.08           O  
+ATOM   5875  N   VAL B 233      22.127   4.585  -2.789  1.00 43.71           N  
+ATOM   5876  CA  VAL B 233      22.487   3.893  -1.563  1.00 44.47           C  
+ATOM   5877  C   VAL B 233      21.774   2.556  -1.458  1.00 46.24           C  
+ATOM   5878  O   VAL B 233      20.554   2.480  -1.582  1.00 46.93           O  
+ATOM   5879  CB  VAL B 233      22.127   4.732  -0.318  1.00 43.41           C  
+ATOM   5880  CG1 VAL B 233      22.535   3.987   0.940  1.00 44.19           C  
+ATOM   5881  CG2 VAL B 233      22.824   6.091  -0.381  1.00 42.83           C  
+ATOM   5882  N   LYS B 234      22.545   1.500  -1.233  1.00 49.12           N  
+ATOM   5883  CA  LYS B 234      21.988   0.158  -1.085  1.00 52.16           C  
+ATOM   5884  C   LYS B 234      21.662  -0.013   0.392  1.00 50.68           C  
+ATOM   5885  O   LYS B 234      22.428  -0.607   1.148  1.00 50.58           O  
+ATOM   5886  CB  LYS B 234      23.011  -0.896  -1.527  1.00 55.79           C  
+ATOM   5887  CG  LYS B 234      23.529  -0.717  -2.950  1.00 58.83           C  
+ATOM   5888  CD  LYS B 234      22.381  -0.656  -3.957  1.00 63.56           C  
+ATOM   5889  CE  LYS B 234      22.893  -0.648  -5.395  1.00 65.71           C  
+ATOM   5890  NZ  LYS B 234      23.578  -1.934  -5.740  1.00 67.62           N  
+ATOM   5891  N   MET B 235      20.517   0.530   0.788  1.00 50.80           N  
+ATOM   5892  CA  MET B 235      20.058   0.498   2.169  1.00 50.11           C  
+ATOM   5893  C   MET B 235      20.041  -0.884   2.814  1.00 49.03           C  
+ATOM   5894  O   MET B 235      20.655  -1.084   3.859  1.00 48.56           O  
+ATOM   5895  CB  MET B 235      18.664   1.116   2.256  1.00 51.54           C  
+ATOM   5896  CG  MET B 235      18.183   1.380   3.675  1.00 55.72           C  
+ATOM   5897  SD  MET B 235      19.122   2.688   4.512  1.00 60.05           S  
+ATOM   5898  CE  MET B 235      18.226   4.155   3.988  1.00 56.03           C  
+ATOM   5899  N   ALA B 236      19.337  -1.827   2.193  1.00 48.01           N  
+ATOM   5900  CA  ALA B 236      19.214  -3.185   2.716  1.00 47.12           C  
+ATOM   5901  C   ALA B 236      20.561  -3.822   3.053  1.00 45.90           C  
+ATOM   5902  O   ALA B 236      20.809  -4.184   4.201  1.00 46.55           O  
+ATOM   5903  CB  ALA B 236      18.442  -4.062   1.723  1.00 48.79           C  
+ATOM   5904  N   PRO B 237      21.446  -3.972   2.059  1.00 44.25           N  
+ATOM   5905  CA  PRO B 237      22.761  -4.571   2.311  1.00 44.02           C  
+ATOM   5906  C   PRO B 237      23.524  -3.887   3.446  1.00 43.45           C  
+ATOM   5907  O   PRO B 237      24.058  -4.548   4.336  1.00 43.62           O  
+ATOM   5908  CB  PRO B 237      23.476  -4.400   0.973  1.00 43.39           C  
+ATOM   5909  CG  PRO B 237      22.369  -4.515  -0.007  1.00 43.12           C  
+ATOM   5910  CD  PRO B 237      21.267  -3.693   0.624  1.00 43.29           C  
+ATOM   5911  N   LEU B 238      23.577  -2.558   3.392  1.00 43.00           N  
+ATOM   5912  CA  LEU B 238      24.283  -1.756   4.389  1.00 41.63           C  
+ATOM   5913  C   LEU B 238      23.726  -1.972   5.793  1.00 40.61           C  
+ATOM   5914  O   LEU B 238      24.473  -2.188   6.749  1.00 38.40           O  
+ATOM   5915  CB  LEU B 238      24.182  -0.269   4.018  1.00 43.07           C  
+ATOM   5916  CG  LEU B 238      24.693   0.746   5.050  1.00 44.54           C  
+ATOM   5917  CD1 LEU B 238      26.195   0.589   5.215  1.00 43.58           C  
+ATOM   5918  CD2 LEU B 238      24.347   2.168   4.604  1.00 44.47           C  
+ATOM   5919  N   ARG B 239      22.404  -1.906   5.894  1.00 39.25           N  
+ATOM   5920  CA  ARG B 239      21.693  -2.067   7.149  1.00 41.73           C  
+ATOM   5921  C   ARG B 239      21.999  -3.422   7.797  1.00 42.59           C  
+ATOM   5922  O   ARG B 239      22.303  -3.494   8.992  1.00 42.97           O  
+ATOM   5923  CB  ARG B 239      20.197  -1.911   6.876  1.00 44.41           C  
+ATOM   5924  CG  ARG B 239      19.332  -1.680   8.089  1.00 47.49           C  
+ATOM   5925  CD  ARG B 239      17.891  -1.380   7.674  1.00 50.98           C  
+ATOM   5926  NE  ARG B 239      17.722  -0.046   7.093  1.00 52.09           N  
+ATOM   5927  CZ  ARG B 239      16.567   0.416   6.621  1.00 54.02           C  
+ATOM   5928  NH1 ARG B 239      16.492   1.636   6.115  1.00 56.30           N  
+ATOM   5929  NH2 ARG B 239      15.481  -0.344   6.650  1.00 54.66           N  
+ATOM   5930  N   TRP B 240      21.930  -4.490   7.006  1.00 41.95           N  
+ATOM   5931  CA  TRP B 240      22.215  -5.828   7.505  1.00 43.23           C  
+ATOM   5932  C   TRP B 240      23.680  -6.009   7.881  1.00 43.05           C  
+ATOM   5933  O   TRP B 240      23.989  -6.706   8.846  1.00 42.88           O  
+ATOM   5934  CB  TRP B 240      21.805  -6.881   6.474  1.00 45.81           C  
+ATOM   5935  CG  TRP B 240      20.330  -7.070   6.430  1.00 48.08           C  
+ATOM   5936  CD1 TRP B 240      19.494  -6.781   5.391  1.00 47.99           C  
+ATOM   5937  CD2 TRP B 240      19.500  -7.531   7.502  1.00 49.22           C  
+ATOM   5938  NE1 TRP B 240      18.188  -7.028   5.752  1.00 49.98           N  
+ATOM   5939  CE2 TRP B 240      18.164  -7.489   7.043  1.00 50.28           C  
+ATOM   5940  CE3 TRP B 240      19.756  -7.974   8.808  1.00 50.13           C  
+ATOM   5941  CZ2 TRP B 240      17.083  -7.873   7.844  1.00 50.20           C  
+ATOM   5942  CZ3 TRP B 240      18.678  -8.357   9.609  1.00 50.31           C  
+ATOM   5943  CH2 TRP B 240      17.359  -8.302   9.121  1.00 50.65           C  
+ATOM   5944  N   LEU B 241      24.581  -5.376   7.133  1.00 41.20           N  
+ATOM   5945  CA  LEU B 241      26.003  -5.475   7.437  1.00 41.18           C  
+ATOM   5946  C   LEU B 241      26.243  -4.899   8.831  1.00 41.52           C  
+ATOM   5947  O   LEU B 241      26.927  -5.504   9.661  1.00 42.25           O  
+ATOM   5948  CB  LEU B 241      26.834  -4.688   6.420  1.00 40.88           C  
+ATOM   5949  CG  LEU B 241      28.275  -5.152   6.149  1.00 41.40           C  
+ATOM   5950  CD1 LEU B 241      29.152  -3.939   5.962  1.00 41.55           C  
+ATOM   5951  CD2 LEU B 241      28.806  -6.012   7.280  1.00 42.14           C  
+ATOM   5952  N   VAL B 242      25.678  -3.720   9.077  1.00 40.23           N  
+ATOM   5953  CA  VAL B 242      25.817  -3.049  10.366  1.00 39.98           C  
+ATOM   5954  C   VAL B 242      25.145  -3.863  11.480  1.00 39.43           C  
+ATOM   5955  O   VAL B 242      25.683  -3.980  12.576  1.00 37.04           O  
+ATOM   5956  CB  VAL B 242      25.204  -1.625  10.310  1.00 40.00           C  
+ATOM   5957  CG1 VAL B 242      25.241  -0.971  11.680  1.00 42.01           C  
+ATOM   5958  CG2 VAL B 242      25.968  -0.783   9.312  1.00 39.94           C  
+ATOM   5959  N   ILE B 243      23.970  -4.424  11.201  1.00 39.63           N  
+ATOM   5960  CA  ILE B 243      23.284  -5.229  12.204  1.00 40.66           C  
+ATOM   5961  C   ILE B 243      24.148  -6.432  12.598  1.00 42.52           C  
+ATOM   5962  O   ILE B 243      24.287  -6.734  13.787  1.00 42.46           O  
+ATOM   5963  CB  ILE B 243      21.907  -5.746  11.703  1.00 40.70           C  
+ATOM   5964  CG1 ILE B 243      20.886  -4.599  11.670  1.00 38.19           C  
+ATOM   5965  CG2 ILE B 243      21.417  -6.882  12.603  1.00 39.18           C  
+ATOM   5966  CD1 ILE B 243      19.523  -5.002  11.146  0.00 39.18           C  
+ATOM   5967  N   PHE B 244      24.733  -7.109  11.609  1.00 42.27           N  
+ATOM   5968  CA  PHE B 244      25.570  -8.272  11.887  1.00 43.63           C  
+ATOM   5969  C   PHE B 244      26.860  -7.925  12.621  1.00 42.78           C  
+ATOM   5970  O   PHE B 244      27.281  -8.653  13.515  1.00 43.51           O  
+ATOM   5971  CB  PHE B 244      25.891  -9.039  10.595  1.00 47.58           C  
+ATOM   5972  CG  PHE B 244      24.755  -9.916  10.113  1.00 53.31           C  
+ATOM   5973  CD1 PHE B 244      23.990  -9.557   9.002  1.00 53.99           C  
+ATOM   5974  CD2 PHE B 244      24.430 -11.093  10.791  1.00 54.26           C  
+ATOM   5975  CE1 PHE B 244      22.917 -10.355   8.574  1.00 53.83           C  
+ATOM   5976  CE2 PHE B 244      23.359 -11.893  10.369  1.00 54.77           C  
+ATOM   5977  CZ  PHE B 244      22.603 -11.520   9.259  1.00 54.07           C  
+ATOM   5978  N   LEU B 245      27.479  -6.809  12.259  1.00 41.36           N  
+ATOM   5979  CA  LEU B 245      28.715  -6.390  12.910  1.00 40.61           C  
+ATOM   5980  C   LEU B 245      28.484  -5.964  14.354  1.00 40.84           C  
+ATOM   5981  O   LEU B 245      29.290  -6.269  15.233  1.00 41.19           O  
+ATOM   5982  CB  LEU B 245      29.363  -5.238  12.139  1.00 40.67           C  
+ATOM   5983  CG  LEU B 245      29.892  -5.595  10.747  1.00 43.00           C  
+ATOM   5984  CD1 LEU B 245      30.330  -4.334  10.023  1.00 41.89           C  
+ATOM   5985  CD2 LEU B 245      31.052  -6.575  10.883  1.00 42.25           C  
+ATOM   5986  N   SER B 246      27.402  -5.242  14.608  1.00 39.48           N  
+ATOM   5987  CA  SER B 246      27.132  -4.819  15.973  1.00 41.40           C  
+ATOM   5988  C   SER B 246      26.647  -6.021  16.790  1.00 40.32           C  
+ATOM   5989  O   SER B 246      26.929  -6.122  17.981  1.00 39.09           O  
+ATOM   5990  CB  SER B 246      26.100  -3.684  15.993  1.00 40.76           C  
+ATOM   5991  OG  SER B 246      24.970  -3.997  15.203  1.00 46.64           O  
+ATOM   5992  N   GLY B 247      25.938  -6.936  16.134  1.00 39.82           N  
+ATOM   5993  CA  GLY B 247      25.444  -8.121  16.813  1.00 41.11           C  
+ATOM   5994  C   GLY B 247      26.596  -9.038  17.169  1.00 42.64           C  
+ATOM   5995  O   GLY B 247      26.640  -9.605  18.260  1.00 43.04           O  
+ATOM   5996  N   SER B 248      27.538  -9.181  16.245  1.00 43.61           N  
+ATOM   5997  CA  SER B 248      28.702 -10.022  16.477  1.00 46.64           C  
+ATOM   5998  C   SER B 248      29.487  -9.492  17.673  1.00 46.54           C  
+ATOM   5999  O   SER B 248      30.004 -10.251  18.497  1.00 45.84           O  
+ATOM   6000  CB  SER B 248      29.603 -10.024  15.242  1.00 47.76           C  
+ATOM   6001  OG  SER B 248      28.925 -10.574  14.124  1.00 52.71           O  
+ATOM   6002  N   LEU B 249      29.558  -8.173  17.754  1.00 45.97           N  
+ATOM   6003  CA  LEU B 249      30.279  -7.498  18.813  1.00 46.64           C  
+ATOM   6004  C   LEU B 249      29.693  -7.823  20.182  1.00 46.46           C  
+ATOM   6005  O   LEU B 249      30.427  -8.067  21.139  1.00 46.44           O  
+ATOM   6006  CB  LEU B 249      30.233  -5.993  18.555  1.00 46.46           C  
+ATOM   6007  CG  LEU B 249      31.400  -5.109  18.987  1.00 48.25           C  
+ATOM   6008  CD1 LEU B 249      32.717  -5.783  18.681  1.00 47.73           C  
+ATOM   6009  CD2 LEU B 249      31.296  -3.770  18.246  1.00 48.59           C  
+ATOM   6010  N   VAL B 250      28.368  -7.840  20.270  1.00 45.74           N  
+ATOM   6011  CA  VAL B 250      27.698  -8.114  21.533  1.00 45.27           C  
+ATOM   6012  C   VAL B 250      27.783  -9.582  21.935  1.00 44.83           C  
+ATOM   6013  O   VAL B 250      28.026  -9.894  23.102  1.00 42.00           O  
+ATOM   6014  CB  VAL B 250      26.215  -7.691  21.481  1.00 46.15           C  
+ATOM   6015  CG1 VAL B 250      25.552  -7.973  22.810  1.00 47.67           C  
+ATOM   6016  CG2 VAL B 250      26.110  -6.211  21.160  1.00 47.46           C  
+ATOM   6017  N   ALA B 251      27.581 -10.475  20.971  1.00 44.41           N  
+ATOM   6018  CA  ALA B 251      27.646 -11.907  21.239  1.00 44.15           C  
+ATOM   6019  C   ALA B 251      29.005 -12.254  21.830  1.00 44.25           C  
+ATOM   6020  O   ALA B 251      29.088 -12.970  22.831  1.00 43.28           O  
+ATOM   6021  CB  ALA B 251      27.408 -12.701  19.961  1.00 44.87           C  
+ATOM   6022  N   CYS B 252      30.071 -11.738  21.224  1.00 41.95           N  
+ATOM   6023  CA  CYS B 252      31.406 -12.011  21.731  1.00 42.38           C  
+ATOM   6024  C   CYS B 252      31.596 -11.399  23.112  1.00 43.42           C  
+ATOM   6025  O   CYS B 252      32.310 -11.951  23.950  1.00 44.07           O  
+ATOM   6026  CB  CYS B 252      32.466 -11.481  20.766  1.00 42.08           C  
+ATOM   6027  SG  CYS B 252      32.478 -12.359  19.182  1.00 46.55           S  
+ATOM   6028  N   GLN B 253      30.950 -10.264  23.355  1.00 43.91           N  
+ATOM   6029  CA  GLN B 253      31.057  -9.605  24.653  1.00 44.15           C  
+ATOM   6030  C   GLN B 253      30.378 -10.447  25.733  1.00 43.78           C  
+ATOM   6031  O   GLN B 253      30.932 -10.650  26.811  1.00 42.63           O  
+ATOM   6032  CB  GLN B 253      30.430  -8.203  24.596  1.00 44.12           C  
+ATOM   6033  CG  GLN B 253      30.312  -7.499  25.946  1.00 43.72           C  
+ATOM   6034  CD  GLN B 253      28.981  -7.760  26.634  1.00 45.59           C  
+ATOM   6035  OE1 GLN B 253      28.910  -7.835  27.860  1.00 49.14           O  
+ATOM   6036  NE2 GLN B 253      27.919  -7.886  25.847  1.00 43.65           N  
+ATOM   6037  N   VAL B 254      29.177 -10.932  25.443  1.00 43.10           N  
+ATOM   6038  CA  VAL B 254      28.449 -11.749  26.402  1.00 44.40           C  
+ATOM   6039  C   VAL B 254      29.280 -12.991  26.723  1.00 46.11           C  
+ATOM   6040  O   VAL B 254      29.476 -13.339  27.889  1.00 46.24           O  
+ATOM   6041  CB  VAL B 254      27.079 -12.175  25.833  1.00 43.11           C  
+ATOM   6042  CG1 VAL B 254      26.397 -13.178  26.767  1.00 39.09           C  
+ATOM   6043  CG2 VAL B 254      26.202 -10.941  25.651  1.00 43.01           C  
+ATOM   6044  N   ALA B 255      29.781 -13.628  25.670  1.00 46.28           N  
+ATOM   6045  CA  ALA B 255      30.594 -14.831  25.774  1.00 46.58           C  
+ATOM   6046  C   ALA B 255      31.702 -14.751  26.826  1.00 46.90           C  
+ATOM   6047  O   ALA B 255      31.986 -15.742  27.492  1.00 47.10           O  
+ATOM   6048  CB  ALA B 255      31.197 -15.163  24.410  1.00 43.76           C  
+ATOM   6049  N   ILE B 256      32.321 -13.584  26.990  1.00 46.03           N  
+ATOM   6050  CA  ILE B 256      33.401 -13.460  27.963  1.00 44.61           C  
+ATOM   6051  C   ILE B 256      33.113 -12.598  29.192  1.00 45.07           C  
+ATOM   6052  O   ILE B 256      34.000 -12.407  30.031  1.00 44.04           O  
+ATOM   6053  CB  ILE B 256      34.695 -12.919  27.302  1.00 44.60           C  
+ATOM   6054  CG1 ILE B 256      34.550 -11.423  26.995  1.00 43.05           C  
+ATOM   6055  CG2 ILE B 256      34.994 -13.710  26.027  1.00 43.63           C  
+ATOM   6056  CD1 ILE B 256      35.855 -10.740  26.672  0.00 43.69           C  
+ATOM   6057  N   SER B 257      31.893 -12.082  29.320  1.00 44.06           N  
+ATOM   6058  CA  SER B 257      31.588 -11.243  30.474  1.00 45.10           C  
+ATOM   6059  C   SER B 257      30.117 -11.180  30.875  1.00 45.07           C  
+ATOM   6060  O   SER B 257      29.736 -10.377  31.729  1.00 45.28           O  
+ATOM   6061  CB  SER B 257      32.113  -9.823  30.237  1.00 47.19           C  
+ATOM   6062  OG  SER B 257      31.565  -9.258  29.053  1.00 47.92           O  
+ATOM   6063  N   GLY B 258      29.289 -12.021  30.268  1.00 44.49           N  
+ATOM   6064  CA  GLY B 258      27.879 -12.019  30.616  1.00 45.03           C  
+ATOM   6065  C   GLY B 258      27.070 -10.849  30.079  1.00 46.01           C  
+ATOM   6066  O   GLY B 258      27.524 -10.091  29.220  1.00 46.11           O  
+ATOM   6067  N   SER B 259      25.860 -10.703  30.605  1.00 45.63           N  
+ATOM   6068  CA  SER B 259      24.948  -9.652  30.185  1.00 44.53           C  
+ATOM   6069  C   SER B 259      25.177  -8.320  30.896  1.00 43.48           C  
+ATOM   6070  O   SER B 259      24.974  -8.207  32.104  1.00 43.18           O  
+ATOM   6071  CB  SER B 259      23.507 -10.122  30.403  1.00 46.07           C  
+ATOM   6072  OG  SER B 259      22.572  -9.115  30.056  1.00 51.73           O  
+ATOM   6073  N   ILE B 260      25.603  -7.314  30.136  1.00 41.89           N  
+ATOM   6074  CA  ILE B 260      25.845  -5.980  30.681  1.00 41.73           C  
+ATOM   6075  C   ILE B 260      24.983  -4.948  29.946  1.00 40.88           C  
+ATOM   6076  O   ILE B 260      25.042  -4.833  28.723  1.00 41.41           O  
+ATOM   6077  CB  ILE B 260      27.326  -5.573  30.541  1.00 42.27           C  
+ATOM   6078  CG1 ILE B 260      28.230  -6.615  31.215  1.00 42.60           C  
+ATOM   6079  CG2 ILE B 260      27.536  -4.191  31.153  1.00 39.13           C  
+ATOM   6080  CD1 ILE B 260      29.710  -6.323  31.084  0.00 42.53           C  
+ATOM   6081  N   GLY B 261      24.187  -4.193  30.690  1.00 40.79           N  
+ATOM   6082  CA  GLY B 261      23.330  -3.207  30.060  1.00 37.61           C  
+ATOM   6083  C   GLY B 261      23.580  -1.771  30.475  1.00 37.64           C  
+ATOM   6084  O   GLY B 261      24.576  -1.466  31.135  1.00 35.17           O  
+ATOM   6085  N   TRP B 262      22.664  -0.892  30.072  1.00 36.14           N  
+ATOM   6086  CA  TRP B 262      22.733   0.532  30.378  1.00 36.09           C  
+ATOM   6087  C   TRP B 262      24.021   1.221  29.945  1.00 36.68           C  
+ATOM   6088  O   TRP B 262      24.443   2.195  30.562  1.00 38.00           O  
+ATOM   6089  CB  TRP B 262      22.500   0.772  31.876  1.00 37.19           C  
+ATOM   6090  CG  TRP B 262      21.109   0.439  32.291  1.00 39.82           C  
+ATOM   6091  CD1 TRP B 262      20.658  -0.758  32.762  1.00 39.79           C  
+ATOM   6092  CD2 TRP B 262      19.959   1.287  32.179  1.00 40.62           C  
+ATOM   6093  NE1 TRP B 262      19.297  -0.711  32.947  1.00 42.34           N  
+ATOM   6094  CE2 TRP B 262      18.842   0.533  32.598  1.00 41.80           C  
+ATOM   6095  CE3 TRP B 262      19.765   2.613  31.760  1.00 42.52           C  
+ATOM   6096  CZ2 TRP B 262      17.544   1.058  32.613  1.00 43.51           C  
+ATOM   6097  CZ3 TRP B 262      18.474   3.138  31.774  1.00 43.73           C  
+ATOM   6098  CH2 TRP B 262      17.380   2.358  32.199  1.00 45.88           C  
+ATOM   6099  N   VAL B 263      24.654   0.720  28.895  1.00 36.04           N  
+ATOM   6100  CA  VAL B 263      25.871   1.352  28.411  1.00 38.70           C  
+ATOM   6101  C   VAL B 263      25.649   1.929  27.010  1.00 39.44           C  
+ATOM   6102  O   VAL B 263      25.770   3.138  26.794  1.00 37.90           O  
+ATOM   6103  CB  VAL B 263      27.054   0.358  28.376  1.00 38.37           C  
+ATOM   6104  CG1 VAL B 263      28.259   1.010  27.717  1.00 37.02           C  
+ATOM   6105  CG2 VAL B 263      27.414  -0.065  29.785  1.00 39.01           C  
+ATOM   6106  N   GLY B 264      25.305   1.057  26.069  1.00 40.08           N  
+ATOM   6107  CA  GLY B 264      25.077   1.495  24.706  1.00 44.27           C  
+ATOM   6108  C   GLY B 264      23.934   2.475  24.551  1.00 44.80           C  
+ATOM   6109  O   GLY B 264      23.742   3.039  23.479  1.00 48.61           O  
+ATOM   6110  N   LEU B 265      23.182   2.692  25.619  1.00 44.93           N  
+ATOM   6111  CA  LEU B 265      22.048   3.599  25.573  1.00 44.38           C  
+ATOM   6112  C   LEU B 265      22.420   5.025  25.957  1.00 45.31           C  
+ATOM   6113  O   LEU B 265      21.867   5.977  25.415  1.00 48.98           O  
+ATOM   6114  CB  LEU B 265      20.948   3.108  26.520  1.00 44.85           C  
+ATOM   6115  CG  LEU B 265      19.465   3.406  26.251  1.00 46.30           C  
+ATOM   6116  CD1 LEU B 265      18.790   3.742  27.578  1.00 46.90           C  
+ATOM   6117  CD2 LEU B 265      19.296   4.560  25.269  1.00 48.27           C  
+ATOM   6118  N   ILE B 266      23.349   5.182  26.895  1.00 43.07           N  
+ATOM   6119  CA  ILE B 266      23.719   6.515  27.347  1.00 41.46           C  
+ATOM   6120  C   ILE B 266      24.983   7.108  26.737  1.00 39.62           C  
+ATOM   6121  O   ILE B 266      25.072   8.328  26.573  1.00 38.04           O  
+ATOM   6122  CB  ILE B 266      23.871   6.560  28.893  1.00 43.27           C  
+ATOM   6123  CG1 ILE B 266      25.040   5.682  29.344  1.00 43.41           C  
+ATOM   6124  CG2 ILE B 266      22.585   6.078  29.553  1.00 46.69           C  
+ATOM   6125  CD1 ILE B 266      25.298   5.717  30.837  0.00 43.43           C  
+ATOM   6126  N   ILE B 267      25.946   6.257  26.396  1.00 35.80           N  
+ATOM   6127  CA  ILE B 267      27.209   6.729  25.848  1.00 35.01           C  
+ATOM   6128  C   ILE B 267      27.111   7.494  24.529  1.00 33.60           C  
+ATOM   6129  O   ILE B 267      27.758   8.520  24.374  1.00 33.39           O  
+ATOM   6130  CB  ILE B 267      28.232   5.566  25.720  1.00 35.27           C  
+ATOM   6131  CG1 ILE B 267      28.545   5.013  27.116  1.00 36.61           C  
+ATOM   6132  CG2 ILE B 267      29.530   6.070  25.094  1.00 32.92           C  
+ATOM   6133  CD1 ILE B 267      29.489   3.845  27.116  0.00 36.07           C  
+ATOM   6134  N   PRO B 268      26.310   7.011  23.564  1.00 33.18           N  
+ATOM   6135  CA  PRO B 268      26.206   7.746  22.296  1.00 33.07           C  
+ATOM   6136  C   PRO B 268      25.689   9.169  22.518  1.00 34.55           C  
+ATOM   6137  O   PRO B 268      26.140  10.108  21.860  1.00 34.81           O  
+ATOM   6138  CB  PRO B 268      25.240   6.893  21.478  1.00 32.57           C  
+ATOM   6139  CG  PRO B 268      25.543   5.503  21.969  1.00 31.30           C  
+ATOM   6140  CD  PRO B 268      25.635   5.704  23.469  1.00 31.32           C  
+ATOM   6141  N   HIS B 269      24.754   9.332  23.452  1.00 36.19           N  
+ATOM   6142  CA  HIS B 269      24.218  10.657  23.757  1.00 38.23           C  
+ATOM   6143  C   HIS B 269      25.323  11.572  24.296  1.00 38.33           C  
+ATOM   6144  O   HIS B 269      25.447  12.729  23.872  1.00 33.99           O  
+ATOM   6145  CB  HIS B 269      23.093  10.572  24.793  1.00 43.74           C  
+ATOM   6146  CG  HIS B 269      22.544  11.909  25.186  1.00 49.85           C  
+ATOM   6147  ND1 HIS B 269      21.858  12.720  24.306  1.00 52.84           N  
+ATOM   6148  CD2 HIS B 269      22.623  12.600  26.349  1.00 52.90           C  
+ATOM   6149  CE1 HIS B 269      21.539  13.852  24.908  1.00 53.94           C  
+ATOM   6150  NE2 HIS B 269      21.992  13.806  26.148  1.00 54.73           N  
+ATOM   6151  N   LEU B 270      26.116  11.060  25.239  1.00 36.82           N  
+ATOM   6152  CA  LEU B 270      27.209  11.848  25.799  1.00 37.89           C  
+ATOM   6153  C   LEU B 270      28.195  12.210  24.691  1.00 36.86           C  
+ATOM   6154  O   LEU B 270      28.660  13.346  24.602  1.00 36.04           O  
+ATOM   6155  CB  LEU B 270      27.949  11.068  26.888  1.00 39.54           C  
+ATOM   6156  CG  LEU B 270      27.196  10.781  28.187  1.00 43.70           C  
+ATOM   6157  CD1 LEU B 270      28.083   9.960  29.118  1.00 43.43           C  
+ATOM   6158  CD2 LEU B 270      26.796  12.089  28.847  1.00 44.88           C  
+ATOM   6159  N   SER B 271      28.506  11.232  23.849  1.00 35.33           N  
+ATOM   6160  CA  SER B 271      29.436  11.433  22.751  1.00 36.64           C  
+ATOM   6161  C   SER B 271      28.885  12.472  21.796  1.00 36.69           C  
+ATOM   6162  O   SER B 271      29.620  13.294  21.266  1.00 37.88           O  
+ATOM   6163  CB  SER B 271      29.665  10.114  22.017  1.00 35.39           C  
+ATOM   6164  OG  SER B 271      30.277   9.183  22.886  1.00 37.63           O  
+ATOM   6165  N   ARG B 272      27.577  12.404  21.592  1.00 37.67           N  
+ATOM   6166  CA  ARG B 272      26.832  13.306  20.728  1.00 38.89           C  
+ATOM   6167  C   ARG B 272      26.999  14.746  21.235  1.00 38.66           C  
+ATOM   6168  O   ARG B 272      27.191  15.674  20.450  1.00 39.02           O  
+ATOM   6169  CB  ARG B 272      25.359  12.895  20.764  1.00 40.53           C  
+ATOM   6170  CG  ARG B 272      24.508  13.370  19.625  1.00 44.17           C  
+ATOM   6171  CD  ARG B 272      24.418  12.344  18.514  1.00 44.16           C  
+ATOM   6172  NE  ARG B 272      23.871  11.074  18.975  1.00 46.16           N  
+ATOM   6173  CZ  ARG B 272      23.607  10.053  18.169  1.00 48.66           C  
+ATOM   6174  NH1 ARG B 272      23.119   8.917  18.663  1.00 42.38           N  
+ATOM   6175  NH2 ARG B 272      23.821  10.180  16.855  1.00 50.86           N  
+ATOM   6176  N   MET B 273      26.931  14.924  22.550  1.00 39.05           N  
+ATOM   6177  CA  MET B 273      27.084  16.242  23.162  1.00 39.59           C  
+ATOM   6178  C   MET B 273      28.499  16.764  22.977  1.00 39.19           C  
+ATOM   6179  O   MET B 273      28.730  17.970  23.011  1.00 39.64           O  
+ATOM   6180  CB  MET B 273      26.785  16.181  24.664  1.00 42.19           C  
+ATOM   6181  CG  MET B 273      25.349  15.824  25.024  1.00 48.39           C  
+ATOM   6182  SD  MET B 273      25.182  15.423  26.791  1.00 53.05           S  
+ATOM   6183  CE  MET B 273      24.759  17.040  27.462  1.00 52.16           C  
+ATOM   6184  N   LEU B 274      29.445  15.850  22.791  1.00 37.75           N  
+ATOM   6185  CA  LEU B 274      30.840  16.224  22.617  1.00 38.00           C  
+ATOM   6186  C   LEU B 274      31.234  16.579  21.192  1.00 37.45           C  
+ATOM   6187  O   LEU B 274      31.835  17.626  20.958  1.00 36.87           O  
+ATOM   6188  CB  LEU B 274      31.760  15.102  23.102  1.00 39.51           C  
+ATOM   6189  CG  LEU B 274      31.946  14.920  24.612  1.00 43.34           C  
+ATOM   6190  CD1 LEU B 274      32.810  13.685  24.867  1.00 42.21           C  
+ATOM   6191  CD2 LEU B 274      32.600  16.171  25.205  1.00 42.05           C  
+ATOM   6192  N   VAL B 275      30.901  15.715  20.239  1.00 34.81           N  
+ATOM   6193  CA  VAL B 275      31.289  15.969  18.865  1.00 35.12           C  
+ATOM   6194  C   VAL B 275      30.176  16.087  17.832  1.00 35.14           C  
+ATOM   6195  O   VAL B 275      30.458  16.246  16.647  1.00 37.25           O  
+ATOM   6196  CB  VAL B 275      32.280  14.902  18.385  1.00 35.02           C  
+ATOM   6197  CG1 VAL B 275      33.483  14.874  19.309  1.00 36.35           C  
+ATOM   6198  CG2 VAL B 275      31.604  13.535  18.348  1.00 34.49           C  
+ATOM   6199  N   GLY B 276      28.919  16.013  18.258  1.00 34.16           N  
+ATOM   6200  CA  GLY B 276      27.837  16.130  17.292  1.00 30.97           C  
+ATOM   6201  C   GLY B 276      27.296  14.829  16.710  1.00 32.44           C  
+ATOM   6202  O   GLY B 276      27.684  13.722  17.125  1.00 28.30           O  
+ATOM   6203  N   ALA B 277      26.420  14.983  15.713  1.00 30.42           N  
+ATOM   6204  CA  ALA B 277      25.738  13.874  15.048  1.00 30.00           C  
+ATOM   6205  C   ALA B 277      26.446  13.174  13.887  1.00 29.63           C  
+ATOM   6206  O   ALA B 277      26.106  12.035  13.556  1.00 31.10           O  
+ATOM   6207  CB  ALA B 277      24.347  14.347  14.581  1.00 29.67           C  
+ATOM   6208  N   ASN B 278      27.399  13.841  13.246  1.00 29.33           N  
+ATOM   6209  CA  ASN B 278      28.118  13.229  12.123  1.00 29.42           C  
+ATOM   6210  C   ASN B 278      28.789  11.939  12.618  1.00 29.29           C  
+ATOM   6211  O   ASN B 278      29.679  11.985  13.456  1.00 28.93           O  
+ATOM   6212  CB  ASN B 278      29.164  14.214  11.596  1.00 28.87           C  
+ATOM   6213  CG  ASN B 278      30.002  13.651  10.456  1.00 32.67           C  
+ATOM   6214  OD1 ASN B 278      31.068  14.190  10.151  1.00 41.54           O  
+ATOM   6215  ND2 ASN B 278      29.535  12.586   9.822  1.00 29.56           N  
+ATOM   6216  N   HIS B 279      28.363  10.795  12.092  1.00 31.48           N  
+ATOM   6217  CA  HIS B 279      28.911   9.506  12.527  1.00 33.03           C  
+ATOM   6218  C   HIS B 279      30.406   9.329  12.310  1.00 34.91           C  
+ATOM   6219  O   HIS B 279      31.061   8.568  13.040  1.00 36.42           O  
+ATOM   6220  CB  HIS B 279      28.160   8.341  11.864  1.00 31.66           C  
+ATOM   6221  CG  HIS B 279      26.729   8.212  12.297  1.00 31.71           C  
+ATOM   6222  ND1 HIS B 279      25.695   8.875  11.671  1.00 33.44           N  
+ATOM   6223  CD2 HIS B 279      26.167   7.517  13.313  1.00 31.77           C  
+ATOM   6224  CE1 HIS B 279      24.557   8.595  12.282  1.00 32.85           C  
+ATOM   6225  NE2 HIS B 279      24.816   7.773  13.283  1.00 33.48           N  
+ATOM   6226  N   GLN B 280      30.950  10.027  11.318  1.00 35.93           N  
+ATOM   6227  CA  GLN B 280      32.373   9.935  11.013  1.00 36.49           C  
+ATOM   6228  C   GLN B 280      33.212  10.274  12.237  1.00 36.54           C  
+ATOM   6229  O   GLN B 280      34.252   9.670  12.484  1.00 39.23           O  
+ATOM   6230  CB  GLN B 280      32.733  10.882   9.870  1.00 38.04           C  
+ATOM   6231  CG  GLN B 280      34.088  10.618   9.259  1.00 37.87           C  
+ATOM   6232  CD  GLN B 280      34.395  11.577   8.118  1.00 40.52           C  
+ATOM   6233  OE1 GLN B 280      33.496  11.998   7.397  1.00 41.53           O  
+ATOM   6234  NE2 GLN B 280      35.669  11.911   7.942  1.00 38.01           N  
+ATOM   6235  N   SER B 281      32.763  11.249  13.010  1.00 36.45           N  
+ATOM   6236  CA  SER B 281      33.502  11.614  14.199  1.00 37.30           C  
+ATOM   6237  C   SER B 281      32.828  11.080  15.461  1.00 36.50           C  
+ATOM   6238  O   SER B 281      33.462  10.981  16.511  1.00 37.40           O  
+ATOM   6239  CB  SER B 281      33.654  13.131  14.267  1.00 39.05           C  
+ATOM   6240  OG  SER B 281      32.425  13.763  13.999  1.00 45.15           O  
+ATOM   6241  N   LEU B 282      31.552  10.712  15.347  1.00 34.43           N  
+ATOM   6242  CA  LEU B 282      30.794  10.194  16.483  1.00 34.27           C  
+ATOM   6243  C   LEU B 282      31.284   8.818  16.939  1.00 35.09           C  
+ATOM   6244  O   LEU B 282      31.448   8.590  18.132  1.00 34.85           O  
+ATOM   6245  CB  LEU B 282      29.310  10.071  16.136  1.00 32.76           C  
+ATOM   6246  CG  LEU B 282      28.256  10.508  17.167  1.00 34.19           C  
+ATOM   6247  CD1 LEU B 282      26.969   9.735  16.886  1.00 30.85           C  
+ATOM   6248  CD2 LEU B 282      28.713  10.281  18.599  1.00 26.82           C  
+ATOM   6249  N   LEU B 283      31.509   7.908  15.990  1.00 34.70           N  
+ATOM   6250  CA  LEU B 283      31.945   6.555  16.328  1.00 35.61           C  
+ATOM   6251  C   LEU B 283      33.229   6.475  17.158  1.00 37.71           C  
+ATOM   6252  O   LEU B 283      33.233   5.861  18.229  1.00 38.67           O  
+ATOM   6253  CB  LEU B 283      32.085   5.687  15.066  1.00 30.98           C  
+ATOM   6254  CG  LEU B 283      30.857   5.382  14.196  1.00 29.98           C  
+ATOM   6255  CD1 LEU B 283      30.872   3.922  13.829  1.00 24.49           C  
+ATOM   6256  CD2 LEU B 283      29.560   5.727  14.899  1.00 30.50           C  
+ATOM   6257  N   PRO B 284      34.333   7.084  16.685  1.00 38.18           N  
+ATOM   6258  CA  PRO B 284      35.551   6.993  17.501  1.00 38.55           C  
+ATOM   6259  C   PRO B 284      35.399   7.650  18.870  1.00 37.53           C  
+ATOM   6260  O   PRO B 284      35.936   7.165  19.870  1.00 36.82           O  
+ATOM   6261  CB  PRO B 284      36.624   7.660  16.622  1.00 39.82           C  
+ATOM   6262  CG  PRO B 284      35.850   8.505  15.661  1.00 40.00           C  
+ATOM   6263  CD  PRO B 284      34.621   7.685  15.371  1.00 39.57           C  
+ATOM   6264  N   CYS B 285      34.657   8.748  18.916  1.00 35.98           N  
+ATOM   6265  CA  CYS B 285      34.437   9.434  20.179  1.00 35.28           C  
+ATOM   6266  C   CYS B 285      33.629   8.543  21.117  1.00 34.45           C  
+ATOM   6267  O   CYS B 285      33.878   8.505  22.320  1.00 34.45           O  
+ATOM   6268  CB  CYS B 285      33.686  10.745  19.951  1.00 33.72           C  
+ATOM   6269  SG  CYS B 285      33.232  11.616  21.484  1.00 37.93           S  
+ATOM   6270  N   THR B 286      32.657   7.835  20.550  1.00 33.13           N  
+ATOM   6271  CA  THR B 286      31.792   6.950  21.311  1.00 33.83           C  
+ATOM   6272  C   THR B 286      32.602   5.782  21.880  1.00 34.69           C  
+ATOM   6273  O   THR B 286      32.422   5.395  23.033  1.00 33.39           O  
+ATOM   6274  CB  THR B 286      30.632   6.445  20.421  1.00 32.89           C  
+ATOM   6275  OG1 THR B 286      29.758   7.541  20.141  1.00 32.81           O  
+ATOM   6276  CG2 THR B 286      29.840   5.353  21.107  1.00 30.63           C  
+ATOM   6277  N   MET B 287      33.504   5.238  21.075  1.00 34.87           N  
+ATOM   6278  CA  MET B 287      34.357   4.150  21.537  1.00 37.45           C  
+ATOM   6279  C   MET B 287      35.238   4.605  22.705  1.00 36.91           C  
+ATOM   6280  O   MET B 287      35.372   3.895  23.692  1.00 36.87           O  
+ATOM   6281  CB  MET B 287      35.240   3.648  20.401  1.00 37.45           C  
+ATOM   6282  CG  MET B 287      34.463   3.039  19.261  1.00 39.23           C  
+ATOM   6283  SD  MET B 287      35.535   2.123  18.154  1.00 42.84           S  
+ATOM   6284  CE  MET B 287      36.360   3.486  17.371  1.00 48.66           C  
+ATOM   6285  N   LEU B 288      35.821   5.796  22.600  1.00 37.79           N  
+ATOM   6286  CA  LEU B 288      36.682   6.310  23.668  1.00 38.16           C  
+ATOM   6287  C   LEU B 288      35.915   6.620  24.947  1.00 37.82           C  
+ATOM   6288  O   LEU B 288      36.381   6.316  26.049  1.00 37.90           O  
+ATOM   6289  CB  LEU B 288      37.422   7.562  23.203  1.00 37.50           C  
+ATOM   6290  CG  LEU B 288      38.544   7.289  22.199  1.00 40.80           C  
+ATOM   6291  CD1 LEU B 288      39.022   8.598  21.586  1.00 40.49           C  
+ATOM   6292  CD2 LEU B 288      39.688   6.562  22.903  1.00 42.01           C  
+ATOM   6293  N   VAL B 289      34.743   7.226  24.798  1.00 36.18           N  
+ATOM   6294  CA  VAL B 289      33.906   7.562  25.943  1.00 34.24           C  
+ATOM   6295  C   VAL B 289      33.398   6.283  26.612  1.00 34.29           C  
+ATOM   6296  O   VAL B 289      33.353   6.186  27.831  1.00 34.95           O  
+ATOM   6297  CB  VAL B 289      32.698   8.426  25.508  1.00 33.98           C  
+ATOM   6298  CG1 VAL B 289      31.745   8.639  26.691  1.00 28.54           C  
+ATOM   6299  CG2 VAL B 289      33.197   9.768  24.953  1.00 28.93           C  
+ATOM   6300  N   GLY B 290      33.015   5.307  25.798  1.00 34.71           N  
+ATOM   6301  CA  GLY B 290      32.527   4.047  26.325  1.00 35.16           C  
+ATOM   6302  C   GLY B 290      33.597   3.269  27.076  1.00 36.97           C  
+ATOM   6303  O   GLY B 290      33.337   2.736  28.154  1.00 33.81           O  
+ATOM   6304  N   ALA B 291      34.801   3.205  26.507  1.00 36.15           N  
+ATOM   6305  CA  ALA B 291      35.908   2.493  27.138  1.00 36.93           C  
+ATOM   6306  C   ALA B 291      36.205   3.098  28.509  1.00 36.73           C  
+ATOM   6307  O   ALA B 291      36.267   2.388  29.512  1.00 34.98           O  
+ATOM   6308  CB  ALA B 291      37.152   2.557  26.253  1.00 33.05           C  
+ATOM   6309  N   THR B 292      36.369   4.414  28.546  1.00 36.98           N  
+ATOM   6310  CA  THR B 292      36.662   5.110  29.792  1.00 38.47           C  
+ATOM   6311  C   THR B 292      35.532   4.991  30.802  1.00 37.24           C  
+ATOM   6312  O   THR B 292      35.777   4.901  31.999  1.00 38.24           O  
+ATOM   6313  CB  THR B 292      36.947   6.608  29.542  1.00 39.48           C  
+ATOM   6314  OG1 THR B 292      38.001   6.731  28.579  1.00 41.26           O  
+ATOM   6315  CG2 THR B 292      37.368   7.300  30.840  1.00 37.99           C  
+ATOM   6316  N   TYR B 293      34.294   4.996  30.322  1.00 37.72           N  
+ATOM   6317  CA  TYR B 293      33.146   4.885  31.213  1.00 37.30           C  
+ATOM   6318  C   TYR B 293      33.108   3.512  31.908  1.00 37.87           C  
+ATOM   6319  O   TYR B 293      32.885   3.432  33.116  1.00 36.44           O  
+ATOM   6320  CB  TYR B 293      31.849   5.129  30.433  1.00 35.91           C  
+ATOM   6321  CG  TYR B 293      30.590   5.023  31.268  1.00 34.05           C  
+ATOM   6322  CD1 TYR B 293      29.788   3.882  31.220  1.00 34.47           C  
+ATOM   6323  CD2 TYR B 293      30.204   6.062  32.108  1.00 35.23           C  
+ATOM   6324  CE1 TYR B 293      28.627   3.782  31.993  1.00 34.78           C  
+ATOM   6325  CE2 TYR B 293      29.051   5.974  32.885  1.00 36.94           C  
+ATOM   6326  CZ  TYR B 293      28.266   4.834  32.823  1.00 37.51           C  
+ATOM   6327  OH  TYR B 293      27.120   4.758  33.590  1.00 38.84           O  
+ATOM   6328  N   MET B 294      33.324   2.443  31.148  1.00 38.77           N  
+ATOM   6329  CA  MET B 294      33.325   1.097  31.714  1.00 42.03           C  
+ATOM   6330  C   MET B 294      34.447   0.926  32.729  1.00 42.24           C  
+ATOM   6331  O   MET B 294      34.234   0.402  33.817  1.00 40.82           O  
+ATOM   6332  CB  MET B 294      33.479   0.048  30.617  1.00 41.86           C  
+ATOM   6333  CG  MET B 294      32.161  -0.534  30.175  1.00 48.32           C  
+ATOM   6334  SD  MET B 294      31.300  -1.469  31.463  1.00 45.33           S  
+ATOM   6335  CE  MET B 294      30.761  -2.838  30.484  1.00 49.18           C  
+ATOM   6336  N   LEU B 295      35.645   1.363  32.366  1.00 43.03           N  
+ATOM   6337  CA  LEU B 295      36.769   1.256  33.274  1.00 44.97           C  
+ATOM   6338  C   LEU B 295      36.420   2.049  34.529  1.00 45.49           C  
+ATOM   6339  O   LEU B 295      36.720   1.633  35.646  1.00 45.24           O  
+ATOM   6340  CB  LEU B 295      38.037   1.811  32.615  1.00 44.95           C  
+ATOM   6341  CG  LEU B 295      39.339   1.712  33.424  1.00 47.10           C  
+ATOM   6342  CD1 LEU B 295      39.541   0.292  33.928  1.00 45.08           C  
+ATOM   6343  CD2 LEU B 295      40.505   2.139  32.556  1.00 44.85           C  
+ATOM   6344  N   LEU B 296      35.753   3.180  34.326  1.00 46.61           N  
+ATOM   6345  CA  LEU B 296      35.351   4.063  35.413  1.00 47.88           C  
+ATOM   6346  C   LEU B 296      34.357   3.378  36.354  1.00 47.50           C  
+ATOM   6347  O   LEU B 296      34.469   3.488  37.573  1.00 48.09           O  
+ATOM   6348  CB  LEU B 296      34.728   5.331  34.828  1.00 50.40           C  
+ATOM   6349  CG  LEU B 296      34.793   6.641  35.616  1.00 54.08           C  
+ATOM   6350  CD1 LEU B 296      33.983   6.535  36.895  1.00 54.20           C  
+ATOM   6351  CD2 LEU B 296      36.251   6.971  35.914  1.00 55.43           C  
+ATOM   6352  N   VAL B 297      33.386   2.673  35.788  1.00 45.60           N  
+ATOM   6353  CA  VAL B 297      32.391   1.984  36.598  1.00 45.94           C  
+ATOM   6354  C   VAL B 297      33.016   0.787  37.324  1.00 46.34           C  
+ATOM   6355  O   VAL B 297      32.668   0.494  38.467  1.00 44.34           O  
+ATOM   6356  CB  VAL B 297      31.200   1.508  35.729  1.00 45.73           C  
+ATOM   6357  CG1 VAL B 297      30.217   0.706  36.571  1.00 42.53           C  
+ATOM   6358  CG2 VAL B 297      30.500   2.712  35.115  1.00 44.45           C  
+ATOM   6359  N   ASP B 298      33.945   0.107  36.658  1.00 47.71           N  
+ATOM   6360  CA  ASP B 298      34.623  -1.040  37.253  1.00 50.15           C  
+ATOM   6361  C   ASP B 298      35.372  -0.597  38.516  1.00 50.94           C  
+ATOM   6362  O   ASP B 298      35.304  -1.259  39.552  1.00 51.43           O  
+ATOM   6363  CB  ASP B 298      35.618  -1.647  36.262  1.00 50.69           C  
+ATOM   6364  CG  ASP B 298      36.011  -3.072  36.627  1.00 53.30           C  
+ATOM   6365  OD1 ASP B 298      37.171  -3.464  36.368  1.00 54.59           O  
+ATOM   6366  OD2 ASP B 298      35.153  -3.807  37.162  1.00 53.89           O  
+ATOM   6367  N   ASN B 299      36.084   0.525  38.422  1.00 50.15           N  
+ATOM   6368  CA  ASN B 299      36.836   1.052  39.554  1.00 49.61           C  
+ATOM   6369  C   ASN B 299      35.909   1.400  40.714  1.00 50.54           C  
+ATOM   6370  O   ASN B 299      36.282   1.262  41.880  1.00 51.09           O  
+ATOM   6371  CB  ASN B 299      37.626   2.293  39.138  1.00 48.97           C  
+ATOM   6372  CG  ASN B 299      38.771   1.972  38.200  1.00 49.08           C  
+ATOM   6373  OD1 ASN B 299      39.462   2.869  37.732  1.00 51.94           O  
+ATOM   6374  ND2 ASN B 299      38.979   0.692  37.923  1.00 50.52           N  
+ATOM   6375  N   VAL B 300      34.704   1.862  40.396  1.00 50.74           N  
+ATOM   6376  CA  VAL B 300      33.740   2.201  41.432  1.00 51.48           C  
+ATOM   6377  C   VAL B 300      33.342   0.919  42.146  1.00 53.03           C  
+ATOM   6378  O   VAL B 300      33.134   0.911  43.353  1.00 54.38           O  
+ATOM   6379  CB  VAL B 300      32.478   2.852  40.839  1.00 50.93           C  
+ATOM   6380  CG1 VAL B 300      31.465   3.135  41.942  1.00 49.27           C  
+ATOM   6381  CG2 VAL B 300      32.850   4.138  40.125  1.00 50.24           C  
+ATOM   6382  N   ALA B 301      33.246  -0.164  41.383  1.00 54.55           N  
+ATOM   6383  CA  ALA B 301      32.878  -1.468  41.920  1.00 56.58           C  
+ATOM   6384  C   ALA B 301      33.959  -1.986  42.864  1.00 57.76           C  
+ATOM   6385  O   ALA B 301      33.698  -2.262  44.036  1.00 57.59           O  
+ATOM   6386  CB  ALA B 301      32.675  -2.459  40.778  1.00 55.62           C  
+ATOM   6387  N   ARG B 302      35.169  -2.114  42.328  1.00 58.00           N  
+ATOM   6388  CA  ARG B 302      36.324  -2.602  43.065  1.00 58.29           C  
+ATOM   6389  C   ARG B 302      36.640  -1.801  44.322  1.00 59.55           C  
+ATOM   6390  O   ARG B 302      37.135  -2.353  45.306  1.00 60.93           O  
+ATOM   6391  CB  ARG B 302      37.548  -2.604  42.152  1.00 57.12           C  
+ATOM   6392  CG  ARG B 302      37.495  -3.630  41.038  1.00 57.91           C  
+ATOM   6393  CD  ARG B 302      38.581  -3.353  40.024  1.00 59.18           C  
+ATOM   6394  NE  ARG B 302      39.888  -3.238  40.656  1.00 62.52           N  
+ATOM   6395  CZ  ARG B 302      40.932  -2.624  40.106  1.00 64.65           C  
+ATOM   6396  NH1 ARG B 302      42.088  -2.568  40.753  1.00 65.61           N  
+ATOM   6397  NH2 ARG B 302      40.819  -2.054  38.915  1.00 67.69           N  
+ATOM   6398  N   SER B 303      36.357  -0.503  44.290  1.00 59.01           N  
+ATOM   6399  CA  SER B 303      36.631   0.358  45.432  1.00 59.01           C  
+ATOM   6400  C   SER B 303      35.521   0.329  46.483  1.00 57.80           C  
+ATOM   6401  O   SER B 303      35.789   0.522  47.666  1.00 56.54           O  
+ATOM   6402  CB  SER B 303      36.858   1.801  44.966  1.00 60.51           C  
+ATOM   6403  OG  SER B 303      35.664   2.363  44.444  1.00 63.80           O  
+ATOM   6404  N   LEU B 304      34.283   0.095  46.054  1.00 57.10           N  
+ATOM   6405  CA  LEU B 304      33.154   0.050  46.984  1.00 57.44           C  
+ATOM   6406  C   LEU B 304      33.156  -1.192  47.869  1.00 57.81           C  
+ATOM   6407  O   LEU B 304      32.640  -1.166  48.985  1.00 58.24           O  
+ATOM   6408  CB  LEU B 304      31.819   0.102  46.233  1.00 57.78           C  
+ATOM   6409  CG  LEU B 304      31.196   1.453  45.870  1.00 58.80           C  
+ATOM   6410  CD1 LEU B 304      29.885   1.208  45.148  1.00 58.67           C  
+ATOM   6411  CD2 LEU B 304      30.952   2.283  47.122  1.00 57.99           C  
+ATOM   6412  N   SER B 305      33.729  -2.280  47.370  1.00 57.18           N  
+ATOM   6413  CA  SER B 305      33.757  -3.522  48.124  1.00 57.04           C  
+ATOM   6414  C   SER B 305      34.607  -4.581  47.438  1.00 56.06           C  
+ATOM   6415  O   SER B 305      34.766  -4.562  46.216  1.00 55.86           O  
+ATOM   6416  CB  SER B 305      32.329  -4.049  48.296  1.00 58.23           C  
+ATOM   6417  OG  SER B 305      32.320  -5.437  48.594  1.00 61.43           O  
+ATOM   6418  N   ASP B 306      35.151  -5.499  48.232  1.00 53.37           N  
+ATOM   6419  CA  ASP B 306      35.967  -6.579  47.700  1.00 52.84           C  
+ATOM   6420  C   ASP B 306      35.071  -7.784  47.449  1.00 50.55           C  
+ATOM   6421  O   ASP B 306      35.554  -8.867  47.135  1.00 50.72           O  
+ATOM   6422  CB  ASP B 306      37.073  -6.963  48.689  1.00 57.24           C  
+ATOM   6423  CG  ASP B 306      38.070  -5.840  48.926  1.00 60.74           C  
+ATOM   6424  OD1 ASP B 306      37.636  -4.715  49.249  1.00 65.55           O  
+ATOM   6425  OD2 ASP B 306      39.291  -6.084  48.799  1.00 62.35           O  
+ATOM   6426  N   ALA B 307      33.763  -7.586  47.576  1.00 48.74           N  
+ATOM   6427  CA  ALA B 307      32.802  -8.668  47.374  1.00 49.30           C  
+ATOM   6428  C   ALA B 307      32.565  -8.997  45.903  1.00 49.21           C  
+ATOM   6429  O   ALA B 307      31.771  -9.888  45.579  1.00 48.96           O  
+ATOM   6430  CB  ALA B 307      31.470  -8.321  48.049  1.00 48.26           C  
+ATOM   6431  N   GLU B 308      33.245  -8.282  45.012  1.00 48.94           N  
+ATOM   6432  CA  GLU B 308      33.090  -8.523  43.580  1.00 48.62           C  
+ATOM   6433  C   GLU B 308      31.642  -8.370  43.102  1.00 44.21           C  
+ATOM   6434  O   GLU B 308      31.072  -9.278  42.497  1.00 41.64           O  
+ATOM   6435  CB  GLU B 308      33.604  -9.925  43.223  1.00 52.22           C  
+ATOM   6436  CG  GLU B 308      35.116 -10.034  43.186  1.00 59.93           C  
+ATOM   6437  CD  GLU B 308      35.736  -9.068  42.184  1.00 64.66           C  
+ATOM   6438  OE1 GLU B 308      35.425  -9.169  40.975  1.00 67.58           O  
+ATOM   6439  OE2 GLU B 308      36.534  -8.204  42.605  1.00 67.91           O  
+ATOM   6440  N   ILE B 309      31.042  -7.226  43.394  1.00 43.56           N  
+ATOM   6441  CA  ILE B 309      29.676  -6.973  42.951  1.00 44.32           C  
+ATOM   6442  C   ILE B 309      29.705  -6.972  41.419  1.00 42.05           C  
+ATOM   6443  O   ILE B 309      30.478  -6.239  40.803  1.00 37.72           O  
+ATOM   6444  CB  ILE B 309      29.170  -5.606  43.465  1.00 45.93           C  
+ATOM   6445  CG1 ILE B 309      29.074  -5.635  44.999  1.00 45.88           C  
+ATOM   6446  CG2 ILE B 309      27.818  -5.282  42.841  1.00 43.96           C  
+ATOM   6447  CD1 ILE B 309      28.632  -4.323  45.614  0.00 45.90           C  
+ATOM   6448  N   PRO B 310      28.888  -7.822  40.785  1.00 41.54           N  
+ATOM   6449  CA  PRO B 310      28.910  -7.834  39.316  1.00 42.43           C  
+ATOM   6450  C   PRO B 310      28.654  -6.444  38.714  1.00 41.39           C  
+ATOM   6451  O   PRO B 310      27.725  -5.736  39.115  1.00 39.06           O  
+ATOM   6452  CB  PRO B 310      27.851  -8.884  38.953  1.00 42.08           C  
+ATOM   6453  CG  PRO B 310      26.973  -8.950  40.164  1.00 44.93           C  
+ATOM   6454  CD  PRO B 310      27.917  -8.787  41.321  1.00 41.11           C  
+ATOM   6455  N   ILE B 311      29.507  -6.068  37.762  1.00 40.09           N  
+ATOM   6456  CA  ILE B 311      29.448  -4.760  37.111  1.00 38.92           C  
+ATOM   6457  C   ILE B 311      28.089  -4.430  36.487  1.00 39.00           C  
+ATOM   6458  O   ILE B 311      27.713  -3.262  36.399  1.00 37.64           O  
+ATOM   6459  CB  ILE B 311      30.591  -4.623  36.048  1.00 38.92           C  
+ATOM   6460  CG1 ILE B 311      30.845  -3.140  35.737  1.00 38.52           C  
+ATOM   6461  CG2 ILE B 311      30.258  -5.430  34.809  1.00 34.95           C  
+ATOM   6462  CD1 ILE B 311      31.985  -2.893  34.780  0.00 38.55           C  
+ATOM   6463  N   SER B 312      27.348  -5.454  36.075  1.00 37.86           N  
+ATOM   6464  CA  SER B 312      26.035  -5.235  35.494  1.00 37.59           C  
+ATOM   6465  C   SER B 312      25.113  -4.545  36.497  1.00 38.25           C  
+ATOM   6466  O   SER B 312      24.251  -3.757  36.108  1.00 38.15           O  
+ATOM   6467  CB  SER B 312      25.421  -6.562  35.040  1.00 39.55           C  
+ATOM   6468  OG  SER B 312      25.544  -7.556  36.044  1.00 40.92           O  
+ATOM   6469  N   ILE B 313      25.282  -4.838  37.785  1.00 36.49           N  
+ATOM   6470  CA  ILE B 313      24.452  -4.200  38.799  1.00 34.61           C  
+ATOM   6471  C   ILE B 313      24.789  -2.707  38.844  1.00 34.95           C  
+ATOM   6472  O   ILE B 313      23.899  -1.868  38.941  1.00 35.08           O  
+ATOM   6473  CB  ILE B 313      24.692  -4.787  40.221  1.00 36.07           C  
+ATOM   6474  CG1 ILE B 313      24.303  -6.270  40.263  1.00 37.86           C  
+ATOM   6475  CG2 ILE B 313      23.884  -3.990  41.265  1.00 32.74           C  
+ATOM   6476  CD1 ILE B 313      24.538  -6.931  41.606  0.00 37.10           C  
+ATOM   6477  N   LEU B 314      26.078  -2.384  38.774  1.00 34.69           N  
+ATOM   6478  CA  LEU B 314      26.514  -0.989  38.836  1.00 37.04           C  
+ATOM   6479  C   LEU B 314      26.229  -0.142  37.597  1.00 34.66           C  
+ATOM   6480  O   LEU B 314      25.966   1.048  37.720  1.00 34.07           O  
+ATOM   6481  CB  LEU B 314      28.008  -0.902  39.154  1.00 40.05           C  
+ATOM   6482  CG  LEU B 314      28.424  -1.249  40.585  1.00 45.77           C  
+ATOM   6483  CD1 LEU B 314      29.906  -0.984  40.715  1.00 50.09           C  
+ATOM   6484  CD2 LEU B 314      27.662  -0.410  41.599  1.00 46.11           C  
+ATOM   6485  N   THR B 315      26.285  -0.737  36.411  1.00 32.65           N  
+ATOM   6486  CA  THR B 315      26.012   0.039  35.209  1.00 35.00           C  
+ATOM   6487  C   THR B 315      24.554   0.478  35.217  1.00 35.69           C  
+ATOM   6488  O   THR B 315      24.208   1.499  34.640  1.00 34.97           O  
+ATOM   6489  CB  THR B 315      26.302  -0.761  33.924  1.00 33.16           C  
+ATOM   6490  OG1 THR B 315      25.593  -2.002  33.960  1.00 31.40           O  
+ATOM   6491  CG2 THR B 315      27.788  -1.022  33.790  1.00 28.62           C  
+ATOM   6492  N   ALA B 316      23.707  -0.297  35.892  1.00 37.44           N  
+ATOM   6493  CA  ALA B 316      22.286   0.022  35.996  1.00 37.31           C  
+ATOM   6494  C   ALA B 316      22.034   1.044  37.105  1.00 39.08           C  
+ATOM   6495  O   ALA B 316      21.230   1.960  36.936  1.00 38.51           O  
+ATOM   6496  CB  ALA B 316      21.483  -1.248  36.261  1.00 36.80           C  
+ATOM   6497  N   LEU B 317      22.716   0.889  38.238  1.00 39.43           N  
+ATOM   6498  CA  LEU B 317      22.544   1.812  39.361  1.00 40.88           C  
+ATOM   6499  C   LEU B 317      23.100   3.188  39.033  1.00 41.10           C  
+ATOM   6500  O   LEU B 317      22.572   4.208  39.481  1.00 40.90           O  
+ATOM   6501  CB  LEU B 317      23.232   1.272  40.618  1.00 39.85           C  
+ATOM   6502  CG  LEU B 317      22.508   0.137  41.344  1.00 43.59           C  
+ATOM   6503  CD1 LEU B 317      23.355  -0.343  42.515  1.00 42.20           C  
+ATOM   6504  CD2 LEU B 317      21.140   0.630  41.835  1.00 41.90           C  
+ATOM   6505  N   ILE B 318      24.186   3.212  38.269  1.00 40.96           N  
+ATOM   6506  CA  ILE B 318      24.794   4.469  37.863  1.00 41.62           C  
+ATOM   6507  C   ILE B 318      24.101   4.929  36.577  1.00 42.32           C  
+ATOM   6508  O   ILE B 318      23.737   6.093  36.430  1.00 43.35           O  
+ATOM   6509  CB  ILE B 318      26.311   4.302  37.561  1.00 41.69           C  
+ATOM   6510  CG1 ILE B 318      27.074   3.908  38.834  1.00 39.34           C  
+ATOM   6511  CG2 ILE B 318      26.864   5.602  36.965  1.00 40.60           C  
+ATOM   6512  CD1 ILE B 318      28.556   3.682  38.618  0.00 40.23           C  
+ATOM   6513  N   GLY B 319      23.908   3.986  35.662  1.00 41.65           N  
+ATOM   6514  CA  GLY B 319      23.305   4.283  34.375  1.00 43.11           C  
+ATOM   6515  C   GLY B 319      21.883   4.803  34.307  1.00 44.01           C  
+ATOM   6516  O   GLY B 319      21.627   5.777  33.603  1.00 44.60           O  
+ATOM   6517  N   ALA B 320      20.953   4.158  35.004  1.00 44.17           N  
+ATOM   6518  CA  ALA B 320      19.559   4.590  34.974  1.00 45.77           C  
+ATOM   6519  C   ALA B 320      19.393   6.051  35.422  1.00 47.91           C  
+ATOM   6520  O   ALA B 320      18.773   6.853  34.724  1.00 46.03           O  
+ATOM   6521  CB  ALA B 320      18.701   3.662  35.834  1.00 44.99           C  
+ATOM   6522  N   PRO B 321      19.933   6.412  36.597  1.00 49.66           N  
+ATOM   6523  CA  PRO B 321      19.792   7.802  37.042  1.00 51.07           C  
+ATOM   6524  C   PRO B 321      20.549   8.788  36.147  1.00 52.63           C  
+ATOM   6525  O   PRO B 321      20.120   9.932  35.978  1.00 52.19           O  
+ATOM   6526  CB  PRO B 321      20.332   7.768  38.473  1.00 49.87           C  
+ATOM   6527  CG  PRO B 321      21.304   6.645  38.446  1.00 50.79           C  
+ATOM   6528  CD  PRO B 321      20.574   5.597  37.641  1.00 49.71           C  
+ATOM   6529  N   LEU B 322      21.669   8.348  35.577  1.00 52.38           N  
+ATOM   6530  CA  LEU B 322      22.441   9.214  34.692  1.00 52.08           C  
+ATOM   6531  C   LEU B 322      21.629   9.484  33.428  1.00 51.86           C  
+ATOM   6532  O   LEU B 322      21.680  10.578  32.864  1.00 52.81           O  
+ATOM   6533  CB  LEU B 322      23.777   8.568  34.327  1.00 50.80           C  
+ATOM   6534  CG  LEU B 322      24.669   9.374  33.377  1.00 52.22           C  
+ATOM   6535  CD1 LEU B 322      24.749  10.827  33.823  1.00 51.19           C  
+ATOM   6536  CD2 LEU B 322      26.058   8.754  33.346  1.00 52.31           C  
+ATOM   6537  N   PHE B 323      20.883   8.477  32.989  1.00 51.32           N  
+ATOM   6538  CA  PHE B 323      20.029   8.593  31.813  1.00 51.47           C  
+ATOM   6539  C   PHE B 323      18.965   9.644  32.137  1.00 52.96           C  
+ATOM   6540  O   PHE B 323      18.575  10.439  31.282  1.00 52.85           O  
+ATOM   6541  CB  PHE B 323      19.371   7.242  31.526  1.00 50.41           C  
+ATOM   6542  CG  PHE B 323      18.380   7.263  30.397  1.00 49.84           C  
+ATOM   6543  CD1 PHE B 323      18.804   7.400  29.078  1.00 50.59           C  
+ATOM   6544  CD2 PHE B 323      17.018   7.113  30.649  1.00 50.26           C  
+ATOM   6545  CE1 PHE B 323      17.888   7.382  28.026  1.00 49.07           C  
+ATOM   6546  CE2 PHE B 323      16.092   7.095  29.603  1.00 50.44           C  
+ATOM   6547  CZ  PHE B 323      16.529   7.228  28.290  1.00 49.87           C  
+ATOM   6548  N   GLY B 324      18.512   9.642  33.388  1.00 53.23           N  
+ATOM   6549  CA  GLY B 324      17.511  10.597  33.823  1.00 54.17           C  
+ATOM   6550  C   GLY B 324      18.011  12.028  33.740  1.00 55.13           C  
+ATOM   6551  O   GLY B 324      17.339  12.892  33.180  1.00 53.40           O  
+ATOM   6552  N   VAL B 325      19.189  12.288  34.301  1.00 56.12           N  
+ATOM   6553  CA  VAL B 325      19.754  13.630  34.262  1.00 57.81           C  
+ATOM   6554  C   VAL B 325      19.978  14.050  32.811  1.00 59.05           C  
+ATOM   6555  O   VAL B 325      19.836  15.219  32.472  1.00 59.12           O  
+ATOM   6556  CB  VAL B 325      21.097  13.709  35.017  1.00 57.45           C  
+ATOM   6557  CG1 VAL B 325      20.945  13.122  36.399  1.00 56.59           C  
+ATOM   6558  CG2 VAL B 325      22.180  12.988  34.238  1.00 59.22           C  
+ATOM   6559  N   LEU B 326      20.320  13.090  31.960  1.00 60.39           N  
+ATOM   6560  CA  LEU B 326      20.550  13.372  30.552  1.00 62.37           C  
+ATOM   6561  C   LEU B 326      19.256  13.779  29.866  1.00 64.22           C  
+ATOM   6562  O   LEU B 326      19.231  14.745  29.101  1.00 65.01           O  
+ATOM   6563  CB  LEU B 326      21.143  12.147  29.852  1.00 63.15           C  
+ATOM   6564  CG  LEU B 326      22.665  12.106  29.670  1.00 65.71           C  
+ATOM   6565  CD1 LEU B 326      23.371  12.580  30.928  1.00 67.05           C  
+ATOM   6566  CD2 LEU B 326      23.090  10.690  29.311  1.00 65.33           C  
+ATOM   6567  N   VAL B 327      18.183  13.041  30.133  1.00 65.63           N  
+ATOM   6568  CA  VAL B 327      16.893  13.349  29.529  1.00 67.52           C  
+ATOM   6569  C   VAL B 327      16.359  14.647  30.122  1.00 69.92           C  
+ATOM   6570  O   VAL B 327      15.608  15.377  29.476  1.00 69.66           O  
+ATOM   6571  CB  VAL B 327      15.876  12.216  29.759  1.00 66.32           C  
+ATOM   6572  CG1 VAL B 327      14.525  12.605  29.183  1.00 66.52           C  
+ATOM   6573  CG2 VAL B 327      16.369  10.942  29.098  1.00 65.52           C  
+ATOM   6574  N   TYR B 328      16.756  14.932  31.358  1.00 72.74           N  
+ATOM   6575  CA  TYR B 328      16.348  16.163  32.022  1.00 76.02           C  
+ATOM   6576  C   TYR B 328      17.037  17.291  31.257  1.00 77.78           C  
+ATOM   6577  O   TYR B 328      16.844  18.472  31.546  1.00 78.09           O  
+ATOM   6578  CB  TYR B 328      16.812  16.151  33.478  1.00 77.74           C  
+ATOM   6579  CG  TYR B 328      16.485  17.408  34.254  1.00 79.63           C  
+ATOM   6580  CD1 TYR B 328      15.163  17.760  34.531  1.00 80.32           C  
+ATOM   6581  CD2 TYR B 328      17.501  18.241  34.724  1.00 80.04           C  
+ATOM   6582  CE1 TYR B 328      14.863  18.913  35.260  1.00 80.80           C  
+ATOM   6583  CE2 TYR B 328      17.214  19.391  35.450  1.00 80.87           C  
+ATOM   6584  CZ  TYR B 328      15.895  19.722  35.716  1.00 81.38           C  
+ATOM   6585  OH  TYR B 328      15.615  20.857  36.441  1.00 82.03           O  
+ATOM   6586  N   LYS B 329      17.850  16.890  30.281  1.00 79.88           N  
+ATOM   6587  CA  LYS B 329      18.600  17.787  29.405  1.00 81.39           C  
+ATOM   6588  C   LYS B 329      19.723  18.587  30.050  1.00 83.59           C  
+ATOM   6589  O   LYS B 329      19.907  18.562  31.268  1.00 83.24           O  
+ATOM   6590  CB  LYS B 329      17.642  18.733  28.672  1.00 80.39           C  
+ATOM   6591  CG  LYS B 329      16.803  18.031  27.617  1.00 79.33           C  
+ATOM   6592  CD  LYS B 329      17.701  17.265  26.658  1.00 78.67           C  
+ATOM   6593  CE  LYS B 329      16.904  16.425  25.680  1.00 79.11           C  
+ATOM   6594  NZ  LYS B 329      17.802  15.656  24.775  1.00 78.42           N  
+ATOM   6595  N   LEU B 330      20.480  19.283  29.204  1.00 85.60           N  
+ATOM   6596  CA  LEU B 330      21.605  20.106  29.642  1.00 86.96           C  
+ATOM   6597  C   LEU B 330      21.379  21.542  29.157  1.00 86.93           C  
+ATOM   6598  O   LEU B 330      20.366  21.767  28.462  0.00 86.83           O  
+ATOM   6599  CB  LEU B 330      22.913  19.551  29.058  1.00 86.99           C  
+ATOM   6600  CG  LEU B 330      24.204  19.585  29.890  1.00 87.63           C  
+ATOM   6601  CD1 LEU B 330      24.624  21.019  30.165  1.00 87.55           C  
+ATOM   6602  CD2 LEU B 330      23.993  18.820  31.190  1.00 86.69           C  
+TER    6603      LEU B 330                                                      
+ATOM   6604  N   MET D   1      21.489  14.233 -28.081  1.00 65.94           N  
+ATOM   6605  CA  MET D   1      20.004  14.146 -28.062  1.00 65.25           C  
+ATOM   6606  C   MET D   1      19.459  15.278 -27.194  1.00 64.01           C  
+ATOM   6607  O   MET D   1      20.121  15.729 -26.258  1.00 64.00           O  
+ATOM   6608  CB  MET D   1      19.566  12.797 -27.489  1.00 66.50           C  
+ATOM   6609  CG  MET D   1      20.002  12.587 -26.053  1.00 70.14           C  
+ATOM   6610  SD  MET D   1      19.434  11.037 -25.347  1.00 73.49           S  
+ATOM   6611  CE  MET D   1      20.975  10.113 -25.255  1.00 72.32           C  
+ATOM   6612  N   ASN D   2      18.250  15.731 -27.503  1.00 61.98           N  
+ATOM   6613  CA  ASN D   2      17.641  16.815 -26.746  1.00 60.38           C  
+ATOM   6614  C   ASN D   2      16.700  16.301 -25.653  1.00 56.40           C  
+ATOM   6615  O   ASN D   2      16.200  17.085 -24.848  1.00 53.87           O  
+ATOM   6616  CB  ASN D   2      16.890  17.754 -27.703  1.00 63.07           C  
+ATOM   6617  CG  ASN D   2      16.369  19.011 -27.012  1.00 65.94           C  
+ATOM   6618  OD1 ASN D   2      17.078  19.650 -26.229  1.00 66.66           O  
+ATOM   6619  ND2 ASN D   2      15.129  19.380 -27.318  1.00 67.68           N  
+ATOM   6620  N   LYS D   3      16.474  14.988 -25.624  1.00 51.85           N  
+ATOM   6621  CA  LYS D   3      15.595  14.384 -24.630  1.00 50.18           C  
+ATOM   6622  C   LYS D   3      16.244  14.160 -23.265  1.00 47.66           C  
+ATOM   6623  O   LYS D   3      17.427  13.826 -23.167  1.00 46.91           O  
+ATOM   6624  CB  LYS D   3      15.046  13.050 -25.132  1.00 53.27           C  
+ATOM   6625  CG  LYS D   3      13.891  13.165 -26.112  1.00 58.47           C  
+ATOM   6626  CD  LYS D   3      13.192  11.819 -26.261  1.00 61.14           C  
+ATOM   6627  CE  LYS D   3      12.068  11.869 -27.279  1.00 62.78           C  
+ATOM   6628  NZ  LYS D   3      11.275  10.604 -27.263  1.00 64.77           N  
+ATOM   6629  N   ALA D   4      15.449  14.352 -22.213  1.00 43.77           N  
+ATOM   6630  CA  ALA D   4      15.915  14.168 -20.843  1.00 38.58           C  
+ATOM   6631  C   ALA D   4      15.269  12.909 -20.306  1.00 36.04           C  
+ATOM   6632  O   ALA D   4      15.864  12.189 -19.516  1.00 33.78           O  
+ATOM   6633  CB  ALA D   4      15.528  15.375 -19.976  1.00 38.29           C  
+ATOM   6634  N   LEU D   5      14.044  12.649 -20.749  1.00 35.06           N  
+ATOM   6635  CA  LEU D   5      13.313  11.470 -20.315  1.00 35.55           C  
+ATOM   6636  C   LEU D   5      12.076  11.306 -21.174  1.00 36.90           C  
+ATOM   6637  O   LEU D   5      11.635  12.254 -21.840  1.00 35.10           O  
+ATOM   6638  CB  LEU D   5      12.890  11.607 -18.843  1.00 40.00           C  
+ATOM   6639  CG  LEU D   5      11.736  12.569 -18.518  1.00 40.72           C  
+ATOM   6640  CD1 LEU D   5      10.405  11.868 -18.742  1.00 36.81           C  
+ATOM   6641  CD2 LEU D   5      11.832  13.022 -17.062  1.00 41.60           C  
+ATOM   6642  N   SER D   6      11.522  10.098 -21.156  1.00 36.04           N  
+ATOM   6643  CA  SER D   6      10.316   9.801 -21.906  1.00 39.64           C  
+ATOM   6644  C   SER D   6       9.601   8.651 -21.228  1.00 39.65           C  
+ATOM   6645  O   SER D   6      10.243   7.741 -20.701  1.00 40.08           O  
+ATOM   6646  CB  SER D   6      10.649   9.433 -23.363  1.00 42.73           C  
+ATOM   6647  OG  SER D   6      11.551   8.344 -23.441  1.00 47.40           O  
+ATOM   6648  N   VAL D   7       8.273   8.707 -21.205  1.00 39.40           N  
+ATOM   6649  CA  VAL D   7       7.502   7.638 -20.595  1.00 42.62           C  
+ATOM   6650  C   VAL D   7       6.499   7.184 -21.648  1.00 45.22           C  
+ATOM   6651  O   VAL D   7       5.873   8.006 -22.325  1.00 45.72           O  
+ATOM   6652  CB  VAL D   7       6.784   8.100 -19.288  1.00 40.74           C  
+ATOM   6653  CG1 VAL D   7       7.623   9.160 -18.577  1.00 38.95           C  
+ATOM   6654  CG2 VAL D   7       5.392   8.598 -19.586  1.00 42.83           C  
+ATOM   6655  N   GLU D   8       6.357   5.870 -21.780  1.00 48.01           N  
+ATOM   6656  CA  GLU D   8       5.488   5.288 -22.789  1.00 51.28           C  
+ATOM   6657  C   GLU D   8       4.424   4.366 -22.213  1.00 51.33           C  
+ATOM   6658  O   GLU D   8       4.733   3.473 -21.423  1.00 52.68           O  
+ATOM   6659  CB  GLU D   8       6.368   4.524 -23.781  1.00 53.67           C  
+ATOM   6660  CG  GLU D   8       5.649   3.881 -24.952  1.00 59.99           C  
+ATOM   6661  CD  GLU D   8       6.557   2.919 -25.707  1.00 62.23           C  
+ATOM   6662  OE1 GLU D   8       7.620   3.358 -26.204  1.00 63.10           O  
+ATOM   6663  OE2 GLU D   8       6.210   1.721 -25.793  1.00 64.78           O  
+ATOM   6664  N   ASN D   9       3.175   4.591 -22.617  1.00 52.03           N  
+ATOM   6665  CA  ASN D   9       2.035   3.780 -22.182  1.00 54.22           C  
+ATOM   6666  C   ASN D   9       2.149   3.346 -20.726  1.00 53.74           C  
+ATOM   6667  O   ASN D   9       1.789   2.222 -20.374  1.00 54.06           O  
+ATOM   6668  CB  ASN D   9       1.909   2.530 -23.067  1.00 56.54           C  
+ATOM   6669  CG  ASN D   9       0.592   1.787 -22.854  1.00 61.57           C  
+ATOM   6670  OD1 ASN D   9       0.497   0.581 -23.093  1.00 63.53           O  
+ATOM   6671  ND2 ASN D   9      -0.434   2.510 -22.415  1.00 63.73           N  
+ATOM   6672  N   LEU D  10       2.638   4.242 -19.877  1.00 53.66           N  
+ATOM   6673  CA  LEU D  10       2.819   3.922 -18.470  1.00 53.02           C  
+ATOM   6674  C   LEU D  10       1.518   3.641 -17.732  1.00 52.97           C  
+ATOM   6675  O   LEU D  10       0.564   4.409 -17.813  1.00 51.66           O  
+ATOM   6676  CB  LEU D  10       3.570   5.055 -17.772  1.00 52.56           C  
+ATOM   6677  CG  LEU D  10       3.876   4.862 -16.286  1.00 51.87           C  
+ATOM   6678  CD1 LEU D  10       4.653   3.572 -16.078  1.00 49.45           C  
+ATOM   6679  CD2 LEU D  10       4.676   6.062 -15.779  1.00 50.76           C  
+ATOM   6680  N   GLY D  11       1.494   2.524 -17.013  1.00 55.02           N  
+ATOM   6681  CA  GLY D  11       0.324   2.145 -16.240  1.00 57.12           C  
+ATOM   6682  C   GLY D  11       0.793   1.566 -14.919  1.00 58.81           C  
+ATOM   6683  O   GLY D  11       1.768   0.817 -14.890  1.00 59.24           O  
+ATOM   6684  N   PHE D  12       0.113   1.897 -13.825  1.00 61.11           N  
+ATOM   6685  CA  PHE D  12       0.526   1.391 -12.520  1.00 63.15           C  
+ATOM   6686  C   PHE D  12      -0.562   1.411 -11.454  1.00 65.74           C  
+ATOM   6687  O   PHE D  12      -1.485   2.228 -11.493  1.00 64.24           O  
+ATOM   6688  CB  PHE D  12       1.750   2.183 -12.028  1.00 61.85           C  
+ATOM   6689  CG  PHE D  12       2.202   1.822 -10.632  1.00 60.38           C  
+ATOM   6690  CD1 PHE D  12       1.588   2.384  -9.514  1.00 58.90           C  
+ATOM   6691  CD2 PHE D  12       3.237   0.911 -10.435  1.00 59.24           C  
+ATOM   6692  CE1 PHE D  12       2.000   2.043  -8.224  1.00 57.43           C  
+ATOM   6693  CE2 PHE D  12       3.655   0.564  -9.146  1.00 56.69           C  
+ATOM   6694  CZ  PHE D  12       3.036   1.131  -8.043  1.00 55.63           C  
+ATOM   6695  N   TYR D  13      -0.431   0.488 -10.504  1.00 69.55           N  
+ATOM   6696  CA  TYR D  13      -1.345   0.361  -9.376  1.00 74.19           C  
+ATOM   6697  C   TYR D  13      -0.567  -0.272  -8.227  1.00 76.85           C  
+ATOM   6698  O   TYR D  13       0.367  -1.041  -8.459  1.00 77.51           O  
+ATOM   6699  CB  TYR D  13      -2.559  -0.506  -9.746  1.00 75.62           C  
+ATOM   6700  CG  TYR D  13      -2.233  -1.905 -10.237  1.00 77.96           C  
+ATOM   6701  CD1 TYR D  13      -1.675  -2.861  -9.383  1.00 78.11           C  
+ATOM   6702  CD2 TYR D  13      -2.487  -2.275 -11.560  1.00 78.73           C  
+ATOM   6703  CE1 TYR D  13      -1.377  -4.148  -9.834  1.00 78.90           C  
+ATOM   6704  CE2 TYR D  13      -2.193  -3.560 -12.022  1.00 79.29           C  
+ATOM   6705  CZ  TYR D  13      -1.638  -4.490 -11.154  1.00 79.79           C  
+ATOM   6706  OH  TYR D  13      -1.341  -5.757 -11.608  1.00 80.87           O  
+ATOM   6707  N   TYR D  14      -0.935   0.063  -6.994  1.00 79.76           N  
+ATOM   6708  CA  TYR D  14      -0.255  -0.496  -5.831  1.00 82.84           C  
+ATOM   6709  C   TYR D  14      -0.798  -1.873  -5.467  1.00 85.68           C  
+ATOM   6710  O   TYR D  14      -0.035  -2.789  -5.153  1.00 85.40           O  
+ATOM   6711  CB  TYR D  14      -0.393   0.430  -4.619  1.00 82.29           C  
+ATOM   6712  CG  TYR D  14       0.583   1.583  -4.597  1.00 82.07           C  
+ATOM   6713  CD1 TYR D  14       0.332   2.752  -5.310  1.00 82.42           C  
+ATOM   6714  CD2 TYR D  14       1.766   1.500  -3.863  1.00 82.08           C  
+ATOM   6715  CE1 TYR D  14       1.235   3.814  -5.292  1.00 82.92           C  
+ATOM   6716  CE2 TYR D  14       2.676   2.553  -3.839  1.00 82.62           C  
+ATOM   6717  CZ  TYR D  14       2.405   3.707  -4.554  1.00 82.99           C  
+ATOM   6718  OH  TYR D  14       3.306   4.750  -4.531  1.00 83.52           O  
+ATOM   6719  N   GLN D  15      -2.120  -2.014  -5.511  1.00 88.67           N  
+ATOM   6720  CA  GLN D  15      -2.758  -3.277  -5.169  1.00 91.88           C  
+ATOM   6721  C   GLN D  15      -3.827  -3.677  -6.186  1.00 92.97           C  
+ATOM   6722  O   GLN D  15      -3.873  -4.829  -6.625  1.00 93.32           O  
+ATOM   6723  CB  GLN D  15      -3.370  -3.176  -3.770  1.00 93.26           C  
+ATOM   6724  CG  GLN D  15      -3.914  -4.484  -3.221  1.00 96.50           C  
+ATOM   6725  CD  GLN D  15      -4.368  -4.364  -1.774  1.00 98.30           C  
+ATOM   6726  OE1 GLN D  15      -4.891  -5.317  -1.191  1.00 99.18           O  
+ATOM   6727  NE2 GLN D  15      -4.166  -3.188  -1.186  1.00 98.89           N  
+ATOM   6728  N   ALA D  16      -4.678  -2.725  -6.560  1.00 93.73           N  
+ATOM   6729  CA  ALA D  16      -5.746  -2.980  -7.525  1.00 94.33           C  
+ATOM   6730  C   ALA D  16      -5.210  -3.653  -8.788  1.00 94.75           C  
+ATOM   6731  O   ALA D  16      -5.683  -4.720  -9.188  1.00 94.68           O  
+ATOM   6732  CB  ALA D  16      -6.446  -1.670  -7.888  1.00 94.07           C  
+ATOM   6733  N   PHE D  21      -3.357   5.722 -12.767  1.00 68.59           N  
+ATOM   6734  CA  PHE D  21      -3.331   6.064 -14.187  1.00 68.67           C  
+ATOM   6735  C   PHE D  21      -3.058   4.868 -15.102  1.00 68.26           C  
+ATOM   6736  O   PHE D  21      -2.707   3.780 -14.642  1.00 67.84           O  
+ATOM   6737  CB  PHE D  21      -2.297   7.172 -14.455  1.00 68.36           C  
+ATOM   6738  CG  PHE D  21      -1.071   7.091 -13.584  1.00 68.37           C  
+ATOM   6739  CD1 PHE D  21      -0.941   7.916 -12.469  1.00 67.71           C  
+ATOM   6740  CD2 PHE D  21      -0.055   6.181 -13.866  1.00 67.93           C  
+ATOM   6741  CE1 PHE D  21       0.181   7.836 -11.648  1.00 66.69           C  
+ATOM   6742  CE2 PHE D  21       1.070   6.094 -13.051  1.00 66.50           C  
+ATOM   6743  CZ  PHE D  21       1.188   6.924 -11.939  1.00 66.62           C  
+ATOM   6744  N   GLN D  22      -3.226   5.090 -16.403  1.00 68.46           N  
+ATOM   6745  CA  GLN D  22      -3.027   4.056 -17.413  1.00 68.03           C  
+ATOM   6746  C   GLN D  22      -2.820   4.747 -18.768  1.00 66.35           C  
+ATOM   6747  O   GLN D  22      -3.381   5.813 -19.011  1.00 65.57           O  
+ATOM   6748  CB  GLN D  22      -4.265   3.148 -17.453  1.00 69.77           C  
+ATOM   6749  CG  GLN D  22      -4.038   1.759 -18.043  1.00 72.35           C  
+ATOM   6750  CD  GLN D  22      -5.278   0.872 -17.956  1.00 73.53           C  
+ATOM   6751  OE1 GLN D  22      -5.818   0.644 -16.871  1.00 73.67           O  
+ATOM   6752  NE2 GLN D  22      -5.728   0.365 -19.101  1.00 74.21           N  
+ATOM   6753  N   GLN D  23      -2.013   4.145 -19.639  1.00 65.92           N  
+ATOM   6754  CA  GLN D  23      -1.729   4.713 -20.963  1.00 65.04           C  
+ATOM   6755  C   GLN D  23      -1.149   6.129 -20.903  1.00 63.26           C  
+ATOM   6756  O   GLN D  23      -1.473   6.975 -21.745  1.00 61.89           O  
+ATOM   6757  CB  GLN D  23      -2.995   4.738 -21.831  1.00 68.17           C  
+ATOM   6758  CG  GLN D  23      -3.301   3.444 -22.576  1.00 72.20           C  
+ATOM   6759  CD  GLN D  23      -3.707   2.310 -21.654  1.00 75.29           C  
+ATOM   6760  OE1 GLN D  23      -4.716   2.399 -20.949  1.00 76.08           O  
+ATOM   6761  NE2 GLN D  23      -2.924   1.234 -21.655  1.00 75.78           N  
+ATOM   6762  N   LEU D  24      -0.284   6.380 -19.923  1.00 60.40           N  
+ATOM   6763  CA  LEU D  24       0.322   7.701 -19.758  1.00 56.85           C  
+ATOM   6764  C   LEU D  24       1.535   7.872 -20.661  1.00 54.79           C  
+ATOM   6765  O   LEU D  24       2.449   7.046 -20.642  1.00 53.88           O  
+ATOM   6766  CB  LEU D  24       0.750   7.904 -18.307  1.00 56.88           C  
+ATOM   6767  CG  LEU D  24       0.660   9.315 -17.719  1.00 56.91           C  
+ATOM   6768  CD1 LEU D  24       1.494   9.353 -16.444  1.00 55.68           C  
+ATOM   6769  CD2 LEU D  24       1.153  10.357 -18.712  1.00 55.95           C  
+ATOM   6770  N   ASN D  25       1.546   8.951 -21.441  1.00 52.26           N  
+ATOM   6771  CA  ASN D  25       2.654   9.224 -22.350  1.00 50.94           C  
+ATOM   6772  C   ASN D  25       3.110  10.676 -22.313  1.00 50.86           C  
+ATOM   6773  O   ASN D  25       2.292  11.601 -22.315  1.00 51.42           O  
+ATOM   6774  CB  ASN D  25       2.274   8.903 -23.806  1.00 52.17           C  
+ATOM   6775  CG  ASN D  25       1.703   7.511 -23.977  1.00 51.55           C  
+ATOM   6776  OD1 ASN D  25       0.514   7.283 -23.756  1.00 53.77           O  
+ATOM   6777  ND2 ASN D  25       2.551   6.570 -24.363  1.00 51.79           N  
+ATOM   6778  N   PHE D  26       4.422  10.865 -22.281  1.00 47.65           N  
+ATOM   6779  CA  PHE D  26       5.012  12.192 -22.315  1.00 45.76           C  
+ATOM   6780  C   PHE D  26       6.523  12.096 -22.308  1.00 44.87           C  
+ATOM   6781  O   PHE D  26       7.093  11.086 -21.901  1.00 43.94           O  
+ATOM   6782  CB  PHE D  26       4.522  13.088 -21.152  1.00 43.32           C  
+ATOM   6783  CG  PHE D  26       5.007  12.675 -19.786  1.00 40.80           C  
+ATOM   6784  CD1 PHE D  26       4.311  11.732 -19.038  1.00 39.09           C  
+ATOM   6785  CD2 PHE D  26       6.148  13.257 -19.233  1.00 40.31           C  
+ATOM   6786  CE1 PHE D  26       4.744  11.372 -17.754  1.00 39.24           C  
+ATOM   6787  CE2 PHE D  26       6.589  12.905 -17.951  1.00 38.55           C  
+ATOM   6788  CZ  PHE D  26       5.884  11.960 -17.213  1.00 38.18           C  
+ATOM   6789  N   ASP D  27       7.168  13.143 -22.802  1.00 45.63           N  
+ATOM   6790  CA  ASP D  27       8.616  13.186 -22.823  1.00 46.44           C  
+ATOM   6791  C   ASP D  27       9.096  14.607 -22.583  1.00 42.57           C  
+ATOM   6792  O   ASP D  27       8.387  15.576 -22.858  1.00 42.01           O  
+ATOM   6793  CB  ASP D  27       9.163  12.640 -24.149  1.00 51.74           C  
+ATOM   6794  CG  ASP D  27       8.543  13.300 -25.358  1.00 57.28           C  
+ATOM   6795  OD1 ASP D  27       8.619  14.547 -25.465  1.00 58.71           O  
+ATOM   6796  OD2 ASP D  27       7.990  12.561 -26.209  1.00 62.75           O  
+ATOM   6797  N   LEU D  28      10.305  14.724 -22.056  1.00 40.27           N  
+ATOM   6798  CA  LEU D  28      10.871  16.028 -21.762  1.00 38.76           C  
+ATOM   6799  C   LEU D  28      12.203  16.222 -22.434  1.00 38.82           C  
+ATOM   6800  O   LEU D  28      12.961  15.270 -22.643  1.00 39.05           O  
+ATOM   6801  CB  LEU D  28      11.076  16.204 -20.255  1.00 37.04           C  
+ATOM   6802  CG  LEU D  28       9.853  16.184 -19.349  1.00 37.87           C  
+ATOM   6803  CD1 LEU D  28      10.316  16.319 -17.899  1.00 38.45           C  
+ATOM   6804  CD2 LEU D  28       8.905  17.309 -19.741  1.00 36.62           C  
+ATOM   6805  N   ASN D  29      12.490  17.476 -22.746  1.00 37.78           N  
+ATOM   6806  CA  ASN D  29      13.742  17.832 -23.366  1.00 39.60           C  
+ATOM   6807  C   ASN D  29      14.599  18.484 -22.299  1.00 39.62           C  
+ATOM   6808  O   ASN D  29      14.079  18.996 -21.306  1.00 41.70           O  
+ATOM   6809  CB  ASN D  29      13.482  18.788 -24.528  1.00 41.09           C  
+ATOM   6810  CG  ASN D  29      12.650  18.145 -25.625  1.00 43.22           C  
+ATOM   6811  OD1 ASN D  29      11.843  18.806 -26.269  1.00 46.42           O  
+ATOM   6812  ND2 ASN D  29      12.847  16.848 -25.842  1.00 42.58           N  
+ATOM   6813  N   LYS D  30      15.910  18.453 -22.488  1.00 38.10           N  
+ATOM   6814  CA  LYS D  30      16.804  19.058 -21.521  1.00 38.26           C  
+ATOM   6815  C   LYS D  30      16.421  20.523 -21.361  1.00 37.43           C  
+ATOM   6816  O   LYS D  30      16.064  21.184 -22.340  1.00 38.33           O  
+ATOM   6817  CB  LYS D  30      18.260  18.939 -21.993  1.00 38.79           C  
+ATOM   6818  CG  LYS D  30      18.682  17.511 -22.356  1.00 44.20           C  
+ATOM   6819  CD  LYS D  30      20.202  17.383 -22.479  1.00 47.73           C  
+ATOM   6820  CE  LYS D  30      20.627  16.101 -23.210  1.00 50.06           C  
+ATOM   6821  NZ  LYS D  30      20.157  14.841 -22.567  1.00 53.04           N  
+ATOM   6822  N   GLY D  31      16.470  21.024 -20.128  1.00 34.19           N  
+ATOM   6823  CA  GLY D  31      16.143  22.418 -19.896  1.00 30.16           C  
+ATOM   6824  C   GLY D  31      14.669  22.713 -19.701  1.00 29.94           C  
+ATOM   6825  O   GLY D  31      14.288  23.856 -19.460  1.00 31.89           O  
+ATOM   6826  N   ASP D  32      13.830  21.695 -19.827  1.00 28.88           N  
+ATOM   6827  CA  ASP D  32      12.394  21.867 -19.637  1.00 30.83           C  
+ATOM   6828  C   ASP D  32      12.047  21.927 -18.137  1.00 32.00           C  
+ATOM   6829  O   ASP D  32      12.792  21.420 -17.286  1.00 29.28           O  
+ATOM   6830  CB  ASP D  32      11.633  20.677 -20.245  1.00 32.89           C  
+ATOM   6831  CG  ASP D  32      11.303  20.857 -21.727  1.00 34.70           C  
+ATOM   6832  OD1 ASP D  32      10.769  19.888 -22.314  1.00 35.30           O  
+ATOM   6833  OD2 ASP D  32      11.552  21.946 -22.298  1.00 33.59           O  
+ATOM   6834  N   ILE D  33      10.933  22.578 -17.817  1.00 30.99           N  
+ATOM   6835  CA  ILE D  33      10.448  22.596 -16.445  1.00 29.50           C  
+ATOM   6836  C   ILE D  33       9.065  21.960 -16.515  1.00 27.71           C  
+ATOM   6837  O   ILE D  33       8.145  22.504 -17.124  1.00 28.70           O  
+ATOM   6838  CB  ILE D  33      10.306  24.002 -15.840  1.00 30.90           C  
+ATOM   6839  CG1 ILE D  33      11.679  24.683 -15.721  1.00 29.35           C  
+ATOM   6840  CG2 ILE D  33       9.653  23.876 -14.444  1.00 26.38           C  
+ATOM   6841  CD1 ILE D  33      11.630  26.082 -15.147  0.00 29.84           C  
+ATOM   6842  N   LEU D  34       8.931  20.789 -15.914  1.00 27.68           N  
+ATOM   6843  CA  LEU D  34       7.664  20.069 -15.906  1.00 27.17           C  
+ATOM   6844  C   LEU D  34       6.999  20.189 -14.541  1.00 27.61           C  
+ATOM   6845  O   LEU D  34       7.619  19.915 -13.509  1.00 25.18           O  
+ATOM   6846  CB  LEU D  34       7.893  18.573 -16.179  1.00 28.14           C  
+ATOM   6847  CG  LEU D  34       6.751  17.670 -16.670  1.00 30.16           C  
+ATOM   6848  CD1 LEU D  34       6.839  16.344 -15.982  1.00 30.30           C  
+ATOM   6849  CD2 LEU D  34       5.393  18.288 -16.427  1.00 32.48           C  
+ATOM   6850  N   ALA D  35       5.736  20.591 -14.542  1.00 27.50           N  
+ATOM   6851  CA  ALA D  35       4.978  20.668 -13.312  1.00 27.48           C  
+ATOM   6852  C   ALA D  35       3.904  19.595 -13.415  1.00 28.34           C  
+ATOM   6853  O   ALA D  35       3.168  19.536 -14.405  1.00 26.53           O  
+ATOM   6854  CB  ALA D  35       4.329  22.045 -13.145  1.00 26.92           C  
+ATOM   6855  N   VAL D  36       3.858  18.719 -12.414  1.00 27.66           N  
+ATOM   6856  CA  VAL D  36       2.839  17.686 -12.352  1.00 29.49           C  
+ATOM   6857  C   VAL D  36       1.798  18.282 -11.404  1.00 29.32           C  
+ATOM   6858  O   VAL D  36       1.988  18.285 -10.193  1.00 29.63           O  
+ATOM   6859  CB  VAL D  36       3.396  16.372 -11.759  1.00 30.78           C  
+ATOM   6860  CG1 VAL D  36       2.332  15.293 -11.820  1.00 29.40           C  
+ATOM   6861  CG2 VAL D  36       4.635  15.933 -12.530  1.00 30.16           C  
+ATOM   6862  N   LEU D  37       0.716  18.805 -11.971  1.00 31.59           N  
+ATOM   6863  CA  LEU D  37      -0.348  19.456 -11.212  1.00 32.31           C  
+ATOM   6864  C   LEU D  37      -1.433  18.494 -10.772  1.00 32.88           C  
+ATOM   6865  O   LEU D  37      -1.994  17.769 -11.586  1.00 33.53           O  
+ATOM   6866  CB  LEU D  37      -0.996  20.546 -12.062  1.00 32.50           C  
+ATOM   6867  CG  LEU D  37      -1.265  21.942 -11.504  1.00 34.70           C  
+ATOM   6868  CD1 LEU D  37      -2.463  22.507 -12.258  1.00 27.91           C  
+ATOM   6869  CD2 LEU D  37      -1.520  21.918  -9.994  1.00 31.07           C  
+ATOM   6870  N   GLY D  38      -1.742  18.512  -9.480  1.00 34.59           N  
+ATOM   6871  CA  GLY D  38      -2.770  17.637  -8.951  1.00 34.51           C  
+ATOM   6872  C   GLY D  38      -2.990  17.831  -7.466  1.00 34.94           C  
+ATOM   6873  O   GLY D  38      -2.272  18.586  -6.812  1.00 36.29           O  
+ATOM   6874  N   GLN D  39      -3.991  17.153  -6.925  1.00 37.06           N  
+ATOM   6875  CA  GLN D  39      -4.281  17.263  -5.505  1.00 40.36           C  
+ATOM   6876  C   GLN D  39      -3.774  16.006  -4.789  1.00 44.72           C  
+ATOM   6877  O   GLN D  39      -3.606  14.957  -5.412  1.00 45.51           O  
+ATOM   6878  CB  GLN D  39      -5.781  17.454  -5.299  1.00 36.64           C  
+ATOM   6879  CG  GLN D  39      -6.350  18.613  -6.110  1.00 36.43           C  
+ATOM   6880  CD  GLN D  39      -7.696  19.098  -5.595  1.00 36.24           C  
+ATOM   6881  OE1 GLN D  39      -7.762  19.910  -4.669  1.00 33.70           O  
+ATOM   6882  NE2 GLN D  39      -8.774  18.594  -6.186  1.00 32.10           N  
+ATOM   6883  N   ASN D  40      -3.518  16.127  -3.488  1.00 49.54           N  
+ATOM   6884  CA  ASN D  40      -3.001  15.024  -2.677  1.00 53.73           C  
+ATOM   6885  C   ASN D  40      -3.646  13.669  -2.926  1.00 54.94           C  
+ATOM   6886  O   ASN D  40      -4.870  13.553  -3.032  1.00 56.32           O  
+ATOM   6887  CB  ASN D  40      -3.128  15.352  -1.183  1.00 56.97           C  
+ATOM   6888  CG  ASN D  40      -2.667  14.196  -0.287  1.00 62.15           C  
+ATOM   6889  OD1 ASN D  40      -1.465  13.946  -0.132  1.00 62.62           O  
+ATOM   6890  ND2 ASN D  40      -3.628  13.480   0.294  1.00 61.01           N  
+ATOM   6891  N   GLY D  41      -2.801  12.644  -2.999  1.00 55.80           N  
+ATOM   6892  CA  GLY D  41      -3.269  11.284  -3.207  1.00 56.20           C  
+ATOM   6893  C   GLY D  41      -3.897  11.014  -4.557  1.00 56.14           C  
+ATOM   6894  O   GLY D  41      -4.595  10.017  -4.731  1.00 56.11           O  
+ATOM   6895  N   CYS D  42      -3.646  11.889  -5.523  1.00 56.53           N  
+ATOM   6896  CA  CYS D  42      -4.222  11.705  -6.845  1.00 57.04           C  
+ATOM   6897  C   CYS D  42      -3.231  11.256  -7.913  1.00 55.24           C  
+ATOM   6898  O   CYS D  42      -3.469  11.453  -9.098  1.00 56.05           O  
+ATOM   6899  CB  CYS D  42      -4.942  12.986  -7.284  1.00 58.99           C  
+ATOM   6900  SG  CYS D  42      -6.408  13.376  -6.266  1.00 63.18           S  
+ATOM   6901  N   GLY D  43      -2.121  10.657  -7.491  1.00 54.04           N  
+ATOM   6902  CA  GLY D  43      -1.147  10.161  -8.447  1.00 53.13           C  
+ATOM   6903  C   GLY D  43       0.257  10.748  -8.508  1.00 52.44           C  
+ATOM   6904  O   GLY D  43       1.234   9.992  -8.552  1.00 49.47           O  
+ATOM   6905  N   LYS D  44       0.359  12.079  -8.506  1.00 51.88           N  
+ATOM   6906  CA  LYS D  44       1.645  12.773  -8.617  1.00 51.93           C  
+ATOM   6907  C   LYS D  44       2.787  12.253  -7.752  1.00 51.54           C  
+ATOM   6908  O   LYS D  44       3.930  12.190  -8.203  1.00 51.89           O  
+ATOM   6909  CB  LYS D  44       1.463  14.273  -8.375  1.00 52.23           C  
+ATOM   6910  CG  LYS D  44       1.015  14.639  -6.985  1.00 48.55           C  
+ATOM   6911  CD  LYS D  44       0.683  16.114  -6.913  1.00 46.25           C  
+ATOM   6912  CE  LYS D  44       0.196  16.476  -5.526  1.00 45.38           C  
+ATOM   6913  NZ  LYS D  44      -0.100  17.912  -5.438  1.00 46.16           N  
+ATOM   6914  N   SER D  45       2.496  11.877  -6.517  1.00 50.18           N  
+ATOM   6915  CA  SER D  45       3.554  11.364  -5.661  1.00 50.05           C  
+ATOM   6916  C   SER D  45       4.088  10.024  -6.181  1.00 48.14           C  
+ATOM   6917  O   SER D  45       5.294   9.827  -6.278  1.00 49.63           O  
+ATOM   6918  CB  SER D  45       3.048  11.203  -4.230  1.00 49.82           C  
+ATOM   6919  OG  SER D  45       4.110  10.809  -3.383  1.00 53.11           O  
+ATOM   6920  N   THR D  46       3.188   9.106  -6.513  1.00 47.86           N  
+ATOM   6921  CA  THR D  46       3.580   7.791  -7.029  1.00 47.17           C  
+ATOM   6922  C   THR D  46       4.335   7.901  -8.362  1.00 45.26           C  
+ATOM   6923  O   THR D  46       5.217   7.091  -8.658  1.00 42.71           O  
+ATOM   6924  CB  THR D  46       2.339   6.887  -7.203  1.00 47.76           C  
+ATOM   6925  OG1 THR D  46       1.777   6.619  -5.911  1.00 48.08           O  
+ATOM   6926  CG2 THR D  46       2.708   5.569  -7.877  1.00 46.35           C  
+ATOM   6927  N   LEU D  47       3.989   8.912  -9.153  1.00 43.93           N  
+ATOM   6928  CA  LEU D  47       4.653   9.142 -10.429  1.00 44.65           C  
+ATOM   6929  C   LEU D  47       6.145   9.378 -10.185  1.00 45.17           C  
+ATOM   6930  O   LEU D  47       6.987   8.817 -10.887  1.00 44.01           O  
+ATOM   6931  CB  LEU D  47       4.063  10.368 -11.123  1.00 46.10           C  
+ATOM   6932  CG  LEU D  47       3.884  10.375 -12.646  1.00 48.03           C  
+ATOM   6933  CD1 LEU D  47       4.005  11.817 -13.121  1.00 47.33           C  
+ATOM   6934  CD2 LEU D  47       4.922   9.497 -13.344  1.00 46.55           C  
+ATOM   6935  N   LEU D  48       6.473  10.210  -9.191  1.00 44.93           N  
+ATOM   6936  CA  LEU D  48       7.875  10.496  -8.884  1.00 45.37           C  
+ATOM   6937  C   LEU D  48       8.606   9.229  -8.491  1.00 45.66           C  
+ATOM   6938  O   LEU D  48       9.763   9.035  -8.855  1.00 45.24           O  
+ATOM   6939  CB  LEU D  48       8.009  11.522  -7.748  1.00 46.33           C  
+ATOM   6940  CG  LEU D  48       7.737  12.995  -8.054  1.00 44.82           C  
+ATOM   6941  CD1 LEU D  48       8.189  13.837  -6.873  1.00 46.59           C  
+ATOM   6942  CD2 LEU D  48       8.481  13.423  -9.297  1.00 45.01           C  
+ATOM   6943  N   ASP D  49       7.933   8.378  -7.727  1.00 47.29           N  
+ATOM   6944  CA  ASP D  49       8.519   7.113  -7.309  1.00 50.77           C  
+ATOM   6945  C   ASP D  49       8.884   6.287  -8.544  1.00 49.13           C  
+ATOM   6946  O   ASP D  49       9.917   5.614  -8.568  1.00 48.86           O  
+ATOM   6947  CB  ASP D  49       7.528   6.333  -6.439  1.00 56.16           C  
+ATOM   6948  CG  ASP D  49       7.367   6.935  -5.050  1.00 62.39           C  
+ATOM   6949  OD1 ASP D  49       7.250   8.176  -4.945  1.00 65.76           O  
+ATOM   6950  OD2 ASP D  49       7.348   6.164  -4.062  1.00 65.32           O  
+ATOM   6951  N   LEU D  50       8.032   6.346  -9.565  1.00 46.65           N  
+ATOM   6952  CA  LEU D  50       8.261   5.604 -10.806  1.00 45.94           C  
+ATOM   6953  C   LEU D  50       9.408   6.196 -11.610  1.00 44.76           C  
+ATOM   6954  O   LEU D  50      10.212   5.457 -12.183  1.00 43.58           O  
+ATOM   6955  CB  LEU D  50       6.999   5.591 -11.672  1.00 45.47           C  
+ATOM   6956  CG  LEU D  50       5.811   4.805 -11.116  1.00 48.24           C  
+ATOM   6957  CD1 LEU D  50       4.587   5.004 -12.006  1.00 48.06           C  
+ATOM   6958  CD2 LEU D  50       6.182   3.333 -11.030  1.00 47.79           C  
+ATOM   6959  N   LEU D  51       9.482   7.524 -11.655  1.00 42.63           N  
+ATOM   6960  CA  LEU D  51      10.542   8.186 -12.395  1.00 43.77           C  
+ATOM   6961  C   LEU D  51      11.901   7.921 -11.751  1.00 45.96           C  
+ATOM   6962  O   LEU D  51      12.926   7.923 -12.436  1.00 45.78           O  
+ATOM   6963  CB  LEU D  51      10.277   9.693 -12.491  1.00 42.88           C  
+ATOM   6964  CG  LEU D  51       9.075  10.128 -13.339  1.00 44.20           C  
+ATOM   6965  CD1 LEU D  51       8.917  11.644 -13.285  1.00 43.19           C  
+ATOM   6966  CD2 LEU D  51       9.269   9.668 -14.782  1.00 44.12           C  
+ATOM   6967  N   LEU D  52      11.908   7.677 -10.441  1.00 47.64           N  
+ATOM   6968  CA  LEU D  52      13.152   7.390  -9.726  1.00 49.59           C  
+ATOM   6969  C   LEU D  52      13.519   5.923  -9.869  1.00 51.14           C  
+ATOM   6970  O   LEU D  52      14.685   5.551  -9.751  1.00 53.38           O  
+ATOM   6971  CB  LEU D  52      13.024   7.735  -8.237  1.00 49.35           C  
+ATOM   6972  CG  LEU D  52      13.194   9.211  -7.866  1.00 49.41           C  
+ATOM   6973  CD1 LEU D  52      12.728   9.456  -6.440  1.00 49.83           C  
+ATOM   6974  CD2 LEU D  52      14.651   9.602  -8.044  1.00 48.23           C  
+ATOM   6975  N   GLY D  53      12.515   5.093 -10.124  1.00 52.78           N  
+ATOM   6976  CA  GLY D  53      12.755   3.673 -10.278  1.00 54.61           C  
+ATOM   6977  C   GLY D  53      12.536   2.892  -8.996  1.00 56.57           C  
+ATOM   6978  O   GLY D  53      12.935   1.734  -8.901  1.00 56.43           O  
+ATOM   6979  N   ILE D  54      11.909   3.520  -8.006  1.00 58.97           N  
+ATOM   6980  CA  ILE D  54      11.644   2.848  -6.738  1.00 61.48           C  
+ATOM   6981  C   ILE D  54      10.667   1.695  -6.950  1.00 63.59           C  
+ATOM   6982  O   ILE D  54      10.685   0.708  -6.212  1.00 65.60           O  
+ATOM   6983  CB  ILE D  54      11.063   3.826  -5.693  1.00 61.38           C  
+ATOM   6984  CG1 ILE D  54      12.157   4.786  -5.215  1.00 60.05           C  
+ATOM   6985  CG2 ILE D  54      10.484   3.055  -4.515  1.00 61.47           C  
+ATOM   6986  CD1 ILE D  54      11.672   5.820  -4.229  0.00 60.57           C  
+ATOM   6987  N   HIS D  55       9.821   1.821  -7.968  1.00 64.69           N  
+ATOM   6988  CA  HIS D  55       8.840   0.791  -8.287  1.00 65.70           C  
+ATOM   6989  C   HIS D  55       8.837   0.445  -9.770  1.00 65.76           C  
+ATOM   6990  O   HIS D  55       9.061   1.304 -10.627  1.00 65.26           O  
+ATOM   6991  CB  HIS D  55       7.443   1.246  -7.861  1.00 66.60           C  
+ATOM   6992  CG  HIS D  55       7.243   1.261  -6.379  1.00 68.48           C  
+ATOM   6993  ND1 HIS D  55       6.257   2.006  -5.769  1.00 68.65           N  
+ATOM   6994  CD2 HIS D  55       7.890   0.607  -5.385  1.00 69.35           C  
+ATOM   6995  CE1 HIS D  55       6.307   1.811  -4.463  1.00 70.62           C  
+ATOM   6996  NE2 HIS D  55       7.289   0.966  -4.204  1.00 69.24           N  
+ATOM   6997  N   ARG D  56       8.586  -0.825 -10.061  1.00 66.24           N  
+ATOM   6998  CA  ARG D  56       8.545  -1.315 -11.431  1.00 67.16           C  
+ATOM   6999  C   ARG D  56       7.165  -1.030 -12.026  1.00 65.46           C  
+ATOM   7000  O   ARG D  56       6.141  -1.333 -11.412  1.00 66.20           O  
+ATOM   7001  CB  ARG D  56       8.810  -2.824 -11.445  1.00 70.49           C  
+ATOM   7002  CG  ARG D  56       9.002  -3.426 -12.828  1.00 75.72           C  
+ATOM   7003  CD  ARG D  56       8.685  -4.923 -12.839  1.00 79.47           C  
+ATOM   7004  NE  ARG D  56       9.448  -5.678 -11.844  1.00 83.33           N  
+ATOM   7005  CZ  ARG D  56       9.291  -6.980 -11.609  1.00 84.97           C  
+ATOM   7006  NH1 ARG D  56       8.396  -7.680 -12.298  1.00 85.06           N  
+ATOM   7007  NH2 ARG D  56      10.024  -7.582 -10.681  1.00 84.94           N  
+ATOM   7008  N   PRO D  57       7.121  -0.434 -13.226  1.00 63.71           N  
+ATOM   7009  CA  PRO D  57       5.860  -0.112 -13.902  1.00 63.18           C  
+ATOM   7010  C   PRO D  57       5.081  -1.385 -14.229  1.00 63.19           C  
+ATOM   7011  O   PRO D  57       5.673  -2.383 -14.628  1.00 64.07           O  
+ATOM   7012  CB  PRO D  57       6.322   0.593 -15.177  1.00 62.45           C  
+ATOM   7013  CG  PRO D  57       7.645   1.164 -14.803  1.00 61.27           C  
+ATOM   7014  CD  PRO D  57       8.268   0.061 -14.003  1.00 62.84           C  
+ATOM   7015  N   ILE D  58       3.763  -1.359 -14.063  1.00 63.56           N  
+ATOM   7016  CA  ILE D  58       2.957  -2.534 -14.381  1.00 64.32           C  
+ATOM   7017  C   ILE D  58       2.786  -2.613 -15.898  1.00 63.95           C  
+ATOM   7018  O   ILE D  58       2.762  -3.701 -16.475  1.00 63.89           O  
+ATOM   7019  CB  ILE D  58       1.570  -2.485 -13.681  1.00 64.93           C  
+ATOM   7020  CG1 ILE D  58       1.699  -2.983 -12.236  1.00 63.72           C  
+ATOM   7021  CG2 ILE D  58       0.562  -3.345 -14.435  1.00 65.26           C  
+ATOM   7022  CD1 ILE D  58       2.650  -2.178 -11.381  0.00 64.32           C  
+ATOM   7023  N   GLN D  59       2.678  -1.450 -16.533  1.00 62.73           N  
+ATOM   7024  CA  GLN D  59       2.543  -1.360 -17.983  1.00 61.86           C  
+ATOM   7025  C   GLN D  59       3.388  -0.193 -18.485  1.00 60.83           C  
+ATOM   7026  O   GLN D  59       3.600   0.788 -17.764  1.00 60.01           O  
+ATOM   7027  CB  GLN D  59       1.079  -1.149 -18.382  1.00 63.54           C  
+ATOM   7028  CG  GLN D  59       0.174  -2.316 -18.025  1.00 67.62           C  
+ATOM   7029  CD  GLN D  59      -1.268  -2.119 -18.470  1.00 69.80           C  
+ATOM   7030  OE1 GLN D  59      -2.119  -2.990 -18.253  1.00 69.88           O  
+ATOM   7031  NE2 GLN D  59      -1.552  -0.976 -19.096  1.00 69.92           N  
+ATOM   7032  N   GLY D  60       3.875  -0.307 -19.716  1.00 57.92           N  
+ATOM   7033  CA  GLY D  60       4.690   0.746 -20.294  1.00 54.95           C  
+ATOM   7034  C   GLY D  60       6.139   0.703 -19.849  1.00 53.34           C  
+ATOM   7035  O   GLY D  60       6.618  -0.318 -19.352  1.00 52.67           O  
+ATOM   7036  N   LYS D  61       6.840   1.817 -20.030  1.00 51.27           N  
+ATOM   7037  CA  LYS D  61       8.241   1.914 -19.644  1.00 49.68           C  
+ATOM   7038  C   LYS D  61       8.681   3.367 -19.492  1.00 48.08           C  
+ATOM   7039  O   LYS D  61       8.097   4.278 -20.086  1.00 47.00           O  
+ATOM   7040  CB  LYS D  61       9.137   1.221 -20.676  1.00 50.70           C  
+ATOM   7041  CG  LYS D  61       9.105   1.855 -22.059  1.00 52.67           C  
+ATOM   7042  CD  LYS D  61      10.247   1.345 -22.932  1.00 54.98           C  
+ATOM   7043  CE  LYS D  61      10.312   2.119 -24.249  1.00 56.82           C  
+ATOM   7044  NZ  LYS D  61      11.486   1.726 -25.086  1.00 60.26           N  
+ATOM   7045  N   ILE D  62       9.727   3.566 -18.697  1.00 46.56           N  
+ATOM   7046  CA  ILE D  62      10.268   4.892 -18.438  1.00 44.50           C  
+ATOM   7047  C   ILE D  62      11.751   4.921 -18.765  1.00 42.89           C  
+ATOM   7048  O   ILE D  62      12.510   4.059 -18.333  1.00 42.09           O  
+ATOM   7049  CB  ILE D  62      10.087   5.293 -16.947  1.00 45.07           C  
+ATOM   7050  CG1 ILE D  62       8.601   5.299 -16.584  1.00 44.19           C  
+ATOM   7051  CG2 ILE D  62      10.700   6.670 -16.696  1.00 45.36           C  
+ATOM   7052  CD1 ILE D  62       8.323   5.624 -15.131  0.00 44.54           C  
+ATOM   7053  N   GLU D  63      12.160   5.920 -19.532  1.00 42.54           N  
+ATOM   7054  CA  GLU D  63      13.555   6.064 -19.907  1.00 43.85           C  
+ATOM   7055  C   GLU D  63      14.089   7.408 -19.439  1.00 42.21           C  
+ATOM   7056  O   GLU D  63      13.502   8.453 -19.713  1.00 41.93           O  
+ATOM   7057  CB  GLU D  63      13.711   5.934 -21.426  1.00 48.30           C  
+ATOM   7058  CG  GLU D  63      13.817   4.496 -21.921  1.00 52.76           C  
+ATOM   7059  CD  GLU D  63      13.830   4.399 -23.438  1.00 55.00           C  
+ATOM   7060  OE1 GLU D  63      14.560   5.177 -24.086  1.00 56.67           O  
+ATOM   7061  OE2 GLU D  63      13.113   3.536 -23.985  1.00 58.00           O  
+ATOM   7062  N   VAL D  64      15.209   7.367 -18.728  1.00 41.11           N  
+ATOM   7063  CA  VAL D  64      15.844   8.565 -18.206  1.00 40.46           C  
+ATOM   7064  C   VAL D  64      17.205   8.727 -18.869  1.00 39.46           C  
+ATOM   7065  O   VAL D  64      18.045   7.832 -18.796  1.00 40.44           O  
+ATOM   7066  CB  VAL D  64      16.014   8.462 -16.678  1.00 40.43           C  
+ATOM   7067  CG1 VAL D  64      16.613   9.751 -16.130  1.00 40.21           C  
+ATOM   7068  CG2 VAL D  64      14.658   8.179 -16.031  1.00 39.72           C  
+ATOM   7069  N   TYR D  65      17.428   9.871 -19.505  1.00 37.35           N  
+ATOM   7070  CA  TYR D  65      18.684  10.102 -20.209  1.00 37.87           C  
+ATOM   7071  C   TYR D  65      19.656  11.041 -19.515  1.00 38.33           C  
+ATOM   7072  O   TYR D  65      20.595  11.528 -20.133  1.00 37.54           O  
+ATOM   7073  CB  TYR D  65      18.392  10.620 -21.613  1.00 36.41           C  
+ATOM   7074  CG  TYR D  65      17.298   9.851 -22.317  1.00 35.22           C  
+ATOM   7075  CD1 TYR D  65      16.106  10.480 -22.685  1.00 35.21           C  
+ATOM   7076  CD2 TYR D  65      17.454   8.496 -22.621  1.00 34.08           C  
+ATOM   7077  CE1 TYR D  65      15.096   9.783 -23.342  1.00 36.86           C  
+ATOM   7078  CE2 TYR D  65      16.444   7.782 -23.281  1.00 36.09           C  
+ATOM   7079  CZ  TYR D  65      15.272   8.434 -23.638  1.00 37.96           C  
+ATOM   7080  OH  TYR D  65      14.277   7.749 -24.300  1.00 40.03           O  
+ATOM   7081  N   GLN D  66      19.429  11.293 -18.231  1.00 39.15           N  
+ATOM   7082  CA  GLN D  66      20.306  12.160 -17.460  1.00 38.53           C  
+ATOM   7083  C   GLN D  66      20.388  11.687 -16.013  1.00 37.98           C  
+ATOM   7084  O   GLN D  66      19.493  10.999 -15.529  1.00 37.85           O  
+ATOM   7085  CB  GLN D  66      19.790  13.591 -17.484  1.00 41.73           C  
+ATOM   7086  CG  GLN D  66      19.778  14.242 -18.850  1.00 46.11           C  
+ATOM   7087  CD  GLN D  66      19.446  15.716 -18.759  1.00 47.71           C  
+ATOM   7088  OE1 GLN D  66      18.369  16.091 -18.291  1.00 49.47           O  
+ATOM   7089  NE2 GLN D  66      20.374  16.564 -19.193  1.00 48.75           N  
+ATOM   7090  N   SER D  67      21.468  12.048 -15.328  1.00 35.36           N  
+ATOM   7091  CA  SER D  67      21.627  11.678 -13.928  1.00 35.95           C  
+ATOM   7092  C   SER D  67      20.508  12.373 -13.149  1.00 34.11           C  
+ATOM   7093  O   SER D  67      20.232  13.554 -13.366  1.00 33.83           O  
+ATOM   7094  CB  SER D  67      23.002  12.120 -13.414  1.00 33.97           C  
+ATOM   7095  OG  SER D  67      23.213  13.502 -13.667  1.00 41.70           O  
+ATOM   7096  N   ILE D  68      19.859  11.628 -12.262  1.00 34.89           N  
+ATOM   7097  CA  ILE D  68      18.750  12.142 -11.477  1.00 35.12           C  
+ATOM   7098  C   ILE D  68      19.112  12.498 -10.041  1.00 33.70           C  
+ATOM   7099  O   ILE D  68      19.908  11.825  -9.395  1.00 33.33           O  
+ATOM   7100  CB  ILE D  68      17.575  11.128 -11.445  1.00 39.56           C  
+ATOM   7101  CG1 ILE D  68      16.919  11.032 -12.824  1.00 41.54           C  
+ATOM   7102  CG2 ILE D  68      16.517  11.577 -10.439  1.00 42.97           C  
+ATOM   7103  CD1 ILE D  68      15.770  10.044 -12.891  0.00 40.74           C  
+ATOM   7104  N   GLY D  69      18.522  13.587  -9.568  1.00 33.25           N  
+ATOM   7105  CA  GLY D  69      18.725  14.052  -8.209  1.00 31.11           C  
+ATOM   7106  C   GLY D  69      17.321  14.165  -7.639  1.00 31.52           C  
+ATOM   7107  O   GLY D  69      16.378  14.472  -8.377  1.00 30.99           O  
+ATOM   7108  N   PHE D  70      17.151  13.911  -6.346  1.00 28.83           N  
+ATOM   7109  CA  PHE D  70      15.817  14.001  -5.773  1.00 26.03           C  
+ATOM   7110  C   PHE D  70      15.735  14.914  -4.561  1.00 24.61           C  
+ATOM   7111  O   PHE D  70      16.643  14.950  -3.725  1.00 22.80           O  
+ATOM   7112  CB  PHE D  70      15.302  12.598  -5.413  1.00 26.00           C  
+ATOM   7113  CG  PHE D  70      13.951  12.597  -4.729  1.00 28.31           C  
+ATOM   7114  CD1 PHE D  70      13.847  12.352  -3.360  1.00 23.49           C  
+ATOM   7115  CD2 PHE D  70      12.787  12.862  -5.451  1.00 26.44           C  
+ATOM   7116  CE1 PHE D  70      12.604  12.373  -2.724  1.00 26.48           C  
+ATOM   7117  CE2 PHE D  70      11.529  12.888  -4.817  1.00 24.48           C  
+ATOM   7118  CZ  PHE D  70      11.439  12.644  -3.456  1.00 22.82           C  
+ATOM   7119  N   VAL D  71      14.641  15.668  -4.482  1.00 23.54           N  
+ATOM   7120  CA  VAL D  71      14.414  16.557  -3.350  1.00 20.87           C  
+ATOM   7121  C   VAL D  71      13.083  16.234  -2.681  1.00 22.15           C  
+ATOM   7122  O   VAL D  71      12.026  16.513  -3.233  1.00 23.56           O  
+ATOM   7123  CB  VAL D  71      14.386  18.052  -3.769  1.00 21.16           C  
+ATOM   7124  CG1 VAL D  71      14.395  18.939  -2.506  1.00 15.36           C  
+ATOM   7125  CG2 VAL D  71      15.598  18.385  -4.658  1.00 16.07           C  
+ATOM   7126  N   PRO D  72      13.118  15.615  -1.491  1.00 23.14           N  
+ATOM   7127  CA  PRO D  72      11.885  15.270  -0.765  1.00 22.60           C  
+ATOM   7128  C   PRO D  72      11.273  16.537  -0.159  1.00 23.58           C  
+ATOM   7129  O   PRO D  72      11.944  17.559  -0.057  1.00 26.22           O  
+ATOM   7130  CB  PRO D  72      12.378  14.310   0.315  1.00 22.16           C  
+ATOM   7131  CG  PRO D  72      13.738  14.884   0.646  1.00 22.67           C  
+ATOM   7132  CD  PRO D  72      14.312  15.176  -0.741  1.00 22.05           C  
+ATOM   7133  N   GLN D  73      10.015  16.479   0.257  1.00 23.81           N  
+ATOM   7134  CA  GLN D  73       9.399  17.659   0.834  1.00 25.46           C  
+ATOM   7135  C   GLN D  73      10.014  18.000   2.184  1.00 26.94           C  
+ATOM   7136  O   GLN D  73      10.168  19.171   2.529  1.00 27.78           O  
+ATOM   7137  CB  GLN D  73       7.889  17.469   0.987  1.00 25.91           C  
+ATOM   7138  CG  GLN D  73       7.180  18.778   1.301  1.00 33.53           C  
+ATOM   7139  CD  GLN D  73       5.668  18.649   1.455  1.00 34.80           C  
+ATOM   7140  OE1 GLN D  73       4.981  19.638   1.720  1.00 37.86           O  
+ATOM   7141  NE2 GLN D  73       5.147  17.441   1.290  1.00 33.94           N  
+ATOM   7142  N   PHE D  74      10.380  16.970   2.938  1.00 27.63           N  
+ATOM   7143  CA  PHE D  74      10.962  17.152   4.258  1.00 29.08           C  
+ATOM   7144  C   PHE D  74      12.089  16.188   4.516  1.00 30.39           C  
+ATOM   7145  O   PHE D  74      12.224  15.171   3.839  1.00 31.08           O  
+ATOM   7146  CB  PHE D  74       9.917  16.898   5.354  1.00 27.11           C  
+ATOM   7147  CG  PHE D  74       8.701  17.751   5.241  1.00 29.19           C  
+ATOM   7148  CD1 PHE D  74       8.789  19.135   5.392  1.00 28.46           C  
+ATOM   7149  CD2 PHE D  74       7.461  17.175   4.967  1.00 27.29           C  
+ATOM   7150  CE1 PHE D  74       7.654  19.937   5.269  1.00 30.21           C  
+ATOM   7151  CE2 PHE D  74       6.321  17.965   4.843  1.00 28.90           C  
+ATOM   7152  CZ  PHE D  74       6.414  19.348   4.994  1.00 29.96           C  
+ATOM   7153  N   PHE D  75      12.881  16.527   5.523  1.00 31.17           N  
+ATOM   7154  CA  PHE D  75      13.965  15.686   5.987  1.00 35.16           C  
+ATOM   7155  C   PHE D  75      13.837  15.648   7.514  1.00 39.06           C  
+ATOM   7156  O   PHE D  75      14.089  16.656   8.192  1.00 41.83           O  
+ATOM   7157  CB  PHE D  75      15.334  16.254   5.644  1.00 32.29           C  
+ATOM   7158  CG  PHE D  75      16.444  15.516   6.318  1.00 30.93           C  
+ATOM   7159  CD1 PHE D  75      16.909  14.312   5.799  1.00 35.87           C  
+ATOM   7160  CD2 PHE D  75      16.952  15.960   7.530  1.00 30.68           C  
+ATOM   7161  CE1 PHE D  75      17.871  13.551   6.487  1.00 35.64           C  
+ATOM   7162  CE2 PHE D  75      17.911  15.214   8.230  1.00 29.82           C  
+ATOM   7163  CZ  PHE D  75      18.370  14.009   7.708  1.00 31.71           C  
+ATOM   7164  N   SER D  76      13.435  14.506   8.054  1.00 39.52           N  
+ATOM   7165  CA  SER D  76      13.292  14.367   9.504  1.00 43.49           C  
+ATOM   7166  C   SER D  76      14.311  13.408  10.091  1.00 43.11           C  
+ATOM   7167  O   SER D  76      14.464  12.279   9.627  1.00 44.61           O  
+ATOM   7168  CB  SER D  76      11.893  13.863   9.875  1.00 45.34           C  
+ATOM   7169  OG  SER D  76      10.898  14.817   9.553  1.00 53.56           O  
+ATOM   7170  N   SER D  77      15.007  13.866  11.119  1.00 43.48           N  
+ATOM   7171  CA  SER D  77      15.983  13.037  11.797  1.00 42.07           C  
+ATOM   7172  C   SER D  77      16.111  13.478  13.245  1.00 42.15           C  
+ATOM   7173  O   SER D  77      16.190  14.670  13.536  1.00 41.19           O  
+ATOM   7174  CB  SER D  77      17.346  13.144  11.123  1.00 43.34           C  
+ATOM   7175  OG  SER D  77      18.361  12.670  11.996  1.00 43.67           O  
+ATOM   7176  N   PRO D  78      16.097  12.520  14.179  1.00 42.04           N  
+ATOM   7177  CA  PRO D  78      16.232  12.902  15.587  1.00 41.45           C  
+ATOM   7178  C   PRO D  78      17.663  13.397  15.848  1.00 42.35           C  
+ATOM   7179  O   PRO D  78      17.956  13.981  16.902  1.00 40.18           O  
+ATOM   7180  CB  PRO D  78      15.907  11.605  16.328  1.00 41.96           C  
+ATOM   7181  CG  PRO D  78      16.278  10.524  15.320  1.00 41.59           C  
+ATOM   7182  CD  PRO D  78      15.742  11.096  14.044  1.00 40.01           C  
+ATOM   7183  N   PHE D  79      18.541  13.179  14.865  1.00 39.61           N  
+ATOM   7184  CA  PHE D  79      19.945  13.588  14.968  1.00 38.22           C  
+ATOM   7185  C   PHE D  79      20.175  14.998  14.440  1.00 35.61           C  
+ATOM   7186  O   PHE D  79      19.764  15.336  13.330  1.00 36.63           O  
+ATOM   7187  CB  PHE D  79      20.823  12.592  14.213  1.00 35.03           C  
+ATOM   7188  CG  PHE D  79      20.607  11.181  14.643  1.00 32.70           C  
+ATOM   7189  CD1 PHE D  79      20.427  10.170  13.703  1.00 31.46           C  
+ATOM   7190  CD2 PHE D  79      20.534  10.866  16.004  1.00 29.13           C  
+ATOM   7191  CE1 PHE D  79      20.169   8.856  14.117  1.00 32.51           C  
+ATOM   7192  CE2 PHE D  79      20.279   9.564  16.423  1.00 30.76           C  
+ATOM   7193  CZ  PHE D  79      20.094   8.558  15.482  1.00 32.69           C  
+ATOM   7194  N   ALA D  80      20.851  15.806  15.246  1.00 32.99           N  
+ATOM   7195  CA  ALA D  80      21.132  17.195  14.902  1.00 31.03           C  
+ATOM   7196  C   ALA D  80      22.253  17.379  13.878  1.00 27.68           C  
+ATOM   7197  O   ALA D  80      23.268  18.007  14.166  1.00 27.00           O  
+ATOM   7198  CB  ALA D  80      21.449  17.991  16.184  1.00 28.95           C  
+ATOM   7199  N   TYR D  81      22.070  16.828  12.685  1.00 26.35           N  
+ATOM   7200  CA  TYR D  81      23.059  16.981  11.634  1.00 26.59           C  
+ATOM   7201  C   TYR D  81      23.146  18.469  11.260  1.00 26.26           C  
+ATOM   7202  O   TYR D  81      22.158  19.210  11.346  1.00 25.80           O  
+ATOM   7203  CB  TYR D  81      22.651  16.195  10.379  1.00 28.99           C  
+ATOM   7204  CG  TYR D  81      22.753  14.687  10.469  1.00 29.57           C  
+ATOM   7205  CD1 TYR D  81      21.615  13.881  10.358  1.00 31.60           C  
+ATOM   7206  CD2 TYR D  81      23.990  14.058  10.627  1.00 29.89           C  
+ATOM   7207  CE1 TYR D  81      21.710  12.482  10.400  1.00 29.32           C  
+ATOM   7208  CE2 TYR D  81      24.093  12.658  10.672  1.00 31.18           C  
+ATOM   7209  CZ  TYR D  81      22.950  11.884  10.556  1.00 31.00           C  
+ATOM   7210  OH  TYR D  81      23.058  10.512  10.571  1.00 37.08           O  
+ATOM   7211  N   SER D  82      24.331  18.898  10.848  1.00 24.14           N  
+ATOM   7212  CA  SER D  82      24.546  20.280  10.411  1.00 23.41           C  
+ATOM   7213  C   SER D  82      24.145  20.406   8.934  1.00 22.34           C  
+ATOM   7214  O   SER D  82      23.986  19.402   8.220  1.00 21.73           O  
+ATOM   7215  CB  SER D  82      26.024  20.642  10.503  1.00 23.49           C  
+ATOM   7216  OG  SER D  82      26.732  19.970   9.462  1.00 25.93           O  
+ATOM   7217  N   VAL D  83      24.019  21.645   8.475  1.00 23.07           N  
+ATOM   7218  CA  VAL D  83      23.691  21.926   7.078  1.00 20.44           C  
+ATOM   7219  C   VAL D  83      24.708  21.232   6.170  1.00 20.89           C  
+ATOM   7220  O   VAL D  83      24.349  20.557   5.204  1.00 20.85           O  
+ATOM   7221  CB  VAL D  83      23.696  23.470   6.817  1.00 19.54           C  
+ATOM   7222  CG1 VAL D  83      23.734  23.772   5.325  1.00 12.82           C  
+ATOM   7223  CG2 VAL D  83      22.460  24.086   7.438  1.00 18.33           C  
+ATOM   7224  N   LEU D  84      25.988  21.389   6.484  1.00 24.20           N  
+ATOM   7225  CA  LEU D  84      27.025  20.755   5.683  1.00 24.95           C  
+ATOM   7226  C   LEU D  84      26.918  19.226   5.693  1.00 26.45           C  
+ATOM   7227  O   LEU D  84      27.131  18.598   4.660  1.00 28.17           O  
+ATOM   7228  CB  LEU D  84      28.404  21.179   6.178  1.00 28.24           C  
+ATOM   7229  CG  LEU D  84      29.538  20.637   5.308  1.00 32.79           C  
+ATOM   7230  CD1 LEU D  84      29.388  21.149   3.872  1.00 31.81           C  
+ATOM   7231  CD2 LEU D  84      30.870  21.069   5.900  1.00 34.64           C  
+ATOM   7232  N   ASP D  85      26.604  18.627   6.849  1.00 26.84           N  
+ATOM   7233  CA  ASP D  85      26.462  17.165   6.936  1.00 24.67           C  
+ATOM   7234  C   ASP D  85      25.404  16.721   5.927  1.00 24.35           C  
+ATOM   7235  O   ASP D  85      25.595  15.742   5.196  1.00 24.52           O  
+ATOM   7236  CB  ASP D  85      25.971  16.709   8.322  1.00 26.89           C  
+ATOM   7237  CG  ASP D  85      27.012  16.846   9.420  1.00 31.00           C  
+ATOM   7238  OD1 ASP D  85      26.593  17.045  10.593  1.00 31.29           O  
+ATOM   7239  OD2 ASP D  85      28.225  16.739   9.135  1.00 31.87           O  
+ATOM   7240  N   ILE D  86      24.272  17.428   5.918  1.00 20.80           N  
+ATOM   7241  CA  ILE D  86      23.171  17.107   5.015  1.00 21.96           C  
+ATOM   7242  C   ILE D  86      23.520  17.272   3.530  1.00 22.56           C  
+ATOM   7243  O   ILE D  86      23.240  16.385   2.723  1.00 20.36           O  
+ATOM   7244  CB  ILE D  86      21.909  17.954   5.353  1.00 25.24           C  
+ATOM   7245  CG1 ILE D  86      21.374  17.574   6.748  1.00 23.45           C  
+ATOM   7246  CG2 ILE D  86      20.829  17.729   4.297  1.00 21.36           C  
+ATOM   7247  CD1 ILE D  86      20.997  16.113   6.890  0.00 24.20           C  
+ATOM   7248  N   VAL D  87      24.136  18.397   3.169  1.00 23.36           N  
+ATOM   7249  CA  VAL D  87      24.515  18.637   1.771  1.00 23.75           C  
+ATOM   7250  C   VAL D  87      25.558  17.626   1.310  1.00 23.65           C  
+ATOM   7251  O   VAL D  87      25.515  17.146   0.167  1.00 23.29           O  
+ATOM   7252  CB  VAL D  87      25.101  20.063   1.568  1.00 25.23           C  
+ATOM   7253  CG1 VAL D  87      25.563  20.240   0.126  1.00 19.57           C  
+ATOM   7254  CG2 VAL D  87      24.054  21.108   1.927  1.00 23.46           C  
+ATOM   7255  N   LEU D  88      26.492  17.297   2.198  1.00 23.01           N  
+ATOM   7256  CA  LEU D  88      27.561  16.342   1.861  1.00 25.39           C  
+ATOM   7257  C   LEU D  88      27.043  14.938   1.516  1.00 26.12           C  
+ATOM   7258  O   LEU D  88      27.701  14.181   0.793  1.00 26.43           O  
+ATOM   7259  CB  LEU D  88      28.563  16.253   3.017  1.00 25.58           C  
+ATOM   7260  CG  LEU D  88      29.949  15.651   2.757  1.00 30.54           C  
+ATOM   7261  CD1 LEU D  88      30.730  16.489   1.723  1.00 24.91           C  
+ATOM   7262  CD2 LEU D  88      30.709  15.584   4.090  1.00 28.25           C  
+ATOM   7263  N   MET D  89      25.870  14.583   2.026  1.00 27.00           N  
+ATOM   7264  CA  MET D  89      25.315  13.265   1.734  1.00 28.75           C  
+ATOM   7265  C   MET D  89      25.075  13.152   0.241  1.00 27.44           C  
+ATOM   7266  O   MET D  89      25.021  12.047  -0.308  1.00 26.46           O  
+ATOM   7267  CB  MET D  89      24.008  13.033   2.510  1.00 30.46           C  
+ATOM   7268  CG  MET D  89      24.224  12.842   4.010  1.00 35.56           C  
+ATOM   7269  SD  MET D  89      22.711  12.557   4.969  1.00 43.77           S  
+ATOM   7270  CE  MET D  89      23.271  13.074   6.634  1.00 40.45           C  
+ATOM   7271  N   GLY D  90      24.940  14.301  -0.419  1.00 27.19           N  
+ATOM   7272  CA  GLY D  90      24.730  14.294  -1.859  1.00 26.56           C  
+ATOM   7273  C   GLY D  90      25.938  13.771  -2.628  1.00 27.70           C  
+ATOM   7274  O   GLY D  90      25.826  13.464  -3.815  1.00 29.22           O  
+ATOM   7275  N   ARG D  91      27.088  13.668  -1.954  1.00 27.61           N  
+ATOM   7276  CA  ARG D  91      28.332  13.176  -2.565  1.00 29.68           C  
+ATOM   7277  C   ARG D  91      28.390  11.660  -2.494  1.00 31.80           C  
+ATOM   7278  O   ARG D  91      29.384  11.045  -2.880  1.00 32.32           O  
+ATOM   7279  CB  ARG D  91      29.568  13.759  -1.851  1.00 25.65           C  
+ATOM   7280  CG  ARG D  91      29.689  15.276  -1.968  1.00 26.40           C  
+ATOM   7281  CD  ARG D  91      29.651  15.691  -3.440  1.00 28.51           C  
+ATOM   7282  NE  ARG D  91      30.853  15.278  -4.168  1.00 28.87           N  
+ATOM   7283  CZ  ARG D  91      30.993  15.348  -5.492  1.00 30.35           C  
+ATOM   7284  NH1 ARG D  91      32.127  14.962  -6.061  1.00 23.75           N  
+ATOM   7285  NH2 ARG D  91      29.996  15.787  -6.252  1.00 29.82           N  
+ATOM   7286  N   SER D  92      27.310  11.072  -1.999  1.00 31.61           N  
+ATOM   7287  CA  SER D  92      27.201   9.631  -1.846  1.00 34.02           C  
+ATOM   7288  C   SER D  92      27.770   8.768  -2.984  1.00 34.17           C  
+ATOM   7289  O   SER D  92      28.578   7.877  -2.736  1.00 33.73           O  
+ATOM   7290  CB  SER D  92      25.734   9.263  -1.611  1.00 34.54           C  
+ATOM   7291  OG  SER D  92      25.616   7.888  -1.312  1.00 40.60           O  
+ATOM   7292  N   THR D  93      27.348   9.015  -4.222  1.00 35.51           N  
+ATOM   7293  CA  THR D  93      27.823   8.214  -5.354  1.00 38.43           C  
+ATOM   7294  C   THR D  93      29.247   8.539  -5.812  1.00 38.06           C  
+ATOM   7295  O   THR D  93      29.763   7.901  -6.722  1.00 39.62           O  
+ATOM   7296  CB  THR D  93      26.899   8.358  -6.590  1.00 39.73           C  
+ATOM   7297  OG1 THR D  93      27.018   9.681  -7.119  1.00 42.24           O  
+ATOM   7298  CG2 THR D  93      25.442   8.110  -6.210  1.00 40.84           C  
+ATOM   7299  N   HIS D  94      29.881   9.525  -5.190  1.00 36.86           N  
+ATOM   7300  CA  HIS D  94      31.244   9.903  -5.560  1.00 35.84           C  
+ATOM   7301  C   HIS D  94      32.221   9.434  -4.498  1.00 35.16           C  
+ATOM   7302  O   HIS D  94      33.421   9.683  -4.587  1.00 35.12           O  
+ATOM   7303  CB  HIS D  94      31.342  11.423  -5.718  1.00 35.46           C  
+ATOM   7304  CG  HIS D  94      30.446  11.973  -6.784  1.00 38.82           C  
+ATOM   7305  ND1 HIS D  94      30.768  11.926  -8.124  1.00 41.18           N  
+ATOM   7306  CD2 HIS D  94      29.218  12.540  -6.712  1.00 38.71           C  
+ATOM   7307  CE1 HIS D  94      29.776  12.439  -8.831  1.00 41.59           C  
+ATOM   7308  NE2 HIS D  94      28.822  12.819  -7.999  1.00 41.31           N  
+ATOM   7309  N   ILE D  95      31.690   8.769  -3.479  1.00 35.25           N  
+ATOM   7310  CA  ILE D  95      32.498   8.261  -2.381  1.00 34.20           C  
+ATOM   7311  C   ILE D  95      32.258   6.758  -2.284  1.00 35.03           C  
+ATOM   7312  O   ILE D  95      31.121   6.315  -2.162  1.00 36.83           O  
+ATOM   7313  CB  ILE D  95      32.095   8.912  -1.034  1.00 33.45           C  
+ATOM   7314  CG1 ILE D  95      32.268  10.439  -1.095  1.00 33.13           C  
+ATOM   7315  CG2 ILE D  95      32.922   8.314   0.089  1.00 29.43           C  
+ATOM   7316  CD1 ILE D  95      31.792  11.160   0.148  0.00 33.22           C  
+ATOM   7317  N   ASN D  96      33.326   5.976  -2.342  1.00 35.19           N  
+ATOM   7318  CA  ASN D  96      33.206   4.527  -2.256  1.00 36.84           C  
+ATOM   7319  C   ASN D  96      32.627   4.076  -0.911  1.00 36.87           C  
+ATOM   7320  O   ASN D  96      32.828   4.725   0.114  1.00 35.79           O  
+ATOM   7321  CB  ASN D  96      34.580   3.895  -2.487  1.00 36.85           C  
+ATOM   7322  CG  ASN D  96      35.059   4.056  -3.932  1.00 43.28           C  
+ATOM   7323  OD1 ASN D  96      36.263   4.061  -4.204  1.00 42.79           O  
+ATOM   7324  ND2 ASN D  96      34.112   4.178  -4.864  1.00 40.46           N  
+ATOM   7325  N   THR D  97      31.917   2.954  -0.934  1.00 36.83           N  
+ATOM   7326  CA  THR D  97      31.291   2.384   0.248  1.00 38.36           C  
+ATOM   7327  C   THR D  97      32.097   2.475   1.542  1.00 39.27           C  
+ATOM   7328  O   THR D  97      31.568   2.895   2.570  1.00 40.33           O  
+ATOM   7329  CB  THR D  97      30.954   0.904   0.030  1.00 40.51           C  
+ATOM   7330  OG1 THR D  97      30.151   0.762  -1.146  1.00 43.72           O  
+ATOM   7331  CG2 THR D  97      30.180   0.359   1.226  1.00 40.40           C  
+ATOM   7332  N   PHE D  98      33.365   2.079   1.510  1.00 39.92           N  
+ATOM   7333  CA  PHE D  98      34.172   2.122   2.726  1.00 39.58           C  
+ATOM   7334  C   PHE D  98      35.140   3.281   2.802  1.00 39.15           C  
+ATOM   7335  O   PHE D  98      36.018   3.308   3.664  1.00 40.92           O  
+ATOM   7336  CB  PHE D  98      34.925   0.798   2.909  1.00 41.14           C  
+ATOM   7337  CG  PHE D  98      34.020  -0.399   2.942  1.00 42.05           C  
+ATOM   7338  CD1 PHE D  98      33.591  -0.993   1.758  1.00 42.25           C  
+ATOM   7339  CD2 PHE D  98      33.537  -0.887   4.154  1.00 42.30           C  
+ATOM   7340  CE1 PHE D  98      32.687  -2.058   1.777  1.00 44.51           C  
+ATOM   7341  CE2 PHE D  98      32.631  -1.950   4.188  1.00 43.60           C  
+ATOM   7342  CZ  PHE D  98      32.203  -2.537   2.998  1.00 43.88           C  
+ATOM   7343  N   ALA D  99      34.972   4.253   1.916  1.00 38.76           N  
+ATOM   7344  CA  ALA D  99      35.851   5.415   1.918  1.00 37.86           C  
+ATOM   7345  C   ALA D  99      35.196   6.605   2.610  1.00 36.60           C  
+ATOM   7346  O   ALA D  99      33.993   6.614   2.866  1.00 36.10           O  
+ATOM   7347  CB  ALA D  99      36.230   5.785   0.492  1.00 36.44           C  
+ATOM   7348  N   LYS D 100      36.003   7.613   2.897  1.00 35.73           N  
+ATOM   7349  CA  LYS D 100      35.542   8.830   3.548  1.00 36.07           C  
+ATOM   7350  C   LYS D 100      35.517   9.975   2.532  1.00 34.86           C  
+ATOM   7351  O   LYS D 100      36.189   9.913   1.507  1.00 33.51           O  
+ATOM   7352  CB  LYS D 100      36.499   9.195   4.678  1.00 35.98           C  
+ATOM   7353  CG  LYS D 100      36.584   8.166   5.780  1.00 39.36           C  
+ATOM   7354  CD  LYS D 100      35.256   8.025   6.509  1.00 40.91           C  
+ATOM   7355  CE  LYS D 100      35.452   7.478   7.924  1.00 43.63           C  
+ATOM   7356  NZ  LYS D 100      36.102   6.147   7.936  1.00 42.43           N  
+ATOM   7357  N   PRO D 101      34.723  11.025   2.788  1.00 34.03           N  
+ATOM   7358  CA  PRO D 101      34.727  12.116   1.804  1.00 34.38           C  
+ATOM   7359  C   PRO D 101      36.091  12.800   1.742  1.00 34.31           C  
+ATOM   7360  O   PRO D 101      36.760  12.956   2.766  1.00 34.83           O  
+ATOM   7361  CB  PRO D 101      33.622  13.056   2.305  1.00 32.69           C  
+ATOM   7362  CG  PRO D 101      33.464  12.702   3.759  1.00 36.50           C  
+ATOM   7363  CD  PRO D 101      33.650  11.207   3.780  1.00 32.65           C  
+ATOM   7364  N   LYS D 102      36.499  13.205   0.542  1.00 34.20           N  
+ATOM   7365  CA  LYS D 102      37.787  13.879   0.350  1.00 33.72           C  
+ATOM   7366  C   LYS D 102      37.577  15.381   0.188  1.00 33.78           C  
+ATOM   7367  O   LYS D 102      36.442  15.854   0.188  1.00 35.33           O  
+ATOM   7368  CB  LYS D 102      38.501  13.314  -0.885  1.00 36.30           C  
+ATOM   7369  CG  LYS D 102      38.709  11.799  -0.842  1.00 38.31           C  
+ATOM   7370  CD  LYS D 102      39.553  11.310  -2.019  1.00 45.44           C  
+ATOM   7371  CE  LYS D 102      39.553   9.778  -2.134  1.00 46.82           C  
+ATOM   7372  NZ  LYS D 102      40.016   9.100  -0.885  1.00 48.79           N  
+ATOM   7373  N   SER D 103      38.668  16.128   0.047  1.00 33.35           N  
+ATOM   7374  CA  SER D 103      38.598  17.586  -0.099  1.00 34.57           C  
+ATOM   7375  C   SER D 103      37.638  18.035  -1.188  1.00 32.57           C  
+ATOM   7376  O   SER D 103      36.839  18.954  -0.993  1.00 29.64           O  
+ATOM   7377  CB  SER D 103      39.985  18.167  -0.401  1.00 34.16           C  
+ATOM   7378  OG  SER D 103      40.786  18.131   0.764  1.00 42.32           O  
+ATOM   7379  N   HIS D 104      37.735  17.388  -2.340  1.00 29.97           N  
+ATOM   7380  CA  HIS D 104      36.874  17.734  -3.445  1.00 31.23           C  
+ATOM   7381  C   HIS D 104      35.399  17.663  -3.050  1.00 30.69           C  
+ATOM   7382  O   HIS D 104      34.615  18.516  -3.450  1.00 32.12           O  
+ATOM   7383  CB  HIS D 104      37.131  16.814  -4.637  1.00 29.88           C  
+ATOM   7384  CG  HIS D 104      36.455  17.277  -5.886  1.00 31.65           C  
+ATOM   7385  ND1 HIS D 104      35.635  16.463  -6.638  1.00 30.54           N  
+ATOM   7386  CD2 HIS D 104      36.434  18.491  -6.483  1.00 28.91           C  
+ATOM   7387  CE1 HIS D 104      35.135  17.158  -7.644  1.00 29.12           C  
+ATOM   7388  NE2 HIS D 104      35.603  18.390  -7.573  1.00 31.24           N  
+ATOM   7389  N   ASP D 105      35.027  16.653  -2.265  1.00 30.73           N  
+ATOM   7390  CA  ASP D 105      33.634  16.491  -1.835  1.00 29.12           C  
+ATOM   7391  C   ASP D 105      33.166  17.679  -1.002  1.00 28.24           C  
+ATOM   7392  O   ASP D 105      32.035  18.138  -1.155  1.00 28.77           O  
+ATOM   7393  CB  ASP D 105      33.463  15.187  -1.043  1.00 26.82           C  
+ATOM   7394  CG  ASP D 105      33.765  13.970  -1.874  1.00 26.65           C  
+ATOM   7395  OD1 ASP D 105      34.706  13.227  -1.528  1.00 30.46           O  
+ATOM   7396  OD2 ASP D 105      33.067  13.758  -2.883  1.00 26.24           O  
+ATOM   7397  N   TYR D 106      34.023  18.179  -0.119  1.00 26.64           N  
+ATOM   7398  CA  TYR D 106      33.644  19.334   0.684  1.00 28.03           C  
+ATOM   7399  C   TYR D 106      33.556  20.592  -0.190  1.00 29.58           C  
+ATOM   7400  O   TYR D 106      32.720  21.471   0.050  1.00 28.58           O  
+ATOM   7401  CB  TYR D 106      34.650  19.567   1.819  1.00 30.52           C  
+ATOM   7402  CG  TYR D 106      34.620  18.496   2.880  1.00 35.38           C  
+ATOM   7403  CD1 TYR D 106      35.379  17.335   2.741  1.00 37.60           C  
+ATOM   7404  CD2 TYR D 106      33.789  18.613   4.001  1.00 35.86           C  
+ATOM   7405  CE1 TYR D 106      35.318  16.318   3.684  1.00 39.03           C  
+ATOM   7406  CE2 TYR D 106      33.718  17.592   4.955  1.00 37.46           C  
+ATOM   7407  CZ  TYR D 106      34.490  16.451   4.786  1.00 39.75           C  
+ATOM   7408  OH  TYR D 106      34.468  15.441   5.725  1.00 44.22           O  
+ATOM   7409  N   GLN D 107      34.411  20.661  -1.211  1.00 27.94           N  
+ATOM   7410  CA  GLN D 107      34.447  21.804  -2.121  1.00 27.76           C  
+ATOM   7411  C   GLN D 107      33.173  21.915  -2.933  1.00 26.69           C  
+ATOM   7412  O   GLN D 107      32.626  23.007  -3.109  1.00 24.83           O  
+ATOM   7413  CB  GLN D 107      35.648  21.689  -3.069  1.00 27.64           C  
+ATOM   7414  CG  GLN D 107      36.993  21.798  -2.355  1.00 30.82           C  
+ATOM   7415  CD  GLN D 107      38.161  21.324  -3.206  1.00 31.49           C  
+ATOM   7416  OE1 GLN D 107      39.294  21.302  -2.747  1.00 35.90           O  
+ATOM   7417  NE2 GLN D 107      37.886  20.944  -4.446  1.00 31.10           N  
+ATOM   7418  N   VAL D 108      32.706  20.780  -3.439  1.00 25.59           N  
+ATOM   7419  CA  VAL D 108      31.492  20.777  -4.224  1.00 25.00           C  
+ATOM   7420  C   VAL D 108      30.284  21.104  -3.349  1.00 24.94           C  
+ATOM   7421  O   VAL D 108      29.422  21.878  -3.760  1.00 23.89           O  
+ATOM   7422  CB  VAL D 108      31.294  19.428  -4.921  1.00 26.22           C  
+ATOM   7423  CG1 VAL D 108      29.942  19.409  -5.648  1.00 24.81           C  
+ATOM   7424  CG2 VAL D 108      32.439  19.204  -5.918  1.00 26.07           C  
+ATOM   7425  N   ALA D 109      30.225  20.522  -2.150  1.00 22.76           N  
+ATOM   7426  CA  ALA D 109      29.118  20.792  -1.240  1.00 23.16           C  
+ATOM   7427  C   ALA D 109      29.121  22.288  -0.941  1.00 24.46           C  
+ATOM   7428  O   ALA D 109      28.076  22.936  -0.982  1.00 25.38           O  
+ATOM   7429  CB  ALA D 109      29.267  19.976   0.056  1.00 19.44           C  
+ATOM   7430  N   MET D 110      30.302  22.837  -0.657  1.00 25.63           N  
+ATOM   7431  CA  MET D 110      30.429  24.271  -0.381  1.00 26.52           C  
+ATOM   7432  C   MET D 110      30.020  25.085  -1.606  1.00 26.98           C  
+ATOM   7433  O   MET D 110      29.422  26.158  -1.480  1.00 26.01           O  
+ATOM   7434  CB  MET D 110      31.874  24.623  -0.006  1.00 30.06           C  
+ATOM   7435  CG  MET D 110      32.285  24.232   1.411  1.00 34.70           C  
+ATOM   7436  SD  MET D 110      31.506  25.269   2.665  1.00 44.37           S  
+ATOM   7437  CE  MET D 110      30.226  24.221   3.200  1.00 42.45           C  
+ATOM   7438  N   GLN D 111      30.339  24.569  -2.791  1.00 25.95           N  
+ATOM   7439  CA  GLN D 111      30.013  25.250  -4.040  1.00 28.39           C  
+ATOM   7440  C   GLN D 111      28.494  25.341  -4.214  1.00 27.32           C  
+ATOM   7441  O   GLN D 111      27.970  26.332  -4.724  1.00 28.59           O  
+ATOM   7442  CB  GLN D 111      30.631  24.495  -5.224  1.00 31.32           C  
+ATOM   7443  CG  GLN D 111      30.593  25.232  -6.556  1.00 40.94           C  
+ATOM   7444  CD  GLN D 111      31.059  24.356  -7.721  1.00 49.50           C  
+ATOM   7445  OE1 GLN D 111      31.912  23.476  -7.548  1.00 53.22           O  
+ATOM   7446  NE2 GLN D 111      30.510  24.603  -8.914  1.00 50.10           N  
+ATOM   7447  N   ALA D 112      27.790  24.297  -3.794  1.00 26.10           N  
+ATOM   7448  CA  ALA D 112      26.339  24.277  -3.891  1.00 25.14           C  
+ATOM   7449  C   ALA D 112      25.740  25.298  -2.907  1.00 26.25           C  
+ATOM   7450  O   ALA D 112      24.779  25.991  -3.236  1.00 27.94           O  
+ATOM   7451  CB  ALA D 112      25.811  22.867  -3.602  1.00 22.40           C  
+ATOM   7452  N   LEU D 113      26.307  25.397  -1.704  1.00 25.40           N  
+ATOM   7453  CA  LEU D 113      25.815  26.370  -0.729  1.00 25.67           C  
+ATOM   7454  C   LEU D 113      26.101  27.791  -1.235  1.00 27.08           C  
+ATOM   7455  O   LEU D 113      25.274  28.687  -1.067  1.00 25.05           O  
+ATOM   7456  CB  LEU D 113      26.476  26.160   0.641  1.00 21.80           C  
+ATOM   7457  CG  LEU D 113      26.090  24.867   1.383  1.00 25.31           C  
+ATOM   7458  CD1 LEU D 113      26.911  24.731   2.648  1.00 22.31           C  
+ATOM   7459  CD2 LEU D 113      24.605  24.877   1.712  1.00 21.47           C  
+ATOM   7460  N   ASP D 114      27.270  27.983  -1.855  1.00 27.82           N  
+ATOM   7461  CA  ASP D 114      27.663  29.287  -2.401  1.00 27.50           C  
+ATOM   7462  C   ASP D 114      26.637  29.735  -3.435  1.00 28.06           C  
+ATOM   7463  O   ASP D 114      26.172  30.871  -3.419  1.00 30.96           O  
+ATOM   7464  CB  ASP D 114      29.021  29.210  -3.105  1.00 26.88           C  
+ATOM   7465  CG  ASP D 114      30.190  29.043  -2.149  1.00 31.66           C  
+ATOM   7466  OD1 ASP D 114      31.240  28.540  -2.605  1.00 33.22           O  
+ATOM   7467  OD2 ASP D 114      30.084  29.419  -0.958  1.00 34.15           O  
+ATOM   7468  N   TYR D 115      26.293  28.826  -4.336  1.00 27.02           N  
+ATOM   7469  CA  TYR D 115      25.340  29.122  -5.393  1.00 28.54           C  
+ATOM   7470  C   TYR D 115      23.984  29.592  -4.862  1.00 27.64           C  
+ATOM   7471  O   TYR D 115      23.352  30.456  -5.463  1.00 28.15           O  
+ATOM   7472  CB  TYR D 115      25.181  27.895  -6.291  1.00 29.11           C  
+ATOM   7473  CG  TYR D 115      24.077  28.011  -7.294  1.00 31.86           C  
+ATOM   7474  CD1 TYR D 115      24.154  28.907  -8.359  1.00 34.64           C  
+ATOM   7475  CD2 TYR D 115      22.923  27.244  -7.157  1.00 33.89           C  
+ATOM   7476  CE1 TYR D 115      23.092  29.033  -9.265  1.00 33.92           C  
+ATOM   7477  CE2 TYR D 115      21.873  27.358  -8.038  1.00 32.06           C  
+ATOM   7478  CZ  TYR D 115      21.954  28.250  -9.086  1.00 33.54           C  
+ATOM   7479  OH  TYR D 115      20.874  28.354  -9.927  1.00 37.01           O  
+ATOM   7480  N   LEU D 116      23.539  29.030  -3.740  1.00 27.42           N  
+ATOM   7481  CA  LEU D 116      22.271  29.441  -3.147  1.00 26.04           C  
+ATOM   7482  C   LEU D 116      22.494  30.585  -2.152  1.00 27.48           C  
+ATOM   7483  O   LEU D 116      21.546  31.098  -1.570  1.00 24.65           O  
+ATOM   7484  CB  LEU D 116      21.618  28.264  -2.427  1.00 28.15           C  
+ATOM   7485  CG  LEU D 116      21.334  27.016  -3.267  1.00 30.49           C  
+ATOM   7486  CD1 LEU D 116      20.642  25.974  -2.411  1.00 30.77           C  
+ATOM   7487  CD2 LEU D 116      20.452  27.382  -4.456  1.00 29.16           C  
+ATOM   7488  N   ASN D 117      23.749  30.991  -1.969  1.00 27.29           N  
+ATOM   7489  CA  ASN D 117      24.080  32.060  -1.020  1.00 31.33           C  
+ATOM   7490  C   ASN D 117      23.685  31.649   0.406  1.00 29.16           C  
+ATOM   7491  O   ASN D 117      23.242  32.481   1.194  1.00 31.59           O  
+ATOM   7492  CB  ASN D 117      23.356  33.378  -1.389  1.00 32.94           C  
+ATOM   7493  CG  ASN D 117      23.612  33.820  -2.839  1.00 37.70           C  
+ATOM   7494  OD1 ASN D 117      22.692  34.254  -3.539  1.00 38.90           O  
+ATOM   7495  ND2 ASN D 117      24.860  33.724  -3.283  1.00 37.44           N  
+ATOM   7496  N   LEU D 118      23.850  30.369   0.739  1.00 29.76           N  
+ATOM   7497  CA  LEU D 118      23.501  29.868   2.072  1.00 29.93           C  
+ATOM   7498  C   LEU D 118      24.712  29.333   2.838  1.00 29.49           C  
+ATOM   7499  O   LEU D 118      24.575  28.695   3.887  1.00 29.37           O  
+ATOM   7500  CB  LEU D 118      22.427  28.775   1.959  1.00 30.78           C  
+ATOM   7501  CG  LEU D 118      21.096  29.204   1.313  1.00 30.96           C  
+ATOM   7502  CD1 LEU D 118      20.117  28.039   1.315  1.00 31.87           C  
+ATOM   7503  CD2 LEU D 118      20.508  30.368   2.075  1.00 29.35           C  
+ATOM   7504  N   THR D 119      25.898  29.596   2.301  1.00 28.67           N  
+ATOM   7505  CA  THR D 119      27.148  29.167   2.912  1.00 28.31           C  
+ATOM   7506  C   THR D 119      27.313  29.557   4.394  1.00 27.15           C  
+ATOM   7507  O   THR D 119      27.948  28.833   5.159  1.00 24.41           O  
+ATOM   7508  CB  THR D 119      28.336  29.726   2.114  1.00 30.88           C  
+ATOM   7509  OG1 THR D 119      28.211  29.325   0.742  1.00 35.50           O  
+ATOM   7510  CG2 THR D 119      29.653  29.204   2.668  1.00 31.37           C  
+ATOM   7511  N   HIS D 120      26.749  30.691   4.802  1.00 25.22           N  
+ATOM   7512  CA  HIS D 120      26.876  31.126   6.191  1.00 26.00           C  
+ATOM   7513  C   HIS D 120      26.150  30.202   7.179  1.00 25.82           C  
+ATOM   7514  O   HIS D 120      26.355  30.282   8.393  1.00 25.66           O  
+ATOM   7515  CB  HIS D 120      26.364  32.562   6.357  1.00 23.74           C  
+ATOM   7516  CG  HIS D 120      24.896  32.721   6.106  1.00 26.19           C  
+ATOM   7517  ND1 HIS D 120      24.352  32.751   4.839  1.00 29.05           N  
+ATOM   7518  CD2 HIS D 120      23.857  32.868   6.963  1.00 27.68           C  
+ATOM   7519  CE1 HIS D 120      23.042  32.914   4.925  1.00 26.56           C  
+ATOM   7520  NE2 HIS D 120      22.717  32.986   6.203  1.00 29.65           N  
+ATOM   7521  N   LEU D 121      25.311  29.325   6.645  1.00 25.44           N  
+ATOM   7522  CA  LEU D 121      24.541  28.379   7.445  1.00 27.13           C  
+ATOM   7523  C   LEU D 121      25.239  27.023   7.573  1.00 26.95           C  
+ATOM   7524  O   LEU D 121      24.737  26.132   8.267  1.00 30.09           O  
+ATOM   7525  CB  LEU D 121      23.177  28.146   6.785  1.00 25.88           C  
+ATOM   7526  CG  LEU D 121      21.900  28.962   7.046  1.00 30.51           C  
+ATOM   7527  CD1 LEU D 121      22.160  30.269   7.776  1.00 28.36           C  
+ATOM   7528  CD2 LEU D 121      21.223  29.189   5.709  1.00 26.46           C  
+ATOM   7529  N   ALA D 122      26.387  26.869   6.918  1.00 24.38           N  
+ATOM   7530  CA  ALA D 122      27.108  25.593   6.894  1.00 26.88           C  
+ATOM   7531  C   ALA D 122      27.270  24.830   8.213  1.00 28.52           C  
+ATOM   7532  O   ALA D 122      27.127  23.604   8.244  1.00 29.13           O  
+ATOM   7533  CB  ALA D 122      28.481  25.780   6.231  1.00 25.32           C  
+ATOM   7534  N   LYS D 123      27.566  25.537   9.297  1.00 30.00           N  
+ATOM   7535  CA  LYS D 123      27.751  24.869  10.578  1.00 32.59           C  
+ATOM   7536  C   LYS D 123      26.498  24.843  11.443  1.00 32.34           C  
+ATOM   7537  O   LYS D 123      26.524  24.330  12.558  1.00 33.11           O  
+ATOM   7538  CB  LYS D 123      28.910  25.520  11.347  1.00 34.79           C  
+ATOM   7539  CG  LYS D 123      30.284  25.290  10.719  1.00 37.47           C  
+ATOM   7540  CD  LYS D 123      30.664  23.820  10.770  1.00 43.83           C  
+ATOM   7541  CE  LYS D 123      32.078  23.552  10.235  1.00 47.27           C  
+ATOM   7542  NZ  LYS D 123      32.147  23.544   8.746  1.00 47.74           N  
+ATOM   7543  N   ARG D 124      25.402  25.388  10.932  1.00 30.93           N  
+ATOM   7544  CA  ARG D 124      24.150  25.401  11.686  1.00 31.04           C  
+ATOM   7545  C   ARG D 124      23.477  24.032  11.728  1.00 31.14           C  
+ATOM   7546  O   ARG D 124      23.669  23.190  10.842  1.00 28.61           O  
+ATOM   7547  CB  ARG D 124      23.171  26.401  11.067  1.00 32.30           C  
+ATOM   7548  CG  ARG D 124      23.574  27.848  11.247  1.00 38.33           C  
+ATOM   7549  CD  ARG D 124      22.769  28.491  12.343  1.00 42.89           C  
+ATOM   7550  NE  ARG D 124      21.938  29.553  11.783  1.00 51.59           N  
+ATOM   7551  CZ  ARG D 124      20.619  29.632  11.913  1.00 51.21           C  
+ATOM   7552  NH1 ARG D 124      19.972  30.643  11.352  1.00 56.27           N  
+ATOM   7553  NH2 ARG D 124      19.948  28.713  12.600  1.00 50.06           N  
+ATOM   7554  N   GLU D 125      22.689  23.809  12.771  1.00 31.13           N  
+ATOM   7555  CA  GLU D 125      21.948  22.564  12.880  1.00 31.90           C  
+ATOM   7556  C   GLU D 125      20.759  22.723  11.942  1.00 28.06           C  
+ATOM   7557  O   GLU D 125      20.000  23.681  12.038  1.00 25.48           O  
+ATOM   7558  CB  GLU D 125      21.470  22.329  14.320  1.00 34.23           C  
+ATOM   7559  CG  GLU D 125      22.368  21.387  15.116  1.00 45.01           C  
+ATOM   7560  CD  GLU D 125      22.171  21.508  16.625  1.00 49.09           C  
+ATOM   7561  OE1 GLU D 125      21.003  21.559  17.075  1.00 52.87           O  
+ATOM   7562  OE2 GLU D 125      23.186  21.541  17.356  1.00 48.89           O  
+ATOM   7563  N   PHE D 126      20.625  21.780  11.025  1.00 25.70           N  
+ATOM   7564  CA  PHE D 126      19.551  21.792  10.059  1.00 25.84           C  
+ATOM   7565  C   PHE D 126      18.167  22.058  10.670  1.00 28.04           C  
+ATOM   7566  O   PHE D 126      17.390  22.843  10.115  1.00 25.97           O  
+ATOM   7567  CB  PHE D 126      19.544  20.465   9.319  1.00 23.27           C  
+ATOM   7568  CG  PHE D 126      18.474  20.354   8.283  1.00 26.88           C  
+ATOM   7569  CD1 PHE D 126      18.656  20.904   7.012  1.00 21.91           C  
+ATOM   7570  CD2 PHE D 126      17.300  19.652   8.554  1.00 24.77           C  
+ATOM   7571  CE1 PHE D 126      17.695  20.746   6.022  1.00 23.83           C  
+ATOM   7572  CE2 PHE D 126      16.321  19.490   7.562  1.00 27.00           C  
+ATOM   7573  CZ  PHE D 126      16.521  20.034   6.294  1.00 25.17           C  
+ATOM   7574  N   THR D 127      17.853  21.419  11.798  1.00 28.64           N  
+ATOM   7575  CA  THR D 127      16.542  21.617  12.424  1.00 33.88           C  
+ATOM   7576  C   THR D 127      16.300  23.020  12.998  1.00 35.35           C  
+ATOM   7577  O   THR D 127      15.166  23.374  13.310  1.00 37.28           O  
+ATOM   7578  CB  THR D 127      16.254  20.556  13.541  1.00 34.76           C  
+ATOM   7579  OG1 THR D 127      17.361  20.478  14.447  1.00 38.33           O  
+ATOM   7580  CG2 THR D 127      16.025  19.190  12.923  1.00 33.46           C  
+ATOM   7581  N   SER D 128      17.347  23.829  13.125  1.00 34.59           N  
+ATOM   7582  CA  SER D 128      17.171  25.182  13.652  1.00 34.62           C  
+ATOM   7583  C   SER D 128      16.820  26.169  12.536  1.00 35.06           C  
+ATOM   7584  O   SER D 128      16.615  27.356  12.792  1.00 36.28           O  
+ATOM   7585  CB  SER D 128      18.449  25.668  14.345  1.00 34.63           C  
+ATOM   7586  OG  SER D 128      19.412  26.090  13.390  1.00 36.29           O  
+ATOM   7587  N   LEU D 129      16.769  25.684  11.300  1.00 31.75           N  
+ATOM   7588  CA  LEU D 129      16.451  26.540  10.160  1.00 31.04           C  
+ATOM   7589  C   LEU D 129      14.945  26.656   9.921  1.00 30.03           C  
+ATOM   7590  O   LEU D 129      14.162  25.848  10.399  1.00 28.29           O  
+ATOM   7591  CB  LEU D 129      17.097  25.980   8.884  1.00 32.09           C  
+ATOM   7592  CG  LEU D 129      18.545  26.294   8.479  1.00 36.11           C  
+ATOM   7593  CD1 LEU D 129      19.468  26.343   9.675  1.00 33.58           C  
+ATOM   7594  CD2 LEU D 129      19.002  25.238   7.478  1.00 35.39           C  
+ATOM   7595  N   SER D 130      14.556  27.666   9.157  1.00 29.17           N  
+ATOM   7596  CA  SER D 130      13.159  27.865   8.809  1.00 26.64           C  
+ATOM   7597  C   SER D 130      12.832  26.803   7.758  1.00 27.39           C  
+ATOM   7598  O   SER D 130      13.734  26.165   7.203  1.00 26.96           O  
+ATOM   7599  CB  SER D 130      12.967  29.246   8.186  1.00 27.00           C  
+ATOM   7600  OG  SER D 130      13.578  29.294   6.898  1.00 29.60           O  
+ATOM   7601  N   GLY D 131      11.544  26.622   7.482  1.00 26.90           N  
+ATOM   7602  CA  GLY D 131      11.124  25.658   6.482  1.00 25.28           C  
+ATOM   7603  C   GLY D 131      11.702  25.996   5.114  1.00 25.32           C  
+ATOM   7604  O   GLY D 131      12.077  25.096   4.360  1.00 24.94           O  
+ATOM   7605  N   GLY D 132      11.785  27.292   4.806  1.00 24.23           N  
+ATOM   7606  CA  GLY D 132      12.322  27.733   3.529  1.00 22.88           C  
+ATOM   7607  C   GLY D 132      13.789  27.374   3.363  1.00 23.47           C  
+ATOM   7608  O   GLY D 132      14.200  26.876   2.324  1.00 24.71           O  
+ATOM   7609  N   GLN D 133      14.580  27.625   4.399  1.00 24.94           N  
+ATOM   7610  CA  GLN D 133      16.001  27.315   4.365  1.00 25.50           C  
+ATOM   7611  C   GLN D 133      16.228  25.813   4.278  1.00 26.07           C  
+ATOM   7612  O   GLN D 133      17.107  25.356   3.536  1.00 25.16           O  
+ATOM   7613  CB  GLN D 133      16.697  27.888   5.603  1.00 23.92           C  
+ATOM   7614  CG  GLN D 133      16.660  29.417   5.665  1.00 24.32           C  
+ATOM   7615  CD  GLN D 133      17.187  29.965   6.987  1.00 28.19           C  
+ATOM   7616  OE1 GLN D 133      16.829  29.478   8.067  1.00 27.46           O  
+ATOM   7617  NE2 GLN D 133      18.033  30.991   6.908  1.00 28.13           N  
+ATOM   7618  N   ARG D 134      15.430  25.049   5.026  1.00 25.87           N  
+ATOM   7619  CA  ARG D 134      15.554  23.601   5.019  1.00 27.27           C  
+ATOM   7620  C   ARG D 134      15.289  23.052   3.620  1.00 27.48           C  
+ATOM   7621  O   ARG D 134      16.013  22.176   3.145  1.00 28.97           O  
+ATOM   7622  CB  ARG D 134      14.594  22.978   6.036  1.00 25.98           C  
+ATOM   7623  CG  ARG D 134      15.030  23.225   7.468  1.00 30.96           C  
+ATOM   7624  CD  ARG D 134      13.972  22.858   8.497  1.00 31.73           C  
+ATOM   7625  NE  ARG D 134      13.844  21.418   8.670  1.00 42.45           N  
+ATOM   7626  CZ  ARG D 134      13.340  20.842   9.761  1.00 45.96           C  
+ATOM   7627  NH1 ARG D 134      13.255  19.518   9.842  1.00 46.07           N  
+ATOM   7628  NH2 ARG D 134      12.932  21.593  10.779  1.00 45.53           N  
+ATOM   7629  N   GLN D 135      14.259  23.574   2.959  1.00 25.02           N  
+ATOM   7630  CA  GLN D 135      13.928  23.132   1.609  1.00 24.25           C  
+ATOM   7631  C   GLN D 135      15.074  23.471   0.645  1.00 23.72           C  
+ATOM   7632  O   GLN D 135      15.439  22.651  -0.195  1.00 23.65           O  
+ATOM   7633  CB  GLN D 135      12.617  23.787   1.147  1.00 24.90           C  
+ATOM   7634  CG  GLN D 135      12.193  23.468  -0.291  1.00 28.30           C  
+ATOM   7635  CD  GLN D 135      12.187  21.980  -0.602  1.00 29.93           C  
+ATOM   7636  OE1 GLN D 135      11.744  21.157   0.199  1.00 33.66           O  
+ATOM   7637  NE2 GLN D 135      12.669  21.632  -1.777  1.00 29.19           N  
+ATOM   7638  N   LEU D 136      15.636  24.675   0.773  1.00 22.77           N  
+ATOM   7639  CA  LEU D 136      16.747  25.099  -0.079  1.00 23.44           C  
+ATOM   7640  C   LEU D 136      17.984  24.221   0.165  1.00 22.60           C  
+ATOM   7641  O   LEU D 136      18.694  23.857  -0.770  1.00 22.56           O  
+ATOM   7642  CB  LEU D 136      17.089  26.577   0.179  1.00 22.35           C  
+ATOM   7643  CG  LEU D 136      15.990  27.575  -0.222  1.00 24.18           C  
+ATOM   7644  CD1 LEU D 136      16.277  28.943   0.383  1.00 22.28           C  
+ATOM   7645  CD2 LEU D 136      15.894  27.663  -1.738  1.00 22.11           C  
+ATOM   7646  N   ILE D 137      18.237  23.870   1.421  1.00 22.77           N  
+ATOM   7647  CA  ILE D 137      19.378  23.023   1.725  1.00 21.58           C  
+ATOM   7648  C   ILE D 137      19.198  21.640   1.088  1.00 21.95           C  
+ATOM   7649  O   ILE D 137      20.170  21.048   0.616  1.00 21.65           O  
+ATOM   7650  CB  ILE D 137      19.602  22.916   3.266  1.00 24.70           C  
+ATOM   7651  CG1 ILE D 137      20.092  24.281   3.803  1.00 21.28           C  
+ATOM   7652  CG2 ILE D 137      20.596  21.783   3.599  1.00 16.03           C  
+ATOM   7653  CD1 ILE D 137      21.366  24.782   3.151  0.00 22.62           C  
+ATOM   7654  N   LEU D 138      17.964  21.137   1.034  1.00 20.80           N  
+ATOM   7655  CA  LEU D 138      17.738  19.822   0.421  1.00 23.69           C  
+ATOM   7656  C   LEU D 138      17.930  19.905  -1.097  1.00 22.69           C  
+ATOM   7657  O   LEU D 138      18.267  18.913  -1.734  1.00 22.87           O  
+ATOM   7658  CB  LEU D 138      16.340  19.266   0.768  1.00 22.41           C  
+ATOM   7659  CG  LEU D 138      16.112  19.008   2.269  1.00 26.72           C  
+ATOM   7660  CD1 LEU D 138      14.717  18.434   2.513  1.00 23.46           C  
+ATOM   7661  CD2 LEU D 138      17.186  18.047   2.796  1.00 24.88           C  
+ATOM   7662  N   ILE D 139      17.721  21.089  -1.674  1.00 22.62           N  
+ATOM   7663  CA  ILE D 139      17.941  21.267  -3.105  1.00 21.91           C  
+ATOM   7664  C   ILE D 139      19.465  21.286  -3.312  1.00 22.05           C  
+ATOM   7665  O   ILE D 139      19.983  20.700  -4.263  1.00 22.11           O  
+ATOM   7666  CB  ILE D 139      17.332  22.591  -3.630  1.00 22.92           C  
+ATOM   7667  CG1 ILE D 139      15.797  22.514  -3.611  1.00 24.47           C  
+ATOM   7668  CG2 ILE D 139      17.832  22.872  -5.047  1.00 21.06           C  
+ATOM   7669  CD1 ILE D 139      15.109  23.788  -4.061  0.00 23.99           C  
+ATOM   7670  N   ALA D 140      20.176  21.953  -2.407  1.00 19.89           N  
+ATOM   7671  CA  ALA D 140      21.633  22.021  -2.479  1.00 22.83           C  
+ATOM   7672  C   ALA D 140      22.226  20.613  -2.416  1.00 22.85           C  
+ATOM   7673  O   ALA D 140      23.212  20.325  -3.081  1.00 24.95           O  
+ATOM   7674  CB  ALA D 140      22.188  22.876  -1.335  1.00 22.27           C  
+ATOM   7675  N   ARG D 141      21.623  19.744  -1.612  1.00 22.52           N  
+ATOM   7676  CA  ARG D 141      22.088  18.367  -1.498  1.00 23.36           C  
+ATOM   7677  C   ARG D 141      21.980  17.677  -2.866  1.00 24.28           C  
+ATOM   7678  O   ARG D 141      22.882  16.944  -3.258  1.00 23.05           O  
+ATOM   7679  CB  ARG D 141      21.256  17.598  -0.460  1.00 22.22           C  
+ATOM   7680  CG  ARG D 141      21.714  16.163  -0.263  1.00 25.24           C  
+ATOM   7681  CD  ARG D 141      20.908  15.438   0.809  1.00 22.61           C  
+ATOM   7682  NE  ARG D 141      19.520  15.243   0.409  1.00 24.41           N  
+ATOM   7683  CZ  ARG D 141      18.592  14.676   1.172  1.00 24.18           C  
+ATOM   7684  NH1 ARG D 141      17.355  14.540   0.719  1.00 24.39           N  
+ATOM   7685  NH2 ARG D 141      18.898  14.253   2.389  1.00 25.97           N  
+ATOM   7686  N   ALA D 142      20.871  17.894  -3.577  1.00 21.69           N  
+ATOM   7687  CA  ALA D 142      20.705  17.305  -4.916  1.00 24.08           C  
+ATOM   7688  C   ALA D 142      21.732  17.908  -5.870  1.00 23.45           C  
+ATOM   7689  O   ALA D 142      22.297  17.211  -6.706  1.00 26.45           O  
+ATOM   7690  CB  ALA D 142      19.289  17.563  -5.466  1.00 16.24           C  
+ATOM   7691  N   ILE D 143      21.959  19.211  -5.749  1.00 25.14           N  
+ATOM   7692  CA  ILE D 143      22.925  19.893  -6.601  1.00 26.20           C  
+ATOM   7693  C   ILE D 143      24.342  19.348  -6.360  1.00 26.74           C  
+ATOM   7694  O   ILE D 143      25.105  19.132  -7.302  1.00 25.69           O  
+ATOM   7695  CB  ILE D 143      22.914  21.417  -6.347  1.00 26.64           C  
+ATOM   7696  CG1 ILE D 143      21.616  22.033  -6.890  1.00 28.44           C  
+ATOM   7697  CG2 ILE D 143      24.130  22.062  -6.993  1.00 28.48           C  
+ATOM   7698  CD1 ILE D 143      21.490  23.523  -6.642  0.00 27.81           C  
+ATOM   7699  N   ALA D 144      24.690  19.121  -5.098  1.00 25.96           N  
+ATOM   7700  CA  ALA D 144      26.014  18.605  -4.776  1.00 26.35           C  
+ATOM   7701  C   ALA D 144      26.242  17.226  -5.396  1.00 27.41           C  
+ATOM   7702  O   ALA D 144      27.388  16.820  -5.597  1.00 28.84           O  
+ATOM   7703  CB  ALA D 144      26.205  18.548  -3.253  1.00 24.81           C  
+ATOM   7704  N   SER D 145      25.164  16.504  -5.706  1.00 27.41           N  
+ATOM   7705  CA  SER D 145      25.306  15.182  -6.315  1.00 30.49           C  
+ATOM   7706  C   SER D 145      25.644  15.291  -7.806  1.00 31.59           C  
+ATOM   7707  O   SER D 145      26.001  14.300  -8.442  1.00 32.83           O  
+ATOM   7708  CB  SER D 145      24.028  14.364  -6.155  1.00 29.79           C  
+ATOM   7709  OG  SER D 145      23.052  14.772  -7.095  1.00 32.38           O  
+ATOM   7710  N   GLU D 146      25.510  16.495  -8.352  1.00 31.57           N  
+ATOM   7711  CA  GLU D 146      25.815  16.771  -9.749  1.00 35.29           C  
+ATOM   7712  C   GLU D 146      24.807  16.233 -10.759  1.00 36.40           C  
+ATOM   7713  O   GLU D 146      25.154  15.992 -11.912  1.00 38.07           O  
+ATOM   7714  CB  GLU D 146      27.220  16.256 -10.103  1.00 38.22           C  
+ATOM   7715  CG  GLU D 146      28.359  17.004  -9.406  1.00 42.68           C  
+ATOM   7716  CD  GLU D 146      29.728  16.369  -9.646  1.00 46.72           C  
+ATOM   7717  OE1 GLU D 146      30.730  16.875  -9.100  1.00 50.14           O  
+ATOM   7718  OE2 GLU D 146      29.812  15.361 -10.379  1.00 52.61           O  
+ATOM   7719  N   CYS D 147      23.559  16.065 -10.340  1.00 36.36           N  
+ATOM   7720  CA  CYS D 147      22.516  15.578 -11.239  1.00 36.72           C  
+ATOM   7721  C   CYS D 147      22.167  16.664 -12.269  1.00 35.82           C  
+ATOM   7722  O   CYS D 147      22.411  17.849 -12.038  1.00 35.31           O  
+ATOM   7723  CB  CYS D 147      21.263  15.230 -10.440  1.00 37.89           C  
+ATOM   7724  SG  CYS D 147      20.467  16.690  -9.707  1.00 42.60           S  
+ATOM   7725  N   LYS D 148      21.595  16.257 -13.400  1.00 35.65           N  
+ATOM   7726  CA  LYS D 148      21.204  17.201 -14.448  1.00 36.67           C  
+ATOM   7727  C   LYS D 148      19.680  17.259 -14.540  1.00 35.12           C  
+ATOM   7728  O   LYS D 148      19.109  18.199 -15.079  1.00 35.02           O  
+ATOM   7729  CB  LYS D 148      21.790  16.774 -15.793  1.00 42.32           C  
+ATOM   7730  CG  LYS D 148      23.274  17.049 -15.961  1.00 45.36           C  
+ATOM   7731  CD  LYS D 148      23.530  18.502 -16.323  1.00 51.93           C  
+ATOM   7732  CE  LYS D 148      24.948  18.689 -16.860  1.00 57.90           C  
+ATOM   7733  NZ  LYS D 148      25.165  20.052 -17.442  1.00 60.75           N  
+ATOM   7734  N   LEU D 149      19.035  16.225 -14.017  1.00 35.27           N  
+ATOM   7735  CA  LEU D 149      17.580  16.138 -13.988  1.00 34.26           C  
+ATOM   7736  C   LEU D 149      17.215  16.101 -12.509  1.00 33.55           C  
+ATOM   7737  O   LEU D 149      17.554  15.142 -11.798  1.00 33.50           O  
+ATOM   7738  CB  LEU D 149      17.099  14.861 -14.674  1.00 32.11           C  
+ATOM   7739  CG  LEU D 149      15.652  14.438 -14.405  1.00 35.23           C  
+ATOM   7740  CD1 LEU D 149      14.687  15.453 -14.993  1.00 36.65           C  
+ATOM   7741  CD2 LEU D 149      15.403  13.066 -15.012  1.00 32.09           C  
+ATOM   7742  N   ILE D 150      16.538  17.147 -12.043  1.00 30.37           N  
+ATOM   7743  CA  ILE D 150      16.159  17.224 -10.638  1.00 28.52           C  
+ATOM   7744  C   ILE D 150      14.646  17.053 -10.443  1.00 27.61           C  
+ATOM   7745  O   ILE D 150      13.840  17.720 -11.094  1.00 28.97           O  
+ATOM   7746  CB  ILE D 150      16.679  18.574 -10.014  1.00 26.88           C  
+ATOM   7747  CG1 ILE D 150      16.379  18.627  -8.507  1.00 28.24           C  
+ATOM   7748  CG2 ILE D 150      16.090  19.756 -10.751  1.00 23.32           C  
+ATOM   7749  CD1 ILE D 150      16.892  19.877  -7.820  0.00 27.69           C  
+ATOM   7750  N   LEU D 151      14.276  16.118  -9.569  1.00 27.49           N  
+ATOM   7751  CA  LEU D 151      12.876  15.831  -9.256  1.00 28.31           C  
+ATOM   7752  C   LEU D 151      12.575  16.351  -7.855  1.00 27.70           C  
+ATOM   7753  O   LEU D 151      13.264  16.000  -6.895  1.00 26.10           O  
+ATOM   7754  CB  LEU D 151      12.608  14.322  -9.300  1.00 31.91           C  
+ATOM   7755  CG  LEU D 151      12.371  13.635 -10.651  1.00 35.68           C  
+ATOM   7756  CD1 LEU D 151      13.326  14.165 -11.693  1.00 34.69           C  
+ATOM   7757  CD2 LEU D 151      12.532  12.124 -10.485  1.00 31.73           C  
+ATOM   7758  N   LEU D 152      11.544  17.186  -7.748  1.00 27.35           N  
+ATOM   7759  CA  LEU D 152      11.170  17.772  -6.469  1.00 26.38           C  
+ATOM   7760  C   LEU D 152       9.727  17.473  -6.082  1.00 26.43           C  
+ATOM   7761  O   LEU D 152       8.795  17.738  -6.847  1.00 28.92           O  
+ATOM   7762  CB  LEU D 152      11.380  19.287  -6.498  1.00 22.48           C  
+ATOM   7763  CG  LEU D 152      12.780  19.800  -6.852  1.00 23.37           C  
+ATOM   7764  CD1 LEU D 152      12.845  20.099  -8.347  1.00 19.30           C  
+ATOM   7765  CD2 LEU D 152      13.090  21.073  -6.039  1.00 19.16           C  
+ATOM   7766  N   ASP D 153       9.563  16.925  -4.885  1.00 25.79           N  
+ATOM   7767  CA  ASP D 153       8.254  16.579  -4.345  1.00 28.07           C  
+ATOM   7768  C   ASP D 153       7.671  17.741  -3.527  1.00 28.72           C  
+ATOM   7769  O   ASP D 153       8.172  18.041  -2.442  1.00 24.98           O  
+ATOM   7770  CB  ASP D 153       8.394  15.360  -3.441  1.00 30.27           C  
+ATOM   7771  CG  ASP D 153       7.085  14.963  -2.790  1.00 37.97           C  
+ATOM   7772  OD1 ASP D 153       7.133  14.466  -1.646  1.00 42.61           O  
+ATOM   7773  OD2 ASP D 153       6.013  15.132  -3.418  1.00 42.59           O  
+ATOM   7774  N   GLU D 154       6.628  18.386  -4.053  1.00 27.89           N  
+ATOM   7775  CA  GLU D 154       5.956  19.510  -3.377  1.00 29.17           C  
+ATOM   7776  C   GLU D 154       6.939  20.486  -2.726  1.00 29.79           C  
+ATOM   7777  O   GLU D 154       6.855  20.745  -1.526  1.00 30.85           O  
+ATOM   7778  CB  GLU D 154       5.009  18.983  -2.300  1.00 27.91           C  
+ATOM   7779  CG  GLU D 154       3.970  18.006  -2.807  1.00 34.07           C  
+ATOM   7780  CD  GLU D 154       2.918  18.668  -3.683  1.00 40.96           C  
+ATOM   7781  OE1 GLU D 154       2.608  18.104  -4.754  1.00 45.95           O  
+ATOM   7782  OE2 GLU D 154       2.393  19.743  -3.303  1.00 40.78           O  
+ATOM   7783  N   PRO D 155       7.865  21.058  -3.515  1.00 28.45           N  
+ATOM   7784  CA  PRO D 155       8.858  21.998  -2.985  1.00 27.31           C  
+ATOM   7785  C   PRO D 155       8.364  23.308  -2.370  1.00 28.77           C  
+ATOM   7786  O   PRO D 155       9.081  23.929  -1.585  1.00 31.33           O  
+ATOM   7787  CB  PRO D 155       9.784  22.231  -4.181  1.00 27.58           C  
+ATOM   7788  CG  PRO D 155       8.855  22.055  -5.375  1.00 26.60           C  
+ATOM   7789  CD  PRO D 155       8.054  20.841  -4.964  1.00 25.58           C  
+ATOM   7790  N   THR D 156       7.152  23.731  -2.703  1.00 29.40           N  
+ATOM   7791  CA  THR D 156       6.635  24.993  -2.172  1.00 27.72           C  
+ATOM   7792  C   THR D 156       5.443  24.877  -1.221  1.00 28.01           C  
+ATOM   7793  O   THR D 156       5.109  25.836  -0.527  1.00 29.50           O  
+ATOM   7794  CB  THR D 156       6.181  25.922  -3.316  1.00 28.64           C  
+ATOM   7795  OG1 THR D 156       5.066  25.321  -3.988  1.00 23.75           O  
+ATOM   7796  CG2 THR D 156       7.312  26.154  -4.318  1.00 26.81           C  
+ATOM   7797  N   SER D 157       4.814  23.712  -1.186  1.00 28.52           N  
+ATOM   7798  CA  SER D 157       3.607  23.496  -0.383  1.00 33.34           C  
+ATOM   7799  C   SER D 157       3.585  23.943   1.070  1.00 33.32           C  
+ATOM   7800  O   SER D 157       2.618  24.571   1.504  1.00 35.24           O  
+ATOM   7801  CB  SER D 157       3.188  22.023  -0.447  1.00 34.20           C  
+ATOM   7802  OG  SER D 157       3.024  21.616  -1.795  1.00 41.06           O  
+ATOM   7803  N   ALA D 158       4.636  23.637   1.819  1.00 30.13           N  
+ATOM   7804  CA  ALA D 158       4.670  23.992   3.229  1.00 29.90           C  
+ATOM   7805  C   ALA D 158       5.432  25.281   3.566  1.00 30.29           C  
+ATOM   7806  O   ALA D 158       5.576  25.628   4.737  1.00 33.12           O  
+ATOM   7807  CB  ALA D 158       5.251  22.821   4.019  1.00 26.28           C  
+ATOM   7808  N   LEU D 159       5.905  25.997   2.554  1.00 29.01           N  
+ATOM   7809  CA  LEU D 159       6.679  27.216   2.793  1.00 27.97           C  
+ATOM   7810  C   LEU D 159       5.810  28.463   2.824  1.00 26.31           C  
+ATOM   7811  O   LEU D 159       4.711  28.462   2.292  1.00 26.13           O  
+ATOM   7812  CB  LEU D 159       7.743  27.393   1.695  1.00 25.03           C  
+ATOM   7813  CG  LEU D 159       8.574  26.187   1.224  1.00 27.71           C  
+ATOM   7814  CD1 LEU D 159       9.692  26.682   0.289  1.00 24.18           C  
+ATOM   7815  CD2 LEU D 159       9.166  25.452   2.410  1.00 22.35           C  
+ATOM   7816  N   ASP D 160       6.276  29.527   3.466  1.00 27.27           N  
+ATOM   7817  CA  ASP D 160       5.482  30.740   3.411  1.00 30.88           C  
+ATOM   7818  C   ASP D 160       5.744  31.319   2.020  1.00 29.62           C  
+ATOM   7819  O   ASP D 160       6.714  30.940   1.355  1.00 28.24           O  
+ATOM   7820  CB  ASP D 160       5.852  31.738   4.508  1.00 37.88           C  
+ATOM   7821  CG  ASP D 160       7.305  32.050   4.547  1.00 43.78           C  
+ATOM   7822  OD1 ASP D 160       7.929  32.164   3.471  1.00 49.93           O  
+ATOM   7823  OD2 ASP D 160       7.821  32.195   5.673  1.00 50.36           O  
+ATOM   7824  N   LEU D 161       4.864  32.209   1.576  1.00 29.21           N  
+ATOM   7825  CA  LEU D 161       4.948  32.801   0.250  1.00 26.31           C  
+ATOM   7826  C   LEU D 161       6.297  33.352  -0.189  1.00 26.69           C  
+ATOM   7827  O   LEU D 161       6.738  33.084  -1.309  1.00 25.76           O  
+ATOM   7828  CB  LEU D 161       3.875  33.879   0.098  1.00 28.96           C  
+ATOM   7829  CG  LEU D 161       2.452  33.373  -0.150  1.00 31.93           C  
+ATOM   7830  CD1 LEU D 161       1.501  34.559  -0.268  1.00 34.38           C  
+ATOM   7831  CD2 LEU D 161       2.418  32.559  -1.437  1.00 35.91           C  
+ATOM   7832  N   ALA D 162       6.956  34.116   0.672  1.00 24.22           N  
+ATOM   7833  CA  ALA D 162       8.247  34.686   0.308  1.00 26.79           C  
+ATOM   7834  C   ALA D 162       9.276  33.601   0.006  1.00 26.53           C  
+ATOM   7835  O   ALA D 162      10.140  33.777  -0.855  1.00 25.16           O  
+ATOM   7836  CB  ALA D 162       8.760  35.607   1.424  1.00 26.87           C  
+ATOM   7837  N   ASN D 163       9.197  32.483   0.719  1.00 26.71           N  
+ATOM   7838  CA  ASN D 163      10.145  31.401   0.480  1.00 27.18           C  
+ATOM   7839  C   ASN D 163       9.737  30.612  -0.753  1.00 25.68           C  
+ATOM   7840  O   ASN D 163      10.595  30.104  -1.475  1.00 23.95           O  
+ATOM   7841  CB  ASN D 163      10.260  30.506   1.717  1.00 28.22           C  
+ATOM   7842  CG  ASN D 163      11.137  31.135   2.793  1.00 31.49           C  
+ATOM   7843  OD1 ASN D 163      10.977  30.875   3.985  1.00 36.55           O  
+ATOM   7844  ND2 ASN D 163      12.076  31.963   2.367  1.00 27.55           N  
+ATOM   7845  N   GLN D 164       8.431  30.524  -0.998  1.00 23.61           N  
+ATOM   7846  CA  GLN D 164       7.932  29.839  -2.186  1.00 26.04           C  
+ATOM   7847  C   GLN D 164       8.494  30.613  -3.387  1.00 25.24           C  
+ATOM   7848  O   GLN D 164       8.975  30.031  -4.359  1.00 25.43           O  
+ATOM   7849  CB  GLN D 164       6.398  29.856  -2.218  1.00 26.04           C  
+ATOM   7850  CG  GLN D 164       5.723  28.874  -1.256  1.00 29.47           C  
+ATOM   7851  CD  GLN D 164       4.203  29.002  -1.231  1.00 29.83           C  
+ATOM   7852  OE1 GLN D 164       3.564  29.077  -2.267  1.00 33.65           O  
+ATOM   7853  NE2 GLN D 164       3.626  29.021  -0.037  1.00 31.61           N  
+ATOM   7854  N   ASP D 165       8.448  31.937  -3.292  1.00 26.01           N  
+ATOM   7855  CA  ASP D 165       8.955  32.812  -4.341  1.00 25.64           C  
+ATOM   7856  C   ASP D 165      10.437  32.504  -4.614  1.00 24.83           C  
+ATOM   7857  O   ASP D 165      10.847  32.367  -5.766  1.00 23.57           O  
+ATOM   7858  CB  ASP D 165       8.772  34.274  -3.912  1.00 24.38           C  
+ATOM   7859  CG  ASP D 165       9.218  35.261  -4.972  1.00 28.47           C  
+ATOM   7860  OD1 ASP D 165      10.047  36.135  -4.634  1.00 28.85           O  
+ATOM   7861  OD2 ASP D 165       8.742  35.175  -6.130  1.00 24.51           O  
+ATOM   7862  N   ILE D 166      11.232  32.375  -3.555  1.00 24.98           N  
+ATOM   7863  CA  ILE D 166      12.660  32.080  -3.706  1.00 24.72           C  
+ATOM   7864  C   ILE D 166      12.896  30.733  -4.400  1.00 23.14           C  
+ATOM   7865  O   ILE D 166      13.792  30.603  -5.240  1.00 23.50           O  
+ATOM   7866  CB  ILE D 166      13.383  32.104  -2.327  1.00 27.52           C  
+ATOM   7867  CG1 ILE D 166      13.450  33.554  -1.809  1.00 26.93           C  
+ATOM   7868  CG2 ILE D 166      14.808  31.506  -2.443  1.00 25.48           C  
+ATOM   7869  CD1 ILE D 166      14.097  33.693  -0.446  0.00 27.00           C  
+ATOM   7870  N   VAL D 167      12.081  29.741  -4.063  1.00 23.41           N  
+ATOM   7871  CA  VAL D 167      12.205  28.425  -4.664  1.00 23.77           C  
+ATOM   7872  C   VAL D 167      11.852  28.466  -6.152  1.00 24.28           C  
+ATOM   7873  O   VAL D 167      12.564  27.886  -6.977  1.00 23.80           O  
+ATOM   7874  CB  VAL D 167      11.292  27.389  -3.937  1.00 25.72           C  
+ATOM   7875  CG1 VAL D 167      11.277  26.060  -4.708  1.00 22.62           C  
+ATOM   7876  CG2 VAL D 167      11.813  27.150  -2.524  1.00 24.70           C  
+ATOM   7877  N   LEU D 168      10.762  29.156  -6.491  1.00 22.92           N  
+ATOM   7878  CA  LEU D 168      10.331  29.267  -7.884  1.00 23.40           C  
+ATOM   7879  C   LEU D 168      11.404  29.930  -8.746  1.00 23.99           C  
+ATOM   7880  O   LEU D 168      11.721  29.446  -9.840  1.00 21.10           O  
+ATOM   7881  CB  LEU D 168       9.006  30.048  -7.982  1.00 22.81           C  
+ATOM   7882  CG  LEU D 168       7.761  29.385  -7.345  1.00 22.55           C  
+ATOM   7883  CD1 LEU D 168       6.566  30.326  -7.438  1.00 21.52           C  
+ATOM   7884  CD2 LEU D 168       7.443  28.064  -8.046  1.00 20.09           C  
+ATOM   7885  N   SER D 169      11.973  31.025  -8.251  1.00 24.63           N  
+ATOM   7886  CA  SER D 169      13.020  31.726  -8.991  1.00 28.78           C  
+ATOM   7887  C   SER D 169      14.266  30.844  -9.142  1.00 30.28           C  
+ATOM   7888  O   SER D 169      14.964  30.920 -10.150  1.00 31.40           O  
+ATOM   7889  CB  SER D 169      13.393  33.038  -8.283  1.00 27.21           C  
+ATOM   7890  OG  SER D 169      12.278  33.914  -8.226  1.00 28.27           O  
+ATOM   7891  N   LEU D 170      14.534  30.004  -8.143  1.00 29.38           N  
+ATOM   7892  CA  LEU D 170      15.697  29.124  -8.187  1.00 28.45           C  
+ATOM   7893  C   LEU D 170      15.529  28.026  -9.234  1.00 27.83           C  
+ATOM   7894  O   LEU D 170      16.453  27.736  -9.990  1.00 25.84           O  
+ATOM   7895  CB  LEU D 170      15.943  28.491  -6.806  1.00 25.79           C  
+ATOM   7896  CG  LEU D 170      16.984  27.365  -6.713  1.00 26.66           C  
+ATOM   7897  CD1 LEU D 170      18.361  27.869  -7.144  1.00 25.68           C  
+ATOM   7898  CD2 LEU D 170      17.042  26.841  -5.284  1.00 25.36           C  
+ATOM   7899  N   LEU D 171      14.345  27.422  -9.278  1.00 27.86           N  
+ATOM   7900  CA  LEU D 171      14.078  26.345 -10.225  1.00 29.19           C  
+ATOM   7901  C   LEU D 171      14.217  26.813 -11.671  1.00 30.64           C  
+ATOM   7902  O   LEU D 171      14.815  26.127 -12.503  1.00 29.39           O  
+ATOM   7903  CB  LEU D 171      12.684  25.746  -9.979  1.00 25.27           C  
+ATOM   7904  CG  LEU D 171      12.532  25.051  -8.620  1.00 25.13           C  
+ATOM   7905  CD1 LEU D 171      11.148  24.420  -8.488  1.00 20.85           C  
+ATOM   7906  CD2 LEU D 171      13.612  23.994  -8.477  1.00 20.85           C  
+ATOM   7907  N   ILE D 172      13.678  27.989 -11.967  1.00 31.98           N  
+ATOM   7908  CA  ILE D 172      13.769  28.516 -13.315  1.00 33.03           C  
+ATOM   7909  C   ILE D 172      15.251  28.812 -13.616  1.00 34.19           C  
+ATOM   7910  O   ILE D 172      15.729  28.582 -14.732  1.00 34.93           O  
+ATOM   7911  CB  ILE D 172      12.862  29.778 -13.467  1.00 34.68           C  
+ATOM   7912  CG1 ILE D 172      12.201  29.781 -14.855  1.00 36.25           C  
+ATOM   7913  CG2 ILE D 172      13.665  31.037 -13.239  1.00 37.64           C  
+ATOM   7914  CD1 ILE D 172      11.248  30.938 -15.081  0.00 35.49           C  
+ATOM   7915  N   ASP D 173      15.989  29.279 -12.613  1.00 33.08           N  
+ATOM   7916  CA  ASP D 173      17.412  29.559 -12.799  1.00 34.39           C  
+ATOM   7917  C   ASP D 173      18.214  28.277 -13.047  1.00 33.17           C  
+ATOM   7918  O   ASP D 173      19.164  28.281 -13.820  1.00 31.59           O  
+ATOM   7919  CB  ASP D 173      17.980  30.288 -11.582  1.00 37.67           C  
+ATOM   7920  CG  ASP D 173      19.413  30.753 -11.793  1.00 47.01           C  
+ATOM   7921  OD1 ASP D 173      20.327  29.906 -11.789  1.00 49.70           O  
+ATOM   7922  OD2 ASP D 173      19.633  31.974 -11.971  1.00 53.37           O  
+ATOM   7923  N   LEU D 174      17.837  27.183 -12.393  1.00 32.75           N  
+ATOM   7924  CA  LEU D 174      18.545  25.916 -12.587  1.00 33.93           C  
+ATOM   7925  C   LEU D 174      18.377  25.453 -14.035  1.00 33.47           C  
+ATOM   7926  O   LEU D 174      19.329  24.985 -14.666  1.00 31.62           O  
+ATOM   7927  CB  LEU D 174      18.007  24.831 -11.630  1.00 31.59           C  
+ATOM   7928  CG  LEU D 174      18.300  24.995 -10.129  1.00 33.86           C  
+ATOM   7929  CD1 LEU D 174      17.670  23.858  -9.322  1.00 32.29           C  
+ATOM   7930  CD2 LEU D 174      19.813  25.017  -9.916  1.00 30.76           C  
+ATOM   7931  N   ALA D 175      17.160  25.588 -14.552  1.00 33.15           N  
+ATOM   7932  CA  ALA D 175      16.862  25.176 -15.917  1.00 36.84           C  
+ATOM   7933  C   ALA D 175      17.441  26.130 -16.956  1.00 37.85           C  
+ATOM   7934  O   ALA D 175      18.069  25.695 -17.911  1.00 39.68           O  
+ATOM   7935  CB  ALA D 175      15.347  25.051 -16.114  1.00 33.02           C  
+ATOM   7936  N   GLN D 176      17.247  27.427 -16.755  1.00 40.87           N  
+ATOM   7937  CA  GLN D 176      17.721  28.426 -17.708  1.00 44.84           C  
+ATOM   7938  C   GLN D 176      19.213  28.715 -17.766  1.00 45.79           C  
+ATOM   7939  O   GLN D 176      19.707  29.123 -18.816  1.00 47.68           O  
+ATOM   7940  CB  GLN D 176      16.953  29.745 -17.515  1.00 46.17           C  
+ATOM   7941  CG  GLN D 176      15.482  29.627 -17.923  1.00 50.00           C  
+ATOM   7942  CD  GLN D 176      14.717  30.946 -17.893  1.00 52.55           C  
+ATOM   7943  OE1 GLN D 176      13.558  31.008 -18.326  1.00 53.46           O  
+ATOM   7944  NE2 GLN D 176      15.350  32.003 -17.381  1.00 52.25           N  
+ATOM   7945  N   SER D 177      19.946  28.510 -16.675  1.00 46.15           N  
+ATOM   7946  CA  SER D 177      21.376  28.798 -16.720  1.00 46.20           C  
+ATOM   7947  C   SER D 177      22.296  27.715 -16.181  1.00 46.40           C  
+ATOM   7948  O   SER D 177      23.516  27.854 -16.246  1.00 47.02           O  
+ATOM   7949  CB  SER D 177      21.678  30.117 -16.001  1.00 46.32           C  
+ATOM   7950  OG  SER D 177      21.556  29.984 -14.600  1.00 49.06           O  
+ATOM   7951  N   GLN D 178      21.733  26.634 -15.654  1.00 47.79           N  
+ATOM   7952  CA  GLN D 178      22.573  25.564 -15.131  1.00 48.60           C  
+ATOM   7953  C   GLN D 178      22.378  24.272 -15.914  1.00 48.87           C  
+ATOM   7954  O   GLN D 178      22.827  23.204 -15.497  1.00 50.67           O  
+ATOM   7955  CB  GLN D 178      22.290  25.347 -13.643  1.00 49.78           C  
+ATOM   7956  CG  GLN D 178      22.476  26.609 -12.817  1.00 53.26           C  
+ATOM   7957  CD  GLN D 178      23.901  27.150 -12.871  1.00 56.71           C  
+ATOM   7958  OE1 GLN D 178      24.119  28.362 -12.797  1.00 57.26           O  
+ATOM   7959  NE2 GLN D 178      24.877  26.251 -12.986  1.00 57.39           N  
+ATOM   7960  N   ASN D 179      21.702  24.383 -17.052  1.00 49.48           N  
+ATOM   7961  CA  ASN D 179      21.459  23.245 -17.932  1.00 50.80           C  
+ATOM   7962  C   ASN D 179      20.770  22.059 -17.279  1.00 48.44           C  
+ATOM   7963  O   ASN D 179      21.106  20.908 -17.560  1.00 49.92           O  
+ATOM   7964  CB  ASN D 179      22.782  22.781 -18.549  1.00 55.61           C  
+ATOM   7965  CG  ASN D 179      23.431  23.857 -19.393  1.00 60.39           C  
+ATOM   7966  OD1 ASN D 179      22.866  24.296 -20.400  1.00 63.58           O  
+ATOM   7967  ND2 ASN D 179      24.617  24.301 -18.981  1.00 61.03           N  
+ATOM   7968  N   MET D 180      19.802  22.332 -16.415  1.00 44.55           N  
+ATOM   7969  CA  MET D 180      19.091  21.254 -15.754  1.00 38.61           C  
+ATOM   7970  C   MET D 180      17.670  21.113 -16.256  1.00 34.80           C  
+ATOM   7971  O   MET D 180      17.105  22.036 -16.842  1.00 34.09           O  
+ATOM   7972  CB  MET D 180      19.062  21.476 -14.242  1.00 40.42           C  
+ATOM   7973  CG  MET D 180      20.352  21.120 -13.549  1.00 45.01           C  
+ATOM   7974  SD  MET D 180      20.210  21.203 -11.766  1.00 46.90           S  
+ATOM   7975  CE  MET D 180      21.254  22.537 -11.442  1.00 48.10           C  
+ATOM   7976  N   THR D 181      17.109  19.934 -16.034  1.00 29.56           N  
+ATOM   7977  CA  THR D 181      15.736  19.658 -16.402  1.00 29.56           C  
+ATOM   7978  C   THR D 181      15.041  19.528 -15.051  1.00 28.62           C  
+ATOM   7979  O   THR D 181      15.570  18.897 -14.131  1.00 29.82           O  
+ATOM   7980  CB  THR D 181      15.635  18.363 -17.203  1.00 28.89           C  
+ATOM   7981  OG1 THR D 181      16.370  18.525 -18.423  1.00 31.26           O  
+ATOM   7982  CG2 THR D 181      14.175  18.030 -17.517  1.00 24.98           C  
+ATOM   7983  N   VAL D 182      13.869  20.135 -14.928  1.00 28.18           N  
+ATOM   7984  CA  VAL D 182      13.152  20.136 -13.662  1.00 27.98           C  
+ATOM   7985  C   VAL D 182      11.775  19.518 -13.687  1.00 29.13           C  
+ATOM   7986  O   VAL D 182      10.961  19.837 -14.551  1.00 32.05           O  
+ATOM   7987  CB  VAL D 182      12.966  21.587 -13.136  1.00 27.41           C  
+ATOM   7988  CG1 VAL D 182      12.246  21.564 -11.792  1.00 25.17           C  
+ATOM   7989  CG2 VAL D 182      14.318  22.301 -13.027  1.00 25.52           C  
+ATOM   7990  N   VAL D 183      11.520  18.629 -12.732  1.00 28.28           N  
+ATOM   7991  CA  VAL D 183      10.199  18.040 -12.588  1.00 26.18           C  
+ATOM   7992  C   VAL D 183       9.789  18.249 -11.133  1.00 26.09           C  
+ATOM   7993  O   VAL D 183      10.519  17.860 -10.207  1.00 25.26           O  
+ATOM   7994  CB  VAL D 183      10.162  16.537 -12.891  1.00 26.89           C  
+ATOM   7995  CG1 VAL D 183       8.712  16.055 -12.810  1.00 26.61           C  
+ATOM   7996  CG2 VAL D 183      10.740  16.250 -14.283  1.00 22.47           C  
+ATOM   7997  N   PHE D 184       8.644  18.897 -10.926  1.00 25.33           N  
+ATOM   7998  CA  PHE D 184       8.155  19.127  -9.569  1.00 25.81           C  
+ATOM   7999  C   PHE D 184       6.642  18.950  -9.459  1.00 26.39           C  
+ATOM   8000  O   PHE D 184       5.892  19.264 -10.393  1.00 24.51           O  
+ATOM   8001  CB  PHE D 184       8.571  20.514  -9.061  1.00 24.87           C  
+ATOM   8002  CG  PHE D 184       7.778  21.651  -9.637  1.00 28.23           C  
+ATOM   8003  CD1 PHE D 184       7.968  22.062 -10.954  1.00 26.88           C  
+ATOM   8004  CD2 PHE D 184       6.859  22.338  -8.845  1.00 29.77           C  
+ATOM   8005  CE1 PHE D 184       7.258  23.145 -11.477  1.00 33.99           C  
+ATOM   8006  CE2 PHE D 184       6.139  23.427  -9.356  1.00 33.84           C  
+ATOM   8007  CZ  PHE D 184       6.337  23.834 -10.674  1.00 32.57           C  
+ATOM   8008  N   THR D 185       6.201  18.407  -8.326  1.00 26.55           N  
+ATOM   8009  CA  THR D 185       4.777  18.203  -8.096  1.00 25.30           C  
+ATOM   8010  C   THR D 185       4.238  19.431  -7.364  1.00 27.97           C  
+ATOM   8011  O   THR D 185       4.972  20.110  -6.631  1.00 26.57           O  
+ATOM   8012  CB  THR D 185       4.502  16.920  -7.273  1.00 26.16           C  
+ATOM   8013  OG1 THR D 185       5.240  16.952  -6.047  1.00 26.79           O  
+ATOM   8014  CG2 THR D 185       4.904  15.688  -8.067  1.00 25.55           C  
+ATOM   8015  N   THR D 186       2.959  19.723  -7.579  1.00 28.17           N  
+ATOM   8016  CA  THR D 186       2.335  20.891  -6.980  1.00 27.82           C  
+ATOM   8017  C   THR D 186       0.827  20.840  -7.130  1.00 28.89           C  
+ATOM   8018  O   THR D 186       0.288  20.078  -7.940  1.00 28.95           O  
+ATOM   8019  CB  THR D 186       2.830  22.175  -7.673  1.00 29.86           C  
+ATOM   8020  OG1 THR D 186       2.083  23.304  -7.206  1.00 33.43           O  
+ATOM   8021  CG2 THR D 186       2.664  22.061  -9.182  1.00 27.82           C  
+ATOM   8022  N   HIS D 187       0.139  21.645  -6.337  1.00 27.18           N  
+ATOM   8023  CA  HIS D 187      -1.306  21.711  -6.452  1.00 30.92           C  
+ATOM   8024  C   HIS D 187      -1.674  23.167  -6.733  1.00 27.44           C  
+ATOM   8025  O   HIS D 187      -2.838  23.534  -6.698  1.00 30.00           O  
+ATOM   8026  CB  HIS D 187      -2.000  21.219  -5.165  1.00 31.87           C  
+ATOM   8027  CG  HIS D 187      -1.646  22.004  -3.940  1.00 37.04           C  
+ATOM   8028  ND1 HIS D 187      -0.604  21.656  -3.106  1.00 39.27           N  
+ATOM   8029  CD2 HIS D 187      -2.176  23.140  -3.426  1.00 37.28           C  
+ATOM   8030  CE1 HIS D 187      -0.505  22.545  -2.134  1.00 39.10           C  
+ATOM   8031  NE2 HIS D 187      -1.448  23.455  -2.305  1.00 41.44           N  
+ATOM   8032  N   GLN D 188      -0.675  23.989  -7.036  1.00 26.52           N  
+ATOM   8033  CA  GLN D 188      -0.927  25.403  -7.274  1.00 27.26           C  
+ATOM   8034  C   GLN D 188      -0.760  25.827  -8.734  1.00 27.66           C  
+ATOM   8035  O   GLN D 188       0.350  26.084  -9.203  1.00 23.92           O  
+ATOM   8036  CB  GLN D 188      -0.022  26.231  -6.356  1.00 30.10           C  
+ATOM   8037  CG  GLN D 188      -0.073  25.755  -4.896  1.00 34.42           C  
+ATOM   8038  CD  GLN D 188       0.845  26.539  -3.978  1.00 40.19           C  
+ATOM   8039  OE1 GLN D 188       1.756  25.976  -3.353  1.00 39.98           O  
+ATOM   8040  NE2 GLN D 188       0.614  27.850  -3.890  1.00 43.58           N  
+ATOM   8041  N   PRO D 189      -1.884  25.920  -9.466  1.00 27.89           N  
+ATOM   8042  CA  PRO D 189      -1.855  26.311 -10.879  1.00 27.89           C  
+ATOM   8043  C   PRO D 189      -1.109  27.595 -11.198  1.00 28.01           C  
+ATOM   8044  O   PRO D 189      -0.473  27.696 -12.248  1.00 28.48           O  
+ATOM   8045  CB  PRO D 189      -3.341  26.375 -11.268  1.00 27.90           C  
+ATOM   8046  CG  PRO D 189      -4.078  26.461  -9.947  1.00 30.97           C  
+ATOM   8047  CD  PRO D 189      -3.257  25.602  -9.030  1.00 26.07           C  
+ATOM   8048  N   ASN D 190      -1.170  28.574 -10.304  1.00 26.27           N  
+ATOM   8049  CA  ASN D 190      -0.487  29.832 -10.568  1.00 26.83           C  
+ATOM   8050  C   ASN D 190       1.039  29.690 -10.503  1.00 27.38           C  
+ATOM   8051  O   ASN D 190       1.772  30.518 -11.048  1.00 25.03           O  
+ATOM   8052  CB  ASN D 190      -0.986  30.919  -9.609  1.00 25.78           C  
+ATOM   8053  CG  ASN D 190      -2.465  31.223  -9.806  1.00 29.29           C  
+ATOM   8054  OD1 ASN D 190      -2.950  31.297 -10.942  1.00 32.32           O  
+ATOM   8055  ND2 ASN D 190      -3.187  31.403  -8.709  1.00 27.61           N  
+ATOM   8056  N   GLN D 191       1.512  28.642  -9.839  1.00 25.42           N  
+ATOM   8057  CA  GLN D 191       2.946  28.407  -9.760  1.00 27.76           C  
+ATOM   8058  C   GLN D 191       3.398  27.670 -11.014  1.00 28.16           C  
+ATOM   8059  O   GLN D 191       4.569  27.721 -11.383  1.00 26.78           O  
+ATOM   8060  CB  GLN D 191       3.300  27.614  -8.499  1.00 27.81           C  
+ATOM   8061  CG  GLN D 191       3.317  28.497  -7.243  1.00 30.85           C  
+ATOM   8062  CD  GLN D 191       3.589  27.720  -5.965  1.00 32.13           C  
+ATOM   8063  OE1 GLN D 191       4.241  26.679  -5.981  1.00 32.00           O  
+ATOM   8064  NE2 GLN D 191       3.107  28.243  -4.844  1.00 32.77           N  
+ATOM   8065  N   VAL D 192       2.463  26.985 -11.670  1.00 28.44           N  
+ATOM   8066  CA  VAL D 192       2.787  26.291 -12.904  1.00 29.80           C  
+ATOM   8067  C   VAL D 192       2.905  27.383 -13.978  1.00 29.52           C  
+ATOM   8068  O   VAL D 192       3.793  27.342 -14.824  1.00 29.86           O  
+ATOM   8069  CB  VAL D 192       1.688  25.279 -13.292  1.00 31.56           C  
+ATOM   8070  CG1 VAL D 192       2.096  24.525 -14.558  1.00 31.01           C  
+ATOM   8071  CG2 VAL D 192       1.454  24.299 -12.142  1.00 27.75           C  
+ATOM   8072  N   VAL D 193       2.014  28.368 -13.917  1.00 29.39           N  
+ATOM   8073  CA  VAL D 193       2.033  29.492 -14.856  1.00 30.55           C  
+ATOM   8074  C   VAL D 193       3.375  30.206 -14.748  1.00 30.27           C  
+ATOM   8075  O   VAL D 193       4.005  30.546 -15.747  1.00 30.21           O  
+ATOM   8076  CB  VAL D 193       0.939  30.556 -14.516  1.00 30.89           C  
+ATOM   8077  CG1 VAL D 193       1.183  31.840 -15.318  1.00 28.70           C  
+ATOM   8078  CG2 VAL D 193      -0.440  30.009 -14.810  1.00 31.37           C  
+ATOM   8079  N   ALA D 194       3.799  30.426 -13.510  1.00 31.05           N  
+ATOM   8080  CA  ALA D 194       5.037  31.137 -13.223  1.00 30.03           C  
+ATOM   8081  C   ALA D 194       6.341  30.524 -13.748  1.00 30.23           C  
+ATOM   8082  O   ALA D 194       7.205  31.253 -14.237  1.00 30.20           O  
+ATOM   8083  CB  ALA D 194       5.146  31.363 -11.715  1.00 27.69           C  
+ATOM   8084  N   ILE D 195       6.500  29.203 -13.669  1.00 29.34           N  
+ATOM   8085  CA  ILE D 195       7.768  28.625 -14.104  1.00 29.32           C  
+ATOM   8086  C   ILE D 195       7.788  27.398 -15.004  1.00 29.39           C  
+ATOM   8087  O   ILE D 195       8.839  27.058 -15.528  1.00 28.96           O  
+ATOM   8088  CB  ILE D 195       8.676  28.291 -12.878  1.00 28.53           C  
+ATOM   8089  CG1 ILE D 195       8.075  27.130 -12.076  1.00 29.67           C  
+ATOM   8090  CG2 ILE D 195       8.861  29.537 -11.993  1.00 24.65           C  
+ATOM   8091  CD1 ILE D 195       8.923  26.689 -10.903  0.00 29.20           C  
+ATOM   8092  N   ALA D 196       6.658  26.730 -15.193  1.00 27.92           N  
+ATOM   8093  CA  ALA D 196       6.660  25.521 -16.011  1.00 29.89           C  
+ATOM   8094  C   ALA D 196       6.223  25.692 -17.474  1.00 31.02           C  
+ATOM   8095  O   ALA D 196       5.120  26.171 -17.744  1.00 29.85           O  
+ATOM   8096  CB  ALA D 196       5.796  24.448 -15.333  1.00 25.40           C  
+ATOM   8097  N   ASN D 197       7.081  25.290 -18.413  1.00 29.98           N  
+ATOM   8098  CA  ASN D 197       6.722  25.378 -19.830  1.00 31.00           C  
+ATOM   8099  C   ASN D 197       5.907  24.144 -20.226  1.00 30.77           C  
+ATOM   8100  O   ASN D 197       5.237  24.131 -21.256  1.00 32.00           O  
+ATOM   8101  CB  ASN D 197       7.974  25.548 -20.724  1.00 32.07           C  
+ATOM   8102  CG  ASN D 197       8.908  24.350 -20.690  1.00 34.12           C  
+ATOM   8103  OD1 ASN D 197       9.326  23.894 -19.626  1.00 34.36           O  
+ATOM   8104  ND2 ASN D 197       9.254  23.845 -21.867  1.00 36.60           N  
+ATOM   8105  N   LYS D 198       5.941  23.111 -19.389  1.00 31.21           N  
+ATOM   8106  CA  LYS D 198       5.156  21.903 -19.644  1.00 30.74           C  
+ATOM   8107  C   LYS D 198       4.435  21.450 -18.380  1.00 31.57           C  
+ATOM   8108  O   LYS D 198       4.950  21.594 -17.268  1.00 30.29           O  
+ATOM   8109  CB  LYS D 198       6.047  20.781 -20.184  1.00 33.39           C  
+ATOM   8110  CG  LYS D 198       6.434  21.008 -21.632  1.00 36.74           C  
+ATOM   8111  CD  LYS D 198       7.359  19.953 -22.157  1.00 39.16           C  
+ATOM   8112  CE  LYS D 198       7.730  20.249 -23.612  1.00 40.69           C  
+ATOM   8113  NZ  LYS D 198       8.620  19.172 -24.148  1.00 45.71           N  
+ATOM   8114  N   THR D 199       3.229  20.916 -18.539  1.00 32.19           N  
+ATOM   8115  CA  THR D 199       2.484  20.473 -17.375  1.00 34.32           C  
+ATOM   8116  C   THR D 199       1.736  19.178 -17.605  1.00 34.37           C  
+ATOM   8117  O   THR D 199       1.289  18.880 -18.713  1.00 33.74           O  
+ATOM   8118  CB  THR D 199       1.479  21.569 -16.864  1.00 35.19           C  
+ATOM   8119  OG1 THR D 199       0.141  21.214 -17.209  1.00 37.52           O  
+ATOM   8120  CG2 THR D 199       1.781  22.906 -17.474  1.00 33.58           C  
+ATOM   8121  N   LEU D 200       1.620  18.408 -16.530  1.00 34.70           N  
+ATOM   8122  CA  LEU D 200       0.930  17.134 -16.546  1.00 35.49           C  
+ATOM   8123  C   LEU D 200      -0.146  17.230 -15.468  1.00 37.16           C  
+ATOM   8124  O   LEU D 200       0.170  17.303 -14.284  1.00 37.40           O  
+ATOM   8125  CB  LEU D 200       1.927  16.011 -16.233  1.00 35.96           C  
+ATOM   8126  CG  LEU D 200       1.555  14.519 -16.216  1.00 39.37           C  
+ATOM   8127  CD1 LEU D 200       0.799  14.205 -14.963  1.00 42.11           C  
+ATOM   8128  CD2 LEU D 200       0.735  14.143 -17.449  1.00 40.75           C  
+ATOM   8129  N   LEU D 201      -1.412  17.272 -15.887  1.00 37.92           N  
+ATOM   8130  CA  LEU D 201      -2.536  17.345 -14.958  1.00 39.77           C  
+ATOM   8131  C   LEU D 201      -2.901  15.925 -14.532  1.00 41.69           C  
+ATOM   8132  O   LEU D 201      -3.301  15.105 -15.356  1.00 41.05           O  
+ATOM   8133  CB  LEU D 201      -3.746  18.007 -15.625  1.00 37.18           C  
+ATOM   8134  CG  LEU D 201      -3.613  19.441 -16.141  1.00 40.03           C  
+ATOM   8135  CD1 LEU D 201      -4.882  19.825 -16.900  1.00 37.27           C  
+ATOM   8136  CD2 LEU D 201      -3.369  20.396 -14.968  1.00 38.18           C  
+ATOM   8137  N   LEU D 202      -2.757  15.634 -13.247  1.00 44.86           N  
+ATOM   8138  CA  LEU D 202      -3.063  14.305 -12.740  1.00 50.63           C  
+ATOM   8139  C   LEU D 202      -4.306  14.262 -11.877  1.00 54.29           C  
+ATOM   8140  O   LEU D 202      -4.452  15.022 -10.920  1.00 55.36           O  
+ATOM   8141  CB  LEU D 202      -1.890  13.742 -11.931  1.00 51.82           C  
+ATOM   8142  CG  LEU D 202      -0.937  12.785 -12.638  1.00 54.13           C  
+ATOM   8143  CD1 LEU D 202       0.042  12.216 -11.627  1.00 54.97           C  
+ATOM   8144  CD2 LEU D 202      -1.731  11.656 -13.288  1.00 57.25           C  
+ATOM   8145  N   ASN D 203      -5.195  13.349 -12.228  1.00 58.86           N  
+ATOM   8146  CA  ASN D 203      -6.436  13.142 -11.507  1.00 63.77           C  
+ATOM   8147  C   ASN D 203      -6.407  11.646 -11.237  1.00 65.60           C  
+ATOM   8148  O   ASN D 203      -5.656  10.920 -11.885  1.00 65.53           O  
+ATOM   8149  CB  ASN D 203      -7.622  13.480 -12.411  1.00 66.98           C  
+ATOM   8150  CG  ASN D 203      -8.872  13.791 -11.634  1.00 68.76           C  
+ATOM   8151  OD1 ASN D 203      -9.142  13.175 -10.602  1.00 74.05           O  
+ATOM   8152  ND2 ASN D 203      -9.653  14.746 -12.128  1.00 68.19           N  
+ATOM   8153  N   LYS D 204      -7.196  11.168 -10.286  1.00 68.90           N  
+ATOM   8154  CA  LYS D 204      -7.198   9.734 -10.036  1.00 71.65           C  
+ATOM   8155  C   LYS D 204      -8.025   9.088 -11.143  1.00 72.56           C  
+ATOM   8156  O   LYS D 204      -8.123   7.867 -11.235  1.00 73.49           O  
+ATOM   8157  CB  LYS D 204      -7.776   9.424  -8.651  1.00 72.10           C  
+ATOM   8158  CG  LYS D 204      -9.119  10.068  -8.359  1.00 74.74           C  
+ATOM   8159  CD  LYS D 204      -9.461   9.960  -6.877  1.00 76.20           C  
+ATOM   8160  CE  LYS D 204      -8.423  10.685  -6.026  1.00 77.81           C  
+ATOM   8161  NZ  LYS D 204      -8.732  10.647  -4.572  1.00 79.41           N  
+ATOM   8162  N   GLN D 205      -8.595   9.933 -11.998  1.00 73.82           N  
+ATOM   8163  CA  GLN D 205      -9.415   9.485 -13.118  1.00 75.24           C  
+ATOM   8164  C   GLN D 205      -8.635   9.591 -14.429  1.00 74.49           C  
+ATOM   8165  O   GLN D 205      -8.244   8.581 -15.023  1.00 75.43           O  
+ATOM   8166  CB  GLN D 205     -10.680  10.343 -13.219  1.00 77.90           C  
+ATOM   8167  CG  GLN D 205     -11.523  10.389 -11.952  1.00 81.56           C  
+ATOM   8168  CD  GLN D 205     -12.498  11.559 -11.939  1.00 82.97           C  
+ATOM   8169  OE1 GLN D 205     -13.339  11.696 -12.830  1.00 84.20           O  
+ATOM   8170  NE2 GLN D 205     -12.383  12.411 -10.925  1.00 83.38           N  
+ATOM   8171  N   ASN D 206      -8.409  10.825 -14.873  1.00 72.16           N  
+ATOM   8172  CA  ASN D 206      -7.692  11.072 -16.118  1.00 69.23           C  
+ATOM   8173  C   ASN D 206      -6.457  11.962 -15.961  1.00 65.88           C  
+ATOM   8174  O   ASN D 206      -6.019  12.261 -14.849  1.00 64.63           O  
+ATOM   8175  CB  ASN D 206      -8.644  11.687 -17.153  1.00 71.24           C  
+ATOM   8176  CG  ASN D 206      -9.973  12.116 -16.546  1.00 73.67           C  
+ATOM   8177  OD1 ASN D 206     -10.014  12.906 -15.599  1.00 74.90           O  
+ATOM   8178  ND2 ASN D 206     -11.068  11.599 -17.095  1.00 73.68           N  
+ATOM   8179  N   PHE D 207      -5.900  12.375 -17.093  1.00 61.99           N  
+ATOM   8180  CA  PHE D 207      -4.722  13.224 -17.107  1.00 58.90           C  
+ATOM   8181  C   PHE D 207      -4.570  13.886 -18.474  1.00 56.38           C  
+ATOM   8182  O   PHE D 207      -5.254  13.527 -19.427  1.00 55.25           O  
+ATOM   8183  CB  PHE D 207      -3.478  12.389 -16.795  1.00 59.01           C  
+ATOM   8184  CG  PHE D 207      -3.178  11.350 -17.831  1.00 59.71           C  
+ATOM   8185  CD1 PHE D 207      -2.594  11.705 -19.043  1.00 59.76           C  
+ATOM   8186  CD2 PHE D 207      -3.514  10.018 -17.614  1.00 60.33           C  
+ATOM   8187  CE1 PHE D 207      -2.352  10.751 -20.026  1.00 59.53           C  
+ATOM   8188  CE2 PHE D 207      -3.275   9.054 -18.594  1.00 59.79           C  
+ATOM   8189  CZ  PHE D 207      -2.694   9.424 -19.800  1.00 58.90           C  
+ATOM   8190  N   LYS D 208      -3.673  14.861 -18.554  1.00 54.31           N  
+ATOM   8191  CA  LYS D 208      -3.401  15.575 -19.795  1.00 53.01           C  
+ATOM   8192  C   LYS D 208      -1.984  16.114 -19.726  1.00 49.59           C  
+ATOM   8193  O   LYS D 208      -1.589  16.692 -18.716  1.00 46.46           O  
+ATOM   8194  CB  LYS D 208      -4.360  16.757 -19.992  1.00 55.77           C  
+ATOM   8195  CG  LYS D 208      -5.792  16.389 -20.295  1.00 60.72           C  
+ATOM   8196  CD  LYS D 208      -6.612  17.638 -20.602  1.00 65.33           C  
+ATOM   8197  CE  LYS D 208      -8.078  17.296 -20.850  1.00 68.00           C  
+ATOM   8198  NZ  LYS D 208      -8.244  16.325 -21.972  1.00 69.65           N  
+ATOM   8199  N   PHE D 209      -1.226  15.918 -20.801  1.00 46.79           N  
+ATOM   8200  CA  PHE D 209       0.145  16.404 -20.872  1.00 44.86           C  
+ATOM   8201  C   PHE D 209       0.266  17.380 -22.029  1.00 43.83           C  
+ATOM   8202  O   PHE D 209      -0.465  17.279 -23.010  1.00 44.11           O  
+ATOM   8203  CB  PHE D 209       1.127  15.253 -21.095  1.00 44.02           C  
+ATOM   8204  CG  PHE D 209       2.536  15.711 -21.329  1.00 44.36           C  
+ATOM   8205  CD1 PHE D 209       3.301  16.218 -20.280  1.00 44.38           C  
+ATOM   8206  CD2 PHE D 209       3.082  15.692 -22.607  1.00 43.78           C  
+ATOM   8207  CE1 PHE D 209       4.585  16.703 -20.501  1.00 44.74           C  
+ATOM   8208  CE2 PHE D 209       4.365  16.174 -22.842  1.00 45.02           C  
+ATOM   8209  CZ  PHE D 209       5.121  16.683 -21.786  1.00 44.98           C  
+ATOM   8210  N   GLY D 210       1.177  18.336 -21.907  1.00 42.11           N  
+ATOM   8211  CA  GLY D 210       1.365  19.287 -22.983  1.00 40.82           C  
+ATOM   8212  C   GLY D 210       1.993  20.577 -22.522  1.00 40.43           C  
+ATOM   8213  O   GLY D 210       2.373  20.709 -21.360  1.00 39.97           O  
+ATOM   8214  N   GLU D 211       2.109  21.535 -23.433  1.00 39.14           N  
+ATOM   8215  CA  GLU D 211       2.680  22.813 -23.073  1.00 42.31           C  
+ATOM   8216  C   GLU D 211       1.684  23.540 -22.180  1.00 42.48           C  
+ATOM   8217  O   GLU D 211       0.465  23.440 -22.366  1.00 40.98           O  
+ATOM   8218  CB  GLU D 211       3.005  23.629 -24.324  1.00 45.41           C  
+ATOM   8219  CG  GLU D 211       4.081  22.978 -25.188  1.00 53.26           C  
+ATOM   8220  CD  GLU D 211       4.651  23.922 -26.227  1.00 58.74           C  
+ATOM   8221  OE1 GLU D 211       3.865  24.456 -27.040  1.00 60.66           O  
+ATOM   8222  OE2 GLU D 211       5.887  24.130 -26.230  1.00 60.82           O  
+ATOM   8223  N   THR D 212       2.218  24.256 -21.198  1.00 42.22           N  
+ATOM   8224  CA  THR D 212       1.407  24.989 -20.237  1.00 41.18           C  
+ATOM   8225  C   THR D 212       0.420  25.956 -20.888  1.00 41.47           C  
+ATOM   8226  O   THR D 212      -0.724  26.073 -20.445  1.00 42.00           O  
+ATOM   8227  CB  THR D 212       2.319  25.739 -19.239  1.00 38.54           C  
+ATOM   8228  OG1 THR D 212       3.208  24.795 -18.629  1.00 35.98           O  
+ATOM   8229  CG2 THR D 212       1.501  26.419 -18.157  1.00 33.26           C  
+ATOM   8230  N   ARG D 213       0.851  26.639 -21.940  1.00 43.19           N  
+ATOM   8231  CA  ARG D 213      -0.027  27.575 -22.640  1.00 46.61           C  
+ATOM   8232  C   ARG D 213      -1.283  26.892 -23.184  1.00 44.92           C  
+ATOM   8233  O   ARG D 213      -2.326  27.521 -23.292  1.00 46.79           O  
+ATOM   8234  CB  ARG D 213       0.719  28.244 -23.801  1.00 52.41           C  
+ATOM   8235  CG  ARG D 213       1.743  29.286 -23.383  1.00 61.81           C  
+ATOM   8236  CD  ARG D 213       1.070  30.554 -22.840  1.00 69.55           C  
+ATOM   8237  NE  ARG D 213       0.296  31.264 -23.863  1.00 74.31           N  
+ATOM   8238  CZ  ARG D 213      -0.387  32.387 -23.645  1.00 75.91           C  
+ATOM   8239  NH1 ARG D 213      -1.061  32.962 -24.638  1.00 75.59           N  
+ATOM   8240  NH2 ARG D 213      -0.399  32.937 -22.436  1.00 76.20           N  
+ATOM   8241  N   ASN D 214      -1.186  25.609 -23.518  1.00 43.51           N  
+ATOM   8242  CA  ASN D 214      -2.330  24.876 -24.068  1.00 44.77           C  
+ATOM   8243  C   ASN D 214      -3.170  24.124 -23.040  1.00 45.67           C  
+ATOM   8244  O   ASN D 214      -4.388  24.056 -23.165  1.00 48.48           O  
+ATOM   8245  CB  ASN D 214      -1.858  23.857 -25.114  1.00 42.43           C  
+ATOM   8246  CG  ASN D 214      -1.082  24.492 -26.248  1.00 45.80           C  
+ATOM   8247  OD1 ASN D 214      -0.196  23.860 -26.830  1.00 46.83           O  
+ATOM   8248  ND2 ASN D 214      -1.414  25.739 -26.581  1.00 42.60           N  
+ATOM   8249  N   ILE D 215      -2.516  23.543 -22.040  1.00 44.76           N  
+ATOM   8250  CA  ILE D 215      -3.203  22.762 -21.023  1.00 43.82           C  
+ATOM   8251  C   ILE D 215      -3.849  23.523 -19.859  1.00 42.21           C  
+ATOM   8252  O   ILE D 215      -4.906  23.117 -19.379  1.00 41.46           O  
+ATOM   8253  CB  ILE D 215      -2.246  21.691 -20.443  1.00 46.33           C  
+ATOM   8254  CG1 ILE D 215      -1.951  20.642 -21.508  1.00 47.60           C  
+ATOM   8255  CG2 ILE D 215      -2.867  21.021 -19.221  1.00 50.26           C  
+ATOM   8256  CD1 ILE D 215      -1.342  19.406 -20.940  0.00 47.18           C  
+ATOM   8257  N   LEU D 216      -3.224  24.606 -19.402  1.00 40.51           N  
+ATOM   8258  CA  LEU D 216      -3.761  25.380 -18.280  1.00 39.11           C  
+ATOM   8259  C   LEU D 216      -4.908  26.299 -18.657  1.00 39.34           C  
+ATOM   8260  O   LEU D 216      -4.695  27.475 -18.956  1.00 40.27           O  
+ATOM   8261  CB  LEU D 216      -2.674  26.230 -17.621  1.00 38.13           C  
+ATOM   8262  CG  LEU D 216      -1.793  25.642 -16.523  1.00 38.07           C  
+ATOM   8263  CD1 LEU D 216      -1.155  26.796 -15.756  1.00 38.79           C  
+ATOM   8264  CD2 LEU D 216      -2.615  24.805 -15.574  1.00 36.15           C  
+ATOM   8265  N   THR D 217      -6.125  25.766 -18.610  1.00 38.93           N  
+ATOM   8266  CA  THR D 217      -7.317  26.527 -18.941  1.00 38.09           C  
+ATOM   8267  C   THR D 217      -8.368  26.308 -17.862  1.00 39.70           C  
+ATOM   8268  O   THR D 217      -8.315  25.317 -17.122  1.00 38.18           O  
+ATOM   8269  CB  THR D 217      -7.918  26.064 -20.281  1.00 38.06           C  
+ATOM   8270  OG1 THR D 217      -8.398  24.718 -20.143  1.00 38.12           O  
+ATOM   8271  CG2 THR D 217      -6.867  26.119 -21.387  1.00 36.91           C  
+ATOM   8272  N   SER D 218      -9.322  27.232 -17.787  1.00 40.21           N  
+ATOM   8273  CA  SER D 218     -10.412  27.150 -16.821  1.00 42.36           C  
+ATOM   8274  C   SER D 218     -11.140  25.830 -16.967  1.00 41.67           C  
+ATOM   8275  O   SER D 218     -11.504  25.191 -15.975  1.00 42.12           O  
+ATOM   8276  CB  SER D 218     -11.417  28.283 -17.045  1.00 43.99           C  
+ATOM   8277  OG  SER D 218     -10.832  29.537 -16.776  1.00 49.44           O  
+ATOM   8278  N   GLU D 219     -11.362  25.433 -18.214  1.00 41.37           N  
+ATOM   8279  CA  GLU D 219     -12.062  24.191 -18.498  1.00 41.83           C  
+ATOM   8280  C   GLU D 219     -11.323  22.994 -17.895  1.00 38.85           C  
+ATOM   8281  O   GLU D 219     -11.901  22.229 -17.132  1.00 39.04           O  
+ATOM   8282  CB  GLU D 219     -12.236  24.024 -20.020  1.00 45.59           C  
+ATOM   8283  CG  GLU D 219     -12.968  22.746 -20.435  1.00 53.16           C  
+ATOM   8284  CD  GLU D 219     -13.351  22.711 -21.921  1.00 60.33           C  
+ATOM   8285  OE1 GLU D 219     -13.817  21.644 -22.386  1.00 61.13           O  
+ATOM   8286  OE2 GLU D 219     -13.198  23.742 -22.622  1.00 62.33           O  
+ATOM   8287  N   ASN D 220     -10.045  22.839 -18.227  1.00 37.55           N  
+ATOM   8288  CA  ASN D 220      -9.257  21.723 -17.706  1.00 35.95           C  
+ATOM   8289  C   ASN D 220      -9.109  21.743 -16.180  1.00 33.52           C  
+ATOM   8290  O   ASN D 220      -9.211  20.705 -15.530  1.00 32.37           O  
+ATOM   8291  CB  ASN D 220      -7.879  21.697 -18.378  1.00 37.37           C  
+ATOM   8292  CG  ASN D 220      -7.934  21.173 -19.819  1.00 38.87           C  
+ATOM   8293  OD1 ASN D 220      -6.981  21.428 -20.592  1.00 36.59           O  
+ATOM   8294  ND2 ASN D 220      -8.924  20.498 -20.176  1.00 39.70           N  
+ATOM   8295  N   LEU D 221      -8.898  22.920 -15.604  1.00 32.53           N  
+ATOM   8296  CA  LEU D 221      -8.749  23.013 -14.153  1.00 31.33           C  
+ATOM   8297  C   LEU D 221     -10.071  22.762 -13.442  1.00 30.86           C  
+ATOM   8298  O   LEU D 221     -10.106  22.099 -12.403  1.00 29.54           O  
+ATOM   8299  CB  LEU D 221      -8.173  24.373 -13.766  1.00 29.72           C  
+ATOM   8300  CG  LEU D 221      -6.755  24.555 -14.321  1.00 30.94           C  
+ATOM   8301  CD1 LEU D 221      -6.153  25.870 -13.824  1.00 30.59           C  
+ATOM   8302  CD2 LEU D 221      -5.894  23.364 -13.888  1.00 29.79           C  
+ATOM   8303  N   THR D 222     -11.159  23.284 -14.003  1.00 31.66           N  
+ATOM   8304  CA  THR D 222     -12.483  23.070 -13.418  1.00 31.38           C  
+ATOM   8305  C   THR D 222     -12.750  21.572 -13.394  1.00 32.95           C  
+ATOM   8306  O   THR D 222     -13.241  21.035 -12.403  1.00 33.59           O  
+ATOM   8307  CB  THR D 222     -13.601  23.736 -14.248  1.00 33.18           C  
+ATOM   8308  OG1 THR D 222     -13.480  25.159 -14.165  1.00 35.84           O  
+ATOM   8309  CG2 THR D 222     -14.979  23.312 -13.730  1.00 32.18           C  
+ATOM   8310  N   ALA D 223     -12.419  20.904 -14.496  1.00 32.71           N  
+ATOM   8311  CA  ALA D 223     -12.617  19.463 -14.603  1.00 35.07           C  
+ATOM   8312  C   ALA D 223     -11.664  18.712 -13.672  1.00 35.09           C  
+ATOM   8313  O   ALA D 223     -12.032  17.705 -13.077  1.00 38.44           O  
+ATOM   8314  CB  ALA D 223     -12.398  19.010 -16.055  1.00 31.91           C  
+ATOM   8315  N   LEU D 224     -10.436  19.204 -13.550  1.00 34.54           N  
+ATOM   8316  CA  LEU D 224      -9.444  18.563 -12.692  1.00 35.50           C  
+ATOM   8317  C   LEU D 224      -9.732  18.748 -11.199  1.00 35.72           C  
+ATOM   8318  O   LEU D 224      -9.579  17.818 -10.416  1.00 34.56           O  
+ATOM   8319  CB  LEU D 224      -8.040  19.106 -13.003  1.00 33.57           C  
+ATOM   8320  CG  LEU D 224      -6.929  18.603 -12.065  1.00 36.78           C  
+ATOM   8321  CD1 LEU D 224      -6.713  17.104 -12.293  1.00 33.76           C  
+ATOM   8322  CD2 LEU D 224      -5.632  19.378 -12.305  1.00 29.62           C  
+ATOM   8323  N   PHE D 225     -10.153  19.951 -10.814  1.00 36.70           N  
+ATOM   8324  CA  PHE D 225     -10.428  20.261  -9.412  1.00 36.58           C  
+ATOM   8325  C   PHE D 225     -11.861  20.006  -8.926  1.00 36.66           C  
+ATOM   8326  O   PHE D 225     -12.116  20.003  -7.718  1.00 32.28           O  
+ATOM   8327  CB  PHE D 225     -10.023  21.717  -9.126  1.00 36.96           C  
+ATOM   8328  CG  PHE D 225      -8.529  21.949  -9.164  1.00 37.87           C  
+ATOM   8329  CD1 PHE D 225      -7.983  22.949  -9.955  1.00 38.13           C  
+ATOM   8330  CD2 PHE D 225      -7.671  21.157  -8.410  1.00 42.59           C  
+ATOM   8331  CE1 PHE D 225      -6.608  23.155  -9.999  1.00 40.54           C  
+ATOM   8332  CE2 PHE D 225      -6.284  21.356  -8.445  1.00 43.50           C  
+ATOM   8333  CZ  PHE D 225      -5.754  22.354  -9.240  1.00 40.65           C  
+ATOM   8334  N   HIS D 226     -12.788  19.783  -9.857  1.00 37.06           N  
+ATOM   8335  CA  HIS D 226     -14.182  19.521  -9.500  1.00 40.13           C  
+ATOM   8336  C   HIS D 226     -14.800  20.737  -8.823  1.00 39.78           C  
+ATOM   8337  O   HIS D 226     -15.622  20.614  -7.923  1.00 41.88           O  
+ATOM   8338  CB  HIS D 226     -14.269  18.320  -8.558  1.00 41.11           C  
+ATOM   8339  CG  HIS D 226     -13.576  17.103  -9.076  1.00 45.61           C  
+ATOM   8340  ND1 HIS D 226     -13.887  16.531 -10.291  1.00 49.46           N  
+ATOM   8341  CD2 HIS D 226     -12.588  16.345  -8.544  1.00 47.34           C  
+ATOM   8342  CE1 HIS D 226     -13.122  15.471 -10.486  1.00 49.90           C  
+ATOM   8343  NE2 HIS D 226     -12.325  15.336  -9.440  1.00 50.65           N  
+ATOM   8344  N   LEU D 227     -14.391  21.913  -9.268  1.00 39.21           N  
+ATOM   8345  CA  LEU D 227     -14.878  23.162  -8.721  1.00 39.24           C  
+ATOM   8346  C   LEU D 227     -14.593  24.178  -9.816  1.00 38.31           C  
+ATOM   8347  O   LEU D 227     -13.544  24.121 -10.450  1.00 39.49           O  
+ATOM   8348  CB  LEU D 227     -14.089  23.507  -7.449  1.00 42.32           C  
+ATOM   8349  CG  LEU D 227     -14.414  24.800  -6.690  1.00 44.14           C  
+ATOM   8350  CD1 LEU D 227     -15.840  24.737  -6.159  1.00 43.77           C  
+ATOM   8351  CD2 LEU D 227     -13.434  24.989  -5.537  1.00 44.21           C  
+ATOM   8352  N   PRO D 228     -15.523  25.107 -10.073  1.00 38.52           N  
+ATOM   8353  CA  PRO D 228     -15.221  26.074 -11.130  1.00 37.57           C  
+ATOM   8354  C   PRO D 228     -13.948  26.859 -10.846  1.00 37.71           C  
+ATOM   8355  O   PRO D 228     -13.739  27.347  -9.739  1.00 39.34           O  
+ATOM   8356  CB  PRO D 228     -16.479  26.952 -11.180  1.00 36.51           C  
+ATOM   8357  CG  PRO D 228     -17.090  26.793  -9.817  1.00 38.87           C  
+ATOM   8358  CD  PRO D 228     -16.873  25.326  -9.524  1.00 40.24           C  
+ATOM   8359  N   MET D 229     -13.093  26.955 -11.858  1.00 39.16           N  
+ATOM   8360  CA  MET D 229     -11.831  27.666 -11.758  1.00 39.06           C  
+ATOM   8361  C   MET D 229     -11.851  28.868 -12.688  1.00 40.52           C  
+ATOM   8362  O   MET D 229     -11.966  28.720 -13.902  1.00 44.52           O  
+ATOM   8363  CB  MET D 229     -10.680  26.740 -12.141  1.00 37.11           C  
+ATOM   8364  CG  MET D 229     -10.485  25.571 -11.187  1.00 40.67           C  
+ATOM   8365  SD  MET D 229     -10.022  26.101  -9.515  1.00 40.59           S  
+ATOM   8366  CE  MET D 229      -8.282  26.428  -9.737  1.00 36.83           C  
+ATOM   8367  N   PHE D 230     -11.731  30.055 -12.110  1.00 39.17           N  
+ATOM   8368  CA  PHE D 230     -11.752  31.292 -12.864  1.00 37.40           C  
+ATOM   8369  C   PHE D 230     -10.367  31.663 -13.387  1.00 38.76           C  
+ATOM   8370  O   PHE D 230      -9.383  31.647 -12.643  1.00 37.91           O  
+ATOM   8371  CB  PHE D 230     -12.282  32.422 -11.973  1.00 37.06           C  
+ATOM   8372  CG  PHE D 230     -12.526  33.717 -12.702  1.00 36.18           C  
+ATOM   8373  CD1 PHE D 230     -13.594  33.845 -13.585  1.00 35.72           C  
+ATOM   8374  CD2 PHE D 230     -11.701  34.814 -12.492  1.00 35.96           C  
+ATOM   8375  CE1 PHE D 230     -13.836  35.053 -14.244  1.00 36.53           C  
+ATOM   8376  CE2 PHE D 230     -11.933  36.028 -13.149  1.00 35.60           C  
+ATOM   8377  CZ  PHE D 230     -13.002  36.146 -14.023  1.00 33.74           C  
+ATOM   8378  N   GLU D 231     -10.305  32.005 -14.670  1.00 38.37           N  
+ATOM   8379  CA  GLU D 231      -9.057  32.402 -15.308  1.00 40.86           C  
+ATOM   8380  C   GLU D 231      -9.134  33.880 -15.641  1.00 41.74           C  
+ATOM   8381  O   GLU D 231     -10.106  34.356 -16.223  1.00 41.72           O  
+ATOM   8382  CB  GLU D 231      -8.809  31.590 -16.580  1.00 40.44           C  
+ATOM   8383  CG  GLU D 231      -7.683  32.134 -17.453  1.00 44.52           C  
+ATOM   8384  CD  GLU D 231      -7.258  31.160 -18.552  1.00 47.09           C  
+ATOM   8385  OE1 GLU D 231      -8.102  30.358 -19.019  1.00 49.30           O  
+ATOM   8386  OE2 GLU D 231      -6.078  31.208 -18.955  1.00 48.15           O  
+ATOM   8387  N   GLN D 232      -8.093  34.606 -15.282  1.00 44.08           N  
+ATOM   8388  CA  GLN D 232      -8.088  36.026 -15.516  1.00 48.33           C  
+ATOM   8389  C   GLN D 232      -6.697  36.532 -15.829  1.00 50.57           C  
+ATOM   8390  O   GLN D 232      -5.712  36.050 -15.275  1.00 51.16           O  
+ATOM   8391  CB  GLN D 232      -8.640  36.716 -14.271  1.00 48.98           C  
+ATOM   8392  CG  GLN D 232      -8.515  38.222 -14.233  1.00 52.23           C  
+ATOM   8393  CD  GLN D 232      -9.145  38.797 -12.978  1.00 53.59           C  
+ATOM   8394  OE1 GLN D 232      -8.801  38.402 -11.864  1.00 55.77           O  
+ATOM   8395  NE2 GLN D 232     -10.076  39.724 -13.153  1.00 52.10           N  
+ATOM   8396  N   GLN D 233      -6.619  37.499 -16.733  1.00 52.80           N  
+ATOM   8397  CA  GLN D 233      -5.341  38.088 -17.084  1.00 56.64           C  
+ATOM   8398  C   GLN D 233      -5.161  39.280 -16.161  1.00 59.17           C  
+ATOM   8399  O   GLN D 233      -5.903  40.254 -16.241  1.00 60.63           O  
+ATOM   8400  CB  GLN D 233      -5.334  38.528 -18.548  1.00 55.74           C  
+ATOM   8401  CG  GLN D 233      -5.407  37.362 -19.515  1.00 57.31           C  
+ATOM   8402  CD  GLN D 233      -4.165  36.489 -19.456  1.00 59.60           C  
+ATOM   8403  OE1 GLN D 233      -4.225  35.283 -19.703  1.00 59.97           O  
+ATOM   8404  NE2 GLN D 233      -3.027  37.100 -19.140  1.00 59.42           N  
+ATOM   8405  N   ALA D 234      -4.192  39.178 -15.259  1.00 62.87           N  
+ATOM   8406  CA  ALA D 234      -3.911  40.245 -14.313  1.00 65.91           C  
+ATOM   8407  C   ALA D 234      -2.727  41.060 -14.809  1.00 68.57           C  
+ATOM   8408  O   ALA D 234      -1.881  40.558 -15.553  1.00 67.06           O  
+ATOM   8409  CB  ALA D 234      -3.606  39.656 -12.938  1.00 64.75           C  
+ATOM   8410  N   GLN D 235      -2.679  42.321 -14.402  1.00 73.56           N  
+ATOM   8411  CA  GLN D 235      -1.589  43.202 -14.791  1.00 78.37           C  
+ATOM   8412  C   GLN D 235      -0.994  43.883 -13.566  1.00 80.52           C  
+ATOM   8413  O   GLN D 235      -1.707  44.234 -12.624  1.00 81.61           O  
+ATOM   8414  CB  GLN D 235      -2.078  44.262 -15.782  1.00 80.56           C  
+ATOM   8415  CG  GLN D 235      -0.996  45.254 -16.197  1.00 83.98           C  
+ATOM   8416  CD  GLN D 235      -1.454  46.209 -17.285  1.00 86.51           C  
+ATOM   8417  OE1 GLN D 235      -1.758  45.794 -18.406  1.00 87.26           O  
+ATOM   8418  NE2 GLN D 235      -1.504  47.498 -16.958  1.00 87.67           N  
+ATOM   8419  N   TYR D 236       0.323  44.050 -13.581  1.00 83.02           N  
+ATOM   8420  CA  TYR D 236       1.031  44.696 -12.489  1.00 85.03           C  
+ATOM   8421  C   TYR D 236       2.057  45.645 -13.078  1.00 86.23           C  
+ATOM   8422  O   TYR D 236       3.155  45.232 -13.453  1.00 86.84           O  
+ATOM   8423  CB  TYR D 236       1.725  43.654 -11.605  1.00 85.95           C  
+ATOM   8424  CG  TYR D 236       2.491  44.239 -10.434  1.00 86.91           C  
+ATOM   8425  CD1 TYR D 236       3.768  44.775 -10.604  1.00 86.39           C  
+ATOM   8426  CD2 TYR D 236       1.933  44.262  -9.153  1.00 87.31           C  
+ATOM   8427  CE1 TYR D 236       4.473  45.317  -9.528  1.00 87.38           C  
+ATOM   8428  CE2 TYR D 236       2.627  44.803  -8.070  1.00 87.55           C  
+ATOM   8429  CZ  TYR D 236       3.897  45.329  -8.264  1.00 87.85           C  
+ATOM   8430  OH  TYR D 236       4.590  45.863  -7.195  1.00 87.31           O  
+ATOM   8431  N   LYS D 237       1.681  46.915 -13.173  1.00 87.45           N  
+ATOM   8432  CA  LYS D 237       2.561  47.943 -13.709  1.00 88.02           C  
+ATOM   8433  C   LYS D 237       3.262  47.482 -14.985  1.00 88.40           C  
+ATOM   8434  O   LYS D 237       4.454  47.169 -14.967  1.00 88.79           O  
+ATOM   8435  CB  LYS D 237       3.599  48.330 -12.651  1.00 88.54           C  
+ATOM   8436  CG  LYS D 237       2.981  48.742 -11.322  1.00 88.78           C  
+ATOM   8437  CD  LYS D 237       4.038  48.986 -10.260  1.00 89.04           C  
+ATOM   8438  CE  LYS D 237       3.398  49.291  -8.917  1.00 89.42           C  
+ATOM   8439  NZ  LYS D 237       4.417  49.487  -7.851  1.00 89.63           N  
+ATOM   8440  N   GLU D 238       2.501  47.438 -16.078  1.00 88.13           N  
+ATOM   8441  CA  GLU D 238       2.990  47.039 -17.398  1.00 88.21           C  
+ATOM   8442  C   GLU D 238       3.226  45.537 -17.545  1.00 87.05           C  
+ATOM   8443  O   GLU D 238       3.458  45.046 -18.651  1.00 87.73           O  
+ATOM   8444  CB  GLU D 238       4.274  47.809 -17.750  1.00 90.14           C  
+ATOM   8445  CG  GLU D 238       5.585  47.103 -17.400  1.00 92.18           C  
+ATOM   8446  CD  GLU D 238       6.106  46.233 -18.528  1.00 93.06           C  
+ATOM   8447  OE1 GLU D 238       7.103  45.512 -18.306  1.00 93.82           O  
+ATOM   8448  OE2 GLU D 238       5.527  46.277 -19.636  1.00 93.09           O  
+ATOM   8449  N   SER D 239       3.169  44.807 -16.437  1.00 84.78           N  
+ATOM   8450  CA  SER D 239       3.370  43.362 -16.482  1.00 82.03           C  
+ATOM   8451  C   SER D 239       2.026  42.637 -16.428  1.00 79.17           C  
+ATOM   8452  O   SER D 239       1.222  42.869 -15.527  1.00 78.77           O  
+ATOM   8453  CB  SER D 239       4.257  42.912 -15.318  1.00 82.49           C  
+ATOM   8454  OG  SER D 239       5.560  43.459 -15.434  1.00 84.05           O  
+ATOM   8455  N   PHE D 240       1.787  41.763 -17.401  1.00 75.27           N  
+ATOM   8456  CA  PHE D 240       0.537  41.015 -17.468  1.00 71.72           C  
+ATOM   8457  C   PHE D 240       0.780  39.508 -17.465  1.00 66.16           C  
+ATOM   8458  O   PHE D 240       1.671  39.009 -18.152  1.00 65.54           O  
+ATOM   8459  CB  PHE D 240      -0.259  41.430 -18.716  1.00 76.15           C  
+ATOM   8460  CG  PHE D 240       0.503  41.288 -20.012  1.00 81.13           C  
+ATOM   8461  CD1 PHE D 240       1.736  41.917 -20.192  1.00 83.46           C  
+ATOM   8462  CD2 PHE D 240      -0.029  40.545 -21.067  1.00 83.84           C  
+ATOM   8463  CE1 PHE D 240       2.430  41.810 -21.404  1.00 84.83           C  
+ATOM   8464  CE2 PHE D 240       0.656  40.430 -22.287  1.00 85.16           C  
+ATOM   8465  CZ  PHE D 240       1.886  41.064 -22.454  1.00 85.48           C  
+ATOM   8466  N   PHE D 241      -0.026  38.788 -16.689  1.00 59.54           N  
+ATOM   8467  CA  PHE D 241       0.113  37.341 -16.572  1.00 53.11           C  
+ATOM   8468  C   PHE D 241      -1.214  36.672 -16.239  1.00 49.53           C  
+ATOM   8469  O   PHE D 241      -2.089  37.285 -15.635  1.00 49.05           O  
+ATOM   8470  CB  PHE D 241       1.136  37.025 -15.485  1.00 50.64           C  
+ATOM   8471  CG  PHE D 241       0.811  37.636 -14.151  1.00 50.04           C  
+ATOM   8472  CD1 PHE D 241       0.025  36.949 -13.226  1.00 49.64           C  
+ATOM   8473  CD2 PHE D 241       1.295  38.898 -13.814  1.00 49.73           C  
+ATOM   8474  CE1 PHE D 241      -0.271  37.508 -11.980  1.00 47.25           C  
+ATOM   8475  CE2 PHE D 241       1.005  39.470 -12.573  1.00 50.15           C  
+ATOM   8476  CZ  PHE D 241       0.219  38.770 -11.651  1.00 50.43           C  
+ATOM   8477  N   THR D 242      -1.366  35.415 -16.638  1.00 46.11           N  
+ATOM   8478  CA  THR D 242      -2.597  34.697 -16.355  1.00 45.62           C  
+ATOM   8479  C   THR D 242      -2.630  34.214 -14.900  1.00 44.29           C  
+ATOM   8480  O   THR D 242      -1.612  33.812 -14.329  1.00 42.05           O  
+ATOM   8481  CB  THR D 242      -2.802  33.522 -17.339  1.00 45.25           C  
+ATOM   8482  OG1 THR D 242      -3.562  32.489 -16.706  1.00 49.35           O  
+ATOM   8483  CG2 THR D 242      -1.492  32.983 -17.806  1.00 49.82           C  
+ATOM   8484  N   HIS D 243      -3.815  34.287 -14.303  1.00 40.84           N  
+ATOM   8485  CA  HIS D 243      -4.009  33.914 -12.912  1.00 38.27           C  
+ATOM   8486  C   HIS D 243      -5.319  33.164 -12.714  1.00 36.21           C  
+ATOM   8487  O   HIS D 243      -6.348  33.546 -13.265  1.00 33.10           O  
+ATOM   8488  CB  HIS D 243      -4.011  35.172 -12.051  1.00 39.41           C  
+ATOM   8489  CG  HIS D 243      -4.194  34.902 -10.594  1.00 41.37           C  
+ATOM   8490  ND1 HIS D 243      -3.187  34.396  -9.801  1.00 43.79           N  
+ATOM   8491  CD2 HIS D 243      -5.272  35.049  -9.788  1.00 42.07           C  
+ATOM   8492  CE1 HIS D 243      -3.637  34.244  -8.568  1.00 43.24           C  
+ATOM   8493  NE2 HIS D 243      -4.899  34.633  -8.534  1.00 43.26           N  
+ATOM   8494  N   PHE D 244      -5.274  32.098 -11.922  1.00 34.59           N  
+ATOM   8495  CA  PHE D 244      -6.461  31.300 -11.659  1.00 32.74           C  
+ATOM   8496  C   PHE D 244      -6.912  31.460 -10.225  1.00 33.26           C  
+ATOM   8497  O   PHE D 244      -6.099  31.567  -9.311  1.00 32.63           O  
+ATOM   8498  CB  PHE D 244      -6.202  29.815 -11.925  1.00 31.80           C  
+ATOM   8499  CG  PHE D 244      -5.910  29.490 -13.366  1.00 34.72           C  
+ATOM   8500  CD1 PHE D 244      -4.602  29.528 -13.855  1.00 35.03           C  
+ATOM   8501  CD2 PHE D 244      -6.941  29.111 -14.232  1.00 34.01           C  
+ATOM   8502  CE1 PHE D 244      -4.319  29.183 -15.191  1.00 34.20           C  
+ATOM   8503  CE2 PHE D 244      -6.671  28.766 -15.566  1.00 34.94           C  
+ATOM   8504  CZ  PHE D 244      -5.355  28.801 -16.044  1.00 33.83           C  
+ATOM   8505  N   VAL D 245      -8.224  31.481 -10.033  1.00 33.57           N  
+ATOM   8506  CA  VAL D 245      -8.784  31.603  -8.703  1.00 33.85           C  
+ATOM   8507  C   VAL D 245      -9.933  30.610  -8.583  1.00 33.58           C  
+ATOM   8508  O   VAL D 245     -10.810  30.550  -9.447  1.00 30.69           O  
+ATOM   8509  CB  VAL D 245      -9.280  33.052  -8.429  1.00 34.83           C  
+ATOM   8510  CG1 VAL D 245     -10.144  33.529  -9.559  1.00 39.48           C  
+ATOM   8511  CG2 VAL D 245     -10.059  33.108  -7.118  1.00 34.46           C  
+ATOM   8512  N   PRO D 246      -9.917  29.785  -7.526  1.00 32.92           N  
+ATOM   8513  CA  PRO D 246     -10.989  28.808  -7.342  1.00 33.80           C  
+ATOM   8514  C   PRO D 246     -12.252  29.532  -6.918  1.00 34.02           C  
+ATOM   8515  O   PRO D 246     -12.230  30.318  -5.976  1.00 36.22           O  
+ATOM   8516  CB  PRO D 246     -10.435  27.870  -6.266  1.00 33.61           C  
+ATOM   8517  CG  PRO D 246      -9.515  28.734  -5.494  1.00 35.82           C  
+ATOM   8518  CD  PRO D 246      -8.843  29.596  -6.537  1.00 33.55           C  
+ATOM   8519  N   LEU D 247     -13.350  29.272  -7.618  1.00 33.39           N  
+ATOM   8520  CA  LEU D 247     -14.609  29.936  -7.315  1.00 35.00           C  
+ATOM   8521  C   LEU D 247     -15.476  29.273  -6.257  1.00 34.72           C  
+ATOM   8522  O   LEU D 247     -16.394  28.530  -6.573  1.00 37.92           O  
+ATOM   8523  CB  LEU D 247     -15.413  30.115  -8.604  1.00 35.47           C  
+ATOM   8524  CG  LEU D 247     -15.368  31.500  -9.265  1.00 38.54           C  
+ATOM   8525  CD1 LEU D 247     -14.101  32.265  -8.882  1.00 38.14           C  
+ATOM   8526  CD2 LEU D 247     -15.472  31.320 -10.760  1.00 38.54           C  
+ATOM   8527  N   TYR D 248     -15.187  29.545  -4.994  1.00 34.84           N  
+ATOM   8528  CA  TYR D 248     -15.991  28.989  -3.919  1.00 33.62           C  
+ATOM   8529  C   TYR D 248     -17.348  29.673  -3.970  1.00 33.90           C  
+ATOM   8530  O   TYR D 248     -17.443  30.860  -4.284  1.00 34.17           O  
+ATOM   8531  CB  TYR D 248     -15.371  29.282  -2.557  1.00 31.60           C  
+ATOM   8532  CG  TYR D 248     -13.934  28.885  -2.425  1.00 32.70           C  
+ATOM   8533  CD1 TYR D 248     -12.942  29.850  -2.346  1.00 34.03           C  
+ATOM   8534  CD2 TYR D 248     -13.560  27.546  -2.368  1.00 30.80           C  
+ATOM   8535  CE1 TYR D 248     -11.615  29.500  -2.211  1.00 34.95           C  
+ATOM   8536  CE2 TYR D 248     -12.228  27.183  -2.235  1.00 32.69           C  
+ATOM   8537  CZ  TYR D 248     -11.262  28.170  -2.156  1.00 34.16           C  
+ATOM   8538  OH  TYR D 248      -9.935  27.845  -2.017  1.00 39.10           O  
+ATOM   8539  N   LYS D 249     -18.394  28.930  -3.641  1.00 33.75           N  
+ATOM   8540  CA  LYS D 249     -19.727  29.489  -3.637  1.00 36.21           C  
+ATOM   8541  C   LYS D 249     -19.777  30.748  -2.770  1.00 37.03           C  
+ATOM   8542  O   LYS D 249     -20.387  31.748  -3.160  1.00 36.65           O  
+ATOM   8543  CB  LYS D 249     -20.719  28.451  -3.116  1.00 39.73           C  
+ATOM   8544  CG  LYS D 249     -20.736  27.184  -3.949  1.00 44.68           C  
+ATOM   8545  CD  LYS D 249     -21.815  26.218  -3.490  1.00 51.06           C  
+ATOM   8546  CE  LYS D 249     -21.876  25.001  -4.408  1.00 52.31           C  
+ATOM   8547  NZ  LYS D 249     -20.529  24.369  -4.532  1.00 54.43           N  
+ATOM   8548  N   THR D 250     -19.129  30.697  -1.606  1.00 33.84           N  
+ATOM   8549  CA  THR D 250     -19.110  31.826  -0.676  1.00 34.29           C  
+ATOM   8550  C   THR D 250     -18.292  33.003  -1.175  1.00 37.05           C  
+ATOM   8551  O   THR D 250     -18.432  34.117  -0.674  1.00 37.25           O  
+ATOM   8552  CB  THR D 250     -18.540  31.423   0.713  1.00 35.80           C  
+ATOM   8553  OG1 THR D 250     -17.271  30.764   0.544  1.00 33.94           O  
+ATOM   8554  CG2 THR D 250     -19.516  30.513   1.451  1.00 29.77           C  
+ATOM   8555  N   LEU D 251     -17.418  32.759  -2.145  1.00 40.24           N  
+ATOM   8556  CA  LEU D 251     -16.600  33.835  -2.690  1.00 42.82           C  
+ATOM   8557  C   LEU D 251     -17.497  34.675  -3.595  1.00 44.38           C  
+ATOM   8558  O   LEU D 251     -17.336  35.889  -3.697  1.00 45.10           O  
+ATOM   8559  CB  LEU D 251     -15.439  33.274  -3.509  1.00 42.83           C  
+ATOM   8560  CG  LEU D 251     -14.065  33.937  -3.366  1.00 44.69           C  
+ATOM   8561  CD1 LEU D 251     -13.219  33.572  -4.584  1.00 42.15           C  
+ATOM   8562  CD2 LEU D 251     -14.200  35.440  -3.257  1.00 43.11           C  
+ATOM   8563  N   LEU D 252     -18.444  34.013  -4.250  1.00 45.51           N  
+ATOM   8564  CA  LEU D 252     -19.373  34.690  -5.143  1.00 48.06           C  
+ATOM   8565  C   LEU D 252     -20.510  35.287  -4.330  1.00 50.50           C  
+ATOM   8566  O   LEU D 252     -20.364  35.350  -3.091  0.00 50.33           O  
+ATOM   8567  CB  LEU D 252     -19.927  33.705  -6.177  1.00 46.91           C  
+ATOM   8568  CG  LEU D 252     -18.861  33.013  -7.034  1.00 47.34           C  
+ATOM   8569  CD1 LEU D 252     -19.518  32.057  -8.005  1.00 45.58           C  
+ATOM   8570  CD2 LEU D 252     -18.039  34.059  -7.779  1.00 47.92           C  
+TER    8571      LEU D 252                                                      
+HETATM 8572  O   HOH A 338      19.551 -16.452  58.274  1.00 71.35           O  
+HETATM 8573  O   HOH A 339       4.779 -15.972  12.301  1.00 57.80           O  
+HETATM 8574  O   HOH A 340     -11.723 -11.785  14.136  1.00 64.36           O  
+HETATM 8575  O   HOH A 341     -12.888  -5.204  15.106  1.00 63.41           O  
+HETATM 8576  O   HOH A 342       1.982  -2.892  14.187  1.00 79.88           O  
+HETATM 8577  O   HOH A 343     -16.447  -4.917  15.083  1.00 61.20           O  
+HETATM 8578  O   HOH A 344     -18.197  -3.463  16.377  1.00 67.02           O  
+HETATM 8579  O   HOH A 345       0.923  -3.946  16.469  1.00 62.26           O  
+HETATM 8580  O   HOH A 346      -3.431 -20.756  18.611  1.00 75.54           O  
+HETATM 8581  O   HOH A 347      -8.702  15.637  19.437  1.00 21.99           O  
+HETATM 8582  O   HOH A 348       5.960 -22.949  20.450  1.00 71.70           O  
+HETATM 8583  O   HOH A 349      -6.203 -17.844  21.585  1.00 52.55           O  
+HETATM 8584  O   HOH A 350     -18.020 -16.383  21.007  1.00 74.58           O  
+HETATM 8585  O   HOH A 351      -4.050  20.338  21.257  1.00 48.05           O  
+HETATM 8586  O   HOH A 352       0.887  15.559  21.937  1.00 71.32           O  
+HETATM 8587  O   HOH A 353      -9.960 -16.785  23.994  1.00 62.52           O  
+HETATM 8588  O   HOH A 354       6.797   1.235  23.375  1.00 61.24           O  
+HETATM 8589  O   HOH A 355       8.072  -3.508  25.257  1.00 69.78           O  
+HETATM 8590  O   HOH A 356       4.842  12.545  24.920  1.00 60.76           O  
+HETATM 8591  O   HOH A 357       2.181  13.476  25.582  1.00 53.14           O  
+HETATM 8592  O   HOH A 358     -28.069 -13.647  27.016  1.00 66.81           O  
+HETATM 8593  O   HOH A 359     -21.456  -1.771  28.424  1.00 63.80           O  
+HETATM 8594  O   HOH A 360      10.713   1.610  27.640  1.00 63.57           O  
+HETATM 8595  O   HOH A 361      -3.826   9.899  27.515  1.00 43.66           O  
+HETATM 8596  O   HOH A 362       2.381  -7.977  28.920  1.00 51.30           O  
+HETATM 8597  O   HOH A 363     -13.577 -32.855  28.606  1.00 67.24           O  
+HETATM 8598  O   HOH A 364     -21.191  -4.602  30.048  1.00 75.04           O  
+HETATM 8599  O   HOH A 365     -15.354  23.100  30.000  1.00 71.07           O  
+HETATM 8600  O   HOH A 366       1.272  -8.898  31.009  1.00 43.05           O  
+HETATM 8601  O   HOH A 367      10.184 -30.307  31.743  1.00 62.95           O  
+HETATM 8602  O   HOH A 368      14.062  -0.422  32.383  1.00 71.94           O  
+HETATM 8603  O   HOH A 369     -10.754  20.983  31.568  1.00 66.88           O  
+HETATM 8604  O   HOH A 370     -14.317 -44.647  35.378  1.00 77.96           O  
+HETATM 8605  O   HOH A 371     -11.766 -43.218  31.700  1.00 84.45           O  
+HETATM 8606  O   HOH A 372     -17.808  -8.245  32.769  1.00 55.88           O  
+HETATM 8607  O   HOH A 373       0.974  16.754  33.643  1.00 78.84           O  
+HETATM 8608  O   HOH A 374      -5.324  18.094  32.719  1.00 55.97           O  
+HETATM 8609  O   HOH A 375       7.177  -9.606  33.324  1.00 77.27           O  
+HETATM 8610  O   HOH A 376       8.099  18.977  36.471  1.00 79.76           O  
+HETATM 8611  O   HOH A 377     -18.376 -14.830  35.607  1.00 58.88           O  
+HETATM 8612  O   HOH A 378     -14.773 -10.980  34.364  1.00 54.42           O  
+HETATM 8613  O   HOH A 379     -19.880  -1.341  34.222  1.00 81.03           O  
+HETATM 8614  O   HOH A 380       0.967 -21.634  37.397  1.00 47.85           O  
+HETATM 8615  O   HOH A 381      -5.430  18.322  37.676  1.00 75.45           O  
+HETATM 8616  O   HOH A 382     -16.363  -7.800  37.892  1.00 64.98           O  
+HETATM 8617  O   HOH A 383      -2.995 -30.750  38.766  1.00 49.96           O  
+HETATM 8618  O   HOH A 384     -14.846 -14.784  39.449  1.00 64.21           O  
+HETATM 8619  O   HOH A 385      -4.956 -28.422  40.560  1.00 63.75           O  
+HETATM 8620  O   HOH A 386     -17.502   4.482  41.113  1.00 63.59           O  
+HETATM 8621  O   HOH A 387      -4.902  12.606  40.748  1.00 53.23           O  
+HETATM 8622  O   HOH A 388      -4.815 -43.172  40.766  1.00 81.74           O  
+HETATM 8623  O   HOH A 389      33.884 -14.101  41.701  1.00 57.05           O  
+HETATM 8624  O   HOH A 390     -19.832   5.507  41.158  1.00 66.71           O  
+HETATM 8625  O   HOH A 391      -5.820  10.102  41.646  1.00 75.40           O  
+HETATM 8626  O   HOH A 392     -21.248 -46.144  35.565  1.00 78.04           O  
+HETATM 8627  O   HOH A 393     -14.964   6.092  42.743  1.00 60.54           O  
+HETATM 8628  O   HOH A 394      -1.938 -17.686  43.500  1.00 45.48           O  
+HETATM 8629  O   HOH A 395      14.355   4.103  43.989  1.00 55.28           O  
+HETATM 8630  O   HOH A 396     -14.133 -14.928  44.441  1.00 64.30           O  
+HETATM 8631  O   HOH A 397     -16.773 -20.045  48.005  1.00 65.14           O  
+HETATM 8632  O   HOH A 398      14.449   1.504  47.550  1.00 60.90           O  
+HETATM 8633  O   HOH A 399       7.925  11.778  49.691  1.00 90.48           O  
+HETATM 8634  O   HOH A 400      -8.607  -1.806  49.680  1.00 79.95           O  
+HETATM 8635  O   HOH A 401      24.373  -3.227  50.817  1.00 71.91           O  
+HETATM 8636  O   HOH A 402     -12.542 -20.095  53.281  1.00 65.62           O  
+HETATM 8637  O   HOH A 403      -6.890 -21.710  51.752  1.00 62.58           O  
+HETATM 8638  O   HOH A 404      -1.377 -19.202  52.142  1.00 61.89           O  
+HETATM 8639  O   HOH A 405      21.192  -5.804  52.802  1.00 62.29           O  
+HETATM 8640  O   HOH A 406     -10.542 -19.305  54.798  1.00 62.93           O  
+HETATM 8641  O   HOH A 407      -9.806 -26.338  54.615  1.00 70.63           O  
+HETATM 8642  O   HOH A 408     -18.883 -30.759  53.615  1.00 62.35           O  
+HETATM 8643  O   HOH A 409      -7.398 -14.352  56.509  1.00 77.47           O  
+HETATM 8644  O   HOH A 410       4.832  -6.973  58.028  1.00 80.49           O  
+HETATM 8645  O   HOH A 411      -7.281 -17.207  59.509  1.00 68.30           O  
+HETATM 8646  O   HOH A 412      20.700 -12.402  56.727  1.00 84.54           O  
+HETATM 8647  O   HOH A 413      14.955  -7.610  58.713  1.00 68.50           O  
+HETATM 8648  O   HOH A 414       5.716 -16.551  14.749  1.00 65.63           O  
+HETATM 8649  O   HOH A 415      -6.301 -17.029  18.997  1.00 66.84           O  
+HETATM 8650  O   HOH A 416      -1.207 -28.335  24.426  1.00 67.73           O  
+HETATM 8651  O   HOH A 417     -28.506 -15.653  25.357  1.00 86.68           O  
+HETATM 8652  O   HOH A 418      14.387  -3.230  33.209  1.00 57.39           O  
+HETATM 8653  O   HOH A 419      -2.481 -42.212  39.795  1.00 73.95           O  
+HETATM 8654  O   HOH A 420      -3.668  17.860  39.706  1.00 78.06           O  
+HETATM 8655  O   HOH A 421     -20.981 -26.231  43.304  1.00 62.14           O  
+HETATM 8656  O   HOH A 422     -18.097 -19.797  45.574  1.00 74.78           O  
+HETATM 8657  O   HOH A 423     -10.377   2.224  50.107  1.00 64.55           O  
+HETATM 8658  O   HOH A 424      15.703  -1.082  50.530  1.00 66.10           O  
+HETATM 8659  O   HOH A 425       2.604  -9.361  59.501  1.00 58.87           O  
+HETATM 8660  O   HOH A 426      10.709  -6.790  27.618  1.00 79.75           O  
+HETATM 8661  O   HOH A 427      10.598  17.259  32.855  1.00 62.23           O  
+HETATM 8662  O   HOH A 428       8.228 -12.952  33.829  1.00 75.13           O  
+HETATM 8663  O   HOH A 429     -21.830 -34.753  38.531  1.00 62.44           O  
+HETATM 8664  O   HOH A 430      -8.230  18.542  41.058  1.00 81.42           O  
+HETATM 8665  O   HOH A 431     -12.252 -49.341  41.844  1.00 97.72           O  
+HETATM 8666  O   HOH A 432      -0.233 -13.784   3.082  1.00 67.02           O  
+HETATM 8667  O   HOH A 433      -9.662  -8.162   9.657  1.00 82.36           O  
+HETATM 8668  O   HOH A 434     -11.182 -13.194  16.521  1.00 64.89           O  
+HETATM 8669  O   HOH A 435       5.386   2.336  17.732  1.00 77.81           O  
+HETATM 8670  O   HOH A 436      -6.896  18.689  20.042  1.00 39.41           O  
+HETATM 8671  O   HOH A 437       1.805  17.076  31.173  1.00 79.18           O  
+HETATM 8672  O   HOH A 438       9.318  -7.465  36.095  1.00 71.50           O  
+HETATM 8673  O   HOH A 439      -2.689 -44.610  38.739  1.00 71.04           O  
+HETATM 8674  O   HOH A 440      -9.397 -41.190  39.452  1.00 80.96           O  
+HETATM 8675  O   HOH A 441     -23.740 -33.504  39.996  1.00 61.41           O  
+HETATM 8676  O   HOH A 442     -19.210 -18.606  39.485  1.00 71.90           O  
+HETATM 8677  O   HOH A 443      -2.972 -46.475  41.069  1.00 71.19           O  
+HETATM 8678  O   HOH A 444     -22.985 -24.146  41.649  1.00 68.90           O  
+HETATM 8679  O   HOH A 445      -8.584 -43.182  43.659  1.00 54.22           O  
+HETATM 8680  O   HOH A 446     -22.715 -33.387  45.479  1.00 67.99           O  
+HETATM 8681  O   HOH A 447       2.346 -16.292  45.443  1.00 66.87           O  
+HETATM 8682  O   HOH A 448     -19.633  -9.771  45.669  1.00 66.59           O  
+HETATM 8683  O   HOH A 449      22.315   0.108  46.677  1.00 62.13           O  
+HETATM 8684  O   HOH A 450     -15.385   6.815  46.520  1.00 68.89           O  
+HETATM 8685  O   HOH A 451      10.275 -22.415  48.702  1.00 75.91           O  
+HETATM 8686  O   HOH A 452       8.270 -18.235  49.112  1.00 81.16           O  
+HETATM 8687  O   HOH A 453     -17.295 -11.942  48.010  1.00 77.19           O  
+HETATM 8688  O   HOH A 454       7.336   8.502  48.162  1.00 76.47           O  
+HETATM 8689  O   HOH A 455       4.141  15.134  49.554  1.00 81.28           O  
+HETATM 8690  O   HOH A 456       4.603  13.179  51.308  1.00 90.00           O  
+HETATM 8691  O   HOH A 457     -16.026 -29.604  51.300  1.00 63.10           O  
+HETATM 8692  O   HOH A 458      -8.936 -25.300  51.684  1.00 57.98           O  
+HETATM 8693  O   HOH A 459      17.237  -2.511  52.894  1.00 70.43           O  
+HETATM 8694  O   HOH A 460      -4.971 -10.281  54.176  1.00 78.48           O  
+HETATM 8695  O   HOH A 461      14.926 -18.770  56.538  1.00 69.53           O  
+HETATM 8696  O   HOH A 462       4.309  -9.088  61.523  1.00 71.02           O  
+HETATM 8697  O   HOH A 463      -4.586 -19.792  15.151  1.00 83.73           O  
+HETATM 8698  O   HOH A 464       2.606  17.015  16.788  1.00 70.88           O  
+HETATM 8699  O   HOH A 465     -19.243  -4.047  19.350  1.00 70.63           O  
+HETATM 8700  O   HOH A 466     -29.833 -18.010  24.438  1.00 78.44           O  
+HETATM 8701  O   HOH A 467       5.899  -8.834  28.621  1.00 62.83           O  
+HETATM 8702  O   HOH A 468      -5.876  19.426  28.215  1.00 51.47           O  
+HETATM 8703  O   HOH A 469       5.842  18.277  30.559  1.00 63.03           O  
+HETATM 8704  O   HOH A 470      10.191  -9.212  32.653  1.00 68.34           O  
+HETATM 8705  O   HOH A 471     -21.146 -17.183  36.302  1.00 86.53           O  
+HETATM 8706  O   HOH A 472     -19.388 -13.059  34.261  1.00 72.71           O  
+HETATM 8707  O   HOH A 473      13.210 -12.276  36.139  1.00 77.62           O  
+HETATM 8708  O   HOH A 474     -16.768 -19.404  37.235  1.00 69.24           O  
+HETATM 8709  O   HOH A 475      13.654 -15.924  37.868  1.00 45.52           O  
+HETATM 8710  O   HOH A 476       0.235   4.715  46.844  1.00 74.93           O  
+HETATM 8711  O   HOH A 477     -23.054 -32.958  49.435  1.00 72.74           O  
+HETATM 8712  O   HOH A 478      -2.080   9.066  49.119  1.00 86.95           O  
+HETATM 8713  O   HOH A 479      -7.438 -11.225  53.420  1.00 68.27           O  
+HETATM 8714  O   HOH C 254     -21.362  37.065 -18.538  1.00 69.03           O  
+HETATM 8715  O   HOH C 255       5.135  37.613 -18.199  1.00 85.58           O  
+HETATM 8716  O   HOH C 256     -18.356  44.622 -18.526  1.00 77.04           O  
+HETATM 8717  O   HOH C 257     -17.970  35.311 -16.797  1.00 60.30           O  
+HETATM 8718  O   HOH C 258     -14.627  34.469 -17.649  1.00 80.60           O  
+HETATM 8719  O   HOH C 259       3.625  34.820 -17.082  1.00 62.34           O  
+HETATM 8720  O   HOH C 260     -26.468  35.642 -14.942  1.00 66.12           O  
+HETATM 8721  O   HOH C 261     -10.948  44.475 -13.053  1.00 87.17           O  
+HETATM 8722  O   HOH C 262      -5.806  45.834 -10.739  1.00 74.44           O  
+HETATM 8723  O   HOH C 263      -8.687  44.790 -10.080  1.00 44.14           O  
+HETATM 8724  O   HOH C 264      15.950  36.471  -8.282  1.00 56.26           O  
+HETATM 8725  O   HOH C 265       0.113  34.174  -7.920  1.00 29.52           O  
+HETATM 8726  O   HOH C 266      -6.618  35.230  -6.188  1.00 27.36           O  
+HETATM 8727  O   HOH C 267      -0.063  30.248  -5.833  1.00 38.52           O  
+HETATM 8728  O   HOH C 268     -17.771  21.661  -3.394  1.00 38.63           O  
+HETATM 8729  O   HOH C 269      -3.720  50.149  -3.184  1.00 70.65           O  
+HETATM 8730  O   HOH C 270      -7.564  30.517  -2.177  1.00 31.61           O  
+HETATM 8731  O   HOH C 271      -0.955  31.462  -3.017  1.00 55.56           O  
+HETATM 8732  O   HOH C 272      -1.908  33.499  -1.515  1.00 38.40           O  
+HETATM 8733  O   HOH C 273       0.942  47.478  -1.845  1.00 50.88           O  
+HETATM 8734  O   HOH C 274      -6.106  32.935  -1.003  1.00 32.19           O  
+HETATM 8735  O   HOH C 275       6.938  43.315  -1.325  1.00 51.13           O  
+HETATM 8736  O   HOH C 276      -6.644  46.665  -1.084  1.00 37.63           O  
+HETATM 8737  O   HOH C 277     -14.687  13.602   0.231  1.00 44.00           O  
+HETATM 8738  O   HOH C 278     -19.359  15.419  -0.829  1.00 58.78           O  
+HETATM 8739  O   HOH C 279     -17.922  28.096  -0.244  1.00 24.08           O  
+HETATM 8740  O   HOH C 280      -3.527  48.730   0.047  1.00 48.60           O  
+HETATM 8741  O   HOH C 281     -19.003   8.094   1.219  1.00 48.01           O  
+HETATM 8742  O   HOH C 282     -10.098  16.269   0.906  1.00 26.56           O  
+HETATM 8743  O   HOH C 283     -19.185  12.510   1.723  1.00 56.65           O  
+HETATM 8744  O   HOH C 284     -16.623  15.652   1.691  1.00 60.27           O  
+HETATM 8745  O   HOH C 285      -0.751  31.974   1.515  1.00 44.02           O  
+HETATM 8746  O   HOH C 286      -2.056  24.039   2.639  1.00 57.62           O  
+HETATM 8747  O   HOH C 287       3.078  47.144   2.599  1.00 34.71           O  
+HETATM 8748  O   HOH C 288       6.080  34.927   3.295  1.00 32.03           O  
+HETATM 8749  O   HOH C 289      10.041  41.658   3.245  1.00 78.15           O  
+HETATM 8750  O   HOH C 290       2.669  51.241   3.211  1.00 64.27           O  
+HETATM 8751  O   HOH C 291     -28.728  19.853   3.996  1.00 86.59           O  
+HETATM 8752  O   HOH C 292     -18.725  39.138  -4.151  1.00 39.79           O  
+HETATM 8753  O   HOH C 293     -27.448  23.375   5.393  1.00 55.01           O  
+HETATM 8754  O   HOH C 294      -0.949  17.724   5.905  1.00 66.02           O  
+HETATM 8755  O   HOH C 295      -2.056  21.516   6.133  1.00 53.69           O  
+HETATM 8756  O   HOH C 296     -14.013  -0.559  -0.311  1.00 73.33           O  
+HETATM 8757  O   HOH C 297     -28.693  20.927   6.575  1.00 66.08           O  
+HETATM 8758  O   HOH C 298      -8.135  27.041   7.220  1.00 45.67           O  
+HETATM 8759  O   HOH C 299      11.180  37.702   7.128  1.00 62.20           O  
+HETATM 8760  O   HOH C 300      -5.619  48.471   8.083  1.00 35.20           O  
+HETATM 8761  O   HOH C 301      -3.425  49.231   8.884  1.00 58.22           O  
+HETATM 8762  O   HOH C 302       6.534  21.017  16.712  1.00 68.25           O  
+HETATM 8763  O   HOH C 303     -22.101  39.678   9.153  1.00 45.64           O  
+HETATM 8764  O   HOH C 304      -3.833  12.735  10.416  1.00 71.25           O  
+HETATM 8765  O   HOH C 305     -20.720  36.901  10.010  1.00 56.00           O  
+HETATM 8766  O   HOH C 306      -7.996  13.348  10.643  1.00 23.59           O  
+HETATM 8767  O   HOH C 307     -11.950  47.997  11.526  1.00 30.50           O  
+HETATM 8768  O   HOH C 308      -9.642  48.682  11.779  1.00 61.60           O  
+HETATM 8769  O   HOH C 309      -2.340   8.974  11.914  1.00 75.21           O  
+HETATM 8770  O   HOH C 310      -9.997  22.600  11.999  1.00 26.15           O  
+HETATM 8771  O   HOH C 311     -32.189  14.310  12.961  1.00 72.26           O  
+HETATM 8772  O   HOH C 312     -30.870  32.814  11.443  1.00 65.92           O  
+HETATM 8773  O   HOH C 313       1.149  46.579  13.145  1.00 81.29           O  
+HETATM 8774  O   HOH C 314      -6.897   8.152  13.699  1.00 46.90           O  
+HETATM 8775  O   HOH C 315     -13.039  47.389  14.616  1.00 75.75           O  
+HETATM 8776  O   HOH C 316     -19.844  44.965 -15.848  1.00 50.44           O  
+HETATM 8777  O   HOH C 317      -9.830  46.872  15.868  1.00 76.94           O  
+HETATM 8778  O   HOH C 318      -3.575  -0.855  16.801  1.00 67.78           O  
+HETATM 8779  O   HOH C 319     -30.384  27.102  15.890  1.00 73.53           O  
+HETATM 8780  O   HOH C 320       8.018  44.916  16.349  1.00 80.68           O  
+HETATM 8781  O   HOH C 321      -8.014  -0.833  16.864  1.00 40.59           O  
+HETATM 8782  O   HOH C 322     -15.687   0.765  16.863  1.00 57.94           O  
+HETATM 8783  O   HOH C 323       0.728  10.367  15.917  1.00 71.44           O  
+HETATM 8784  O   HOH C 324      -4.979  13.311  17.315  1.00 41.29           O  
+HETATM 8785  O   HOH C 325     -13.778  18.623  17.253  1.00 30.81           O  
+HETATM 8786  O   HOH C 326     -27.581  19.673  17.486  1.00 66.23           O  
+HETATM 8787  O   HOH C 327      -2.531  24.239  16.566  1.00 62.47           O  
+HETATM 8788  O   HOH C 328     -32.871  20.245  18.578  1.00 74.34           O  
+HETATM 8789  O   HOH C 329     -26.903  38.038  17.890  1.00 54.39           O  
+HETATM 8790  O   HOH C 330       4.658  28.977  23.524  1.00 66.88           O  
+HETATM 8791  O   HOH C 331       4.041  47.245  19.149  1.00 77.20           O  
+HETATM 8792  O   HOH C 332     -28.420  17.994  25.277  1.00 87.20           O  
+HETATM 8793  O   HOH C 333     -23.980   3.717  25.999  1.00 46.52           O  
+HETATM 8794  O   HOH C 334     -16.315  24.527  26.908  1.00 61.99           O  
+HETATM 8795  O   HOH C 335       4.520  24.159  26.729  1.00 61.57           O  
+HETATM 8796  O   HOH C 336     -22.517  28.973  28.394  1.00 77.78           O  
+HETATM 8797  O   HOH C 337     -27.191  15.913  30.076  1.00 71.02           O  
+HETATM 8798  O   HOH C 338     -22.739  20.985  30.885  1.00 73.17           O  
+HETATM 8799  O   HOH C 339     -14.493  33.368  30.734  1.00 46.94           O  
+HETATM 8800  O   HOH C 340     -25.023  10.389  31.826  1.00 56.69           O  
+HETATM 8801  O   HOH C 341     -27.275  13.697  31.976  1.00 66.75           O  
+HETATM 8802  O   HOH C 342      -7.762  34.805  31.039  1.00 60.94           O  
+HETATM 8803  O   HOH C 343     -14.360  34.244  34.152  1.00 83.02           O  
+HETATM 8804  O   HOH C 344     -20.364  10.376  37.990  1.00 53.54           O  
+HETATM 8805  O   HOH C 345      -4.566  43.791  31.818  1.00 48.36           O  
+HETATM 8806  O   HOH C 346     -15.429  37.783 -17.098  1.00 73.83           O  
+HETATM 8807  O   HOH C 347      -2.103  51.663  -6.256  1.00 73.04           O  
+HETATM 8808  O   HOH C 348      -4.429  34.475  -2.643  1.00 26.56           O  
+HETATM 8809  O   HOH C 349     -20.106  24.745  -1.258  1.00 49.88           O  
+HETATM 8810  O   HOH C 350      -1.940  51.809  -1.338  1.00 67.74           O  
+HETATM 8811  O   HOH C 351     -19.728   5.053  -0.152  1.00 70.25           O  
+HETATM 8812  O   HOH C 352      -5.676  17.776  -1.053  1.00 44.54           O  
+HETATM 8813  O   HOH C 353       2.985  48.143   0.340  1.00 45.14           O  
+HETATM 8814  O   HOH C 354       7.145  47.240   0.844  1.00 70.10           O  
+HETATM 8815  O   HOH C 355      -8.471  12.308   1.394  1.00 44.61           O  
+HETATM 8816  O   HOH C 356       6.390  51.067   2.685  1.00 71.52           O  
+HETATM 8817  O   HOH C 357      -2.171  50.672  12.020  1.00 96.78           O  
+HETATM 8818  O   HOH C 358       8.603  42.302  11.009  1.00 76.79           O  
+HETATM 8819  O   HOH C 359     -12.458  51.468  15.881  1.00 83.23           O  
+HETATM 8820  O   HOH C 360     -22.480  -0.948  17.619  1.00 63.66           O  
+HETATM 8821  O   HOH C 361     -31.008  26.548  18.441  1.00 77.24           O  
+HETATM 8822  O   HOH C 362      10.830  23.171  25.453  1.00 75.12           O  
+HETATM 8823  O   HOH C 363     -23.912  15.881  32.931  1.00 77.54           O  
+HETATM 8824  O   HOH C 364     -23.899  18.491  33.335  1.00 77.60           O  
+HETATM 8825  O   HOH C 365     -13.154  31.748  35.772  1.00101.60           O  
+HETATM 8826  O   HOH C 366     -23.323  17.694  36.205  1.00 95.92           O  
+HETATM 8827  O   HOH C 367     -21.700   2.164  37.643  1.00 59.47           O  
+HETATM 8828  O   HOH C 368     -14.866  13.631  39.339  1.00 61.53           O  
+HETATM 8829  O   HOH C 369     -31.345  22.430   4.293  1.00 74.24           O  
+HETATM 8830  O   HOH C 370      -7.112  11.800   6.394  1.00 68.36           O  
+HETATM 8831  O   HOH C 371      -6.891  21.240   6.846  1.00 39.39           O  
+HETATM 8832  O   HOH C 372     -23.480  34.800  -7.115  1.00 47.72           O  
+HETATM 8833  O   HOH C 373     -30.356  32.576   8.238  1.00 66.33           O  
+HETATM 8834  O   HOH C 374      -5.422  52.128  11.397  1.00 68.53           O  
+HETATM 8835  O   HOH C 375     -34.152  10.808  11.596  1.00 62.04           O  
+HETATM 8836  O   HOH C 376     -27.292  21.622  14.319  1.00 58.84           O  
+HETATM 8837  O   HOH C 377      -4.929  21.370  15.658  1.00 47.95           O  
+HETATM 8838  O   HOH C 378     -31.809  20.394  15.644  1.00100.97           O  
+HETATM 8839  O   HOH C 379     -28.645  22.157  17.749  1.00 77.49           O  
+HETATM 8840  O   HOH C 380      -5.182  47.110  19.476  1.00 69.47           O  
+HETATM 8841  O   HOH C 381     -14.349  29.063  28.060  1.00 61.49           O  
+HETATM 8842  O   HOH C 382     -20.124  29.862  29.551  1.00 69.25           O  
+HETATM 8843  O   HOH C 383      13.228  46.530  -9.688  1.00 78.62           O  
+HETATM 8844  O   HOH C 384     -21.054   9.543   0.057  1.00124.16           O  
+HETATM 8845  O   HOH C 385     -27.622  13.670  -0.949  1.00 82.18           O  
+HETATM 8846  O   HOH C 386       4.269  35.767   7.480  1.00 47.93           O  
+HETATM 8847  O   HOH C 387     -31.698  23.431  10.683  1.00 65.00           O  
+HETATM 8848  O   HOH C 388       2.659  21.358  17.026  1.00 71.71           O  
+HETATM 8849  O   HOH C 389     -31.805  23.847  14.705  1.00 91.52           O  
+HETATM 8850  O   HOH C 390      13.284  23.497  24.353  1.00 85.22           O  
+HETATM 8851  O   HOH C 391     -35.158  16.403  25.343  1.00 72.99           O  
+HETATM 8852  O   HOH C 392     -23.554  30.703  29.951  1.00 90.80           O  
+HETATM 8853  O   HOH C 393     -25.242  13.396  33.615  1.00 78.60           O  
+HETATM 8854  O   HOH C 394     -29.518  14.901  32.717  1.00 82.68           O  
+HETATM 8855  O   HOH C 395     -25.906  15.999  35.382  1.00 81.24           O  
+HETATM 8856  O   HOH C 396       2.367  33.332  27.520  1.00 36.76           O  
+HETATM 8857  O   HOH C 397     -20.954  34.469 -19.029  1.00 70.41           O  
+HETATM 8858  O   HOH C 398       0.021  52.404  -4.799  1.00 88.57           O  
+HETATM 8859  O   HOH C 399       1.527  48.964  -4.235  1.00 55.80           O  
+HETATM 8860  O   HOH C 400     -16.775   6.855   1.121  1.00 86.24           O  
+HETATM 8861  O   HOH C 401      12.643  48.173   1.109  1.00 78.59           O  
+HETATM 8862  O   HOH C 402       1.371  31.356   3.243  1.00 46.32           O  
+HETATM 8863  O   HOH C 403     -16.106  40.437  -2.965  1.00 49.45           O  
+HETATM 8864  O   HOH C 404     -21.026  17.530   4.129  1.00 55.27           O  
+HETATM 8865  O   HOH C 405      -8.605  -1.394   7.080  1.00 78.89           O  
+HETATM 8866  O   HOH C 406       5.487  47.165   7.173  1.00 62.49           O  
+HETATM 8867  O   HOH C 407     -36.371  10.664   7.160  1.00 84.93           O  
+HETATM 8868  O   HOH C 408      -6.112  55.117  -8.713  1.00 61.22           O  
+HETATM 8869  O   HOH C 409     -21.954  -2.984   9.526  1.00 77.29           O  
+HETATM 8870  O   HOH C 410       8.137  45.705   9.997  1.00 80.12           O  
+HETATM 8871  O   HOH C 411     -30.032  21.474  13.226  1.00 71.58           O  
+HETATM 8872  O   HOH C 412     -22.522  39.003  14.025  1.00 54.53           O  
+HETATM 8873  O   HOH C 413      12.374  44.044  12.625  1.00 80.50           O  
+HETATM 8874  O   HOH C 414     -17.242   0.037  14.692  1.00 55.16           O  
+HETATM 8875  O   HOH C 415     -35.267  29.195  14.451  1.00 82.42           O  
+HETATM 8876  O   HOH C 416       1.309  28.743  15.291  1.00 46.62           O  
+HETATM 8877  O   HOH C 417       3.668   7.790  16.090  1.00 80.64           O  
+HETATM 8878  O   HOH C 418     -32.967  24.801  12.528  1.00 84.33           O  
+HETATM 8879  O   HOH C 419     -33.268  10.146  21.762  1.00 67.92           O  
+HETATM 8880  O   HOH C 420     -29.981  16.259  28.726  1.00 85.38           O  
+HETATM 8881  O   HOH C 421       4.126  31.041  38.008  1.00 61.78           O  
+HETATM 8882  O   HOH C 422     -12.694  11.519  42.964  1.00 78.83           O  
+HETATM 8883  O   HOH C 423       6.925  47.186  14.739  1.00 72.44           O  
+HETATM 8884  O   HOH B 338      49.345  23.009  22.413  1.00 67.14           O  
+HETATM 8885  O   HOH B 339       9.353  -2.345  -4.758  1.00 72.56           O  
+HETATM 8886  O   HOH B 340      26.001   5.349  -3.302  1.00 42.05           O  
+HETATM 8887  O   HOH B 341      18.644  -6.942  -1.377  1.00 55.88           O  
+HETATM 8888  O   HOH B 342      10.706  11.305   0.538  1.00 51.60           O  
+HETATM 8889  O   HOH B 343      22.501  -8.546   2.403  1.00 62.60           O  
+HETATM 8890  O   HOH B 344      28.320  -4.253   1.570  1.00 53.34           O  
+HETATM 8891  O   HOH B 345      16.096  -1.260   1.334  1.00 70.89           O  
+HETATM 8892  O   HOH B 346      26.509  -7.279   2.600  1.00 78.11           O  
+HETATM 8893  O   HOH B 347      27.102  -2.002   2.236  1.00 56.60           O  
+HETATM 8894  O   HOH B 348      14.332   2.777   2.360  1.00 65.17           O  
+HETATM 8895  O   HOH B 349      25.330  -8.759   4.832  1.00 60.88           O  
+HETATM 8896  O   HOH B 350      12.312   3.995   5.223  1.00 77.28           O  
+HETATM 8897  O   HOH B 351       3.294  -1.447   8.087  1.00 80.37           O  
+HETATM 8898  O   HOH B 352      10.735   1.854   8.171  1.00 46.52           O  
+HETATM 8899  O   HOH B 353      18.026   2.913   8.316  1.00 38.52           O  
+HETATM 8900  O   HOH B 354      10.923   4.559   9.366  1.00 60.50           O  
+HETATM 8901  O   HOH B 355       9.222   1.309  10.558  1.00 55.00           O  
+HETATM 8902  O   HOH B 356      37.614  10.371   9.821  1.00 54.72           O  
+HETATM 8903  O   HOH B 357      35.373   7.501  11.821  1.00 40.30           O  
+HETATM 8904  O   HOH B 358      14.098 -21.067  17.507  1.00 76.07           O  
+HETATM 8905  O   HOH B 359      33.113 -19.754  17.414  1.00 64.81           O  
+HETATM 8906  O   HOH B 360      30.187  20.013  17.011  1.00 62.82           O  
+HETATM 8907  O   HOH B 361      38.312 -15.172  18.337  1.00 61.94           O  
+HETATM 8908  O   HOH B 362      44.745 -14.848  18.348  1.00 66.24           O  
+HETATM 8909  O   HOH B 363      39.383   4.957  17.827  1.00 58.70           O  
+HETATM 8910  O   HOH B 364      37.252 -21.604  19.730  1.00 70.01           O  
+HETATM 8911  O   HOH B 365      13.228  10.341  17.685  1.00 72.60           O  
+HETATM 8912  O   HOH B 366      20.233  12.596  19.431  1.00 48.01           O  
+HETATM 8913  O   HOH B 367      35.246 -24.587  20.143  1.00 77.97           O  
+HETATM 8914  O   HOH B 368      12.123   9.368  20.028  1.00 54.16           O  
+HETATM 8915  O   HOH B 369      21.555  12.034  21.625  1.00 49.91           O  
+HETATM 8916  O   HOH B 370      41.656 -21.476  21.343  1.00 72.78           O  
+HETATM 8917  O   HOH B 371      17.722  13.499  20.430  1.00 84.84           O  
+HETATM 8918  O   HOH B 372      39.459   2.226  22.544  1.00 47.67           O  
+HETATM 8919  O   HOH B 373      21.013   8.653  23.367  1.00 51.51           O  
+HETATM 8920  O   HOH B 374      30.322  21.088  22.971  1.00 60.34           O  
+HETATM 8921  O   HOH B 375      44.084   3.319  21.482  1.00 71.94           O  
+HETATM 8922  O   HOH B 376      43.386  23.902  24.438  1.00 75.26           O  
+HETATM 8923  O   HOH B 377      49.979 -15.444  25.387  1.00 72.43           O  
+HETATM 8924  O   HOH B 378      50.310 -11.301  26.980  1.00 63.94           O  
+HETATM 8925  O   HOH B 379      15.787  -6.801  26.083  1.00 80.66           O  
+HETATM 8926  O   HOH B 380      24.604  -1.817  26.870  1.00 27.07           O  
+HETATM 8927  O   HOH B 381      14.858   0.468  26.371  1.00 70.21           O  
+HETATM 8928  O   HOH B 382      38.410 -28.875  28.645  1.00 77.72           O  
+HETATM 8929  O   HOH B 383      19.113  -9.723  28.390  1.00 77.35           O  
+HETATM 8930  O   HOH B 384      17.736 -13.939  29.578  1.00 59.77           O  
+HETATM 8931  O   HOH B 385      37.975 -24.915  29.733  1.00 75.50           O  
+HETATM 8932  O   HOH B 386      32.375 -15.816  30.105  1.00 54.78           O  
+HETATM 8933  O   HOH B 387      33.458   8.923  30.613  1.00 42.99           O  
+HETATM 8934  O   HOH B 388      16.955 -14.313  34.108  1.00 74.72           O  
+HETATM 8935  O   HOH B 389      17.464  -3.069  33.243  1.00 48.01           O  
+HETATM 8936  O   HOH B 390      25.866   2.631  32.767  1.00 37.84           O  
+HETATM 8937  O   HOH B 391      15.740 -30.956  38.978  1.00 71.18           O  
+HETATM 8938  O   HOH B 392      30.430 -23.449  38.043  1.00 84.31           O  
+HETATM 8939  O   HOH B 393      40.031  -9.648  38.201  1.00 67.76           O  
+HETATM 8940  O   HOH B 394      17.161   9.818  39.646  1.00 59.59           O  
+HETATM 8941  O   HOH B 395      17.854 -29.497  43.156  1.00 60.39           O  
+HETATM 8942  O   HOH B 396      23.496   6.842  41.793  1.00 64.32           O  
+HETATM 8943  O   HOH B 397      30.519   7.126  43.494  1.00 66.62           O  
+HETATM 8944  O   HOH B 398      32.622  -5.109  43.893  1.00 58.34           O  
+HETATM 8945  O   HOH B 399      26.468   3.135  43.597  1.00 64.92           O  
+HETATM 8946  O   HOH B 400      39.149   5.591  44.122  1.00 65.96           O  
+HETATM 8947  O   HOH B 401      45.893 -11.289  48.807  1.00 93.66           O  
+HETATM 8948  O   HOH B 402      35.203   4.752  48.082  1.00 66.72           O  
+HETATM 8949  O   HOH B 403      31.194   2.487  50.978  1.00 64.77           O  
+HETATM 8950  O   HOH B 404      30.438  -5.398   0.471  1.00 71.84           O  
+HETATM 8951  O   HOH B 405      29.181  -6.751   2.276  1.00 80.25           O  
+HETATM 8952  O   HOH B 406      14.197  -2.993   2.729  1.00 76.00           O  
+HETATM 8953  O   HOH B 407      10.753  11.940   3.206  1.00 42.85           O  
+HETATM 8954  O   HOH B 408      14.431   4.770   4.084  1.00 52.58           O  
+HETATM 8955  O   HOH B 409      20.987 -26.339  11.945  1.00 74.98           O  
+HETATM 8956  O   HOH B 410      40.121   6.182  14.009  1.00 74.53           O  
+HETATM 8957  O   HOH B 411      47.167 -15.383  16.726  1.00 68.85           O  
+HETATM 8958  O   HOH B 412      40.060   0.002  16.120  1.00 48.38           O  
+HETATM 8959  O   HOH B 413      37.751 -27.029  17.377  1.00 78.28           O  
+HETATM 8960  O   HOH B 414      36.207 -15.596  16.836  1.00 66.01           O  
+HETATM 8961  O   HOH B 415      14.369 -19.433  19.728  1.00 74.52           O  
+HETATM 8962  O   HOH B 416      50.307 -15.764  17.766  1.00 72.43           O  
+HETATM 8963  O   HOH B 417      40.417  -0.323  18.653  1.00 61.21           O  
+HETATM 8964  O   HOH B 418      39.287   3.580  20.212  1.00 51.27           O  
+HETATM 8965  O   HOH B 419       9.955   7.592  20.708  1.00 73.06           O  
+HETATM 8966  O   HOH B 420      30.987 -27.247  22.146  1.00 71.31           O  
+HETATM 8967  O   HOH B 421      17.061  18.490  21.445  1.00 70.25           O  
+HETATM 8968  O   HOH B 422      12.309  -4.083  21.005  1.00 69.39           O  
+HETATM 8969  O   HOH B 423      47.386   0.359  23.470  1.00 83.22           O  
+HETATM 8970  O   HOH B 424      50.000 -14.454  27.754  1.00 59.11           O  
+HETATM 8971  O   HOH B 425      16.358  -4.896  28.071  1.00 83.31           O  
+HETATM 8972  O   HOH B 426      37.551  16.361  26.876  1.00 63.06           O  
+HETATM 8973  O   HOH B 427      15.666  -8.957  29.176  1.00 91.56           O  
+HETATM 8974  O   HOH B 428      18.767 -33.278  33.436  1.00 88.61           O  
+HETATM 8975  O   HOH B 429      32.836 -14.384  32.154  1.00 53.71           O  
+HETATM 8976  O   HOH B 430      28.953  13.186  32.692  1.00 59.52           O  
+HETATM 8977  O   HOH B 431      28.406 -26.381  34.096  1.00 79.43           O  
+HETATM 8978  O   HOH B 432      15.466  24.246  35.001  1.00 66.45           O  
+HETATM 8979  O   HOH B 433      15.933 -32.846  36.039  1.00 90.75           O  
+HETATM 8980  O   HOH B 434      11.982 -30.715  36.441  1.00 69.27           O  
+HETATM 8981  O   HOH B 435      33.463 -24.639  37.480  1.00 72.55           O  
+HETATM 8982  O   HOH B 436      20.934   6.151  43.057  1.00 72.97           O  
+HETATM 8983  O   HOH B 437      30.955 -22.438  46.354  1.00 68.77           O  
+HETATM 8984  O   HOH B 438       9.282   3.685   6.074  1.00 76.71           O  
+HETATM 8985  O   HOH B 439      10.516   6.040   6.092  1.00 77.20           O  
+HETATM 8986  O   HOH B 440      35.850  23.429  14.874  1.00 56.37           O  
+HETATM 8987  O   HOH B 441      11.898 -19.840  15.699  1.00 68.13           O  
+HETATM 8988  O   HOH B 442      39.546  25.089  18.043  1.00 86.01           O  
+HETATM 8989  O   HOH B 443      50.295 -14.792  30.483  1.00 84.67           O  
+HETATM 8990  O   HOH B 444      25.848  -7.110  27.278  1.00 42.99           O  
+HETATM 8991  O   HOH B 445      51.532  -7.697  27.760  1.00 89.28           O  
+HETATM 8992  O   HOH B 446      48.733  -2.076  28.424  1.00 81.65           O  
+HETATM 8993  O   HOH B 447      30.828  14.141  28.409  1.00 62.23           O  
+HETATM 8994  O   HOH B 448      43.901 -17.657  30.821  1.00 68.07           O  
+HETATM 8995  O   HOH B 449      26.703  15.510  32.260  1.00 67.83           O  
+HETATM 8996  O   HOH B 450      40.175 -13.757  40.510  1.00 64.68           O  
+HETATM 8997  O   HOH B 451      31.277  -7.686  -0.975  1.00 81.37           O  
+HETATM 8998  O   HOH B 452      18.277  -1.408  -0.650  1.00 57.24           O  
+HETATM 8999  O   HOH B 453      46.982  -3.836  16.742  1.00 73.24           O  
+HETATM 9000  O   HOH B 454      44.372   2.216  18.276  1.00 68.21           O  
+HETATM 9001  O   HOH B 455      49.035   0.903  18.051  1.00 80.72           O  
+HETATM 9002  O   HOH B 456      12.005   1.800  20.533  1.00 70.76           O  
+HETATM 9003  O   HOH B 457      13.429  18.745  21.438  1.00 81.09           O  
+HETATM 9004  O   HOH B 458      19.090 -12.565  31.857  1.00 64.90           O  
+HETATM 9005  O   HOH B 459      31.285 -25.103  35.487  1.00 79.58           O  
+HETATM 9006  O   HOH B 460      27.446 -34.504  37.027  1.00 79.98           O  
+HETATM 9007  O   HOH B 461      34.940 -22.432  37.019  1.00 72.39           O  
+HETATM 9008  O   HOH B 462      24.024  10.364  38.045  1.00 68.50           O  
+HETATM 9009  O   HOH B 463      29.735 -18.394  40.321  1.00 75.49           O  
+HETATM 9010  O   HOH B 464      32.857   9.199  42.766  1.00 86.90           O  
+HETATM 9011  O   HOH B 465      21.065   9.117  43.419  1.00 75.58           O  
+HETATM 9012  O   HOH B 466      44.830   9.116  42.689  1.00 66.80           O  
+HETATM 9013  O   HOH B 467      24.215   8.356  44.039  1.00 74.04           O  
+HETATM 9014  O   HOH B 468      42.041   4.215  48.727  1.00 82.65           O  
+HETATM 9015  O   HOH B 469      42.395   8.747  47.954  1.00 69.19           O  
+HETATM 9016  O   HOH B 470      37.889   8.210  53.162  1.00 75.62           O  
+HETATM 9017  O   HOH B 471      29.561 -24.777  44.703  1.00 76.67           O  
+HETATM 9018  O   HOH B 472      33.000 -24.318  47.815  1.00 71.81           O  
+HETATM 9019  O   HOH B 473      10.668  -1.445  -2.745  1.00 84.29           O  
+HETATM 9020  O   HOH B 474      18.760  -7.855   1.095  1.00 67.01           O  
+HETATM 9021  O   HOH B 475      27.221 -10.195   1.257  1.00 80.80           O  
+HETATM 9022  O   HOH B 476      32.478 -11.324   2.202  1.00 69.68           O  
+HETATM 9023  O   HOH B 477      43.210  -3.189  11.330  1.00 61.53           O  
+HETATM 9024  O   HOH B 478      20.065 -25.766  15.015  1.00 90.94           O  
+HETATM 9025  O   HOH B 479      36.955 -14.146  12.660  1.00 72.12           O  
+HETATM 9026  O   HOH B 480      24.374 -21.020  13.786  1.00 73.07           O  
+HETATM 9027  O   HOH B 481      39.705  24.310  15.185  1.00 84.00           O  
+HETATM 9028  O   HOH B 482      11.033 -21.948  14.410  1.00 76.30           O  
+HETATM 9029  O   HOH B 483      22.278 -26.661  16.587  1.00 73.24           O  
+HETATM 9030  O   HOH B 484      38.613 -24.343  15.714  1.00 86.89           O  
+HETATM 9031  O   HOH B 485      21.818 -23.536  16.316  1.00 85.44           O  
+HETATM 9032  O   HOH B 486      23.674   7.182  15.664  1.00 32.21           O  
+HETATM 9033  O   HOH B 487      42.793 -23.481  20.097  1.00 75.14           O  
+HETATM 9034  O   HOH B 488      44.771   0.061  21.296  1.00 88.45           O  
+HETATM 9035  O   HOH B 489      42.593  -0.179  19.778  1.00 60.78           O  
+HETATM 9036  O   HOH B 490      31.929  23.182  19.224  1.00 76.50           O  
+HETATM 9037  O   HOH B 491      47.090  -0.340  19.456  1.00 81.70           O  
+HETATM 9038  O   HOH B 492      47.253  -7.995  20.711  1.00 71.17           O  
+HETATM 9039  O   HOH B 493      46.067   1.362  27.215  1.00 62.13           O  
+HETATM 9040  O   HOH B 494      44.901 -23.946  25.297  1.00 80.41           O  
+HETATM 9041  O   HOH B 495      28.702  24.849  25.535  1.00 74.63           O  
+HETATM 9042  O   HOH B 496      41.525 -26.840  28.366  1.00 88.66           O  
+HETATM 9043  O   HOH B 497      19.666  -1.763  28.706  1.00 57.30           O  
+HETATM 9044  O   HOH B 498      18.299 -14.555  36.418  1.00 60.63           O  
+HETATM 9045  O   HOH B 499      31.090   7.537  36.636  1.00 71.93           O  
+HETATM 9046  O   HOH D 254       6.581  16.085 -27.660  1.00 68.98           O  
+HETATM 9047  O   HOH D 255       8.940  20.557 -27.161  1.00 45.52           O  
+HETATM 9048  O   HOH D 256       0.377  20.863 -26.139  1.00 35.99           O  
+HETATM 9049  O   HOH D 257       5.279  13.789 -25.232  1.00 73.75           O  
+HETATM 9050  O   HOH D 258       8.071  24.900 -24.396  1.00 46.52           O  
+HETATM 9051  O   HOH D 259      -6.603  20.551 -23.707  1.00 53.17           O  
+HETATM 9052  O   HOH D 260      17.641  22.175 -24.816  1.00 91.25           O  
+HETATM 9053  O   HOH D 261      12.860  25.679 -22.821  1.00 71.39           O  
+HETATM 9054  O   HOH D 262      -2.450  13.808 -22.733  1.00 45.52           O  
+HETATM 9055  O   HOH D 263       4.063  26.434 -22.517  1.00 50.72           O  
+HETATM 9056  O   HOH D 264      -2.732  34.406 -22.412  1.00 67.29           O  
+HETATM 9057  O   HOH D 265      20.325  22.002 -24.454  1.00 59.90           O  
+HETATM 9058  O   HOH D 266      11.776  27.384 -20.969  1.00 59.94           O  
+HETATM 9059  O   HOH D 267      -8.668  18.004 -17.090  1.00 54.96           O  
+HETATM 9060  O   HOH D 268       1.140  33.972 -18.458  1.00 47.66           O  
+HETATM 9061  O   HOH D 269      -9.045  38.703 -18.285  1.00 49.50           O  
+HETATM 9062  O   HOH D 270       7.349  34.732 -17.866  1.00 77.15           O  
+HETATM 9063  O   HOH D 271      26.073  25.780 -17.187  1.00 70.07           O  
+HETATM 9064  O   HOH D 272     -14.723  30.661 -16.169  1.00 71.66           O  
+HETATM 9065  O   HOH D 273       5.484  33.011 -16.660  1.00 56.05           O  
+HETATM 9066  O   HOH D 274      25.097  22.399 -13.477  1.00 69.94           O  
+HETATM 9067  O   HOH D 275      18.431  35.280 -16.301  1.00 64.66           O  
+HETATM 9068  O   HOH D 276      15.067  33.296 -11.720  1.00 34.41           O  
+HETATM 9069  O   HOH D 277      24.449  24.901  -9.969  1.00 57.01           O  
+HETATM 9070  O   HOH D 278      13.218  35.316 -10.701  1.00 49.89           O  
+HETATM 9071  O   HOH D 279      27.755  20.763  -8.998  1.00 56.04           O  
+HETATM 9072  O   HOH D 280      33.260  14.893  -8.547  1.00 40.58           O  
+HETATM 9073  O   HOH D 281      19.421  30.997  -8.448  1.00 42.84           O  
+HETATM 9074  O   HOH D 282      29.763   5.010  -7.687  1.00 59.83           O  
+HETATM 9075  O   HOH D 283      44.267  14.547  -4.427  1.00 79.97           O  
+HETATM 9076  O   HOH D 284      -2.218  14.117  -8.208  1.00 32.95           O  
+HETATM 9077  O   HOH D 285      -5.391  28.847  -8.036  1.00 52.88           O  
+HETATM 9078  O   HOH D 286      38.152   3.500  -7.379  1.00 78.39           O  
+HETATM 9079  O   HOH D 287     -19.067  23.415  -6.917  1.00 67.48           O  
+HETATM 9080  O   HOH D 288      20.605  31.270  -6.004  1.00 36.99           O  
+HETATM 9081  O   HOH D 289      -5.903  32.453  -6.767  1.00 49.81           O  
+HETATM 9082  O   HOH D 290      -1.291  32.239  -6.165  1.00 28.65           O  
+HETATM 9083  O   HOH D 291      12.488  35.395  -5.913  1.00 34.63           O  
+HETATM 9084  O   HOH D 292      -0.144  10.063  -5.253  1.00 51.34           O  
+HETATM 9085  O   HOH D 293      38.042  12.632  -5.702  1.00 65.09           O  
+HETATM 9086  O   HOH D 294     -11.415  19.228  -5.392  1.00 36.29           O  
+HETATM 9087  O   HOH D 295     -22.348  30.632  -5.165  1.00 52.50           O  
+HETATM 9088  O   HOH D 296      25.827  11.203  -4.999  1.00 49.59           O  
+HETATM 9089  O   HOH D 297       1.826  22.999  -4.470  1.00 37.53           O  
+HETATM 9090  O   HOH D 298       5.152  22.670  -4.745  1.00 38.47           O  
+HETATM 9091  O   HOH D 299       7.534  12.126  -4.301  1.00 73.89           O  
+HETATM 9092  O   HOH D 300      -5.674  21.367  -3.888  1.00 38.68           O  
+HETATM 9093  O   HOH D 301      35.353  11.062  -3.065  1.00 30.35           O  
+HETATM 9094  O   HOH D 302      10.785  19.216  -2.890  1.00 23.72           O  
+HETATM 9095  O   HOH D 303      19.739  34.021  -3.030  1.00 53.04           O  
+HETATM 9096  O   HOH D 304      13.454  37.253  -1.971  1.00 40.94           O  
+HETATM 9097  O   HOH D 305      -0.435  44.238 -19.936  1.00 71.00           O  
+HETATM 9098  O   HOH D 306      -1.697   3.682  -1.798  1.00 77.81           O  
+HETATM 9099  O   HOH D 307      17.749  16.251  -1.603  1.00 22.19           O  
+HETATM 9100  O   HOH D 308       7.582  -1.296  -0.673  1.00 88.26           O  
+HETATM 9101  O   HOH D 309      20.369  36.007  -1.151  1.00 70.72           O  
+HETATM 9102  O   HOH D 310      -4.154   9.051  -0.349  1.00 64.01           O  
+HETATM 9103  O   HOH D 311      -1.863  10.438   0.085  1.00 78.93           O  
+HETATM 9104  O   HOH D 312      41.137  14.687   0.540  1.00 45.94           O  
+HETATM 9105  O   HOH D 313      17.756  32.590   0.151  1.00 36.24           O  
+HETATM 9106  O   HOH D 314      17.180  34.796  -1.219  1.00 58.79           O  
+HETATM 9107  O   HOH D 315      26.128  35.126   0.000  1.00 47.32           O  
+HETATM 9108  O   HOH D 316       6.965  22.206   0.959  1.00 42.12           O  
+HETATM 9109  O   HOH D 317      -0.337  24.418   0.438  1.00 57.91           O  
+HETATM 9110  O   HOH D 318      39.046   0.595   1.925  1.00 61.80           O  
+HETATM 9111  O   HOH D 319      15.963  12.296   2.733  1.00 17.15           O  
+HETATM 9112  O   HOH D 320       9.388  21.882   2.188  1.00 33.85           O  
+HETATM 9113  O   HOH D 321      16.356  32.157   2.300  1.00 51.06           O  
+HETATM 9114  O   HOH D 322      20.303  33.446   0.956  1.00 55.19           O  
+HETATM 9115  O   HOH D 323      39.902   2.296   4.217  1.00 70.41           O  
+HETATM 9116  O   HOH D 324       9.038  14.172   2.626  1.00 39.38           O  
+HETATM 9117  O   HOH D 325      13.064  12.705   3.730  1.00 31.82           O  
+HETATM 9118  O   HOH D 326      39.331  16.277   3.767  1.00 47.33           O  
+HETATM 9119  O   HOH D 327      12.376  20.776   3.830  1.00 28.89           O  
+HETATM 9120  O   HOH D 328      18.398  32.427   4.335  1.00 41.37           O  
+HETATM 9121  O   HOH D 329      34.392  -5.495   4.371  1.00 56.66           O  
+HETATM 9122  O   HOH D 330      37.414  21.840   4.302  1.00 61.68           O  
+HETATM 9123  O   HOH D 331      10.597  22.809   4.365  1.00 35.23           O  
+HETATM 9124  O   HOH D 332      36.372  -3.614   5.099  1.00 66.52           O  
+HETATM 9125  O   HOH D 333      36.629  13.096   5.491  1.00 35.55           O  
+HETATM 9126  O   HOH D 334       9.076  28.993   5.294  1.00 13.62           O  
+HETATM 9127  O   HOH D 335       8.499  35.472   5.192  1.00 57.62           O  
+HETATM 9128  O   HOH D 336      13.572  12.203   6.555  1.00 37.08           O  
+HETATM 9129  O   HOH D 337      12.803  19.437   6.323  1.00 18.72           O  
+HETATM 9130  O   HOH D 338      38.088  19.197   5.852  1.00 69.02           O  
+HETATM 9131  O   HOH D 339      36.213  21.209   6.314  1.00 61.33           O  
+HETATM 9132  O   HOH D 340      13.698  31.898   5.926  1.00 41.52           O  
+HETATM 9133  O   HOH D 341      27.493  13.847   5.753  1.00 38.27           O  
+HETATM 9134  O   HOH D 342      28.969  28.574  -6.748  1.00 40.12           O  
+HETATM 9135  O   HOH D 343      -5.802  -2.178   7.711  1.00 81.63           O  
+HETATM 9136  O   HOH D 344       8.510  27.203   8.562  1.00 62.35           O  
+HETATM 9137  O   HOH D 345       9.447  18.751   9.022  1.00 64.60           O  
+HETATM 9138  O   HOH D 346      19.356  32.524   9.165  1.00 44.10           O  
+HETATM 9139  O   HOH D 347      26.904  28.201  10.084  1.00 28.42           O  
+HETATM 9140  O   HOH D 348      15.490  16.684  10.918  1.00 45.00           O  
+HETATM 9141  O   HOH D 349      12.267  19.830  12.951  1.00 55.66           O  
+HETATM 9142  O   HOH D 350      19.515  19.040  12.406  1.00 35.14           O  
+HETATM 9143  O   HOH D 351      13.259  16.890  13.195  1.00 58.30           O  
+HETATM 9144  O   HOH D 352      27.601  17.424  13.209  1.00 52.39           O  
+HETATM 9145  O   HOH D 353      29.168  20.944  12.941  1.00 50.15           O  
+HETATM 9146  O   HOH D 354      13.203  26.312  13.294  1.00 48.76           O  
+HETATM 9147  O   HOH D 355      22.073  14.531  17.855  1.00 30.59           O  
+HETATM 9148  O   HOH D 356      22.485  15.258 -19.935  1.00 59.56           O  
+HETATM 9149  O   HOH D 357      -1.814  14.187 -26.384  1.00 70.70           O  
+HETATM 9150  O   HOH D 358     -10.574  18.622 -24.974  1.00 80.31           O  
+HETATM 9151  O   HOH D 359      -3.996  32.124 -22.721  1.00 77.57           O  
+HETATM 9152  O   HOH D 360       5.682  48.008 -22.546  1.00 79.58           O  
+HETATM 9153  O   HOH D 361      -4.820  12.605 -21.832  1.00 54.78           O  
+HETATM 9154  O   HOH D 362     -11.420  27.532 -20.807  1.00 51.99           O  
+HETATM 9155  O   HOH D 363      -9.976  33.708 -19.987  1.00 73.19           O  
+HETATM 9156  O   HOH D 364     -11.559  31.307 -19.501  1.00 58.20           O  
+HETATM 9157  O   HOH D 365      -2.806  -7.112 -18.646  1.00 75.47           O  
+HETATM 9158  O   HOH D 366       8.143  -2.829 -15.920  1.00 72.04           O  
+HETATM 9159  O   HOH D 367      -7.021   3.020 -16.070  1.00 71.85           O  
+HETATM 9160  O   HOH D 368     -16.129  19.880 -15.560  1.00 60.63           O  
+HETATM 9161  O   HOH D 369     -15.246  28.128 -14.990  1.00 59.40           O  
+HETATM 9162  O   HOH D 370      20.510   3.903 -10.415  1.00 71.87           O  
+HETATM 9163  O   HOH D 371     -11.560   7.415 -11.704  1.00 84.27           O  
+HETATM 9164  O   HOH D 372      36.911  10.463 -10.871  1.00 83.30           O  
+HETATM 9165  O   HOH D 373      35.767   8.778  -9.203  1.00 80.16           O  
+HETATM 9166  O   HOH D 374      -2.562   5.445  -8.755  1.00 64.60           O  
+HETATM 9167  O   HOH D 375       9.442  33.774  -8.237  1.00 23.03           O  
+HETATM 9168  O   HOH D 376      10.709  48.259  -8.637  1.00 68.48           O  
+HETATM 9169  O   HOH D 377      19.670  13.751  -5.095  1.00 43.54           O  
+HETATM 9170  O   HOH D 378     -15.738  15.633  -6.398  1.00 69.45           O  
+HETATM 9171  O   HOH D 379      -5.761  27.089  -6.210  1.00 54.15           O  
+HETATM 9172  O   HOH D 380       9.581  42.710  -3.774  1.00 63.69           O  
+HETATM 9173  O   HOH D 381      31.865   1.745  -3.697  1.00 58.64           O  
+HETATM 9174  O   HOH D 382     -11.682  10.160  -1.586  1.00 63.51           O  
+HETATM 9175  O   HOH D 383      35.187   1.022  -0.647  1.00 40.02           O  
+HETATM 9176  O   HOH D 384       8.994  13.120  -0.614  1.00 46.41           O  
+HETATM 9177  O   HOH D 385      37.883   2.473  -0.725  1.00 61.66           O  
+HETATM 9178  O   HOH D 386      -4.259   5.156  -0.310  1.00 75.69           O  
+HETATM 9179  O   HOH D 387      37.876  -1.741   3.995  1.00 65.51           O  
+HETATM 9180  O   HOH D 388      17.026  35.186   1.591  1.00 73.64           O  
+HETATM 9181  O   HOH D 389      42.356  14.679  -1.687  1.00 51.43           O  
+HETATM 9182  O   HOH D 390      21.230  34.588   3.037  1.00 85.09           O  
+HETATM 9183  O   HOH D 391      26.429  22.033  19.659  1.00 58.34           O  
+HETATM 9184  O   HOH D 392      -5.355  25.199 -27.664  1.00 55.68           O  
+HETATM 9185  O   HOH D 393       4.522  14.544   3.663  1.00 63.60           O  
+HETATM 9186  O   HOH D 394      38.843  15.242   6.181  1.00 70.58           O  
+HETATM 9187  O   HOH D 395      16.367  34.787   6.223  1.00 71.97           O  
+HETATM 9188  O   HOH D 396       6.502  18.328   8.531  1.00 60.52           O  
+HETATM 9189  O   HOH D 397      17.206  30.269  10.537  1.00 47.49           O  
+HETATM 9190  O   HOH D 398       0.075  49.853 -20.203  1.00 72.97           O  
+HETATM 9191  O   HOH D 399      15.327  -0.171  -9.959  1.00 71.33           O  
+HETATM 9192  O   HOH D 400      17.799   5.798  -9.627  1.00 79.77           O  
+HETATM 9193  O   HOH D 401      39.137  12.939 -11.169  1.00 76.27           O  
+HETATM 9194  O   HOH D 402     -18.706  18.383 -11.042  1.00 86.62           O  
+HETATM 9195  O   HOH D 403       7.316  44.655  -8.392  1.00 73.54           O  
+HETATM 9196  O   HOH D 404      26.801  24.757  -8.010  1.00 62.41           O  
+HETATM 9197  O   HOH D 405      34.179   6.742  -6.787  1.00 80.79           O  
+HETATM 9198  O   HOH D 406      17.289  32.377  -7.912  1.00 33.52           O  
+HETATM 9199  O   HOH D 407      -3.311  50.053  -8.930  1.00 74.19           O  
+HETATM 9200  O   HOH D 408      45.889  16.910   8.408  1.00 77.75           O  
+HETATM 9201  O   HOH D 409      -2.229  28.599  -7.486  1.00 29.47           O  
+HETATM 9202  O   HOH D 410       7.176  48.021 -10.446  1.00111.81           O  
+HETATM 9203  O   HOH D 411     -18.692  26.329  -6.428  1.00 56.20           O  
+HETATM 9204  O   HOH D 412     -20.903  17.606  -5.622  1.00 89.64           O  
+HETATM 9205  O   HOH D 413      15.993  32.026  -5.761  1.00 19.14           O  
+HETATM 9206  O   HOH D 414      10.025  38.841  -5.246  1.00 42.90           O  
+HETATM 9207  O   HOH D 415     -12.060   9.487  -5.153  1.00 86.41           O  
+HETATM 9208  O   HOH D 416     -11.169  13.162  -4.925  1.00 82.28           O  
+HETATM 9209  O   HOH D 417       0.782   4.444  -0.991  1.00 79.76           O  
+HETATM 9210  O   HOH D 418      43.973  -0.344  -0.480  1.00 78.64           O  
+HETATM 9211  O   HOH D 419      26.517  33.201   2.537  1.00 43.45           O  
+HETATM 9212  O   HOH D 420      26.273  22.867  17.145  1.00 82.74           O  
+HETATM 9213  O   HOH D 421      26.367  14.199 -19.254  1.00 54.91           O  
+HETATM 9214  O   HOH D 422       1.959  14.474 -29.752  1.00 72.33           O  
+HETATM 9215  O   HOH D 423       1.897  44.905 -27.573  1.00 65.35           O  
+HETATM 9216  O   HOH D 424      -9.421  14.730 -25.905  1.00 71.79           O  
+HETATM 9217  O   HOH D 425     -13.301  18.634 -23.608  1.00 67.11           O  
+HETATM 9218  O   HOH D 426       9.615  50.787 -23.635  1.00 72.09           O  
+HETATM 9219  O   HOH D 427      -8.777  37.875 -21.065  1.00 96.40           O  
+HETATM 9220  O   HOH D 428       8.645  48.700 -22.153  1.00 75.05           O  
+HETATM 9221  O   HOH D 429       4.454  28.740 -17.629  1.00 29.29           O  
+HETATM 9222  O   HOH D 430      -3.974  -8.253 -20.894  1.00 87.09           O  
+HETATM 9223  O   HOH D 431     -22.450  34.586  -2.248  1.00 69.16           O  
+HETATM 9224  O   HOH D 432      -9.971  -3.525 -19.295  1.00 68.66           O  
+HETATM 9225  O   HOH D 433       1.477 -10.775 -17.840  1.00 80.07           O  
+HETATM 9226  O   HOH D 434      -0.934  -8.992 -18.420  1.00101.24           O  
+HETATM 9227  O   HOH D 435      -3.507 -10.791 -16.076  1.00 79.16           O  
+HETATM 9228  O   HOH D 436      -0.442  -7.143 -15.937  1.00 76.43           O  
+HETATM 9229  O   HOH D 437      16.744  33.321 -14.098  1.00 59.07           O  
+HETATM 9230  O   HOH D 438      37.027  14.034 -14.305  1.00 81.90           O  
+HETATM 9231  O   HOH D 439      26.508  19.099 -12.689  1.00 73.04           O  
+HETATM 9232  O   HOH D 440     -15.926  17.863 -11.973  1.00 75.42           O  
+HETATM 9233  O   HOH D 441     -14.100   8.822  -7.020  1.00 62.48           O  
+HETATM 9234  O   HOH D 442     -13.632  13.260  -5.713  1.00 92.01           O  
+HETATM 9235  O   HOH D 443      15.959  34.543  -4.947  1.00 49.31           O  
+HETATM 9236  O   HOH D 444       0.148  12.625  -3.673  1.00 60.73           O  
+HETATM 9237  O   HOH D 445     -16.627  13.110  -3.722  1.00 80.26           O  
+HETATM 9238  O   HOH D 446       9.790  40.199  -2.845  1.00 69.79           O  
+HETATM 9239  O   HOH D 447      35.833   7.070  -2.641  1.00 41.53           O  
+HETATM 9240  O   HOH D 448      40.132  15.710  -2.860  1.00 43.91           O  
+HETATM 9241  O   HOH D 449      12.424  42.753  -3.447  1.00 71.42           O  
+HETATM 9242  O   HOH D 450      11.036  36.197  -2.012  1.00 37.42           O  
+HETATM 9243  O   HOH D 451      13.892  40.286  -2.423  1.00 79.82           O  
+HETATM 9244  O   HOH D 452      -2.702   0.878  -1.924  1.00 83.17           O  
+HETATM 9245  O   HOH D 453      41.189   0.542   0.444  1.00 82.44           O  
+HETATM 9246  O   HOH D 454      -0.827  11.520   2.787  1.00 88.03           O  
+HETATM 9247  O   HOH D 455      -5.433  -3.517   3.399  1.00 85.89           O  
+HETATM 9248  O   HOH D 456      12.470  12.318  13.109  1.00 63.58           O  
+HETATM 9249  O   HOH D 457      12.121  23.941  13.420  1.00 72.44           O  
+HETATM 9250  O   HOH D 458      16.664  16.780  14.970  1.00 49.26           O  
+HETATM 9251  O   HOH D 459      27.306  25.699  19.618  1.00 75.57           O  
+HETATM 9252  O   HOH D 460      20.976  25.074 -23.835  1.00 71.36           O  
+HETATM 9253  O   HOH D 461      30.679  13.476 -17.336  1.00 85.11           O  
+MASTER      615    0    0   51   22    0    0    6 9249    4    0   92          
+END                                                                             
index c472576..b8c12c6 100644 (file)
@@ -31,6 +31,8 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
+import jalview.structure.StructureImportSettings;
+import jalview.structure.StructureImportSettings.StructureParser;
 
 import java.io.File;
 
@@ -65,6 +67,9 @@ public class AnnotatedPDBFileInputTest
     al = af.getViewport().getAlignment();
     pdbId = al.getSequenceAt(0).getDatasetSequence().getAllPDBEntries()
             .get(0).getId();
+    StructureImportSettings.setDefaultStructureFileFormat("PDB");
+    // StructureImportSettings
+    // .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
   }
 
   @Test(groups = { "Functional" })
@@ -80,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]);
       }
     }
   }
@@ -96,7 +101,11 @@ public class AnnotatedPDBFileInputTest
       {
 
         System.out.println("CalcId: " + aa.getCalcId());
-        assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
+        if (StructureImportSettings.getDefaultPDBFileParser().equals(
+                StructureParser.JALVIEW_PARSER))
+        {
+          assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId));
+        }
       }
     }
   }
@@ -180,7 +189,7 @@ public class AnnotatedPDBFileInputTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
@@ -212,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 625244d..c9b5f4a 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;
diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java
new file mode 100644 (file)
index 0000000..c55ddd9
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * 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(), FormatAdapter.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(), FormatAdapter.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(), FormatAdapter.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 6da160d..602ce9f 100644 (file)
@@ -26,14 +26,14 @@ import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.FeatureColourI;
+import jalview.api.FeatureRenderer;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.schemes.AnnotationColourGradient;
-import jalview.schemes.GraduatedColor;
 
 import java.awt.Color;
 import java.io.File;
@@ -53,7 +53,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     FeaturesFile featuresFile = new FeaturesFile(
             "examples/exampleFeatures.txt", FormatAdapter.FILE);
@@ -67,61 +67,71 @@ public class FeaturesFileTest
      */
     colours = af.getFeatureRenderer().getFeatureColours();
     assertEquals("26 feature group colours not found", 26, colours.size());
-    assertEquals(colours.get("Cath"), new Color(0x93b1d1));
-    assertEquals(colours.get("ASX-MOTIF"), new Color(0x6addbb));
+    assertEquals(colours.get("Cath").getColour(), new Color(0x93b1d1));
+    assertEquals(colours.get("ASX-MOTIF").getColour(), new Color(0x6addbb));
 
     /*
      * verify (some) features on sequences
      */
     SequenceFeature[] sfs = al.getSequenceAt(0).getDatasetSequence()
             .getSequenceFeatures(); // FER_CAPAA
-    assertEquals(7, sfs.length);
+    assertEquals(8, sfs.length);
     SequenceFeature sf = sfs[0];
+    assertEquals("Pfam family%LINK%", sf.description);
+    assertEquals(0, sf.begin);
+    assertEquals(0, sf.end);
+    assertEquals("uniprot", sf.featureGroup);
+    assertEquals("Pfam", sf.type);
+    assertEquals(1, sf.links.size());
+    assertEquals("Pfam family|http://pfam.xfam.org/family/PF00111",
+            sf.links.get(0));
+
+    sf = sfs[1];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(39, sf.begin);
     assertEquals(39, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[1];
+    sf = sfs[2];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(44, sf.begin);
     assertEquals(44, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[2];
+    sf = sfs[3];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(47, sf.begin);
     assertEquals(47, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[3];
+    sf = sfs[4];
     assertEquals("Iron-sulfur (2Fe-2S)", sf.description);
     assertEquals(77, sf.begin);
     assertEquals(77, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("METAL", sf.type);
-    sf = sfs[4];
+    sf = sfs[5];
     assertEquals("Fer2 Status: True Positive Pfam 8_8%LINK%",
             sf.description);
-    assertEquals("Pfam 8_8|http://pfam.sanger.ac.uk/family/PF00111",
-            sf.links.get(0).toString());
+    assertEquals("Pfam 8_8|http://pfam.xfam.org/family/PF00111",
+            sf.links.get(0));
     assertEquals(8, sf.begin);
     assertEquals(83, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("Pfam", sf.type);
-    sf = sfs[5];
+    sf = sfs[6];
     assertEquals("Ferredoxin_fold Status: True Positive ", sf.description);
     assertEquals(3, sf.begin);
     assertEquals(93, sf.end);
     assertEquals("uniprot", sf.featureGroup);
     assertEquals("Cath", sf.type);
-    sf = sfs[6];
+    sf = sfs[7];
     assertEquals(
             "High confidence server. Only hits with scores over 0.8 are reported. PHOSPHORYLATION (T) 89_8%LINK%",
             sf.description);
     assertEquals(
             "PHOSPHORYLATION (T) 89_8|http://www.cbs.dtu.dk/cgi-bin/proview/webface-link?seqid=P83527&amp;service=NetPhos-2.0",
-            sf.links.get(0).toString());
+            sf.links.get(0));
     assertEquals(89, sf.begin);
     assertEquals(89, sf.end);
     assertEquals("netphos", sf.featureGroup);
@@ -140,10 +150,11 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    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,
@@ -154,7 +165,7 @@ public class FeaturesFileTest
     // verify colours read or synthesized
     colours = af.getFeatureRenderer().getFeatureColours();
     assertEquals("1 feature group colours not found", 1, colours.size());
-    assertEquals(colours.get("METAL"), new Color(0xcc9900));
+    assertEquals(colours.get("METAL").getColour(), new Color(0xcc9900));
 
     // verify feature on FER_CAPAA
     SequenceFeature[] sfs = al.getSequenceAt(0).getDatasetSequence()
@@ -195,45 +206,6 @@ public class FeaturesFileTest
   }
 
   /**
-   * Test various ways of describing a feature colour scheme
-   * 
-   * @throws Exception
-   */
-  @Test(groups = { "Functional" })
-  public void testParseGraduatedColourScheme() throws Exception
-  {
-    FeaturesFile ff = new FeaturesFile();
-
-    // colour by label:
-    GraduatedColor gc = ff.parseGraduatedColourScheme(
-            "BETA-TURN-IR\t9a6a94", "label");
-    assertTrue(gc.isColourByLabel());
-    assertEquals(Color.white, gc.getMinColor());
-    assertEquals(Color.black, gc.getMaxColor());
-    assertTrue(gc.isAutoScale());
-
-    // using colour name, rgb, etc:
-    String spec = "blue|255,0,255|absolute|20.0|95.0|below|66.0";
-    gc = ff.parseGraduatedColourScheme("BETA-TURN-IR\t" + spec, spec);
-    assertFalse(gc.isColourByLabel());
-    assertEquals(Color.blue, gc.getMinColor());
-    assertEquals(new Color(255, 0, 255), gc.getMaxColor());
-    assertFalse(gc.isAutoScale());
-    assertFalse(gc.getTolow());
-    assertEquals(20.0f, gc.getMin(), 0.001f);
-    assertEquals(95.0f, gc.getMax(), 0.001f);
-    assertEquals(AnnotationColourGradient.BELOW_THRESHOLD,
-            gc.getThreshType());
-    assertEquals(66.0f, gc.getThresh(), 0.001f);
-
-    // inverse gradient high to low:
-    spec = "blue|255,0,255|95.0|20.0|below|66.0";
-    gc = ff.parseGraduatedColourScheme("BETA-TURN-IR\t" + spec, spec);
-    assertTrue(gc.isAutoScale());
-    assertTrue(gc.getTolow());
-  }
-
-  /**
    * Test parsing a features file with GFF formatted content only
    * 
    * @throws Exception
@@ -244,7 +216,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
     // GFF3 uses '=' separator for name/value pairs in colum 9
     String gffData = "##gff-version 3\n"
@@ -275,7 +247,8 @@ public class FeaturesFileTest
     sfs = al.getSequenceAt(2).getDatasetSequence().getSequenceFeatures();
     assertEquals(1, sfs.length);
     sf = sfs[0];
-    assertEquals("uniprot", sf.description);
+    // ID used for description if available
+    assertEquals("$23", sf.description);
     assertEquals(55, sf.begin);
     assertEquals(130, sf.end);
     assertEquals("uniprot", sf.featureGroup);
@@ -295,7 +268,7 @@ public class FeaturesFileTest
     File f = new File("examples/uniref50.fa");
     AlignmentI al = readAlignmentFile(f);
     AlignFrame af = new AlignFrame(al, 500, 500);
-    Map<String, Object> colours = af.getFeatureRenderer()
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
             .getFeatureColours();
 
     /*
@@ -332,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);
@@ -363,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" })
@@ -380,9 +353,8 @@ public class FeaturesFileTest
   public void simpleGff3FileClass() throws IOException
   {
     AlignmentI dataset = new Alignment(new SequenceI[] {});
-    FeaturesFile ffile = new FeaturesFile(simpleGffFile,
-            FormatAdapter.FILE);
-  
+    FeaturesFile ffile = new FeaturesFile(simpleGffFile, FormatAdapter.FILE);
+
     boolean parseResult = ffile.parse(dataset, null, false, false);
     assertTrue("return result should be true", parseResult);
     checkDatasetfromSimpleGff3(dataset);
@@ -403,12 +375,79 @@ public class FeaturesFileTest
   public void simpleGff3RelaxedIdMatching() throws IOException
   {
     AlignmentI dataset = new Alignment(new SequenceI[] {});
-    FeaturesFile ffile = new FeaturesFile(simpleGffFile,
-            FormatAdapter.FILE);
-  
+    FeaturesFile ffile = new FeaturesFile(simpleGffFile, FormatAdapter.FILE);
+
     boolean parseResult = ffile.parse(dataset, null, false, true);
     assertTrue("return result (relaxedID matching) should be true",
             parseResult);
     checkDatasetfromSimpleGff3(dataset);
   }
+
+  @Test(groups = { "Functional" })
+  public void testPrintJalviewFormat() throws Exception
+  {
+    File f = new File("examples/uniref50.fa");
+    AlignmentI al = readAlignmentFile(f);
+    AlignFrame af = new AlignFrame(al, 500, 500);
+    Map<String, FeatureColourI> colours = af.getFeatureRenderer()
+            .getFeatureColours();
+    String features = "METAL\tcc9900\n"
+            + "GAMMA-TURN\tred|0,255,255|20.0|95.0|below|66.0\n"
+            + "Pfam\tred\n"
+            + "STARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\n"
+            + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\n"
+            + "ENDGROUP\tuniprot\n";
+    FeaturesFile featuresFile = new FeaturesFile(features,
+            FormatAdapter.PASTE);
+    featuresFile.parse(al.getDataset(), colours, false);
+
+    /*
+     * first with no features displayed
+     */
+    FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
+    Map<String, FeatureColourI> visible = fr.getDisplayedFeatureCols();
+    String exported = featuresFile.printJalviewFormat(
+            al.getSequencesArray(), visible);
+    String expected = "No Features Visible";
+    assertEquals(expected, exported);
+
+    /*
+     * set METAL (in uniprot group) and GAMMA-TURN visible, but not Pfam
+     */
+    fr.setVisible("METAL");
+    fr.setVisible("GAMMA-TURN");
+    visible = fr.getDisplayedFeatureCols();
+    exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
+            visible);
+    expected = "METAL\tcc9900\n"
+            + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+            + "\nSTARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+            + "ENDGROUP\tuniprot\n";
+    assertEquals(expected, exported);
+
+    /*
+     * now set Pfam visible
+     */
+    fr.setVisible("Pfam");
+    visible = fr.getDisplayedFeatureCols();
+    exported = featuresFile.printJalviewFormat(al.getSequencesArray(),
+            visible);
+    /*
+     * note the order of feature types is uncontrolled - derives from
+     * FeaturesDisplayed.featuresDisplayed which is a HashSet
+     */
+    expected = "METAL\tcc9900\n"
+            + "Pfam\tff0000\n"
+            + "GAMMA-TURN\tff0000|00ffff|20.0|95.0|below|66.0\n"
+            + "\nSTARTGROUP\tuniprot\n"
+            + "Iron\tFER_CAPAA\t-1\t39\t39\tMETAL\t0.0\n"
+            + "Turn\tFER_CAPAA\t-1\t36\t38\tGAMMA-TURN\t0.0\n"
+            + "<html>Pfam domain<a href=\"http://pfam.xfam.org/family/PF00111\">Pfam_3_4</a></html>\tFER_CAPAA\t-1\t20\t20\tPfam\t0.0\n"
+            + "ENDGROUP\tuniprot\n";
+    assertEquals(expected, exported);
+  }
 }
index cde1cbc..2eb3703 100644 (file)
@@ -46,7 +46,7 @@ public class FileIOTester
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
diff --git a/test/jalview/io/FormatAdapterTest.java b/test/jalview/io/FormatAdapterTest.java
new file mode 100644 (file)
index 0000000..d4242a7
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.fail;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class FormatAdapterTest
+{
+
+  /**
+   * Test saving and re-reading in a specified format
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" }, dataProvider = "formats")
+  public void testRoundTrip(String format) throws IOException
+  {
+    try
+    {
+      AlignmentI al = new FormatAdapter().readFile("examples/uniref50.fa",
+              FormatAdapter.FILE, "FASTA");
+
+      /*
+       * 'gap' is the gap character used in the alignment data file here,
+       * not the user preferred gap character
+       */
+      char gap = al.getGapCharacter();
+      assertNotNull(al);
+
+      SequenceI[] seqs = al.getSequencesArray();
+      String formatted = new FormatAdapter().formatSequences(format, al,
+              false);
+
+      AlignmentI reloaded = new FormatAdapter().readFile(formatted,
+              FormatAdapter.PASTE, format);
+      List<SequenceI> reread = reloaded.getSequences();
+      assertEquals("Wrong number of reloaded sequences", seqs.length,
+              reread.size());
+
+      int i = 0;
+      for (SequenceI seq : reread)
+      {
+        String sequenceString = seq.getSequenceAsString();
+
+        /*
+         * special case: MSF always uses '.' as gap character
+         */
+        sequenceString = adjustForGapTreatment(sequenceString, gap, format);
+        assertEquals(
+                String.format("Sequence %d: %s", i, seqs[i].getName()),
+                seqs[i].getSequenceAsString(), sequenceString);
+        i++;
+      }
+    } catch (IOException e)
+    {
+      fail(String
+              .format("Format %s failed with %s", format, e.getMessage()));
+    }
+  }
+
+  /**
+   * Optionally change the gap character in the string to the given character,
+   * depending on the sequence file format
+   * 
+   * @param sequenceString
+   *          a sequence (as written in 'format' format)
+   * @param gap
+   *          the sequence's original gap character
+   * @param format
+   * @return
+   */
+  String adjustForGapTreatment(String sequenceString, char gap,
+          String format)
+  {
+    if ("MSF".equals(format))
+    {
+      /*
+       * MSF forces gap character to '.', so change it back
+       * for comparison purposes
+       */
+      sequenceString = sequenceString.replace('.', gap);
+    }
+    return sequenceString;
+  }
+
+  /**
+   * Data provider that serves alignment formats that are both readable and
+   * writable
+   * 
+   * @return
+   */
+  @DataProvider(name = "formats")
+  static Object[][] getFormats()
+  {
+    List<String> both = new ArrayList<String>();
+    String[] readable = FormatAdapter.READABLE_FORMATS;
+    List<String> writeable = Arrays.asList(FormatAdapter.WRITEABLE_FORMATS);
+    for (String r : readable)
+    {
+      if (writeable.contains(r))
+      {
+        both.add(r);
+      }
+    }
+
+    Object[][] formats = new Object[both.size()][];
+    int i = 0;
+    for (String format : both)
+    {
+      formats[i] = new Object[] { format };
+      i++;
+    }
+    return formats;
+  }
+
+  /**
+   * Enable this to isolate testing to a single file format
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" }, enabled = false)
+  public void testOneFormatRoundTrip() throws IOException
+  {
+    testRoundTrip("JSON");
+  }
+}
index b1efb7a..c00cf06 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
@@ -41,24 +42,34 @@ public class IdentifyFileTest
   }
 
   /**
-   * Additional tests for (a) Jalview features file with no colour
-   * specifications (old style 'groups' file) and (b) Jalview features file with
-   * embedded GFF
+   * Additional tests for Jalview features file
    */
   @Test(groups = "Functional")
   public void testIdentify_featureFile()
   {
     IdentifyFile ider = new IdentifyFile();
 
-    // Jalview format with features only, no feature colours
+    /*
+     * Jalview format with features only, no feature colours
+     */
     String data = "Iron-sulfur (2Fe-2S)\tFER_CAPAA\t-1\t39\t39\tMETAL\n"
             + "Iron-phosphorus (2Fe-P)\tID_NOT_SPECIFIED\t2\t86\t87\tMETALLIC\n";
-    Assert.assertEquals(IdentifyFile.FeaturesFile, ider.identify(data, AppletFormatAdapter.PASTE));
+    assertEquals(IdentifyFile.FeaturesFile,
+            ider.identify(data, AppletFormatAdapter.PASTE));
 
-    // Jalview feature colour followed by GFF format feature data
+    /*
+     * Jalview feature colour followed by GFF format feature data
+     */
     data = "METAL\tcc9900\n" + "GFF\n"
             + "FER_CAPAA\tuniprot\tMETAL\t44\t45\t4.0\t.\t.\n";
-    Assert.assertEquals(IdentifyFile.FeaturesFile,
+    assertEquals(IdentifyFile.FeaturesFile,
+            ider.identify(data, AppletFormatAdapter.PASTE));
+
+    /*
+     * Feature with '<' in the name (JAL-2098)
+     */
+    data = "kD < 3\tred\n" + "Low kD\tFER_CAPAA\t-1\t39\t39\tkD < 3\n";
+    assertEquals(IdentifyFile.FeaturesFile,
             ider.identify(data, AppletFormatAdapter.PASTE));
   }
 
index d327134..f75f433 100644 (file)
@@ -114,7 +114,7 @@ public class JSONFileTest
 
     for (Sequence seq : seqs)
     {
-      seq.setDatasetSequence(seq);
+      seq.createDatasetSequence();
       expectedSeqs.put(seq.getName(), seq);
     }
 
@@ -262,7 +262,7 @@ public class JSONFileTest
     passedCount = 0;
   }
 
-  @AfterTest
+  @AfterTest(alwaysRun = true)
   public void tearDown() throws Exception
   {
     testJsonFile = null;
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 b58a8a6..3d53234 100644 (file)
  */
 package jalview.io;
 
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.ViewStyleI;
-import jalview.bin.Cache;
 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;
 import jalview.gui.AlignFrame;
+import jalview.gui.AlignmentPanel;
 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.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;
 
-public class Jalview2xmlTests
+@Test(singleThreaded = true)
+public class Jalview2xmlTests extends Jalview2xmlBase
 {
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @BeforeClass(alwaysRun = true)
-  public static void setUpBeforeClass() throws Exception
-  {
-    jalview.bin.Jalview.main(new String[] { "-props",
-        "test/jalview/io/testProps.jvprops" });
-  }
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception
-  {
-    jalview.gui.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;
-  }
-
   @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(
-            inFile, FormatAdapter.FILE);
-    assertTrue("Didn't read input file " + inFile, af != null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+            FormatAdapter.FILE);
+    assertNotNull("Didn't read input file " + inFile, af);
     int olddsann = countDsAnn(af.getViewport());
     assertTrue("Didn't find any dataset annotations", olddsann > 0);
     af.rnahelicesColour_actionPerformed(null);
@@ -104,9 +81,8 @@ public class Jalview2xmlTests
             af.saveAlignment(tfile, "Jalview"));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
-            FormatAdapter.FILE);
-    assertTrue("Failed to import new project", af != null);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE);
+    assertNotNull("Failed to import new project", af);
     int newdsann = countDsAnn(af.getViewport());
     assertTrue(
             "Differing numbers of dataset sequence annotation\nOriginally "
@@ -126,32 +102,26 @@ 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(
-            inFile, FormatAdapter.FILE);
-    assertTrue("Didn't read input file " + inFile, af != null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+            FormatAdapter.FILE);
+    assertNotNull("Didn't read input file " + inFile, af);
     af.loadJalviewDataFile(inAnnot, FormatAdapter.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",
+    assertSame("Didn't set T-coffee colourscheme", af.getViewport()
+            .getGlobalColourScheme().getClass(), TCoffeeColourScheme.class);
+    assertNotNull("Recognise T-Coffee score from string",
             jalview.schemes.ColourSchemeProperty.getColour(af.getViewport()
-                    .getAlignment(),
-                    jalview.schemes.ColourSchemeProperty.getColourName(af
-                            .getViewport().getGlobalColourScheme())) != null);
+                    .getAlignment(), ColourSchemeProperty.getColourName(af
+                    .getViewport().getGlobalColourScheme())));
 
     assertTrue("Failed to store as a project.",
             af.saveAlignment(tfile, "Jalview"));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
-            FormatAdapter.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));
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE);
+    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.");
   }
@@ -162,19 +132,19 @@ 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, FormatAdapter.FILE);
-    assertTrue("Didn't read input file " + inFile, af != null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile,
+            FormatAdapter.FILE);
+    assertNotNull("Didn't read input file " + inFile, af);
     af.loadJalviewDataFile(inAnnot, FormatAdapter.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);
@@ -190,16 +160,15 @@ public class Jalview2xmlTests
             af.saveAlignment(tfile, "Jalview"));
     af.closeMenuItem_actionPerformed(true);
     af = null;
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile,
-            FormatAdapter.FILE);
-    assertTrue("Failed to import new project", af != null);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE);
+    assertNotNull("Failed to import new project", af);
 
     // check for group and alignment colourschemes
 
     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;
@@ -221,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;
@@ -247,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", FormatAdapter.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);
 
@@ -258,13 +227,11 @@ public class Jalview2xmlTests
   @Test(groups = { "Functional" })
   public void viewRefPdbAnnotation() throws Exception
   {
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
-            Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
-            Boolean.TRUE.toString());
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    StructureImportSettings.setProcessSecondaryStructure(true);
+    StructureImportSettings.setVisibleChainAnnotation(true);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", FormatAdapter.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())
     {
@@ -274,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())
@@ -286,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;
@@ -321,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", FormatAdapter.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())
     {
@@ -336,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();
@@ -352,37 +321,28 @@ public class Jalview2xmlTests
   }
 
   /**
-   * test store and recovery of expanded views - currently this is disabled
-   * since the Desktop.explodeViews method doesn't seem to result in the views
-   * being expanded to distinct align frames when executed programmatically.
+   * test store and recovery of expanded views
    * 
    * @throws Exception
    */
-  @Test(groups = { "Functional" }, enabled = false)
+  @Test(groups = { "Functional" }, enabled = true)
   public void testStoreAndRecoverExpandedviews() throws Exception
   {
-    AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
+    Desktop.instance.closeAll_actionPerformed(null);
+
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
-    assertTrue("Didn't read in the example file correctly.", af != null);
+    Assert.assertEquals(Desktop.getAlignFrames().length, 1);
     String afid = af.getViewport().getSequenceSetId();
-    {
-      final AlignFrame xaf = af;
-      af = null;
-      new Thread(new Runnable()
-      {
-        @Override
-        public void run()
-        {
-          Desktop.instance.explodeViews(xaf);
-        }
-      }).start();
-      Thread.sleep(1000);
-    }
-    // int times = 0;
-    // while (++times < 5 && Desktop.getAlignFrames().length < )
-    // {
-    // Thread.sleep(300);
-    // }
+
+    // check FileLoader returned a reference to the one alignFrame that is
+    // actually on the Desktop
+    assertTrue(
+            "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window",
+            af == Desktop.getAlignFrameFor(af.getViewport()));
+
+    Desktop.explodeViews(af);
+
     int oldviews = Desktop.getAlignFrames().length;
     Assert.assertEquals(Desktop.getAlignFrames().length,
             Desktop.getAlignmentPanels(afid).length);
@@ -402,8 +362,8 @@ public class Jalview2xmlTests
     {
       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
     }
-    af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
-            tfile.getAbsolutePath(), FormatAdapter.FILE);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            FormatAdapter.FILE);
     Assert.assertNotNull(af);
     Assert.assertEquals(
             Desktop.getAlignFrames().length,
@@ -413,6 +373,85 @@ public class Jalview2xmlTests
             Desktop.getAlignmentPanels(af.getViewport().getSequenceSetId()).length);
   }
 
+  /**
+   * Test save and reload of a project with a different representative sequence
+   * in each view.
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverReferenceSeqSettings() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
+    assertNotNull("Didn't read in the example file correctly.", af);
+    String afid = af.getViewport().getSequenceSetId();
+
+    // remember reference sequence for each panel
+    Map<String, SequenceI> refseqs = new HashMap<String, SequenceI>();
+
+    /*
+     * mark sequence 2, 3, 4.. in panels 1, 2, 3...
+     * as reference sequence for itself and the preceding sequence
+     */
+    int n = 1;
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      AlignViewportI av = ap.getAlignViewport();
+      AlignmentI alignment = ap.getAlignment();
+      int repIndex = n % alignment.getHeight();
+      SequenceI rep = alignment.getSequenceAt(repIndex);
+      refseqs.put(ap.getViewName(), rep);
+
+      // code from mark/unmark sequence as reference in jalview.gui.PopupMenu
+      // todo refactor this to an alignment view controller
+      av.setDisplayReferenceSeq(true);
+      av.setColourByReferenceSeq(true);
+      av.getAlignment().setSeqrep(rep);
+
+      n++;
+    }
+    File tfile = File.createTempFile("testStoreAndRecoverReferenceSeq",
+            ".jvp");
+    try
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the expanded view state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+    if (Desktop.getAlignFrames() != null)
+    {
+      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+    }
+
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            FormatAdapter.FILE);
+    afid = af.getViewport().getSequenceSetId();
+
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      // check representative
+      AlignmentI alignment = ap.getAlignment();
+      SequenceI rep = alignment.getSeqrep();
+      Assert.assertNotNull(rep,
+              "Couldn't restore sequence representative from project");
+      // can't use a strong equals here, because by definition, the sequence IDs
+      // will be different.
+      // could set vamsas session save/restore flag to preserve IDs across
+      // load/saves.
+      Assert.assertEquals(refseqs.get(ap.getViewName()).toString(),
+              rep.toString(),
+              "Representative wasn't the same when recovered.");
+      Assert.assertTrue(ap.getAlignViewport().isDisplayReferenceSeq(),
+              "Display reference sequence view setting not set.");
+      Assert.assertTrue(ap.getAlignViewport().isColourByReferenceSeq(),
+              "Colour By Reference Seq view setting not set.");
+    }
+  }
+
   @Test(groups = { "Functional" })
   public void testIsVersionStringLaterThan()
   {
@@ -422,6 +461,7 @@ public class Jalview2xmlTests
      */
     assertTrue(Jalview2XML.isVersionStringLaterThan(null, null));
     assertTrue(Jalview2XML.isVersionStringLaterThan("2.8.3", null));
+    assertTrue(Jalview2XML.isVersionStringLaterThan(null, "2.8.3"));
     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
             "Development Build"));
     assertTrue(Jalview2XML.isVersionStringLaterThan(null,
@@ -465,4 +505,219 @@ public class Jalview2xmlTests
     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.3", "2.8.2b1"));
     assertFalse(Jalview2XML.isVersionStringLaterThan("2.8.0b2", "2.8.0b1"));
   }
+
+  /**
+   * Test save and reload of a project with a different sequence group (and
+   * representative sequence) in each view.
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverGroupRepSeqs() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", FormatAdapter.FILE);
+    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
+     */
+    int n = 1;
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      AlignViewportI av = ap.getAlignViewport();
+      AlignmentI alignment = ap.getAlignment();
+      int repIndex = n % alignment.getHeight();
+      // ensure at least one preceding sequence i.e. index >= 1
+      repIndex = Math.max(repIndex, 1);
+      SequenceI repSeq = alignment.getSequenceAt(repIndex);
+      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)
+       */
+      SequenceGroup sg = new SequenceGroup();
+      sg.addSequence(repSeq, false);
+      SequenceI precedingSeq = alignment.getSequenceAt(repIndex - 1);
+      sg.addSequence(precedingSeq, false);
+      sg.setSeqrep(repSeq);
+      assertTrue(sg.getSequences().contains(repSeq));
+      assertTrue(sg.getSequences().contains(precedingSeq));
+      av.setSelectionGroup(sg);
+      assertSame(repSeq, sg.getSeqrep());
+
+      /*
+       * represent group with sequence adds to a map of hidden rep sequences
+       * (it does not create a group on the alignment) 
+       */
+      ((AlignmentViewport) av).hideSequences(repSeq, true);
+      assertSame(repSeq, sg.getSeqrep());
+      assertTrue(sg.getSequences().contains(repSeq));
+      assertTrue(sg.getSequences().contains(precedingSeq));
+      assertTrue("alignment has groups", alignment.getGroups().isEmpty());
+      Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
+              .getHiddenRepSequences();
+      assertNotNull(hiddenRepSeqsMap);
+      assertEquals(1, hiddenRepSeqsMap.size());
+      assertSame(sg, hiddenRepSeqsMap.get(repSeq));
+      assertTrue(alignment.getHiddenSequences().isHidden(precedingSeq));
+      assertFalse(alignment.getHiddenSequences().isHidden(repSeq));
+      hiddenNames.add(precedingSeq.getName());
+
+      n++;
+    }
+    File tfile = File
+            .createTempFile("testStoreAndRecoverGroupReps", ".jvp");
+    try
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the expanded view state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+    if (Desktop.getAlignFrames() != null)
+    {
+      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+    }
+
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            FormatAdapter.FILE);
+    afid = af.getViewport().getSequenceSetId();
+
+    for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid))
+    {
+      String viewName = ap.getViewName();
+      AlignViewportI av = ap.getAlignViewport();
+      AlignmentI alignment = ap.getAlignment();
+      List<SequenceGroup> groups = alignment.getGroups();
+      assertNotNull(groups);
+      assertTrue("Alignment has groups", groups.isEmpty());
+      Map<SequenceI, SequenceCollectionI> hiddenRepSeqsMap = av
+              .getHiddenRepSequences();
+      assertNotNull("No hidden represented sequences", hiddenRepSeqsMap);
+      assertEquals(1, hiddenRepSeqsMap.size());
+      assertEquals(repSeqs.get(viewName).getDisplayId(true),
+              hiddenRepSeqsMap.keySet().iterator().next()
+                      .getDisplayId(true));
+
+      /*
+       * verify hidden sequences in restored panel
+       */
+      List<String> hidden = hiddenSeqNames.get(ap.getViewName());
+      HiddenSequences hs = alignment.getHiddenSequences();
+      assertEquals(
+              "wrong number of restored hidden sequences in "
+                      + ap.getViewName(), hidden.size(), hs.getSize());
+    }
+  }
+
+  /**
+   * Test save and reload of PDBEntry in Jalview project
+   * 
+   * @throws Exception
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverPDBEntry() throws Exception
+  {
+    Desktop.instance.closeAll_actionPerformed(null);
+    String exampleFile = "examples/3W5V.pdb";
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
+            FormatAdapter.FILE);
+    assertNotNull("Didn't read in the example file correctly.", af);
+    String afid = af.getViewport().getSequenceSetId();
+
+    AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
+    System.out.println();
+    AlignmentViewPanel ap = alignPanels[0];
+    String tfileBase = new File(".").getAbsolutePath().replace(".", "");
+    String testFile = tfileBase + exampleFile;
+    AlignmentI alignment = ap.getAlignment();
+    System.out.println("blah");
+    SequenceI[] seqs = alignment.getSequencesArray();
+    Assert.assertNotNull(seqs[0]);
+    Assert.assertNotNull(seqs[1]);
+    Assert.assertNotNull(seqs[2]);
+    Assert.assertNotNull(seqs[3]);
+    Assert.assertNotNull(seqs[0].getDatasetSequence());
+    Assert.assertNotNull(seqs[1].getDatasetSequence());
+    Assert.assertNotNull(seqs[2].getDatasetSequence());
+    Assert.assertNotNull(seqs[3].getDatasetSequence());
+    PDBEntry[] pdbEntries = new PDBEntry[4];
+    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
+    {
+      new Jalview2XML(false).saveState(tfile);
+    } catch (Throwable e)
+    {
+      Assert.fail("Didn't save the state", e);
+    }
+    Desktop.instance.closeAll_actionPerformed(null);
+    if (Desktop.getAlignFrames() != null)
+    {
+      Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+    }
+
+    AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
+            tfile.getAbsolutePath(), FormatAdapter.FILE);
+    String rfid = restoredFrame.getViewport().getSequenceSetId();
+    AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
+    AlignmentViewPanel rap = rAlignPanels[0];
+    AlignmentI rAlignment = rap.getAlignment();
+    System.out.println("blah");
+    SequenceI[] rseqs = rAlignment.getSequencesArray();
+    Assert.assertNotNull(rseqs[0]);
+    Assert.assertNotNull(rseqs[1]);
+    Assert.assertNotNull(rseqs[2]);
+    Assert.assertNotNull(rseqs[3]);
+    Assert.assertNotNull(rseqs[0].getDatasetSequence());
+    Assert.assertNotNull(rseqs[1].getDatasetSequence());
+    Assert.assertNotNull(rseqs[2].getDatasetSequence());
+    Assert.assertNotNull(rseqs[3].getDatasetSequence());
+
+    // The Asserts below are expected to fail until the PDB chainCode is
+    // recoverable from a Jalview projects
+    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 ab3d9df..164c259 100644 (file)
@@ -52,7 +52,7 @@ public class JalviewExportPropertiesTests
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     jalview.gui.Desktop.instance.closeAll_actionPerformed(null);
index d8e21c4..4de36f2 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
@@ -172,7 +171,7 @@ public class NewickFileTests
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
index 5dd4ecb..0eaf94b 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;
index d41446b..c084792 100644 (file)
@@ -34,7 +34,7 @@ public class RNAMLfileTest
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
diff --git a/test/jalview/io/SequenceAnnotationReportTest.java b/test/jalview/io/SequenceAnnotationReportTest.java
new file mode 100644 (file)
index 0000000..1392157
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * 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;
+
+import jalview.datamodel.SequenceFeature;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+public class SequenceAnnotationReportTest
+{
+  @Test(groups = "Functional")
+  public void testAppendFeature_disulfideBond()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    StringBuilder sb = new StringBuilder();
+    sb.append("123456");
+    SequenceFeature sf = new SequenceFeature("disulfide bond", "desc", 1,
+            3, 1.2f, "group");
+
+    // residuePos == 2 does not match start or end of feature, nothing done:
+    sar.appendFeature(sb, 2, null, sf);
+    assertEquals("123456", sb.toString());
+
+    // residuePos == 1 matches start of feature, text appended (but no <br>)
+    // feature score is not included
+    sar.appendFeature(sb, 1, null, sf);
+    assertEquals("123456disulfide bond 1:3", sb.toString());
+
+    // residuePos == 3 matches end of feature, text appended
+    // <br> is prefixed once sb.length() > 6
+    sar.appendFeature(sb, 3, null, sf);
+    assertEquals("123456disulfide bond 1:3<br>disulfide bond 1:3",
+            sb.toString());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_status()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    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());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_withScore()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    StringBuilder sb = new StringBuilder();
+    SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
+            "group");
+
+    Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+    sar.appendFeature(sb, 1, minmax, sf);
+    /*
+     * map has no entry for this feature type - score is not shown:
+     */
+    assertEquals("METAL 1 3; Fe2-S", sb.toString());
+
+    /*
+     * map has entry for this feature type - score is shown:
+     */
+    minmax.put("METAL", new float[][] { { 0f, 1f }, null });
+    sar.appendFeature(sb, 1, minmax, sf);
+    // <br> is appended to a buffer > 6 in length
+    assertEquals("METAL 1 3; Fe2-S<br>METAL 1 3; Fe2-S Score=1.3",
+            sb.toString());
+
+    /*
+     * map has min == max for this feature type - score is not shown:
+     */
+    minmax.put("METAL", new float[][] { { 2f, 2f }, null });
+    sb.setLength(0);
+    sar.appendFeature(sb, 1, minmax, sf);
+    assertEquals("METAL 1 3; Fe2-S", sb.toString());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_noScore()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    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());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_clinicalSignificance()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    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());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_withScoreStatusClinicalSignificance()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    StringBuilder sb = new StringBuilder();
+    SequenceFeature sf = new SequenceFeature("METAL", "Fe2-S", 1, 3, 1.3f,
+            "group");
+    sf.setStatus("Confirmed");
+    sf.setValue("clinical_significance", "Benign");
+    Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+    minmax.put("METAL", new float[][] { { 0f, 1f }, null });
+    sar.appendFeature(sb, 1, minmax, sf);
+
+    assertEquals("METAL 1 3; Fe2-S Score=1.3; (Confirmed); Benign",
+            sb.toString());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_DescEqualsType()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    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());
+
+    sb.setLength(0);
+    sf.setDescription("Metal");
+    // test is case-sensitive:
+    sar.appendFeature(sb, 1, null, sf);
+    assertEquals("METAL 1 3; Metal", sb.toString());
+  }
+
+  @Test(groups = "Functional")
+  public void testAppendFeature_stripHtml()
+  {
+    SequenceAnnotationReport sar = new SequenceAnnotationReport(null);
+    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());
+
+    sb.setLength(0);
+    sf.setDescription("<br>&kHD>6");
+    sar.appendFeature(sb, 1, null, sf);
+    // if no <html> tag, html-encodes > and < (only):
+    assertEquals("METAL 1 3; &lt;br&gt;&kHD&gt;6", sb.toString());
+  }
+}
index d7a9166..035f484 100644 (file)
@@ -23,6 +23,7 @@ package jalview.io;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -102,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"
@@ -159,7 +160,7 @@ public class StockholmFileTest
    *          'secondary' or generated alignment from some datapreserving
    *          transformation
    * @param ignoreFeatures
-   *          when true, differences in seuqence feature annotation are ignored.
+   *          when true, differences in sequence feature annotation are ignored
    */
   public static void testAlignmentEquivalence(AlignmentI al,
           AlignmentI al_input, boolean ignoreFeatures)
@@ -167,12 +168,9 @@ public class StockholmFileTest
     assertNotNull("Original alignment was null", al);
     assertNotNull("Generated alignment was null", al_input);
 
-    assertTrue(
-            "Alignment dimension mismatch: originl contains "
-                    + al.getHeight() + " and generated has "
-                    + al_input.getHeight() + " sequences; original has "
-                    + al.getWidth() + " and generated has "
-                    + al_input.getWidth() + " columns.",
+    assertTrue("Alignment dimension mismatch: original: " + al.getHeight()
+            + "x" + al.getWidth() + ", generated: " + al_input.getHeight()
+            + "x" + al_input.getWidth(),
             al.getHeight() == al_input.getHeight()
                     && al.getWidth() == al_input.getWidth());
 
@@ -183,9 +181,10 @@ public class StockholmFileTest
     // note - at moment we do not distinguish between alignment without any
     // annotation rows and alignment with no annotation row vector
     // we might want to revise this in future
-    int aa_new_size = (aa_new == null ? 0 : aa_new.length), aa_original_size = (aa_original == null ? 0
-            : aa_original.length);
-    Map<Integer, java.util.BitSet> orig_groups = new HashMap<Integer, java.util.BitSet>(), new_groups = new HashMap<Integer, java.util.BitSet>();
+    int aa_new_size = (aa_new == null ? 0 : aa_new.length);
+    int aa_original_size = (aa_original == null ? 0 : aa_original.length);
+    Map<Integer, BitSet> orig_groups = new HashMap<Integer, BitSet>();
+    Map<Integer, BitSet> new_groups = new HashMap<Integer, BitSet>();
 
     if (aa_new != null && aa_original != null)
     {
@@ -196,20 +195,17 @@ public class StockholmFileTest
           assertTrue("Different alignment annotation at position " + i,
                   equalss(aa_original[i], aa_new[i]));
           // compare graphGroup or graph properties - needed to verify JAL-1299
-          assertTrue("Graph type not identical.",
-                  aa_original[i].graph == aa_new[i].graph);
-          assertTrue("Visibility not identical.",
-                  aa_original[i].visible == aa_new[i].visible);
-          assertTrue(
-                  "Threshold line not identical.",
-                  aa_original[i].threshold == null ? aa_new[i].threshold == null
-                          : aa_original[i].threshold
-                                  .equals(aa_new[i].threshold));
+          assertEquals("Graph type not identical.", aa_original[i].graph,
+                  aa_new[i].graph);
+          assertEquals("Visibility not identical.", aa_original[i].visible,
+                  aa_new[i].visible);
+          assertEquals("Threshold line not identical.",
+                  aa_original[i].threshold, aa_new[i].threshold);
           // graphGroup may differ, but pattern should be the same
-          Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2), n_ggrp = new Integer(
-                  aa_new[i].graphGroup + 2);
-          BitSet orig_g = orig_groups.get(o_ggrp), new_g = new_groups
-                  .get(n_ggrp);
+          Integer o_ggrp = new Integer(aa_original[i].graphGroup + 2);
+          Integer n_ggrp = new Integer(aa_new[i].graphGroup + 2);
+          BitSet orig_g = orig_groups.get(o_ggrp);
+          BitSet new_g = new_groups.get(n_ggrp);
           if (orig_g == null)
           {
             orig_groups.put(o_ggrp, orig_g = new BitSet());
@@ -218,8 +214,8 @@ public class StockholmFileTest
           {
             new_groups.put(n_ggrp, new_g = new BitSet());
           }
-          assertTrue("Graph Group pattern differs at annotation " + i,
-                  orig_g.equals(new_g));
+          assertEquals("Graph Group pattern differs at annotation " + i,
+                  orig_g, new_g);
           orig_g.set(i);
           new_g.set(i);
         }
@@ -230,10 +226,9 @@ public class StockholmFileTest
         }
       }
     }
-    assertTrue(
-            "Generated and imported alignment have different annotation sets ("
-                    + aa_new_size + " != " + aa_original_size + ")",
-            aa_new_size == aa_original_size);
+    assertEquals(
+            "Generated and imported alignment have different annotation sets",
+            aa_original_size, aa_new_size);
 
     // check sequences, annotation and features
     SequenceI[] seq_original = new SequenceI[al.getSequencesArray().length];
@@ -260,8 +255,8 @@ public class StockholmFileTest
         {
           String ss_original = seq_original[i].getSequenceAsString();
           String ss_new = seq_new[in].getSequenceAsString();
-          assertTrue("The sequences " + name + "/" + start + "-" + end
-                  + " are not equal", ss_original.equals(ss_new));
+          assertEquals("The sequences " + name + "/" + start + "-" + end
+                  + " are not equal", ss_original, ss_new);
 
           assertTrue(
                   "Sequence Features were not equivalent"
@@ -284,15 +279,15 @@ public class StockholmFileTest
                     .getSequenceFeatures().length];
             sequenceFeatures_new = seq_new[in].getSequenceFeatures();
 
-            assertTrue("different number of features", seq_original[i]
-                    .getSequenceFeatures().length == seq_new[in]
-                    .getSequenceFeatures().length);
+            assertEquals("different number of features",
+                    seq_original[i].getSequenceFeatures().length,
+                    seq_new[in].getSequenceFeatures().length);
 
             for (int feat = 0; feat < seq_original[i].getSequenceFeatures().length; feat++)
             {
-              assertTrue("Different features",
-                      sequenceFeatures_original[feat]
-                              .equals(sequenceFeatures_new[feat]));
+              assertEquals("Different features",
+                      sequenceFeatures_original[feat],
+                      sequenceFeatures_new[feat]);
             }
           }
           // compare alignment annotation
@@ -319,9 +314,9 @@ public class StockholmFileTest
           else if (al.getSequenceAt(i).getAnnotation() != null
                   && al_input.getSequenceAt(in).getAnnotation() == null)
           {
-            assertTrue("Annotations differed between sequences ("
+            fail("Annotations differed between sequences ("
                     + al.getSequenceAt(i).getName() + ") and ("
-                    + al_input.getSequenceAt(i).getName() + ")", false);
+                    + al_input.getSequenceAt(i).getName() + ")");
           }
           break;
         }
index 54d6eb2..dbacceb 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;
@@ -238,20 +258,19 @@ public class ExonerateHelperTest
   {
     FileLoader loader = new FileLoader(false);
     AlignFrame af = loader.LoadFileWaitTillLoaded(
-            "examples/testdata/exonerateseqs.fa",
-            FormatAdapter.FILE);
-  
+            "examples/testdata/exonerateseqs.fa", FormatAdapter.FILE);
+
     af.loadJalviewDataFile("examples/testdata/exonerateoutput.gff",
             FormatAdapter.FILE, null, null);
-  
+
     /*
      * verify one mapping to a dummy sequence, one to a real one
      */
-    List<AlignedCodonFrame> mappings = af
-            .getViewport().getAlignment().getDataset().getCodonFrames();
+    List<AlignedCodonFrame> mappings = af.getViewport().getAlignment()
+            .getDataset().getCodonFrames();
     assertEquals(2, mappings.size());
     Iterator<AlignedCodonFrame> iter = mappings.iterator();
-  
+
     // first mapping is to dummy sequence
     AlignedCodonFrame mapping = iter.next();
     Mapping[] mapList = mapping.getProtMappings();
@@ -262,7 +281,7 @@ public class ExonerateHelperTest
     // 143 in protein should map to codon [11270, 11269, 11268] in dna
     int[] mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
     assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
-  
+
     // second mapping is to a sequence in the alignment
     mapping = iter.next();
     mapList = mapping.getProtMappings();
@@ -271,23 +290,23 @@ public class ExonerateHelperTest
             .findName("DDB_G0280897");
     assertSame(proteinSeq.getDatasetSequence(), mapList[0].getTo());
     assertEquals(1, mapping.getdnaToProt().length);
-  
+
     // 143 in protein should map to codon [11270, 11269, 11268] in dna
     mappedRegion = mapList[0].getMap().locateInFrom(143, 143);
     assertArrayEquals(new int[] { 11270, 11268 }, mappedRegion);
-  
+
     // 182 in protein should map to codon [11153, 11152, 11151] in dna
     mappedRegion = mapList[0].getMap().locateInFrom(182, 182);
     assertArrayEquals(new int[] { 11153, 11151 }, mappedRegion);
-  
+
     // and the reverse mapping:
     mappedRegion = mapList[0].getMap().locateInTo(11151, 11153);
     assertArrayEquals(new int[] { 182, 182 }, mappedRegion);
-  
+
     // 11150 in dna should _not_ map to protein
     mappedRegion = mapList[0].getMap().locateInTo(11150, 11150);
     assertNull(mappedRegion);
-  
+
     // similarly 183 in protein should _not_ map to dna
     mappedRegion = mapList[0].getMap().locateInFrom(183, 183);
     assertNull(mappedRegion);
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 2ee4eac..221f612 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);
-  }
 }
diff --git a/test/jalview/schemes/FeatureColourTest.java b/test/jalview/schemes/FeatureColourTest.java
new file mode 100644 (file)
index 0000000..fd49971
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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 static org.testng.AssertJUnit.fail;
+
+import jalview.datamodel.SequenceFeature;
+import jalview.util.Format;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class FeatureColourTest
+{
+  @Test(groups = { "Functional" })
+  public void testCopyConstructor()
+  {
+    /*
+     * plain colour
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    FeatureColour fc1 = new FeatureColour(fc);
+    assertTrue(fc1.getColour().equals(Color.RED));
+    assertFalse(fc1.isGraduatedColour());
+    assertFalse(fc1.isColourByLabel());
+
+    /*
+     * min-max colour
+     */
+    fc = new FeatureColour(Color.gray, Color.black, 10f, 20f);
+    fc.setAboveThreshold(true);
+    fc.setThreshold(12f);
+    fc1 = new FeatureColour(fc);
+    assertTrue(fc1.isGraduatedColour());
+    assertFalse(fc1.isColourByLabel());
+    assertTrue(fc1.isAboveThreshold());
+    assertEquals(12f, fc1.getThreshold());
+    assertEquals(Color.gray, fc1.getMinColour());
+    assertEquals(Color.black, fc1.getMaxColour());
+    assertEquals(10f, fc1.getMin());
+    assertEquals(20f, fc1.getMax());
+
+    /*
+     * colour by label
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    fc1 = new FeatureColour(fc);
+    assertTrue(fc1.isColourByLabel());
+    assertFalse(fc1.isGraduatedColour());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_simpleColour()
+  {
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertTrue(fc.isColored(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_colourByLabel()
+  {
+    FeatureColour fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertTrue(fc.isColored(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsColored_aboveThreshold()
+  {
+    // graduated colour range from score 20 to 100
+    FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 20f,
+            100f);
+
+    // score 0 is adjusted to bottom of range
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 0f,
+            null);
+    assertTrue(fc.isColored(sf));
+    assertEquals(Color.WHITE, fc.getColor(sf));
+
+    // score 120 is adjusted to top of range
+    sf.setScore(120f);
+    assertEquals(Color.BLACK, fc.getColor(sf));
+
+    // value below threshold is still rendered
+    // setting threshold has no effect yet...
+    fc.setThreshold(60f);
+    sf.setScore(36f);
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    // now apply threshold:
+    fc.setAboveThreshold(true);
+    assertFalse(fc.isColored(sf));
+    // colour is still returned though ?!?
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    sf.setScore(84); // above threshold now
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(51, 51, 51), fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_simpleColour()
+  {
+    FeatureColour fc = new FeatureColour(Color.RED);
+    assertEquals(Color.RED, fc.getColor(new SequenceFeature()));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_colourByLabel()
+  {
+    FeatureColour fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 1f,
+            null);
+    Color expected = UserColourScheme.createColourFromName("desc");
+    assertEquals(expected, fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_Graduated()
+  {
+    // 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,
+            null);
+    // the colour gradient is computed in float values from 0-1 (where 1 == 255)
+    float red = 128 / 255f + 3 / 4f * (255 - 128) / 255f;
+    float green = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+    float blue = 128 / 255f + 3 / 4f * (0 - 128) / 255f;
+    Color expected = new Color(red, green, blue);
+    assertEquals(expected, fc.getColor(sf));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetColor_belowThreshold()
+  {
+    // gradient from [50, 150] from WHITE(255, 255, 255) to BLACK(0, 0, 0)
+    FeatureColour fc = new FeatureColour(Color.WHITE, Color.BLACK, 50f,
+            150f);
+    SequenceFeature sf = new SequenceFeature("type", "desc", 0, 20, 70f,
+            null);
+    fc.setThreshold(100f); // ignore for now
+    assertTrue(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+
+    fc.setAboveThreshold(true); // feature lies below threshold
+    assertFalse(fc.isColored(sf));
+    assertEquals(new Color(204, 204, 204), fc.getColor(sf));
+  }
+
+  /**
+   * Test output of feature colours to Jalview features file format
+   */
+  @Test(groups = { "Functional" })
+  public void testToJalviewFormat()
+  {
+    /*
+     * plain colour - to RGB hex code
+     */
+    FeatureColour fc = new FeatureColour(Color.RED);
+    String redHex = Format.getHexString(Color.RED);
+    String hexColour = redHex;
+    assertEquals("domain\t" + hexColour, fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (no threshold)
+     */
+    fc = new FeatureColour();
+    fc.setColourByLabel(true);
+    assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (autoscaled) (an odd state you can reach by selecting
+     * 'above threshold', then deselecting 'threshold is min/max' then 'colour
+     * by label')
+     */
+    fc.setAutoScaled(true);
+    assertEquals("domain\tlabel", fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (above threshold) (min/max values are output though not
+     * used by this scheme)
+     */
+    fc.setAutoScaled(false);
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    assertEquals("domain\tlabel|||0.0|0.0|above|12.5",
+            fc.toJalviewFormat("domain"));
+
+    /*
+     * colour by label (below threshold)
+     */
+    fc.setBelowThreshold(true);
+    assertEquals("domain\tlabel|||0.0|0.0|below|12.5",
+            fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour, no threshold
+     */
+    fc = new FeatureColour(Color.GREEN, Color.RED, 12f, 25f);
+    String greenHex = Format.getHexString(Color.GREEN);
+    String expected = String.format("domain\t%s|%s|abso|12.0|25.0|none",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * colour ranges over the actual score ranges (not min/max)
+     */
+    fc.setAutoScaled(true);
+    expected = String.format("domain\t%s|%s|12.0|25.0|none", greenHex,
+            redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour below threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setBelowThreshold(true);
+    expected = String.format("domain\t%s|%s|12.0|25.0|below|12.5",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+
+    /*
+     * graduated colour above threshold
+     */
+    fc.setThreshold(12.5f);
+    fc.setAboveThreshold(true);
+    fc.setAutoScaled(false);
+    expected = String.format("domain\t%s|%s|abso|12.0|25.0|above|12.5",
+            greenHex, redHex);
+    assertEquals(expected, fc.toJalviewFormat("domain"));
+  }
+
+  /**
+   * Test parsing of feature colours from Jalview features file format
+   */
+  @Test(groups = { "Functional" })
+  public void testParseJalviewFeatureColour()
+  {
+    /*
+     * simple colour by name
+     */
+    FeatureColour fc = FeatureColour.parseJalviewFeatureColour("red");
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * simple colour by hex code
+     */
+    fc = FeatureColour.parseJalviewFeatureColour(Format
+            .getHexString(Color.RED));
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * simple colour by rgb triplet
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("255,0,0");
+    assertTrue(fc.isSimpleColour());
+    assertEquals(Color.RED, fc.getColour());
+
+    /*
+     * malformed colour
+     */
+    try
+    {
+      fc = FeatureColour.parseJalviewFeatureColour("oops");
+      fail("expected exception");
+    } catch (IllegalArgumentException e)
+    {
+      assertEquals("Invalid colour descriptor: oops", e.getMessage());
+    }
+
+    /*
+     * colour by label (no threshold)
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("label");
+    assertTrue(fc.isColourByLabel());
+    assertFalse(fc.hasThreshold());
+
+    /*
+     * colour by label (with threshold)
+     */
+    fc = FeatureColour
+            .parseJalviewFeatureColour("label|||0.0|0.0|above|12.0");
+    assertTrue(fc.isColourByLabel());
+    assertTrue(fc.isAboveThreshold());
+    assertEquals(12.0f, fc.getThreshold());
+
+    /*
+     * graduated colour (by name) (no threshold)
+     */
+    fc = FeatureColour.parseJalviewFeatureColour("red|green|10.0|20.0");
+    assertTrue(fc.isGraduatedColour());
+    assertFalse(fc.hasThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+    assertTrue(fc.isAutoScaled());
+
+    /*
+     * graduated colour (by hex code) (above threshold)
+     */
+    String descriptor = String.format("%s|%s|10.0|20.0|above|15",
+            Format.getHexString(Color.RED),
+            Format.getHexString(Color.GREEN));
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+    assertTrue(fc.hasThreshold());
+    assertTrue(fc.isAboveThreshold());
+    assertEquals(15f, fc.getThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+    assertTrue(fc.isAutoScaled());
+
+    /*
+     * graduated colour (by RGB triplet) (below threshold), absolute scale
+     */
+    descriptor = String.format("255,0,0|0,255,0|abso|10.0|20.0|below|15");
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+    assertFalse(fc.isAutoScaled());
+    assertTrue(fc.hasThreshold());
+    assertTrue(fc.isBelowThreshold());
+    assertEquals(15f, fc.getThreshold());
+    assertEquals(Color.RED, fc.getMinColour());
+    assertEquals(Color.GREEN, fc.getMaxColour());
+    assertEquals(10f, fc.getMin());
+    assertEquals(20f, fc.getMax());
+
+    descriptor = String
+            .format("blue|255,0,255|absolute|20.0|95.0|below|66.0");
+    fc = FeatureColour.parseJalviewFeatureColour(descriptor);
+    assertTrue(fc.isGraduatedColour());
+  }
+}
diff --git a/test/jalview/schemes/ResidueColourSchemeTest.java b/test/jalview/schemes/ResidueColourSchemeTest.java
new file mode 100644 (file)
index 0000000..8173dd1
--- /dev/null
@@ -0,0 +1,147 @@
+package jalview.schemes;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.analysis.Profile;
+
+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
+     */
+    Profile[] profiles = new Profile[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(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));
+  }
+}
diff --git a/test/jalview/schemes/UserColourSchemeTest.java b/test/jalview/schemes/UserColourSchemeTest.java
new file mode 100644 (file)
index 0000000..34af086
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+
+import java.awt.Color;
+
+import org.testng.annotations.Test;
+
+public class UserColourSchemeTest
+{
+
+  @Test(groups = "Functional")
+  public void testGetColourFromString()
+  {
+    /*
+     * by colour name - if known to AWT, and included in
+     * 
+     * @see ColourSchemeProperty.getAWTColorFromName()
+     */
+    assertSame(Color.RED, UserColourScheme.getColourFromString("red"));
+    assertSame(Color.RED, UserColourScheme.getColourFromString("Red"));
+    assertSame(Color.RED, UserColourScheme.getColourFromString(" RED "));
+
+    /*
+     * by RGB hex code
+     */
+    String hexColour = Integer.toHexString(Color.RED.getRGB() & 0xffffff);
+    assertEquals(Color.RED, UserColourScheme.getColourFromString(hexColour));
+    // 'hex' prefixes _not_ wanted here
+    assertNull(UserColourScheme.getColourFromString("0x" + hexColour));
+    assertNull(UserColourScheme.getColourFromString("#" + hexColour));
+
+    /*
+     * by RGB triplet
+     */
+    String rgb = String.format("%d,%d,%d", Color.red.getRed(),
+            Color.red.getGreen(), Color.red.getBlue());
+    assertEquals(Color.RED, UserColourScheme.getColourFromString(rgb));
+
+    /*
+     * odds and ends
+     */
+    assertNull(UserColourScheme.getColourFromString(null));
+    assertNull(UserColourScheme.getColourFromString("rubbish"));
+    assertEquals(Color.WHITE, UserColourScheme.getColourFromString("-1"));
+    assertNull(UserColourScheme.getColourFromString(String
+            .valueOf(Integer.MAX_VALUE)));
+  }
+}
index 1630110..9ec3a92 100644 (file)
@@ -138,8 +138,8 @@ public class Mapping
     // Associate the 1GAQ pdb file with the subsequence 'imported' from another
     // source
     StructureFile pde = ssm.setMapping(true, new SequenceI[] { sq },
-            new String[]
-    { "A" }, inFile = "examples/1gaq.txt", jalview.io.FormatAdapter.FILE);
+            new String[] { "A" }, inFile = "examples/1gaq.txt",
+            jalview.io.FormatAdapter.FILE);
     assertTrue("PDB File couldn't be found", pde != null);
     StructureMapping[] mp = ssm.getMapping(inFile);
     assertTrue("No mappings made.", mp != null && mp.length > 0);
@@ -250,6 +250,7 @@ public class Mapping
   @Test(groups = { "Functional" })
   public void compareTransferredToRefPDBAnnot() throws Exception
   {
+    StructureImportSettings.setShowSeqFeatures(true);
     AlignFrame ref = new FileLoader(false)
             .LoadFileWaitTillLoaded("test/jalview/ext/jmol/1QCF.pdb",
                     jalview.io.FormatAdapter.FILE);
index 3529375..2074fb4 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.FormatAdapter;
 import jalview.io.StructureFile;
+import jalview.util.MapList;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -43,6 +44,7 @@ public class StructureSelectionManagerTest
   @BeforeMethod(alwaysRun = true)
   public void setUp()
   {
+    StructureImportSettings.setShowSeqFeatures(true);
     ssm = new StructureSelectionManager();
   }
 
@@ -50,7 +52,11 @@ public class StructureSelectionManagerTest
   public void testRegisterMapping()
   {
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
+    acf1.addMap(new Sequence("s1", "ttt"), new Sequence("p1", "p"),
+            new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
     AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    acf2.addMap(new Sequence("s2", "ttt"), new Sequence("p2", "p"),
+            new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
 
     ssm.registerMapping(acf1);
     assertEquals(1, ssm.getSequenceMappings().size());
@@ -74,8 +80,14 @@ public class StructureSelectionManagerTest
   public void testRegisterMappings()
   {
     AlignedCodonFrame acf1 = new AlignedCodonFrame();
+    acf1.addMap(new Sequence("s1", "ttt"), new Sequence("p1", "p"),
+            new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
     AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    acf2.addMap(new Sequence("s2", "ttt"), new Sequence("p2", "p"),
+            new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
     AlignedCodonFrame acf3 = new AlignedCodonFrame();
+    acf3.addMap(new Sequence("s3", "ttt"), new Sequence("p3", "p"),
+            new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
 
     List<AlignedCodonFrame> set1 = new ArrayList<AlignedCodonFrame>();
     set1.add(acf1);
index bb81992..0d00169 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,24 +90,28 @@ 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");
+    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");
     String[][] chains = new String[3][];
     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,
             AppletFormatAdapter.PASTE);
     ssm.setMapping(new SequenceI[] { seq2 }, null, PDB_2,
             AppletFormatAdapter.PASTE);
@@ -109,10 +123,6 @@ public class AAStructureBindingModelTest
       @Override
       public String[] getPdbFile()
       {
-        /*
-         * fudge 'filenames' to match those generated when PDBFile parses PASTE
-         * data
-         */
         return new String[] { "INLINE1YCS", "INLINE3A6S", "INLINE1OOT" };
       }
 
@@ -140,7 +150,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 +175,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 2b12a72..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;
 
@@ -72,4 +73,87 @@ public class ColorUtilsTest
     assertEquals("#800080", ColorUtils.toTkCode(new Color(128, 0, 128))); // purple
     assertEquals("#00ff00", ColorUtils.toTkCode(new Color(0, 255, 0))); // lime
   }
+
+  @Test(groups = { "Functional" })
+  public void testGetGraduatedColour()
+  {
+    Color minColour = new Color(100, 100, 100);
+    Color maxColour = new Color(180, 200, 220);
+
+    /*
+     * value half-way between min and max
+     */
+    Color col = ColorUtils.getGraduatedColour(20f, 10f, minColour, 30f,
+            maxColour);
+    assertEquals(140, col.getRed());
+    assertEquals(150, col.getGreen());
+    assertEquals(160, col.getBlue());
+
+    /*
+     * value two-thirds of the way between min and max
+     */
+    col = ColorUtils
+            .getGraduatedColour(30f, 10f, minColour, 40f, maxColour);
+    assertEquals(153, col.getRed());
+    // Color constructor rounds float value to nearest int
+    assertEquals(167, col.getGreen());
+    assertEquals(180, col.getBlue());
+
+    /*
+     * value = min
+     */
+    col = ColorUtils
+            .getGraduatedColour(10f, 10f, minColour, 30f, maxColour);
+    assertEquals(minColour, col);
+
+    /*
+     * value = max
+     */
+    col = ColorUtils
+            .getGraduatedColour(30f, 10f, minColour, 30f, maxColour);
+    assertEquals(maxColour, col);
+
+    /*
+     * value < min
+     */
+    col = ColorUtils.getGraduatedColour(0f, 10f, minColour, 30f, maxColour);
+    assertEquals(minColour, col);
+
+    /*
+     * value > max
+     */
+    col = ColorUtils
+            .getGraduatedColour(40f, 10f, minColour, 30f, maxColour);
+    assertEquals(maxColour, col);
+
+    /*
+     * min = max
+     */
+    col = ColorUtils
+            .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 0c2c998..9aab66c 100644 (file)
@@ -49,7 +49,7 @@ public class ComparisonTest
    * AGCTU. Test is not case-sensitive and ignores gaps.
    */
   @Test(groups = { "Functional" })
-  public void testIsNucleotide()
+  public void testIsNucleotide_sequences()
   {
     SequenceI seq = new Sequence("eightypercent", "agctuAGCPV");
     assertFalse(Comparison.isNucleotide(new SequenceI[] { seq }));
@@ -130,6 +130,23 @@ public class ComparisonTest
             0.001f);
   }
 
+  @Test(groups = { "Functional" })
+  public void testIsNucleotide()
+  {
+    assertTrue(Comparison.isNucleotide('a'));
+    assertTrue(Comparison.isNucleotide('A'));
+    assertTrue(Comparison.isNucleotide('c'));
+    assertTrue(Comparison.isNucleotide('C'));
+    assertTrue(Comparison.isNucleotide('g'));
+    assertTrue(Comparison.isNucleotide('G'));
+    assertTrue(Comparison.isNucleotide('t'));
+    assertTrue(Comparison.isNucleotide('T'));
+    assertTrue(Comparison.isNucleotide('u'));
+    assertTrue(Comparison.isNucleotide('U'));
+    assertFalse(Comparison.isNucleotide('-'));
+    assertFalse(Comparison.isNucleotide('P'));
+  }
+
   /**
    * Test the percentage identity calculation for two sequences
    */
@@ -158,4 +175,17 @@ public class ComparisonTest
     assertEquals(87.5f, Comparison.PID(seq1, seq2, 0, length, false, true),
             0.001f);
   }
+
+  @Test(groups = { "Functional" })
+  public void testIsNucleotideSequence()
+  {
+    assertFalse(Comparison.isNucleotideSequence(null, true));
+    assertTrue(Comparison.isNucleotideSequence("", true));
+    assertTrue(Comparison.isNucleotideSequence("aAgGcCtTuU", true));
+    assertTrue(Comparison.isNucleotideSequence("aAgGcCtTuU", false));
+    assertFalse(Comparison.isNucleotideSequence("xAgGcCtTuU", false));
+    assertFalse(Comparison.isNucleotideSequence("aAgGcCtTuUx", false));
+    assertTrue(Comparison.isNucleotideSequence("a A-g.GcCtTuU", true));
+    assertFalse(Comparison.isNucleotideSequence("a A-g.GcCtTuU", false));
+  }
 }
index c5e8ef5..8d2901d 100644 (file)
@@ -33,6 +33,8 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 
+import java.util.List;
+
 import org.testng.annotations.Test;
 
 public class DBRefUtilsTest
@@ -97,6 +99,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" })
@@ -156,6 +163,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]);
@@ -191,12 +201,12 @@ public class DBRefUtilsTest
     ref5.setMap(new Mapping(new MapList(new int[] { 1, 1 }, new int[] { 1,
         1 }, 1, 1)));
 
-    DBRefEntry[] matches = DBRefUtils.searchRefs(new DBRefEntry[] { ref1,
-        ref2, ref3, ref4, ref5 }, target);
-    assertEquals(3, matches.length);
-    assertSame(ref1, matches[0]);
-    assertSame(ref2, matches[1]);
-    assertSame(ref5, matches[2]);
+    List<DBRefEntry> matches = DBRefUtils.searchRefs(new DBRefEntry[] {
+        ref1, ref2, ref3, ref4, ref5 }, target);
+    assertEquals(3, matches.size());
+    assertSame(ref1, matches.get(0));
+    assertSame(ref2, matches.get(1));
+    assertSame(ref5, matches.get(2));
   }
 
   /**
@@ -224,11 +234,11 @@ public class DBRefUtilsTest
             new int[] { 1, 1 }, 2, 2));
     ref3.setMap(map3);
 
-    DBRefEntry[] matches = DBRefUtils.searchRefs(new DBRefEntry[] { ref1,
-        ref2, ref3 }, target);
-    assertEquals(2, matches.length);
-    assertSame(ref1, matches[0]);
-    assertSame(ref2, matches[1]);
+    List<DBRefEntry> matches = DBRefUtils.searchRefs(new DBRefEntry[] {
+        ref1, ref2, ref3 }, target);
+    assertEquals(2, matches.size());
+    assertSame(ref1, matches.get(0));
+    assertSame(ref2, matches.get(1));
   }
 
   /**
@@ -238,7 +248,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
@@ -248,12 +258,41 @@ 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[] matches = DBRefUtils.searchRefs(new DBRefEntry[] { ref1,
-        ref2, ref3, ref4, ref5 }, "A1234");
-    assertEquals(3, matches.length);
-    assertSame(ref1, matches[0]);
-    assertSame(ref2, matches[1]);
-    assertSame(ref5, matches[2]);
+
+    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));
+    assertSame(ref2, matches.get(1));
+    assertSame(ref5, matches.get(2));
+  }
+
+  /**
+   * Test the method that searches for matches references - case when we are
+   * matching a reference with null (any) accession id
+   */
+  @Test(groups = { "Functional" })
+  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
+    // constructor does not upper-case accession id
+    DBRefEntry ref3 = new DBRefEntry("EMBL", "1", "A1236"); // matches
+    DBRefEntry ref4 = new DBRefEntry("EMBLCDS", "1", "A1234"); // no match
+    // ref5 matches although it has a mapping - ignored
+    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);
+    assertEquals(4, matches.size());
+    assertSame(ref1, matches.get(0));
+    assertSame(ref2, matches.get(1));
+    assertSame(ref3, matches.get(2));
+    assertSame(ref5, matches.get(3));
   }
 }
diff --git a/test/jalview/util/DnaUtilsTest.java b/test/jalview/util/DnaUtilsTest.java
new file mode 100644 (file)
index 0000000..b9083f5
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.fail;
+
+import java.text.ParseException;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class DnaUtilsTest
+{
+  /**
+   * Tests for parsing an ENA/GenBank location specifier
+   * 
+   * @throws ParseException
+   * 
+   * @see http://www.insdc.org/files/feature_table.html#3.4
+   */
+  @Test(groups = { "Functional" })
+  public void testParseLocation() throws ParseException
+  {
+    /*
+     * single locus
+     */
+    List<int[]> ranges = DnaUtils.parseLocation("467");
+    assertEquals(1, ranges.size());
+    assertEquals(467, ranges.get(0)[0]);
+    assertEquals(467, ranges.get(0)[1]);
+
+    /*
+     * simple range
+     */
+    ranges = DnaUtils.parseLocation("12..78");
+    assertEquals(1, ranges.size());
+    assertEquals(12, ranges.get(0)[0]);
+    assertEquals(78, ranges.get(0)[1]);
+
+    /*
+     * join of simple ranges
+     */
+    ranges = DnaUtils.parseLocation("join(12..78,134..202,322..345)");
+    assertEquals(3, ranges.size());
+    assertEquals(12, ranges.get(0)[0]);
+    assertEquals(78, ranges.get(0)[1]);
+    assertEquals(134, ranges.get(1)[0]);
+    assertEquals(202, ranges.get(1)[1]);
+    assertEquals(322, ranges.get(2)[0]);
+    assertEquals(345, ranges.get(2)[1]);
+
+    /*
+     * complement of a simple range
+     */
+    ranges = DnaUtils.parseLocation("complement(34..126)");
+    assertEquals(1, ranges.size());
+    assertEquals(126, ranges.get(0)[0]);
+    assertEquals(34, ranges.get(0)[1]);
+
+    /*
+     * complement of a join
+     */
+    ranges = DnaUtils
+            .parseLocation("complement(join(2691..4571,4918..5163))");
+    assertEquals(2, ranges.size());
+    assertEquals(5163, ranges.get(0)[0]);
+    assertEquals(4918, ranges.get(0)[1]);
+    assertEquals(4571, ranges.get(1)[0]);
+    assertEquals(2691, ranges.get(1)[1]);
+
+    /*
+     * join of two complements
+     */
+    ranges = DnaUtils
+            .parseLocation("join(complement(4918..5163),complement(2691..4571))");
+    assertEquals(2, ranges.size());
+    assertEquals(5163, ranges.get(0)[0]);
+    assertEquals(4918, ranges.get(0)[1]);
+    assertEquals(4571, ranges.get(1)[0]);
+    assertEquals(2691, ranges.get(1)[1]);
+
+    /*
+     * join complement to non-complement
+     * @see http://www.ncbi.nlm.nih.gov/genbank/genomesubmit_annotation/ Transpliced Genes
+     */
+    ranges = DnaUtils
+            .parseLocation("join(complement(36618..36700),86988..87064)");
+    assertEquals(2, ranges.size());
+    assertEquals(36700, ranges.get(0)[0]);
+    assertEquals(36618, ranges.get(0)[1]);
+    assertEquals(86988, ranges.get(1)[0]);
+    assertEquals(87064, ranges.get(1)[1]);
+
+    /*
+     * valid things we don't yet handle
+     */
+    checkForParseException("<34..126");
+    checkForParseException("35..>126");
+    checkForParseException("34.126");
+    checkForParseException("34^126");
+    checkForParseException("order(34..126,130..180)");
+
+    /*
+     * invalid things
+     */
+    checkForParseException("");
+    checkForParseException("JOIN(1..2)");
+    checkForParseException("join(1..2");
+    checkForParseException("join(1..2(");
+    checkForParseException("complement(1..2");
+    checkForParseException("complement(1..2(");
+    try
+    {
+      assertNull(DnaUtils.parseLocation(null));
+      fail("Expected exception");
+    } catch (NullPointerException e)
+    {
+      // expected
+    }
+
+    /*
+     * nested joins are not allowed; just as well since this fails to parse
+     * (splitting tokens by comma fragments the inner join expression)
+     */
+    checkForParseException("join(1..2,join(4..5,10..12),18..22)");
+    /*
+     * complement may not enclose multiple ranges 
+     * parsing fails for the same reason
+     */
+    checkForParseException("join(complement(36618..36700,4000..4200),86988..87064)");
+  }
+
+  /**
+   * Verifies that a ParseException is thrown when the given location is parsed
+   * 
+   * @param location
+   */
+  void checkForParseException(String location)
+  {
+    try
+    {
+      DnaUtils.parseLocation(location);
+      fail("Expected exception");
+    } catch (ParseException e)
+    {
+      // expected;
+    }
+  }
+
+}
diff --git a/test/jalview/util/FormatTest.java b/test/jalview/util/FormatTest.java
new file mode 100644 (file)
index 0000000..18199f9
--- /dev/null
@@ -0,0 +1,32 @@
+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.456f, 0);
+    assertEquals(sb.toString(), "123");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.456f, 1);
+    assertEquals(sb.toString(), "123.4");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.456f, 2);
+    assertEquals(sb.toString(), "123.45");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.456f, 3);
+    assertEquals(sb.toString(), "123.456");
+
+    sb.setLength(0);
+    Format.appendPercentage(sb, 123.456f, 4);
+    assertEquals(sb.toString(), "123.4560");
+  }
+}
index d4ed0ea..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" })
@@ -563,6 +562,21 @@ public class MapListTest
             s);
   }
 
+  /**
+   * Test that confirms adding a map twice does nothing
+   */
+  @Test(groups = { "Functional" })
+  public void testAddMapList_sameMap()
+  {
+    MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
+            new int[] { 72, 22 }, 1, 3);
+    String before = ml.toString();
+    ml.addMapList(ml);
+    assertEquals(before, ml.toString());
+    ml.addMapList(new MapList(ml));
+    assertEquals(before, ml.toString());
+  }
+
   @Test(groups = { "Functional" })
   public void testAddMapList_contiguous()
   {
@@ -656,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 3c417c3..655aa2a 100644 (file)
@@ -703,6 +703,82 @@ public class MappingUtilsTest
     assertEquals(0, result.size());
   }
 
+  /**
+   * just like the one above, but this time, we provide a set of sequences to
+   * subselect the mapping search
+   */
+  @Test(groups = { "Functional" })
+  public void testFindMappingsForSequenceAndOthers()
+  {
+    SequenceI seq1 = new Sequence("Seq1", "ABC");
+    SequenceI seq2 = new Sequence("Seq2", "ABC");
+    SequenceI seq3 = new Sequence("Seq3", "ABC");
+    SequenceI seq4 = new Sequence("Seq4", "ABC");
+    seq1.createDatasetSequence();
+    seq2.createDatasetSequence();
+    seq3.createDatasetSequence();
+    seq4.createDatasetSequence();
+
+    /*
+     * 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);
+    acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
+    AlignedCodonFrame acf2 = new AlignedCodonFrame();
+    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);
+
+    /*
+     * test for null args
+     */
+    List<AlignedCodonFrame> result = MappingUtils
+            .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));
+    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" })
   public void testMapEditCommand()
   {
@@ -791,7 +867,7 @@ public class MappingUtilsTest
   public void testMapColumnSelection_hiddenColumns() throws IOException
   {
     setupMappedAlignments();
-  
+
     ColumnSelection proteinSelection = new ColumnSelection();
 
     /*
@@ -799,8 +875,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());
@@ -815,7 +891,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)));
@@ -826,7 +903,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());
 
     /*
@@ -837,7 +915,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());
@@ -850,7 +929,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)));
@@ -984,42 +1064,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));
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..c9a07a1
--- /dev/null
@@ -0,0 +1,79 @@
+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);
+  }
+
+}
index dc2555b..4dc44d4 100644 (file)
@@ -165,4 +165,57 @@ public class StringUtilsTest
     assertEquals(0,
             StringUtils.parseInt(String.valueOf(Integer.MAX_VALUE) + "1"));
   }
+
+  @Test(groups = { "Functional" })
+  public void testCompareVersions()
+  {
+    assertEquals(0, StringUtils.compareVersions(null, null));
+    assertEquals(0, StringUtils.compareVersions("2.8.3", null));
+
+    /*
+     * same version returns 0
+     */
+    assertEquals(0, StringUtils.compareVersions("2.8", "2.8"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3", "2.8.3"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3b1", "2.8.3b1", "b"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3B1", "2.8.3b1", "b"));
+    assertEquals(0, StringUtils.compareVersions("2.8.3b1", "2.8.3B1", "b"));
+
+    /*
+     * v1 < v2 returns -1
+     */
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.8.4"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.9"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.9.2"));
+    assertEquals(-1, StringUtils.compareVersions("2.8", "2.8.3"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3", "2.8.3b1", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2.8.3b1", "2.8.3b2", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2.8", "2.8.0", "b"));
+    assertEquals(-1, StringUtils.compareVersions("2", "12"));
+    assertEquals(-1, StringUtils.compareVersions("3.2.4", "3.12.11"));
+
+    /*
+     * v1 > v2 returns +1
+     */
+    assertEquals(1, StringUtils.compareVersions("2.8.3", "2.8"));
+    assertEquals(1, StringUtils.compareVersions("2.8.0", "2.8"));
+    assertEquals(1, StringUtils.compareVersions("2.8.4", "2.8.3"));
+    assertEquals(1, StringUtils.compareVersions("2.8.3b1", "2.8.3", "b"));
+    assertEquals(1, StringUtils.compareVersions("2.8.3", "2.8.2b1", "b"));
+    assertEquals(1, StringUtils.compareVersions("2.8.0b2", "2.8.0b1", "b"));
+    assertEquals(1, StringUtils.compareVersions("12", "2"));
+    assertEquals(1, StringUtils.compareVersions("3.12.11", "3.2.4"));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testToSentenceCase()
+  {
+    assertEquals("John", StringUtils.toSentenceCase("john"));
+    assertEquals("John", StringUtils.toSentenceCase("JOHN"));
+    assertEquals("John and james",
+            StringUtils.toSentenceCase("JOHN and JAMES"));
+    assertEquals("J", StringUtils.toSentenceCase("j"));
+    assertEquals("", StringUtils.toSentenceCase(""));
+    assertNull(StringUtils.toSentenceCase(null));
+  }
 }
diff --git a/test/jalview/util/UrlLinkTest.java b/test/jalview/util/UrlLinkTest.java
new file mode 100644 (file)
index 0000000..45ef6af
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * 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.SEQUENCE_ID;
+import static jalview.util.UrlConstants.SEQUENCE_NAME;
+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 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_NAME
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_NAME
+            + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // SEQUENCE_ID
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID + DELIM
+            + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    assertNull(ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // Not dynamic
+    ul = new UrlLink(DB + SEP + URL_PREFIX + URL_SUFFIX.substring(1));
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX + URL_SUFFIX.substring(1), ul.getUrl_prefix());
+    assertFalse(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    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_NAME
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_NAME
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertFalse(ul.usesSeqId());
+    assertEquals(REGEX_NESTED.substring(2, REGEX_NESTED.length() - 2),
+            ul.getRegexReplace());
+    assertTrue(ul.isValid());
+    assertNull(ul.getInvalidMessage());
+
+    // SEQUENCE_ID
+    ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + REGEX_NESTED + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    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 + SEQUENCE_ID
+            + REGEX_RUBBISH + DELIM + URL_SUFFIX);
+    assertEquals(DB.toUpperCase(), ul.getTarget());
+    assertEquals(DB, ul.getLabel());
+    assertEquals(URL_PREFIX, ul.getUrl_prefix());
+    assertEquals(URL_SUFFIX, ul.getUrl_suffix());
+    assertTrue(ul.isDynamic());
+    assertTrue(ul.usesSeqId());
+    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_NAME
+            + 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
+   */
+  @Test(groups = { "Functional" })
+  public void testMakeUrlWithRegex()
+  {
+    // Unused regex
+    UrlLink ul = new UrlLink(DB + SEP + URL_PREFIX + DELIM + SEQUENCE_ID
+            + 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());
+  }
+
+}
diff --git a/test/jalview/workers/AlignCalcManagerTest.java b/test/jalview/workers/AlignCalcManagerTest.java
new file mode 100644 (file)
index 0000000..acb9f33
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcWorkerI;
+import jalview.api.FeatureRenderer;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class AlignCalcManagerTest
+{
+  private AlignFrame alignFrame;
+
+  /**
+   * Test the method that removes a worker associated with an annotation,
+   * provided the worker is marked as 'deletable' (some workers should continue
+   * to run even when their results are no longer displayed)
+   */
+  @Test(groups = "Functional")
+  public void testRemoveWorkerForAnnotation()
+  {
+    AlignCalcManagerI acm = alignFrame.getViewport().getCalcManager();
+    final AlignmentAnnotation ann1 = new AlignmentAnnotation("Ann1",
+            "desc", new Annotation[] {});
+    final AlignmentAnnotation ann2 = new AlignmentAnnotation("Ann2",
+            "desc", new Annotation[] {});
+
+    /*
+     * make two workers for ann1, one deletable, one not
+     * and no worker for ann2
+     */
+    AlignCalcWorkerI worker1 = makeWorker(ann1, true);
+    AlignCalcWorkerI worker2 = makeWorker(ann1, false);
+
+    /*
+     * The new workers will get run each in their own thread.
+     * We can't tell here whether they have finished, or not yet started.
+     * They have to finish to be 'seen' by getRegisteredWorkersOfClass()
+     *   registerWorker adds to the 'restartable' list but
+     *   getRegisteredWorkers reads from the 'canUpdate' list
+     *   (which is only updated after a worker has run) - why?
+     * So just give workers time to start and finish
+     */
+    synchronized (this)
+    {
+      try
+      {
+        wait(100);
+      } catch (InterruptedException e)
+      {
+        //
+      }
+    }
+
+    List<AlignCalcWorkerI> workers = acm
+            .getRegisteredWorkersOfClass(worker1.getClass());
+    assertEquals(2, workers.size());
+    assertTrue(workers.contains(worker1));
+    assertTrue(workers.contains(worker2));
+    assertFalse(acm.isDisabled(worker1));
+    assertFalse(acm.isDisabled(worker2));
+
+    /*
+     * remove workers for ann2 (there aren't any)
+     */
+    acm.removeWorkerForAnnotation(ann2);
+    assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass())
+            .contains(worker1));
+    assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass())
+            .contains(worker2));
+    assertFalse(acm.isDisabled(worker1));
+    assertFalse(acm.isDisabled(worker2));
+
+    /*
+     * remove worker2 for ann1
+     * - should delete worker1 but not worker2
+     */
+    acm.removeWorkerForAnnotation(ann1);
+    assertEquals(1, acm.getRegisteredWorkersOfClass(worker1.getClass())
+            .size());
+    assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass())
+            .contains(worker2));
+    assertFalse(acm.isDisabled(worker1));
+    assertFalse(acm.isDisabled(worker2));
+  }
+
+  /**
+   * Make a worker linked to the given annotation
+   * 
+   * @param ann
+   * @param deletable
+   * @return
+   */
+  AnnotationWorker makeWorker(final AlignmentAnnotation ann,
+          final boolean deletable)
+  {
+    AnnotationProviderI annotationProvider = new AnnotationProviderI()
+    {
+      @Override
+      public List<AlignmentAnnotation> calculateAnnotation(AlignmentI al,
+              FeatureRenderer fr)
+      {
+        return Collections.singletonList(ann);
+      }
+    };
+    return new AnnotationWorker(alignFrame.getViewport(),
+            alignFrame.alignPanel, annotationProvider)
+    {
+      @Override
+      public boolean isDeletable()
+      {
+        return deletable;
+      }
+
+      @Override
+      public boolean involves(AlignmentAnnotation ann1)
+      {
+        return ann == ann1;
+      }
+    };
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp()
+  {
+    AlignmentI al = new Alignment(new SequenceI[] { new Sequence("Seq1",
+            "ABC") });
+    al.setDataset(null);
+    alignFrame = new AlignFrame(al, 3, 1);
+  }
+}
index d020173..4b9437a 100644 (file)
@@ -25,6 +25,8 @@ import static org.testng.AssertJUnit.assertTrue;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.structure.StructureImportSettings;
+import jalview.structure.StructureImportSettings.StructureParser;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
 import java.util.List;
@@ -40,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());
@@ -60,6 +63,7 @@ public class PDBSequenceFetcherTest
   @Test(groups = { "Network" }, enabled = true)
   public void testRnaSeqRetrieve() throws Exception
   {
+    Cache.applicationProperties.setProperty("PDB_DOWNLOAD_FORMAT", "PDB");
     List<DbSourceProxy> sps = sf.getSourceProxy("PDB");
     AlignmentI response = sps.get(0).getSequenceRecords("2GIS");
     assertTrue(response != null);
@@ -76,4 +80,40 @@ public class PDBSequenceFetcherTest
     }
   }
 
+  @Test(groups = { "Network" }, enabled = true)
+  public void testPdbSeqRetrieve() throws Exception
+  {
+    StructureImportSettings.setDefaultStructureFileFormat("PDB");
+    StructureImportSettings
+            .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
+
+    testRetrieveProteinSeqFromPDB();
+  }
+
+  @Test(groups = { "Network" }, enabled = true)
+  public void testmmCifSeqRetrieve() throws Exception
+  {
+    StructureImportSettings.setDefaultStructureFileFormat("mmCIF");
+    testRetrieveProteinSeqFromPDB();
+  }
+
+  private void testRetrieveProteinSeqFromPDB() throws Exception
+  {
+    List<DbSourceProxy> sps = sf.getSourceProxy("PDB");
+    AlignmentI response = sps.get(0).getSequenceRecords("1QIP");
+    assertTrue(response != null);
+    assertTrue(response.getHeight() == 4);
+    for (SequenceI sq : response.getSequences())
+    {
+      assertTrue("No annotation transfered to sequence.",
+              sq.getAnnotation().length > 0);
+      assertTrue("No PDBEntry on sequence.",
+              sq.getAllPDBEntries().size() > 0);
+      org.testng.Assert
+              .assertEquals(sq.getEnd() - sq.getStart() + 1,
+                      sq.getLength(),
+                      "Sequence start/end doesn't match number of residues in sequence");
+    }
+  }
+
 }
index a54ce8b..bc9f9a2 100644 (file)
@@ -1,5 +1,26 @@
+/*
+ * 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;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefSource;
@@ -24,8 +45,6 @@ public class SequenceFetcherTest
     // TODO: extracted from SequenceFetcher - convert to proper unit test with
     // assertions
 
-    AlignmentI ds = null;
-    Vector<Object[]> noProds = new Vector<Object[]>();
     String usage = "SequenceFetcher.main [-nodas] [<DBNAME> [<ACCNO>]]\n"
             + "With no arguments, all DbSources will be queried with their test Accession number.\n"
             + "With one argument, the argument will be resolved to one or more db sources and each will be queried with their test accession only.\n"
@@ -44,7 +63,7 @@ public class SequenceFetcherTest
     {
       List<DbSourceProxy> sps = new SequenceFetcher(withDas)
               .getSourceProxy(argv[0]);
-  
+
       if (sps != null)
       {
         for (DbSourceProxy sp : sps)
@@ -52,8 +71,8 @@ public class SequenceFetcherTest
           AlignmentI al = null;
           try
           {
-            al = sp.getSequenceRecords(argv.length > 1 ? argv[1] : sp
-                    .getTestQuery());
+            testRetrieval(argv[0], sp,
+                    argv.length > 1 ? argv[1] : sp.getTestQuery());
           } catch (Exception e)
           {
             e.printStackTrace();
@@ -61,16 +80,6 @@ public class SequenceFetcherTest
                     + (argv.length > 1 ? argv[1] : sp.getTestQuery())
                     + " from " + argv[0] + "\nUsage: " + usage);
           }
-          SequenceI[] prod = al.getSequencesArray();
-          if (al != null)
-          {
-            for (int p = 0; p < prod.length; p++)
-            {
-              System.out.println("Prod " + p + ": "
-                      + prod[p].getDisplayId(true) + " : "
-                      + prod[p].getDescription());
-            }
-          }
         }
         return;
       }
@@ -95,139 +104,135 @@ public class SequenceFetcherTest
       }
       for (DbSourceProxy sp : sfetcher.getSourceProxy(db))
       {
-        System.out.println("Source: " + sp.getDbName() + " (" + db
-                + "): retrieving test:" + sp.getTestQuery());
-        AlignmentI al = null;
-        try
+        testRetrieval(db, sp, sp.getTestQuery());
+      }
+    }
+
+  }
+
+  private static void testRetrieval(String db, DbSourceProxy sp,
+          String testQuery)
+  {
+    AlignmentI ds = null;
+    Vector<Object[]> noProds = new Vector<Object[]>();
+    System.out.println("Source: " + sp.getDbName() + " (" + db
+            + "): retrieving test:" + sp.getTestQuery());
+    {
+      AlignmentI al = null;
+      try
+      {
+        al = sp.getSequenceRecords(testQuery);
+        if (al != null && al.getHeight() > 0)
         {
-          al = sp.getSequenceRecords(sp.getTestQuery());
-          if (al != null && al.getHeight() > 0)
+          boolean dna = sp.isDnaCoding();
+          al.setDataset(null);
+          AlignmentI alds = al.getDataset();
+          // try and find products
+          CrossRef crossRef = new CrossRef(al.getSequencesArray(), alds);
+          List<String> types = crossRef.findXrefSourcesForSequences(dna);
+          if (types != null)
           {
-            boolean dna = sp.isDnaCoding();
-            // try and find products
-            String types[] = jalview.analysis.CrossRef
-                    .findSequenceXrefTypes(dna, al.getSequencesArray());
-            if (types != null)
+            System.out.println("Xref Types for: " + (dna ? "dna" : "prot"));
+            for (String source : types)
             {
-              System.out.println("Xref Types for: "
-                      + (dna ? "dna" : "prot"));
-              for (int t = 0; t < types.length; t++)
+              System.out.println("Type: " + source);
+              SequenceI[] prod = crossRef.findXrefSequences(source, dna)
+                      .getSequencesArray();
+              System.out.println("Found "
+                      + ((prod == null) ? "no" : "" + prod.length)
+                      + " products");
+              if (prod != null)
               {
-                System.out.println("Type: " + types[t]);
-                SequenceI[] prod = jalview.analysis.CrossRef
-                        .findXrefSequences(al.getSequencesArray(), dna,
-                                types[t], null)
-                        .getSequencesArray();
-                System.out.println("Found "
-                        + ((prod == null) ? "no" : "" + prod.length)
-                        + " products");
-                if (prod != null)
+                for (int p = 0; p < prod.length; p++)
                 {
-                  for (int p = 0; p < prod.length; p++)
-                  {
-                    System.out.println("Prod " + p + ": "
-                            + prod[p].getDisplayId(true));
-                  }
+                  System.out.println("Prod " + p + ": "
+                          + prod[p].getDisplayId(true));
                 }
               }
             }
-            else
-            {
-              noProds.addElement((dna ? new Object[] { al, al }
-                      : new Object[] { al }));
-            }
-  
-          }
-        } catch (Exception ex)
-        {
-          System.out.println("ERROR:Failed to retrieve test query.");
-          ex.printStackTrace(System.out);
-        }
-  
-        if (al == null)
-        {
-          System.out.println("ERROR:No alignment retrieved.");
-          StringBuffer raw = sp.getRawRecords();
-          if (raw != null)
-          {
-            System.out.println(raw.toString());
           }
           else
           {
-            System.out.println("ERROR:No Raw results.");
+            noProds.addElement((dna ? new Object[] { al, al }
+                    : new Object[] { al }));
           }
+
+        }
+      } catch (Exception ex)
+      {
+        System.out.println("ERROR:Failed to retrieve test query.");
+        ex.printStackTrace(System.out);
+      }
+
+      if (al == null)
+      {
+        System.out.println("ERROR:No alignment retrieved.");
+        StringBuffer raw = sp.getRawRecords();
+        if (raw != null)
+        {
+          System.out.println(raw.toString());
         }
         else
         {
-          System.out.println("Retrieved " + al.getHeight() + " sequences.");
-          for (int s = 0; s < al.getHeight(); s++)
-          {
-            SequenceI sq = al.getSequenceAt(s);
-            while (sq.getDatasetSequence() != null)
-            {
-              sq = sq.getDatasetSequence();
-  
-            }
-            if (ds == null)
-            {
-              ds = new Alignment(new SequenceI[] { sq });
-  
-            }
-            else
-            {
-              ds.addSequence(sq);
-            }
-          }
+          System.out.println("ERROR:No Raw results.");
+        }
+      }
+      else
+      {
+        System.out.println("Retrieved " + al.getHeight() + " sequences.");
+        if (ds == null)
+        {
+          ds = al.getDataset();
+        }
+        else
+        {
+          ds.append(al.getDataset());
+          al.setDataset(ds);
         }
-        System.out.flush();
-        System.err.flush();
-  
       }
-      if (noProds.size() > 0)
+      System.out.flush();
+      System.err.flush();
+    }
+    if (noProds.size() > 0)
+    {
+      Enumeration<Object[]> ts = noProds.elements();
+      while (ts.hasMoreElements())
+
       {
-        Enumeration<Object[]> ts = noProds.elements();
-        while (ts.hasMoreElements())
-  
+        Object[] typeSq = ts.nextElement();
+        boolean dna = (typeSq.length > 1);
+        AlignmentI al = (AlignmentI) typeSq[0];
+        System.out.println("Trying getProducts for "
+                + al.getSequenceAt(0).getDisplayId(true));
+        System.out.println("Search DS Xref for: " + (dna ? "dna" : "prot"));
+        // have a bash at finding the products amongst all the retrieved
+        // sequences.
+        SequenceI[] seqs = al.getSequencesArray();
+        Alignment prodal = new CrossRef(seqs, ds).findXrefSequences(null,
+                dna);
+        System.out.println("Found "
+                + ((prodal == null) ? "no" : "" + prodal.getHeight())
+                + " products");
+        if (prodal != null)
         {
-          Object[] typeSq = ts.nextElement();
-          boolean dna = (typeSq.length > 1);
-          AlignmentI al = (AlignmentI) typeSq[0];
-          System.out.println("Trying getProducts for "
-                  + al.getSequenceAt(0).getDisplayId(true));
-          System.out.println("Search DS Xref for: "
-                  + (dna ? "dna" : "prot"));
-          // have a bash at finding the products amongst all the retrieved
-          // sequences.
-          SequenceI[] seqs = al.getSequencesArray();
-          Alignment prodal = jalview.analysis.CrossRef.findXrefSequences(
-                  seqs, dna, null, ds);
-          System.out.println("Found "
-                  + ((prodal == null) ? "no" : "" + prodal.getHeight())
-                  + " products");
-          if (prodal != null)
+          SequenceI[] prod = prodal.getSequencesArray(); // note
+          // should
+          // test
+          // rather
+          // than
+          // throw
+          // away
+          // codon
+          // mapping
+          // (if
+          // present)
+          for (int p = 0; p < prod.length; p++)
           {
-            SequenceI[] prod = prodal.getSequencesArray(); // note
-            // should
-            // test
-            // rather
-            // than
-            // throw
-            // away
-            // codon
-            // mapping
-            // (if
-            // present)
-            for (int p = 0; p < prod.length; p++)
-            {
-              System.out.println("Prod " + p + ": "
-                      + prod[p].getDisplayId(true));
-            }
+            System.out.println("Prod " + p + ": "
+                    + prod[p].getDisplayId(true));
           }
         }
-  
       }
-  
     }
   }
-
 }
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
      */
diff --git a/test/jalview/ws/dbsources/XfamFetcherTest.java b/test/jalview/ws/dbsources/XfamFetcherTest.java
new file mode 100644 (file)
index 0000000..c894fd1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.dbsources;
+
+import jalview.datamodel.AlignmentI;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class XfamFetcherTest
+{
+  @Test(groups = { "External" })
+  public void testRfamSeed() throws Exception
+  {
+    // RfamFull rff = new RfamFull();
+    RfamSeed rfs = new RfamSeed();
+
+    AlignmentI seedrf = rfs.getSequenceRecords(rfs.getTestQuery());
+    Assert.assertNotNull(seedrf, "Seed Alignment for " + rfs.getTestQuery()
+            + " didn't retrieve.");
+    Assert.assertTrue(seedrf.getHeight() > 1,
+            "Seed Alignment for " + rfs.getTestQuery()
+                    + " didn't contain more than one sequence.");
+  }
+
+  @Test(groups = { "External" })
+  public void testPfamFullAndSeed() throws Exception
+  {
+    PfamFull pff = new PfamFull();
+    PfamSeed pfseed = new PfamSeed();
+
+    AlignmentI fullpf = pff.getSequenceRecords(pff.getTestQuery());
+    Assert.assertNotNull(fullpf, "Full Alignment for " + pff.getTestQuery()
+            + " didn't retrieve.");
+    Assert.assertTrue(fullpf.getHeight() > 1,
+            "Full Alignment for " + pff.getTestQuery()
+                    + " didn't have more than one sequence.");
+    AlignmentI seedpf = pfseed.getSequenceRecords(pff.getTestQuery());
+    Assert.assertNotNull(seedpf, "Seed Alignment for " + pff.getTestQuery()
+            + " didn't retrieve.");
+
+    Assert.assertTrue(seedpf.getHeight() < fullpf.getHeight(),
+            "Expected Full alignment to have more sequences than seed for "
+                    + pff.getTestQuery());
+  }
+}
diff --git a/test/jalview/ws/ebi/EBIFetchClientTest.java b/test/jalview/ws/ebi/EBIFetchClientTest.java
new file mode 100644 (file)
index 0000000..e323a0d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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;
+import static org.testng.AssertJUnit.assertNull;
+
+import org.testng.annotations.Test;
+
+public class EBIFetchClientTest
+{
+  /**
+   * Test method that constructs URL to fetch from
+   */
+  @Test(groups = "Functional")
+  public void testBuildUrl()
+  {
+    /*
+     * EMBL
+     */
+    assertEquals("http://www.ebi.ac.uk/ena/data/view/x53838&display=xml",
+            EBIFetchClient.buildUrl("X53838", "EMBL", "display=xml"));
+
+    /*
+     * EMBLCDS
+     */
+    assertEquals("http://www.ebi.ac.uk/ena/data/view/caa37824&display=xml",
+            EBIFetchClient.buildUrl("CAA37824", "EMBL", "display=xml"));
+
+    /*
+     * Uniprot
+     */
+    assertEquals(
+            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/uniprot/p00340/uniprotxml",
+            EBIFetchClient.buildUrl("P00340", "UNIPROT", "uniprotxml"));
+
+    /*
+     * PDB / pdb
+     */
+    assertEquals("http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/pdb",
+            EBIFetchClient.buildUrl("3A6S", "PDB", "pdb"));
+
+    /*
+     * PDB / mmCIF
+     */
+    assertEquals(
+            "http://www.ebi.ac.uk/Tools/dbfetch/dbfetch/pdb/3a6s/mmCIF",
+            EBIFetchClient.buildUrl("3A6S", "PDB", "mmCIF"));
+  }
+
+  /**
+   * Test method that parses db:id;id;id
+   */
+  @Test(groups = "Functional")
+  public void testParseIds()
+  {
+    /*
+     * pdb, two accessions
+     */
+    StringBuilder queries = new StringBuilder();
+    String db = EBIFetchClient.parseIds("pdb:3a6s;1A70", queries);
+    assertEquals("pdb", db);
+    assertEquals("3a6s,1A70", queries.toString());
+
+    /*
+     * pdb specified on second accession
+     */
+    queries.setLength(0);
+    queries = new StringBuilder();
+    db = EBIFetchClient.parseIds("3a6s;pdb:1A70", queries);
+    assertEquals("pdb", db);
+    assertEquals("3a6s,1A70", queries.toString());
+
+    /*
+     * uniprot, one accession
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("uniprot:P00340", queries);
+    assertEquals("uniprot", db);
+    assertEquals("P00340", queries.toString());
+
+    /*
+     * uniprot, one accession, appending to existing queries
+     */
+    queries.setLength(0);
+    queries.append("P30419");
+    db = EBIFetchClient.parseIds("uniprot:P00340", queries);
+    assertEquals("uniprot", db);
+    assertEquals("P30419,P00340", queries.toString());
+
+    /*
+     * pdb and uniprot mixed - rejected
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("pdb:3a6s;1a70;uniprot:P00340", queries);
+    assertNull(db);
+    assertEquals("3a6s,1a70", queries.toString());
+
+    /*
+     * pdb and PDB mixed - ok
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("pdb:3a6s;pdb:1a70;PDB:1QIP", queries);
+    assertEquals("PDB", db);
+    assertEquals("3a6s,1a70,1QIP", queries.toString());
+
+    /*
+     * no database (improper format)
+     */
+    queries.setLength(0);
+    db = EBIFetchClient.parseIds("P00340", queries);
+    assertNull(db);
+    assertEquals("P00340", queries.toString());
+  }
+}
index 1cf1e5f..d672ab6 100644 (file)
@@ -65,6 +65,7 @@ public class Jws2ParamView
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     Cache.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
   }
@@ -139,6 +140,7 @@ public class Jws2ParamView
            */
           jf.addWindowListener(new WindowAdapter()
           {
+            @Override
             public void windowClosing(WindowEvent e)
             {
               thr.interrupt();
index 64840c2..9f62481 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ws.jabaws;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.io.AnnotationFile;
@@ -40,7 +41,7 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-@Test(groups = { "Network" })
+@Test(groups = { "External" })
 public class DisorderAnnotExportImport
 {
   public static String testseqs = "examples/uniref50.fa";
@@ -56,8 +57,8 @@ public class DisorderAnnotExportImport
   @BeforeClass(inheritGroups = true)
   public static void setUpBeforeClass() throws Exception
   {
-
-    jalview.bin.Cache.initLogger();
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
     iupreds = new ArrayList<Jws2Instance>();
     for (Jws2Instance svc : disc.getServices())
index 46feebc..4414782 100644 (file)
@@ -37,7 +37,7 @@ public class JalviewJabawsTestUtils
   {
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
@@ -60,6 +60,20 @@ public class JalviewJabawsTestUtils
     return getJabawsDiscoverer(true);
   }
 
+  /**
+   * Returns a service discoverer that queries localhost and compbio urls.
+   * <p>
+   * If using this method, be sure to have read-only Jalview properties, to
+   * avoid writing the test urls to .jalview_properties. This can be done by
+   * either
+   * <ul>
+   * <li>running Jalview main with arguments -props propFileName</li>
+   * <li>calling Cache.loadProperties(filename)</li>
+   * <ul>
+   * 
+   * @param localhost
+   * @return
+   */
   public static Jws2Discoverer getJabawsDiscoverer(boolean localhost)
   {
     jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
index afb24c4..7f94b6b 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ws.jabaws;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.gui.Jalview2XML;
 import jalview.io.AnnotationFile;
@@ -65,8 +66,8 @@ public class JpredJabaStructExportImport
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-
-    jalview.bin.Cache.initLogger();
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
 
     for (Jws2Instance svc : disc.getServices())
@@ -84,7 +85,7 @@ public class JpredJabaStructExportImport
     assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     if (af != null)
index b57e5d0..7bb6bdd 100644 (file)
@@ -23,10 +23,12 @@ package jalview.ws.jabaws;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.gui.Jalview2XML;
 import jalview.io.AnnotationFile;
+import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
 import jalview.io.StockholmFileTest;
 import jalview.ws.jws2.Jws2Discoverer;
@@ -36,6 +38,7 @@ import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.AutoCalcSetting;
 
 import java.awt.Component;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -47,10 +50,13 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import compbio.metadata.Argument;
 import compbio.metadata.WrongParameterException;
 
 public class RNAStructExportImport
 {
+  private static final String JAR_FILE_NAME = "testRnalifold_param.jar";
+
   public static String testseqs = "examples/RF00031_folded.stk";
 
   public static Jws2Discoverer disc;
@@ -64,8 +70,8 @@ public class RNAStructExportImport
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
-
-    jalview.bin.Cache.initLogger();
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer(false);
 
     for (Jws2Instance svc : disc.getServices())
@@ -84,9 +90,9 @@ public class RNAStructExportImport
       Assert.fail("no web service");
     }
 
-    jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
+    FileLoader fl = new FileLoader(false);
 
-    af = fl.LoadFileWaitTillLoaded(testseqs, jalview.io.FormatAdapter.FILE);
+    af = fl.LoadFileWaitTillLoaded(testseqs, FormatAdapter.FILE);
 
     assertNotNull("Couldn't load test data ('" + testseqs + "')", af);
 
@@ -108,13 +114,18 @@ public class RNAStructExportImport
                                                       // public?
   }
 
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
     if (af != null)
     {
       af.setVisible(false);
       af.dispose();
+      File f = new File(JAR_FILE_NAME);
+      if (f.exists())
+      {
+        f.delete();
+      }
     }
   }
 
@@ -134,7 +145,6 @@ public class RNAStructExportImport
       } catch (InterruptedException x)
       {
       }
-      ;
     } while (af.getViewport().getCalcManager().isWorking());
 
     AlignmentI orig_alig = af.getViewport().getAlignment();
@@ -168,7 +178,6 @@ public class RNAStructExportImport
       } catch (InterruptedException x)
       {
       }
-      ;
     } while (af.getViewport().getCalcManager().isWorking());
 
     AlignmentI orig_alig = af.getViewport().getAlignment();
@@ -187,11 +196,11 @@ public class RNAStructExportImport
 
       String anfileout = new AnnotationFile()
               .printAnnotationsForAlignment(al);
-      assertTrue(
+      assertNotNull(
               "Test "
                       + testname
                       + "\nAlignment annotation file was not regenerated. Null string",
-              anfileout != null);
+              anfileout);
       assertTrue(
               "Test "
                       + testname
@@ -226,9 +235,9 @@ public class RNAStructExportImport
   @Test(groups = { "Functional" })
   public void testRnaalifoldSettingsRecovery()
   {
-    List<compbio.metadata.Argument> opts = new ArrayList<compbio.metadata.Argument>();
-    for (compbio.metadata.Argument rg : (List<compbio.metadata.Argument>) rnaalifoldws
-            .getRunnerConfig().getArguments())
+    List<Argument> opts = new ArrayList<Argument>();
+    for (Argument rg : (List<Argument>) rnaalifoldws.getRunnerConfig()
+            .getArguments())
     {
       if (rg.getDescription().contains("emperature"))
       {
@@ -267,10 +276,10 @@ public class RNAStructExportImport
     // write out parameters
     jalview.gui.AlignFrame nalf = null;
     assertTrue("Couldn't write out the Jar file",
-            new Jalview2XML(false).saveAlignment(af,
-                    "testRnalifold_param.jar", "trial parameter writeout"));
+            new Jalview2XML(false).saveAlignment(af, JAR_FILE_NAME,
+                    "trial parameter writeout"));
     assertTrue("Couldn't read back the Jar file", (nalf = new Jalview2XML(
-            false).loadJalviewAlign("testRnalifold_param.jar")) != null);
+            false).loadJalviewAlign(JAR_FILE_NAME)) != null);
     if (nalf != null)
     {
       AutoCalcSetting acs = af.getViewport().getCalcIdSettingsFor(
index f96b115..1e02213 100644 (file)
@@ -55,6 +55,7 @@ public class ParameterUtilsTest
   public static void setUpBeforeClass() throws Exception
   {
     serviceTests.add("AAConWS".toLowerCase());
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
     Cache.initLogger();
     disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
   }
index 63b1b9c..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;
@@ -62,7 +63,7 @@ public class DbRefFetcherTest
   /**
    * @throws java.lang.Exception
    */
-  @AfterClass
+  @AfterClass(alwaysRun = true)
   public static void tearDownAfterClass() throws Exception
   {
   }
@@ -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,16 +173,15 @@ 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]
             .getMap().getMappedWidth(), 1);
     assertEquals("Expected local reference map to be 3 nucleotides", dr[0]
             .getMap().getWidth(), 3);
-    AlignmentI sprods = CrossRef.findXrefSequences(
-            alsq.getSequencesArray(), true, dr[0].getSource(), alsq);
+    AlignmentI sprods = new CrossRef(alsq.getSequencesArray(), alsq)
+            .findXrefSequences(dr[0].getSource(), true);
     assertNotNull(
             "Couldn't recover cross reference sequence from dataset. Was it ever added ?",
             sprods);
index a1c2c9a..8d26c45 100644 (file)
  */
 package jalview.ws.sifts;
 
+import jalview.api.DBRefEntryI;
+import jalview.bin.Cache;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.io.AppletFormatAdapter;
+import jalview.structure.StructureMapping;
+import jalview.xml.binding.sifts.Entry.Entity;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.PrintStream;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 import org.testng.Assert;
@@ -35,11 +41,11 @@ import org.testng.annotations.AfterTest;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import MCview.Atom;
 import MCview.PDBfile;
 
 public class SiftsClientTest
 {
-  private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
 
   public static final String DEFAULT_SIFTS_DOWNLOAD_DIR = System
           .getProperty("user.home")
@@ -62,26 +68,129 @@ public class SiftsClientTest
 
   @BeforeTest(alwaysRun = true)
   public void populateExpectedMapping() throws SiftsException
-   {
-    for (int x = 1; x <= 97; x++)
-    {
-      expectedMapping.put(50 + x, new int[] { x, u });
-    }
-   }
-   
+  {
+    expectedMapping.put(51, new int[] { 1, 2 });
+    expectedMapping.put(52, new int[] { 2, 7 });
+    expectedMapping.put(53, new int[] { 3, 12 });
+    expectedMapping.put(54, new int[] { 4, 24 });
+    expectedMapping.put(55, new int[] { 5, 33 });
+    expectedMapping.put(56, new int[] { 6, 40 });
+    expectedMapping.put(57, new int[] { 7, 47 });
+    expectedMapping.put(58, new int[] { 8, 55 });
+    expectedMapping.put(59, new int[] { 9, 62 });
+    expectedMapping.put(60, new int[] { 10, 69 });
+    expectedMapping.put(61, new int[] { 11, 76 });
+    expectedMapping.put(62, new int[] { 12, 83 });
+    expectedMapping.put(63, new int[] { 13, 87 });
+    expectedMapping.put(64, new int[] { 14, 95 });
+    expectedMapping.put(65, new int[] { 15, 102 });
+    expectedMapping.put(66, new int[] { 16, 111 });
+    expectedMapping.put(67, new int[] { 17, 122 });
+    expectedMapping.put(68, new int[] { 18, 131 });
+    expectedMapping.put(69, new int[] { 19, 137 });
+    expectedMapping.put(70, new int[] { 20, 144 });
+    expectedMapping.put(71, new int[] { 21, 152 });
+    expectedMapping.put(72, new int[] { 22, 160 });
+    expectedMapping.put(73, new int[] { 23, 167 });
+    expectedMapping.put(74, new int[] { 24, 179 });
+    expectedMapping.put(75, new int[] { 25, 187 });
+    expectedMapping.put(76, new int[] { 26, 195 });
+    expectedMapping.put(77, new int[] { 27, 203 });
+    expectedMapping.put(78, new int[] { 28, 208 });
+    expectedMapping.put(79, new int[] { 29, 213 });
+    expectedMapping.put(80, new int[] { 30, 222 });
+    expectedMapping.put(81, new int[] { 31, 231 });
+    expectedMapping.put(82, new int[] { 32, 240 });
+    expectedMapping.put(83, new int[] { 33, 244 });
+    expectedMapping.put(84, new int[] { 34, 252 });
+    expectedMapping.put(85, new int[] { 35, 260 });
+    expectedMapping.put(86, new int[] { 36, 268 });
+    expectedMapping.put(87, new int[] { 37, 275 });
+    expectedMapping.put(88, new int[] { 38, 287 });
+    expectedMapping.put(89, new int[] { 39, 293 });
+    expectedMapping.put(90, new int[] { 40, 299 });
+    expectedMapping.put(91, new int[] { 41, 310 });
+    expectedMapping.put(92, new int[] { 42, 315 });
+    expectedMapping.put(93, new int[] { 43, 319 });
+    expectedMapping.put(94, new int[] { 44, 325 });
+    expectedMapping.put(95, new int[] { 45, 331 });
+    expectedMapping.put(96, new int[] { 46, 337 });
+    expectedMapping.put(97, new int[] { 47, 343 });
+    expectedMapping.put(98, new int[] { 48, 349 });
+    expectedMapping.put(99, new int[] { 49, 354 });
+    expectedMapping.put(100, new int[] { 50, 358 });
+    expectedMapping.put(101, new int[] { 51, 367 });
+    expectedMapping.put(102, new int[] { 52, 375 });
+    expectedMapping.put(103, new int[] { 53, 384 });
+    expectedMapping.put(104, new int[] { 54, 391 });
+    expectedMapping.put(105, new int[] { 55, 395 });
+    expectedMapping.put(106, new int[] { 56, 401 });
+    expectedMapping.put(107, new int[] { 57, 409 });
+    expectedMapping.put(108, new int[] { 58, 417 });
+    expectedMapping.put(109, new int[] { 59, 426 });
+    expectedMapping.put(110, new int[] { 60, 434 });
+    expectedMapping.put(111, new int[] { 61, 442 });
+    expectedMapping.put(112, new int[] { 62, 451 });
+    expectedMapping.put(113, new int[] { 63, 457 });
+    expectedMapping.put(114, new int[] { 64, 468 });
+    expectedMapping.put(115, new int[] { 65, 476 });
+    expectedMapping.put(116, new int[] { 66, 484 });
+    expectedMapping.put(117, new int[] { 67, 492 });
+    expectedMapping.put(118, new int[] { 68, 500 });
+    expectedMapping.put(119, new int[] { 69, 509 });
+    expectedMapping.put(120, new int[] { 70, 517 });
+    expectedMapping.put(121, new int[] { 71, 525 });
+    expectedMapping.put(122, new int[] { 72, 534 });
+    expectedMapping.put(123, new int[] { 73, 538 });
+    expectedMapping.put(124, new int[] { 74, 552 });
+    expectedMapping.put(125, new int[] { 75, 559 });
+    expectedMapping.put(126, new int[] { 76, 567 });
+    expectedMapping.put(127, new int[] { 77, 574 });
+    expectedMapping.put(128, new int[] { 78, 580 });
+    expectedMapping.put(129, new int[] { 79, 585 });
+    expectedMapping.put(130, new int[] { 80, 590 });
+    expectedMapping.put(131, new int[] { 81, 602 });
+    expectedMapping.put(132, new int[] { 82, 609 });
+    expectedMapping.put(133, new int[] { 83, 616 });
+    expectedMapping.put(134, new int[] { 84, 622 });
+    expectedMapping.put(135, new int[] { 85, 630 });
+    expectedMapping.put(136, new int[] { 86, 637 });
+    expectedMapping.put(137, new int[] { 87, 644 });
+    expectedMapping.put(138, new int[] { 88, 652 });
+    expectedMapping.put(139, new int[] { 89, 661 });
+    expectedMapping.put(140, new int[] { 90, 668 });
+    expectedMapping.put(141, new int[] { 91, 678 });
+    expectedMapping.put(142, new int[] { 92, 687 });
+    expectedMapping.put(143, new int[] { 93, 696 });
+    expectedMapping.put(144, new int[] { 94, 705 });
+    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();
     SiftsSettings.setSiftDownloadDirectory(jalview.bin.Cache.getDefault(
             "sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR));
-
-    File testSiftsFile = new File("test/jalview/io/" + testPDBId
-            + ".xml.gz");
-    PDBfile pdbFile = new PDBfile(false, false, false);
-    pdbFile.setId(testPDBId);
-    siftsClient = new SiftsClient(pdbFile, testSiftsFile);
+    SiftsSettings.setMapWithSifts(true);
+    SiftsSettings.setCacheThresholdInDays("2");
+    SiftsSettings.setFailSafePIDThreshold("70");
+    PDBfile pdbFile;
+    try
+    {
+      pdbFile = new PDBfile(false, false, false, "test/jalview/io/"
+              + testPDBId + ".pdb", AppletFormatAdapter.FILE);
+      siftsClient = new SiftsClient(pdbFile);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @AfterTest(alwaysRun = true)
@@ -90,30 +199,23 @@ public class SiftsClientTest
     siftsClient = null;
   }
 
-  @BeforeTest(alwaysRun = true)
-  public void setUpStreams()
-  {
-    System.setOut(new PrintStream(outContent));
-  }
-
-  @AfterTest(alwaysRun = true)
-  public void cleanUpStreams()
-  {
-    System.setOut(null);
-  }
-
   @Test(groups = { "Functional" })
   public void getSIFTsFileTest() throws SiftsException
   {
-    Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId));
-    SiftsClient.getSiftsFile(testPDBId);
-    Assert.assertFalse(outContent.toString().contains(
-            ">>> SIFTS File already downloaded for " + testPDBId));
-
-    // test for SIFTs file caching
-    SiftsClient.getSiftsFile(testPDBId);
-    Assert.assertTrue(outContent.toString().contains(
-            ">>> SIFTS File already downloaded for " + testPDBId));
+    File siftsFile;
+    try
+    {
+      siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      // test for SIFTs file caching
+      SiftsSettings.setCacheThresholdInDays("0");
+      siftsFile = SiftsClient.getSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      SiftsSettings.setCacheThresholdInDays("2");
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @Test(groups = { "Functional" })
@@ -122,9 +224,16 @@ public class SiftsClientTest
     // Assert that file isn't yet downloaded - if already downloaded, assert it
     // is deleted
     Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId));
-    File siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
-    FileAssert.assertFile(siftsFile);
-    SiftsClient.downloadSiftsFile(testPDBId);
+    File siftsFile;
+    try
+    {
+      siftsFile = SiftsClient.downloadSiftsFile(testPDBId);
+      FileAssert.assertFile(siftsFile);
+      SiftsClient.downloadSiftsFile(testPDBId);
+    } catch (IOException e)
+    {
+      e.printStackTrace();
+    }
   }
 
   @Test(groups = { "Functional" })
@@ -144,19 +253,16 @@ public class SiftsClientTest
 
     // TODO delete when auto-fetching of DBRefEntry is implemented
     DBRefEntry dbRef = new DBRefEntry("uniprot", "", "P00221");
-    dbRef.setStartRes(1);
-    dbRef.setEndRes(147);
     testSeq.addDBRef(dbRef);
     // testSeq.setSourceDBRef(dbRef);
 
     try
     {
       HashMap<Integer, int[]> actualMapping = siftsClient.getGreedyMapping(
-              "A", testSeq,
-              null);
-      Assert.assertEquals(actualMapping, expectedMapping);
+              "A", testSeq, null);
       Assert.assertEquals(testSeq.getStart(), 1);
       Assert.assertEquals(testSeq.getEnd(), 147);
+      Assert.assertEquals(actualMapping, expectedMapping);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -167,8 +273,15 @@ public class SiftsClientTest
   @Test(groups = { "Functional" })
   private void getAtomIndexTest()
   {
-    // siftsClient.getAtomIndex(1, null);
-    // Assert.assertTrue(true);
+    ArrayList<Atom> atoms = new ArrayList<Atom>();
+    Atom atom = new Atom(u, u, u);
+    atom.resNumber = 43;
+    atom.atomIndex = 7;
+    atoms.add(atom);
+    int actualAtomIndex = siftsClient.getAtomIndex(1, atoms);
+    Assert.assertEquals(actualAtomIndex, -1);
+    actualAtomIndex = siftsClient.getAtomIndex(43, atoms);
+    Assert.assertEquals(actualAtomIndex, 7);
   }
 
   @Test(
@@ -185,21 +298,178 @@ public class SiftsClientTest
 
   }
 
-  @Test(groups = { "Functional" })
-  private void populateAtomPositionsTest()
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  private void populateAtomPositionsNullTest1()
+          throws IllegalArgumentException, SiftsException
   {
+    siftsClient.populateAtomPositions(null, null);
+  }
 
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  private void populateAtomPositionsNullTest2()
+          throws IllegalArgumentException, SiftsException
+  {
+    siftsClient.populateAtomPositions("A", null);
   }
 
   @Test(groups = { "Functional" })
   public void getValidSourceDBRefTest()
   {
+    try
+    {
+      DBRefEntryI actualValidSrcDBRef = siftsClient
+              .getValidSourceDBRef(testSeq);
+      DBRefEntryI expectedDBRef = new DBRefEntry();
+      expectedDBRef.setSource(DBRefSource.UNIPROT);
+      expectedDBRef.setAccessionId("P00221");
+      expectedDBRef.setVersion("");
+      Assert.assertEquals(actualValidSrcDBRef, expectedDBRef);
+    } catch (Exception e)
+    {
+    }
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  public void getValidSourceDBRefExceptionTest() throws SiftsException
+  {
+    SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
+    try
+    {
+      siftsClient.getValidSourceDBRef(invalidTestSeq);
+    } catch (SiftsException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
+  }
+
+  @Test(
+    groups = { "Functional" },
+    expectedExceptions = SiftsException.class)
+  public void getValidSourceDBRefExceptionXTest() throws SiftsException
+  {
+    SequenceI invalidTestSeq = new Sequence("testSeq", "ABCDEFGH");
+    DBRefEntry invalidDBRef = new DBRefEntry();
+    invalidDBRef.setAccessionId("BLAR");
+    invalidTestSeq.addDBRef(invalidDBRef);
+    try
+    {
+      siftsClient.getValidSourceDBRef(invalidTestSeq);
+    } catch (SiftsException e)
+    {
+      throw new SiftsException(e.getMessage());
+    }
 
   }
 
   @Test(groups = { "Functional" })
   public void isValidDBRefEntryTest()
   {
+    DBRefEntryI validDBRef = new DBRefEntry();
+    validDBRef.setSource(DBRefSource.UNIPROT);
+    validDBRef.setAccessionId("P00221");
+    validDBRef.setVersion("");
+    Assert.assertTrue(siftsClient.isValidDBRefEntry(validDBRef));
+  }
+
+  @Test(groups = { "Functional" })
+  public void getSiftsStructureMappingTest()
+  {
+    try
+    {
+      Assert.assertTrue(SiftsSettings.isMapWithSifts());
+      StructureMapping strucMapping = siftsClient.getSiftsStructureMapping(
+              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 AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n"
+              + "       |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n"
+              + "1A70|A AAYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDDQSFLD\n\n"
+
+              + "P00221 DDQIDEGWVLTCAAYPVSDVTIETHKEEELTA\n"
+              + "       |||||||||||||||||||||||||| |||||\n"
+              + "1A70|A DDQIDEGWVLTCAAYPVSDVTIETHKKEELTA\n\n" +
+
+              "Length of alignment = 97\n" + "Percentage ID = 98.97\n";
+
+      Assert.assertEquals(strucMapping.getMappingDetailsOutput(),
+              expectedMappingOutput);
+      Assert.assertEquals(strucMapping.getMapping(), expectedMapping);
+    } catch (SiftsException e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  @Test(groups = { "Functional" })
+  public void getEntityCountTest()
+  {
+    int actualEntityCount = siftsClient.getEntityCount();
+    System.out.println("actual entity count : " + actualEntityCount);
+    Assert.assertEquals(actualEntityCount, 1);
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbAccessionIdTest()
+  {
+    String actualDbAccId = siftsClient.getDbAccessionId();
+    System.out.println("Actual Db Accession Id: " + actualDbAccId);
+    Assert.assertEquals(actualDbAccId, "1a70");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbCoordSysTest()
+  {
+    String actualDbCoordSys = siftsClient.getDbCoordSys();
+    System.out.println("Actual DbCoordSys: " + actualDbCoordSys);
+    Assert.assertEquals(actualDbCoordSys, "PDBe");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbSourceTest()
+  {
+    String actualDbSource = siftsClient.getDbSource();
+    System.out.println("Actual DbSource: " + actualDbSource);
+    Assert.assertEquals(actualDbSource, "PDBe");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getDbVersionTest()
+  {
+    String actualDbVersion = siftsClient.getDbVersion();
+    System.out.println("Actual DbVersion: " + actualDbVersion);
+    Assert.assertEquals(actualDbVersion, "2.0");
+  }
+
+  @Test(groups = { "Functional" })
+  public void getEntityByMostOptimalMatchedIdTest()
+  {
+    SiftsClient siftsClientX = null;
+    PDBfile pdbFile;
+    try
+    {
+      pdbFile = new PDBfile(false, false, false, "test/jalview/io/2nq2"
+              + ".pdb", AppletFormatAdapter.FILE);
+      siftsClientX = new SiftsClient(pdbFile);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    Entity entityA = siftsClientX.getEntityByMostOptimalMatchedId("A");
+    Assert.assertEquals(entityA.getEntityId(), "A");
+    Entity entityB = siftsClientX.getEntityByMostOptimalMatchedId("B");
+    Assert.assertEquals(entityB.getEntityId(), "C");
+    Entity entityC = siftsClientX.getEntityByMostOptimalMatchedId("C");
+    Assert.assertEquals(entityC.getEntityId(), "B");
+    Entity entityD = siftsClientX.getEntityByMostOptimalMatchedId("D");
+    Assert.assertEquals(entityD.getEntityId(), "D");
 
   }
 }
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!!!");
+    }
+  }
+}
diff --git a/utils/HelpLinksChecker.java b/utils/HelpLinksChecker.java
new file mode 100644 (file)
index 0000000..1279b31
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * 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;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class to check help file cross-references, and external URLs if internet
+ * access is available
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class HelpLinksChecker implements BufferedLineReader.LineCleaner
+{
+  private static final String HELP_HS = "help.hs";
+
+  private static final String HELP_TOC_XML = "helpTOC.xml";
+
+  private static final String HELP_JHM = "help.jhm";
+
+  private static boolean internetAvailable = true;
+
+  private int targetCount = 0;
+
+  private int mapCount = 0;
+
+  private int internalHrefCount = 0;
+
+  private int anchorRefCount = 0;
+
+  private int invalidAnchorRefCount = 0;
+
+  private int externalHrefCount = 0;
+
+  private int invalidMapUrlCount = 0;
+
+  private int invalidTargetCount = 0;
+
+  private int invalidImageCount = 0;
+
+  private int invalidInternalHrefCount = 0;
+
+  private int invalidExternalHrefCount = 0;
+
+  /**
+   * The only parameter should be a path to the root of the help directory in
+   * the workspace
+   * 
+   * @param args
+   *          [0] path to the /html folder in the workspace
+   * @param args
+   *          [1] (optional) -nointernet to suppress external link checking for
+   *          a fast check of internal links only
+   * @throws IOException
+   */
+  public static void main(String[] args) throws IOException
+  {
+    if (args.length == 0 || args.length > 2
+            || (args.length == 2 && !args[1].equals("-nointernet")))
+    {
+      log("Usage: <pathToHelpFolder> [-nointernet]");
+      return;
+    }
+
+    if (args.length == 2)
+    {
+      internetAvailable = false;
+    }
+
+    new HelpLinksChecker().checkLinks(args[0]);
+  }
+
+  /**
+   * Checks help links and reports results
+   * 
+   * @param helpDirectoryPath
+   * @throws IOException
+   */
+  void checkLinks(String helpDirectoryPath) throws IOException
+  {
+    log("Checking help file links");
+    File helpFolder = new File(helpDirectoryPath).getCanonicalFile();
+    if (!helpFolder.exists())
+    {
+      log("Can't find " + helpDirectoryPath);
+      return;
+    }
+
+    internetAvailable &= connectToUrl("http://www.example.org");
+
+    Map<String, String> tocTargets = checkHelpMappings(helpFolder);
+
+    Map<String, String> unusedTargets = new HashMap<String, String>(
+            tocTargets);
+
+    checkTableOfContents(helpFolder, tocTargets, unusedTargets);
+
+    checkHelpSet(helpFolder, tocTargets, unusedTargets);
+
+    checkHtmlFolder(new File(helpFolder, "html"));
+
+    reportResults(unusedTargets);
+  }
+
+  /**
+   * Checks all html files in the given directory or its sub-directories
+   * 
+   * @param folder
+   * @throws IOException
+   */
+  private void checkHtmlFolder(File folder) throws IOException
+  {
+    File[] files = folder.listFiles();
+    for (File f : files)
+    {
+      if (f.isDirectory())
+      {
+        checkHtmlFolder(f);
+      }
+      else
+      {
+        if (f.getAbsolutePath().endsWith(".html"))
+        {
+          checkHtmlFile(f, folder);
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks that any image attribute in help.hs is a valid target
+   * 
+   * @param helpFolder
+   * @param tocTargets
+   * @param unusedTargets
+   *          used targets are removed from here
+   */
+  private void checkHelpSet(File helpFolder,
+          Map<String, String> tocTargets, Map<String, String> unusedTargets)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_HS)));
+    String data = br.readLine();
+    int lineNo = 0;
+
+    while (data != null)
+    {
+      lineNo++;
+      String image = getAttribute(data, "image");
+      if (image != null)
+      {
+        unusedTargets.remove(image);
+        if (!tocTargets.containsKey(image))
+        {
+          log(String.format("Invalid image '%s' at line %d of %s", image,
+                  lineNo, HELP_HS));
+          invalidImageCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * Print counts to sysout
+   * 
+   * @param unusedTargets
+   */
+  private void reportResults(Map<String, String> unusedTargets)
+  {
+    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())
+    {
+      log(String.format("    %s: %s", target, unusedTargets.get(target)));
+    }
+    log(invalidMapUrlCount + " invalid map urls");
+    log(invalidImageCount + " invalid image attributes");
+    log(String.format("%d internal href links (%d with anchors)",
+            internalHrefCount, anchorRefCount));
+    log(invalidInternalHrefCount + " invalid internal href links");
+    log(invalidAnchorRefCount + " invalid internal anchor links");
+    log(externalHrefCount + " external href links");
+    if (internetAvailable)
+    {
+      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);
+  }
+
+  /**
+   * Reads the given html file and checks any href attibute values are either
+   * <ul>
+   * <li>a valid relative file path, or</li>
+   * <li>a valid absolute URL (if external link checking is enabled)</li>
+   * </ul>
+   * 
+   * @param htmlFile
+   * @param htmlFolder
+   *          the parent folder (for validation of relative paths)
+   */
+  private void checkHtmlFile(File htmlFile, File htmlFolder)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(htmlFile));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+      String href = getAttribute(data, "href");
+      if (href != null)
+      {
+        String anchor = null;
+        int anchorPos = href.indexOf("#");
+        if (anchorPos != -1)
+        {
+          anchor = href.substring(anchorPos + 1);
+          href = href.substring(0, anchorPos);
+        }
+        boolean badLink = false;
+        if (href.startsWith("http"))
+        {
+          externalHrefCount++;
+          if (internetAvailable)
+          {
+            if (!connectToUrl(href))
+            {
+              badLink = true;
+              invalidExternalHrefCount++;
+            }
+          }
+        }
+        else
+        {
+          internalHrefCount++;
+          File hrefFile = href.equals("") ? htmlFile : new File(htmlFolder,
+                  href);
+          if (hrefFile != htmlFile && !fileExists(hrefFile, href))
+          {
+            badLink = true;
+            invalidInternalHrefCount++;
+          }
+          if (anchor != null)
+          {
+            anchorRefCount++;
+            if (!badLink)
+            {
+              if (!checkAnchorExists(hrefFile, anchor))
+              {
+                log(String.format("Invalid anchor: %s at line %d of %s",
+                        anchor, lineNo, getPath(htmlFile)));
+                invalidAnchorRefCount++;
+              }
+            }
+          }
+        }
+        if (badLink)
+        {
+          log(String.format("Invalid href %s at line %d of %s", href,
+                  lineNo, getPath(htmlFile)));
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * 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
+   * @param anchor
+   * @return true if anchor is found else false
+   */
+  private boolean checkAnchorExists(File hrefFile, String anchor)
+  {
+    String nameAnchor = "<a name=\"" + anchor + "\"";
+    String idAnchor = "<a id=\"" + anchor + "\"";
+    boolean found = false;
+    try
+    {
+      BufferedReader br = new BufferedReader(new FileReader(hrefFile));
+      BufferedLineReader blr = new BufferedLineReader(br, 3, this);
+      String data = blr.read();
+      while (data != null)
+      {
+        if (data.contains(nameAnchor) || data.contains(idAnchor))
+        {
+          found = true;
+          break;
+        }
+        data = blr.read();
+      }
+      br.close();
+    } catch (IOException e)
+    {
+      // ignore
+    }
+    return found;
+  }
+
+  /**
+   * Returns the part of the file path starting from /help/
+   * 
+   * @param helpFile
+   * @return
+   */
+  private String getPath(File helpFile)
+  {
+    String path = helpFile.getPath();
+    int helpPos = path.indexOf("/help/");
+    return helpPos == -1 ? path : path.substring(helpPos);
+  }
+
+  /**
+   * Returns true if the URL returns an input stream, or false if the URL
+   * returns an error code or we cannot connect to it (e.g. no internet
+   * available)
+   * 
+   * @param url
+   * @return
+   */
+  private boolean connectToUrl(String url)
+  {
+    try
+    {
+      URL u = new URL(url);
+      InputStream connection = u.openStream();
+      connection.close();
+      return true;
+    } catch (Throwable t)
+    {
+      return false;
+    }
+  }
+
+  /**
+   * Reads file help.jhm and checks that
+   * <ul>
+   * <li>each target attribute is in tocTargets</li>
+   * <li>each url attribute is a valid relative file link</li>
+   * </ul>
+   * 
+   * @param helpFolder
+   */
+  private Map<String, String> checkHelpMappings(File helpFolder)
+          throws IOException
+  {
+    Map<String, String> targets = new HashMap<String, String>();
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_JHM)));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+
+      /*
+       * record target, check for duplicates
+       */
+      String target = getAttribute(data, "target");
+      if (target != null)
+      {
+        mapCount++;
+        if (targets.containsKey(target))
+        {
+          log(String.format(
+                  "Duplicate target mapping to %s at line %d of %s",
+                  target, lineNo, HELP_JHM));
+        }
+        else
+        {
+          targetCount++;
+        }
+      }
+
+      /*
+       * validate url
+       */
+      String url = getAttribute(data, "url");
+      if (url != null)
+      {
+        targets.put(target, url);
+        int anchorPos = url.indexOf("#");
+        if (anchorPos != -1)
+        {
+          url = url.substring(0, anchorPos);
+        }
+        if (!new File(helpFolder, url).exists())
+        {
+          log(String.format("Invalid url path '%s' at line %d of %s", url,
+                  lineNo, HELP_JHM));
+          invalidMapUrlCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+    return targets;
+  }
+
+  /**
+   * Reads file helpTOC.xml and reports any invalid targets
+   * 
+   * @param helpFolder
+   * @param tocTargets
+   * @param unusedTargets
+   *          used targets are removed from this map
+   * 
+   * @return
+   * @throws IOException
+   */
+  private void checkTableOfContents(File helpFolder,
+          Map<String, String> tocTargets, Map<String, String> unusedTargets)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(new File(
+            helpFolder, HELP_TOC_XML)));
+    String data = br.readLine();
+    int lineNo = 0;
+    while (data != null)
+    {
+      lineNo++;
+      /*
+       * assuming no more than one "target" per line of file here
+       */
+      String target = getAttribute(data, "target");
+      if (target != null)
+      {
+        unusedTargets.remove(target);
+        if (!tocTargets.containsKey(target))
+        {
+          log(String.format("Invalid target '%s' at line %d of %s", target,
+                  lineNo, HELP_TOC_XML));
+          invalidTargetCount++;
+        }
+      }
+      data = br.readLine();
+    }
+    br.close();
+  }
+
+  /**
+   * Returns the value of an attribute if found in the data, else null
+   * 
+   * @param data
+   * @param attName
+   * @return
+   */
+  private static String getAttribute(String data, String attName)
+  {
+    /*
+     * make a partial attempt at ignoring within <!-- html comments -->
+     * (doesn't work if multi-line)
+     */
+    int commentStartPos = data.indexOf("<!--");
+    int commentEndPos = commentStartPos == -1 ? -1 : data.substring(
+            commentStartPos + 4).indexOf("-->");
+    String value = null;
+    String match = attName + "=\"";
+    int attPos = data.indexOf(match);
+    if (attPos > 0
+            && (commentStartPos == -1 || attPos < commentStartPos || attPos > commentEndPos))
+    {
+      data = data.substring(attPos + match.length());
+      value = data.substring(0, data.indexOf("\""));
+    }
+    return value;
+  }
+
+  /**
+   * Trim whitespace from concatenated lines but preserve one space for valid
+   * parsing
+   */
+  @Override
+  public String cleanLine(String l)
+  {
+    return l.trim() + " ";
+  }
+}
index 83d1a98..fc799bb 100755 (executable)
@@ -2025,7 +2025,7 @@ and any path to a file to save to the file]]></string>
                                                                <string><![CDATA[664]]></string>
                                                        </property>
                                                        <property name="sourceName">
-                                                               <string><![CDATA[groovy-all-1.8.2.jar]]></string>
+                                                               <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
                                                        </property>
                                                        <property name="overrideUnixPermissions">
                                                                <boolean>false</boolean>
@@ -2043,7 +2043,7 @@ and any path to a file to save to the file]]></string>
                                                                <boolean>true</boolean>
                                                        </property>
                                                        <property name="destinationName">
-                                                               <string><![CDATA[groovy-all-1.8.2.jar]]></string>
+                                                               <string><![CDATA[groovy-all-2.4.6-indy.jar]]></string>
                                                        </property>
                                                        <property name="fileSize">
                                                                <long>6149494</long>
@@ -2891,6 +2891,58 @@ and any path to a file to save to the file]]></string>
                                                        </property>
                                                </object>
                                        </method>
+                                       <method name="addElement">
+                                               <object class="com.zerog.ia.installer.actions.InstallZipfile" objectID="1000ddddfab939">
+                                                       <property name="belongsToUninstallPhase">
+                                                               <boolean>false</boolean>
+                                                       </property>
+                                                       <property name="rollbackEnabledCancel">
+                                                               <boolean>true</boolean>
+                                                       </property>
+                                                       <property name="rollbackEnabledError">
+                                                               <boolean>true</boolean>
+                                                       </property>
+                                                       <property name="ruleExpression">
+                                                               <string><![CDATA[]]></string>
+                                                       </property>
+                                                       <property name="unixPermissions">
+                                                               <string><![CDATA[664]]></string>
+                                                       </property>
+                                                       <property name="sourceName">
+                                                               <string><![CDATA[servlet-api-3.1.jar]]></string>
+                                                       </property>
+                                                       <property name="overrideUnixPermissions">
+                                                               <boolean>false</boolean>
+                                                       </property>
+                                                       <property name="sourcePath">
+                                                               <string><![CDATA[/home/cruisecontrol/jalview/lib/]]></string>
+                                                       </property>
+                                                       <property name="shouldUninstall">
+                                                               <boolean>true</boolean>
+                                                       </property>
+                                                       <property name="rollbackEnabledCancel">
+                                                               <boolean>true</boolean>
+                                                       </property>
+                                                       <property name="rollbackEnabledError">
+                                                               <boolean>true</boolean>
+                                                       </property>
+                                                       <property name="destinationName">
+                                                               <string><![CDATA[servlet-api-3.1.jar]]></string>
+                                                       </property>
+                                                       <property name="fileSize">
+                                                               <long>16046</long>
+                                                       </property>
+                                                       <property name="macBinary">
+                                                               <boolean>false</boolean>
+                                                       </property>
+                                                       <property name="targetCheckKind">
+                                                               <int>0</int>
+                                                       </property>
+                                                       <property name="ruleExpression">
+                                                               <string><![CDATA[]]></string>
+                                                       </property>
+                                               </object>
+                                       </method>
                                </object>
                        </property>
                        <property name="rulesFailedMessage">
@@ -7360,6 +7412,7 @@ and any path to a file to read from that file]]></string>
                                                                                <object refID="1f46efeefab93"/>
                                                                                <object refID="1936efeefab93"/>
                                                                                <object refID="1000ddddfab93"/>
+                                                                               <object refID="1000ddddfab939"/>
                                                                                <object refID="10936efeefab93"/>
                                                                                <object refID="11936efeefab93"/>
                                                                                <object refID="12936efeefab93"/>
@@ -7948,6 +8001,7 @@ and any path to a file to read from that file]]></string>
                                                                                                <object refID="1f46efeefab93"/>
                                                                                                <object refID="1936efeefab93"/>
                                                                                                <object refID="1000ddddfab93"/>
+                                                                                               <object refID="1000ddddfab939"/>
                                                                                                <object refID="10936efeefab93"/>
                                                                                                <object refID="11936efeefab93"/>
                                                                                                <object refID="12936efeefab93"/>
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();
-}
+  }
 }
diff --git a/utils/MessageBundleChecker.java b/utils/MessageBundleChecker.java
new file mode 100644 (file)
index 0000000..4489a93
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+/**
+ * This class scans Java source files for calls to MessageManager and reports
+ * <ul>
+ * <li>calls using keys not found in Messages.properties</li>
+ * <li>any unused keys in Messages.properties</li>
+ * </ul>
+ * It does not handle dynamically constructed keys, these are reported as
+ * possible errors for manual inspection. <br>
+ * For comparing translated bundles with Messages.properties, see i18nAnt.xml
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class MessageBundleChecker implements BufferedLineReader.LineCleaner
+{
+  /*
+   * regex ^"[^"]*"$
+   * opening quote, closing quote, no quotes in between
+   */
+  static Pattern STRING_PATTERN = Pattern.compile("^\"[^\"]*\"$");
+
+  /*
+   * number of text lines to read at a time in order to parse
+   * code that is split over several lines
+   */
+  static int bufferSize = 3;
+
+  /*
+   * resource bundle key is arg0 for these methods
+   */
+  static final String METHOD1 = "MessageManager.getString(";
+
+  static final String METHOD2 = "MessageManager.formatMessage(";
+
+  static final String METHOD3 = "MessageManager.getStringOrReturn(";
+
+  /*
+   * resource bundle key is arg1 for this method
+   */
+  static final String JVINIT = "JvSwingUtils.jvInitComponent(";
+
+  static final String[] METHODS = { METHOD1, METHOD2, METHOD3, JVINIT };
+
+  /*
+   * root of the Java source folders we want to scan
+   */
+  String sourcePath;
+
+  /*
+   * contents of Messages.properties
+   */
+  private Properties messages;
+
+  /*
+   * keys from Messages.properties
+   * we remove entries from here as they are found to be used
+   * any left over are unused entries
+   */
+  private TreeSet<String> messageKeys;
+
+  private int javaCount;
+
+  private HashSet<String> invalidKeys;
+
+  /**
+   * Runs the scan given the path to the root of Java source directories
+   * 
+   * @param args
+   *          [0] path to the source folder to scan
+   * @param args
+   *          [1] (optional) read buffer size (default is 3); increasing this
+   *          may detect more results but will give higher error counts due to
+   *          double counting of the same code
+   * @throws IOException
+   */
+  public static void main(String[] args) throws IOException
+  {
+    if (args.length != 1 && args.length != 2)
+    {
+      System.out.println("Usage: <pathToSourceFolder> [readBufferSize]");
+      return;
+    }
+    if (args.length == 2)
+    {
+      bufferSize = Integer.valueOf(args[1]);
+    }
+    new MessageBundleChecker().doMain(args[0]);
+  }
+
+  /**
+   * Main method to perform the work
+   * 
+   * @param srcPath
+   * @throws IOException
+   */
+  private void doMain(String srcPath) throws IOException
+  {
+    System.out.println("Scanning " + srcPath
+            + " for calls to MessageManager");
+    sourcePath = srcPath;
+    loadMessages();
+    File dir = new File(srcPath);
+    if (!dir.exists())
+    {
+      System.out.println(srcPath + " not found");
+      return;
+    }
+    invalidKeys = new HashSet<String>();
+    if (dir.isDirectory())
+    {
+      scanDirectory(dir);
+    }
+    else
+    {
+      scanFile(dir);
+    }
+    reportResults();
+  }
+
+  /**
+   * Prints out counts to sysout
+   */
+  private void reportResults()
+  {
+    System.out.println("\nScanned " + javaCount + " source files");
+    System.out.println("Message.properties has " + messages.size()
+            + " keys");
+    System.out.println("Found " + invalidKeys.size()
+            + " possibly invalid parameter calls");
+
+    System.out.println(messageKeys.size()
+            + " keys not found, either unused or constructed dynamically");
+    for (String key : messageKeys)
+    {
+      System.out.println("    " + key);
+    }
+  }
+
+  /**
+   * Scan all files within a directory
+   * 
+   * @param dir
+   * @throws IOException
+   */
+  private void scanDirectory(File dir) throws IOException
+  {
+    File[] files = dir.listFiles();
+    if (files != null)
+    {
+      for (File f : files)
+      {
+        if (f.isDirectory())
+        {
+          scanDirectory(f);
+        }
+        else
+        {
+          scanFile(f);
+        }
+      }
+    }
+  }
+
+  /**
+   * Scan a Java file
+   * 
+   * @param f
+   */
+  private void scanFile(File f) throws IOException
+  {
+    String path = f.getPath();
+    if (!path.endsWith(".java"))
+    {
+      return;
+    }
+    javaCount++;
+
+    /*
+     * skip class with designed dynamic lookup call
+     */
+    if (path.endsWith("gui/JvSwingUtils.java"))
+    {
+      return;
+    }
+
+    BufferedReader br = new BufferedReader(new FileReader(f));
+    BufferedLineReader blr = new BufferedLineReader(br, bufferSize, this);
+
+    int lineNo = 0;
+    String line = blr.read();
+    while (line != null)
+    {
+      lineNo++;
+      inspectSourceLines(path, lineNo, line);
+      line = blr.read();
+    }
+    br.close();
+
+  }
+
+  /**
+   * Look for calls to MessageManager methods, possibly split over two or more
+   * lines that have been concatenated while parsing the file
+   * 
+   * @param path
+   * @param lineNo
+   * @param line
+   */
+  private void inspectSourceLines(String path, int lineNo, String line)
+  {
+    String lineNos = String
+            .format("%d-%d", lineNo, lineNo + bufferSize
+            - 1);
+    for (String method : METHODS)
+    {
+      int pos = line.indexOf(method);
+      if (pos == -1)
+      {
+        continue;
+      }
+
+      /*
+       * extract what follows the opening bracket of the method call
+       */
+      String methodArgs = line.substring(pos + method.length()).trim();
+      if ("".equals(methodArgs))
+      {
+        /*
+         * arguments are on next line - catch in the next read loop iteration
+         */
+        continue;
+      }
+      if (methodArgs.indexOf(",") == -1 && methodArgs.indexOf(")") == -1)
+      {
+        /*
+         * arguments continue on next line - catch in the next read loop iteration
+         */
+        continue;
+      }
+
+      if (JVINIT == method && methodArgs.indexOf(",") == -1)
+      {
+        /*
+         * not interested in 1-arg calls to jvInitComponent
+         */
+        continue;
+      }
+
+      if (METHOD3 == method)
+      {
+        System.out.println(String.format("Dynamic key at %s line %s %s",
+                path.substring(sourcePath.length()), lineNos, line));
+        continue;
+      }
+
+      String messageKey = getMessageKey(method, methodArgs);
+      if (messageKey == null)
+      {
+        System.out.println(String.format("Trouble parsing %s line %s %s",
+                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, line));
+        continue;
+      }
+
+      /*
+       * strip leading and trailing quote
+       */
+      messageKey = messageKey.substring(1, messageKey.length() - 1);
+
+      if (!this.messages.containsKey(messageKey))
+      {
+        System.out.println(String.format(
+                "Unmatched key '%s' at line %s of %s", messageKey, lineNos,
+                path.substring(sourcePath.length())));
+        if (!invalidKeys.contains(messageKey))
+        {
+          invalidKeys.add(messageKey);
+        }
+      }
+      messageKeys.remove(messageKey);
+    }
+  }
+
+  /**
+   * Helper method to parse out the resource bundle key parameter of a method
+   * call
+   * 
+   * @param method
+   * @param methodArgs
+   *          the rest of the source line starting with arguments to method
+   * @return
+   */
+  private String getMessageKey(String method, String methodArgs)
+  {
+    String key = methodArgs;
+
+    /*
+     * locate second argument if calling jvInitComponent()
+     */
+    if (method == JVINIT)
+    {
+      int commaLoc = methodArgs.indexOf(",");
+      if (commaLoc == -1)
+      {
+        return null;
+      }
+      key = key.substring(commaLoc + 1).trim();
+    }
+
+    /*
+     * take up to next comma or ) or end of line
+     */
+    int commaPos = key.indexOf(",");
+    int bracePos = key.indexOf(")");
+    int endPos = commaPos == -1 ? bracePos : (bracePos == -1 ? commaPos
+            : Math.min(commaPos, bracePos));
+    if (endPos == -1 && key.length() > 1 && key.endsWith("\""))
+    {
+      endPos = key.length();
+    }
+
+    return endPos == -1 ? null : key.substring(0, endPos);
+  }
+
+  /**
+   * Loads properties from Message.properties
+   * 
+   * @throws IOException
+   */
+  void loadMessages() throws IOException
+  {
+    messages = new Properties();
+    FileReader reader = new FileReader(new File(sourcePath,
+            "../resources/lang/Messages.properties"));
+    messages.load(reader);
+    reader.close();
+
+    messageKeys = new TreeSet<String>();
+    for (Object key : messages.keySet())
+    {
+      messageKeys.add((String) key);
+    }
+
+  }
+
+  /**
+   * 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;
+  }
+
+}
diff --git a/utils/checkstyle/README.txt b/utils/checkstyle/README.txt
new file mode 100644 (file)
index 0000000..e38064e
--- /dev/null
@@ -0,0 +1,85 @@
+Checkstyle for Jalview
+----------------------
+
+http://checkstyle.sourceforge.net/
+GNU LGPL
+
+To get the Eclipse Checkstyle plugin
+------------------------------------
+       - Help | Eclipse Marketplace
+       - search for checkstyle
+       - install eclipse-cs checkstyle plugin
+The current version is 6.19.1 (August 2016).
+
+Config
+------
+
+       File Jalview/.checkstyle holds configuration for the "JalviewCheckstyle" ruleset.
+       This includes confining its scope to src/*.java and resources/*.properties.
+       This can be modified interactively through the checkstyle properties editor.
+       
+       Checkstyle config files in utils/checkstyle:
+               checkstyle.xml          : main configuration file with selected checkstyle modules
+               checkstyle-suppress.xml : rules to exclude certain checks / files
+               import-control.xml      : package import rules
+       
+       Checkstyle error messages can be customised. See TypeName for an example.
+
+How to use checkstyle
+---------------------
+
+       Option 1: enable it for the Jalview project
+               - right-click on project | Checkstyle | Activate Checkstyle
+               - notice CheckstyleNature gets added to the .project file
+               - don't commit this file unless we all agree to!
+               - Checkstyle will run as you recompile changed code
+
+       Option 2: on demand on selected code
+               - right-click on a class or package and Checkstyle | Check code with checkstyle
+               - (or Clear Checkstyle violations to remove checkstyle warnings)
+
+Checkstyle rules
+----------------
+       Documented at http://checkstyle.sourceforge.net/checks.html
+       Should be self-documenting in checkstyle.xml
+       Open for discussion:
+       - which rules to use
+       - what naming and layout standards to apply
+       - settings for complexity metrics
+       - whether any rules should report an error instead of a warning  
+       
+Suppressing findings
+--------------------
+       If there are warnings you judge it ok to suppress (false positives), 
+       your options are (from most global to most local impact):
+       - remove the rule entirely
+       - adjust its properties
+       - add an entry in checkstyle-suppress.xml to skip the file for the rule
+       - add comments around the reported source lines
+               // CHECKSTYLE.OFF: RuleName 'a comment to justify suppression'
+               source code here
+               // CHECKSTYLE.ON: RuleName
+       The suppression should be as localised as possible, to avoid false negatives.
+       
+Tips
+----
+       Sometimes checkstyle needs a kick before it will refresh its findings.
+       A whitespace edit in checkstyle.xml usually does this. There may be better ways.
+       
+       Invalid configuration files may result in checkstyle failing with an error reported
+       in the Eclipse log file. 
+       Help | Installation Details | Configuration takes you to a screen with a 
+       'View Error Log' button.
+       
+       Sometimes checkstyle can fail silently. Try 'touching' (editing) config files, failing
+       that, carefully check / back out / redo any recent changes to its config.
+       
+       Putting <!-- XML comments --> inside a checkstyle <module> causes it to be ignored!
+       
+       If a rule doesn't behave as you expected, read its documentation carefully, including
+       the use and default value of any properties.
+       
+       To highlight a single rule's findings, you can 'Configure Contents' of the Problems view
+       and filter on Text Contains <rule name> (case-sensitive). 
+       Here you should select 'Use item limits' with a value of, say, 500,     or Eclipse may 
+       labour to display all warnings.
diff --git a/utils/checkstyle/checkstyle-suppress.xml b/utils/checkstyle/checkstyle-suppress.xml
new file mode 100644 (file)
index 0000000..ac9e260
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE suppressions PUBLIC
+    "-//Puppy Crawl//DTD Suppressions 1.1//EN"
+    "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+       <!-- 
+               Do not put individual file-level suppressions here.
+               Instead use embedded comments to switch checks on and off.
+    -->
+        
+    <!-- 
+        Suppress check of XML binding generated code packages 
+    --> 
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]schemabinding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]binding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]json[\\/]binding[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="jalview[\\/]xml[\\/]binding[\\/]*"/>
+        
+    <!-- 
+       Suppress check of externally sourced code 
+    --> 
+    <suppress checks="[a-zA-Z0-9]*" files="com[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="ext[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="org[\\/]*"/>
+    <suppress checks="[a-zA-Z0-9]*" files="uk[\\/]*"/>
+    
+    <!-- 
+       ImportControl can only handle one top level package
+    -->
+    <suppress checks="ImportControl" files="MCview[\\/]*" />
+    <suppress checks="ImportControl" files="vamsas[\\/]*" />
+    
+    <!--  
+       Suppress checks by name 
+    -->
+       <suppress checks="FinalLocalVariable" files=".*\.java"/>
+    
+    <!--  
+       Suppress checks by id 
+    -->
+       <suppress id="InterfaceNaming" files=".*\.java"/>
+       <suppress id="NoStaticInitialization" files=".*\.java"/>
+         
+</suppressions>
\ No newline at end of file
diff --git a/utils/checkstyle/checkstyle.xml b/utils/checkstyle/checkstyle.xml
new file mode 100644 (file)
index 0000000..85ac8e6
--- /dev/null
@@ -0,0 +1,607 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+<!--
+       Jalview Checkstyle configuration file
+-->
+<module name="Checker">
+       <!-- Default severity is warning -->
+       <property name="severity" value="warning"/>
+       <property name="fileExtensions" value="java,properties"/>
+
+       <!-- 
+               Add any metrics that you wish to suppress to the following file.
+       -->
+       <module name="SuppressionFilter">
+               <property name="file" value="${basedir}/utils/checkstyle/checkstyle-suppress.xml"/>
+       </module>
+
+       <!-- 
+               Allow suppression of rules by comments, e.g.:
+               // CHECKSTYLE.OFF: ParameterNumber
+               ..method declaration
+               // CHECKSTYLE.ON: ParameterNumber
+       -->
+       <module name="SuppressionCommentFilter">
+               <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
+               <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
+               <property name="checkFormat" value="$1"/>
+       </module>
+
+       <!-- 
+               Check language bundles have the same keys and no duplicates
+               (ensure Checkstyle is configured to scan non-source files)
+        -->
+       <module name="Translation">
+               <property name="fileExtensions" value="properties"/>
+               <property name="baseName" value="^Messages.*$"/>
+       </module>
+       <module name="UniqueProperties">
+           <property name="fileExtensions" value="properties" />
+               <property name="severity" value="error"/>
+       </module>
+
+       <!--
+               Maximum line count for source files
+               (note this can't be inside TreeWalker)
+       -->
+       <module name="FileLength">
+               <property name="max" value="1200"/>
+               <property name="fileExtensions" value="java"/>
+       </module>
+       
+       <module name="TreeWalker">
+
+               <property name="tabWidth" value="4"/>
+
+               <!-- 
+                       Enables parsing of suppressions comments
+                       see http://checkstyle.sourceforge.net/config_filters.html#SuppressionCommentFilter 
+               -->
+               <module name="FileContentsHolder"/>
+
+       <!-- ****************************** -->
+       <!--         NAMING STANDARDS       -->
+       <!-- ****************************** -->
+               
+               <!--
+                       Naming convention for member fields. Start with (optional) underscore, then
+                       lower case, then camel case; no internal underscores
+               -->
+               <module name="MemberName">
+                       <property name="format" value="^_?[a-z][a-zA-Z0-9]*$"/>
+               </module>
+
+               <!-- 
+                       Naming convention for methods. Start with (optional) underscore, then
+                       lower case, then camel case; no internal underscores
+               -->
+               <module name="MethodName">
+                       <property name="format" value="^_?[a-z]([a-zA-Z0-9]+)*$"/>
+               </module>
+
+               <!--
+                       Name pattern for local final variables.
+               -->
+               <module name="LocalFinalVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+
+               <!--
+                       Name pattern for local variables
+               -->
+               <module name="LocalVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for constants (static final fields)
+               -->
+               <module name="ConstantName">
+                       <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"/>
+               </module>
+
+               <!--
+                       Name pattern for parameters (note no underscores allowed)
+               -->
+               <module name="ParameterName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for static (non-final) fields
+               -->
+               <module name="StaticVariableName">
+                       <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
+               </module>
+               
+               <!--
+                       Name pattern for classes
+               -->
+               <module name="TypeName">
+                       <property name="format" value="[A-Z][a-zA-Z0-9]*$"/>
+                       <property name="tokens" value="CLASS_DEF"/>
+               </module>
+               
+               <!--
+                       Name pattern for interfaces. All interfaces names must end with 'I'.
+                       ** currently suppressed in checkstyle-suppress.xml **
+               -->
+               <module name="TypeName">
+                       <property name="id" value="InterfaceNaming"/>
+                       <property name="format" value="^[A-Z][a-zA-Z0-9]*I$"/>
+                       <property name="tokens" value="INTERFACE_DEF"/>
+                       <message key="name.invalidPattern" value="Interface names should end in a I"/>
+               </module>
+
+               <!--
+                       Java package name pattern 
+               -->
+               <module name="PackageName">
+                       <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--         LAYOUT AND STYLE       -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Only one top level type per source file
+               -->
+               <module name="OuterTypeNumber"/>
+               
+               <!-- 
+                       Ensure a class has a package declaration
+                -->
+               <module name="PackageDeclaration"/>
+               
+               <!--
+                       see http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-141855.html#1852
+                       1. Class (static) variables: public, protected, package, private
+                       2. Instance variables: public, protected, package, private
+                       3. Constructors
+                       4. Methods
+                -->
+               <module name="DeclarationOrder"/>
+               
+               <!-- 
+                       Modifier order should conform to JLS
+                       see http://checkstyle.sourceforge.net/config_modifier.html#ModifierOrder 
+                       public protected private abstract static final transient volatile synchronized native strictfp          
+               -->
+               <module name="ModifierOrder"/>
+               
+               <!-- 
+                       Declare variables in separate statements, for readability and bug avoidance
+                -->
+               <module name="MultipleVariableDeclarations"/>
+               
+               <!-- 
+                       Don't have more than one statement on a line
+                       (code formatting on save may enforce this anyway)
+                -->
+               <module name="OneStatementPerLine"/>
+
+               <!-- 
+                       Declare variables close to their point of first use 
+                       (doesn't handle variables used inside loops very well) 
+               -->
+               <module name="VariableDeclarationUsageDistance">
+                       <property name="allowedDistance" value="5" />
+                       <message key="variable.declaration.usage.distance.extend"
+                               value="Distance between declaration of ''{0}'' and its first use is {1}, suggested maximum is {2}. Consider moving, or make final if it may not be modified." />
+               </module>
+       
+               <!-- 
+                       Only use blocks within control statements 
+               -->
+               <module name="AvoidNestedBlocks" />
+
+               <!-- 
+                       Require at least a comment within a block. 
+                       Note this will accept auto-generated // TODO comments, 
+                       (but they should be flagged up by the TodoComment rule) 
+               -->
+               <module name="EmptyBlock">
+                       <property name="option" value="text"/>
+               </module>
+               
+               <!-- 
+                       Require braces round all code blocks within if/else/for/do/while 
+               -->
+               <module name="NeedBraces"/>
+               
+               <!--
+                       Disallow empty ';' statements
+               -->
+               <module name="EmptyStatement"/>
+
+               <!-- 
+                       Maximum number of return statements for a method
+               -->
+               <module name="ReturnCount">
+                       <property name="max" value="4"/>
+               </module>
+
+               <!-- 
+                       Don't use modifiers in contexts where their value is not optional,
+                       for example all interface methods are always public
+                       see http://checkstyle.sourceforge.net/config_modifier.html#RedundantModifier
+               -->
+               <module name="RedundantModifier"/>
+               
+               <!-- 
+                       Variables whose value is not modified should be declared final, both to show the
+                   program's intent, and to  allow compiler optimisation
+                   ** currently suppressed in checkstyle-suppress.xml **
+                -->            
+               <module name="FinalLocalVariable">
+                       <property name="tokens" value="VARIABLE_DEF" />
+               </module>
+
+               <!-- 
+                       Disallows shorthand of assigning values within an expression 
+               -->
+               <module name="InnerAssignment"/>
+
+               <!-- 
+                       Use Java style array declarations to assist in readability 
+               -->
+               <module name="ArrayTypeStyle"/>
+
+               <!-- 
+                       Use L not l to define a long constant 
+               -->
+               <module name="UpperEll"/>
+
+       <!-- ****************************** -->
+       <!--           SIZE LIMITS          -->
+       <!-- ****************************** -->
+
+               <!--
+                       Maximum line count for methods
+               -->
+               <module name="MethodLength">
+                       <property name="tokens" value="METHOD_DEF"/>
+                       <property name="max" value="50"/>
+                       <property name="countEmpty" value="false"/>
+               </module>
+
+               <!--
+                       Maximum statement count for methods, constructors,
+                       instance initialisation and static initialisation blocks
+               -->
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="30"/>
+                       <property name="tokens" value="METHOD_DEF"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="30"/>
+                       <property name="tokens" value="CTOR_DEF"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="max" value="4"/>
+                       <property name="tokens" value="INSTANCE_INIT"/>
+               </module>
+               <module name="ExecutableStatementCount">
+                       <property name="id" value="NoStaticInitialization"/>
+                       <property name="max" value="0"/>
+                       <property name="tokens" value="STATIC_INIT"/>
+               </module>
+
+               <!--
+                       Maximum parameter count for methods 
+               -->
+               <module name="ParameterNumber">
+                       <property name="max" value="5"/>
+               </module>
+
+               <!--
+                       Maximum line length for anonymous inner classes
+               -->
+               <module name="AnonInnerLength">
+                       <property name="max" value="40"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--            IMPORTS             -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Ensures that there are no redundant or unused imports.
+                    Should be handled by Save actions if using Eclipse 
+               -->
+               <module name="RedundantImport"/>
+               <module name="UnusedImports"/>
+
+               <!--
+                       Disallow * imports; may also be enforced by IDE Save Actions
+               -->
+               <module name="AvoidStarImport"/>
+
+               <!-- 
+                       Disallow import of sun.* packages as they are not portable 
+               -->
+               <module name="IllegalImport"/>
+
+               <!--
+                       rules as to what packages each package may (not) import
+                       see http://checkstyle.sourceforge.net/config_imports.html#ImportControl 
+               -->
+               <module name="ImportControl">
+                   <property name="file" value="${basedir}/utils/checkstyle/import-control.xml"/>
+                       <property name="severity" value="error"/>
+               </module>
+               
+       <!-- ****************************** -->
+       <!--         CATCH and THROW        -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Disallow catch of Exception, RunTimeException or Error 
+               -->
+               <module name="IllegalCatch"/>
+
+               <!-- 
+                       Disallow throw of Exception, RunTimeException or Error 
+               -->
+               <module name="IllegalThrows"/>
+
+       <!-- ****************************** -->
+       <!--          CODING CHECKS         -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Check for use of factory method rather than constructor for specified classes
+                       e.g. Boolean.valueOf(true) rather than new Boolean(true)
+               -->
+               <module name="IllegalInstantiation">
+                       <property name="classes" value="java.lang.Boolean"/>
+               </module>
+               
+               <!--
+                       Check that "string".equals(value) is used rather than value.equals("string")
+               -->
+               <module name="EqualsAvoidNull"/>
+
+               <!--
+                       Check that equals() and hashCode() are always overridden together
+               -->
+               <module name="EqualsHashCode"/>
+               
+               <!-- 
+                       Require switch statements to include a default 
+               -->
+               <module name="MissingSwitchDefault"/>
+               
+               <!-- 
+                       Check that switch default follows all case statements
+                -->
+               <module name="DefaultComesLast">
+                       <property name="severity" value="error"/>
+               </module>
+               
+               <!-- 
+                       Disallows fall-through in switch statements 
+                       i.e. a case without a break, return, throw or continue 
+                       NB a comment with the words "fall[s] through" suppresses this message
+                -->
+               <module name="FallThrough">
+                       <property name="severity" value="error" />
+               </module>
+               
+               <!-- 
+                       Warn if boolean expressions can be simplified 
+               -->
+               <module name="SimplifyBooleanExpression"/>
+
+               <!-- 
+                       Warn if boolean return expressions can be simplified 
+               -->
+               <module name="SimplifyBooleanReturn"/>
+
+               <!--
+                       Classes with only private constructors should be declared final
+               -->
+               <module name="FinalClass"/>
+               
+               <!-- 
+                       Classes with only static methods should not be instantiable,
+                       so should declare a private default constructor.
+               -->
+               <module name="HideUtilityClassConstructor"/>
+               
+               <!-- 
+                       An Interface should declare methods (do not use to define constants only) 
+               -->
+               <module name="InterfaceIsType"/>
+               
+               <!-- 
+                       Disallow public fields in classes (other than constants) 
+               -->
+               <module name="VisibilityModifier">
+                       <property name="packageAllowed" value="true"/>
+                       <property name="allowPublicImmutableFields" value="true"/>
+               </module>
+               
+               <!-- 
+                       Checks that a local variable or a parameter does not shadow a field that is defined in the same class.
+                       Note this should also be configured as a compiler warning in the IDE. 
+               -->
+               <module name="HiddenField"/> 
+
+               <!-- 
+                       Check that proper logging is used.
+                       This may be suppressed in the class that provides logging functions.
+               -->
+               <module name="RegexpSinglelineJava">
+                       <property name="id" value="NoSysout" />
+                       <property name="format" value="System\.out\.println"/>
+                       <property name="ignoreComments" value="true"/>
+                       <message key="regexp.exceeded" value="Should use jalview.bin.Cache.log for logging"/>
+               </module>
+               <module name="RegexpSinglelineJava">
+                       <property name="id" value="NoSyserr" />
+                       <property name="format" value="System\.err\.println"/>
+                       <property name="ignoreComments" value="true"/>
+                       <message key="regexp.exceeded" value="Should use jalview.bin.Cache.log for logging"/>
+               </module>
+
+               <!--
+                       Checks that classes that define a covariant equals() method also override 
+                       method equals(java.lang.Object).
+                -->
+               <module name="CovariantEquals"/>
+               
+               <!-- 
+                       Checks that there are no "magic numbers" (numeric literals) 
+               -->
+               <module name="MagicNumber">
+                       <property name="ignoreNumbers" value="-1,0,1,2"/>
+               </module>
+               
+               <!-- 
+                       Check that  loop control variables are not modified inside the for block
+                -->
+               <module name="ModifiedControlVariable">
+               </module>
+               
+               <!-- 
+                       Checks that string literals are not used with == or !=.
+                -->
+               <module name="StringLiteralEquality">
+               </module>
+               
+               <!-- 
+                       Don't override clone - it never works! 
+                -->
+               <module name="NoClone"/>
+               
+               <!-- 
+                       Checks that clone() invokes super.clone()
+                       (for classes that break the NoClone rule)
+                -->
+               <module name="SuperClone"/>
+               
+               <!-- 
+                       Checks that finalize() invokes super.finalize()
+                -->
+               <module name="SuperFinalize"/>
+               
+               <!-- 
+                       Disallow assignment of parameters.
+                -->
+               <module name="ParameterAssignment"/>
+
+               <!-- 
+                       Checks for multiple occurrences of the same string literal within a single file.
+                       NB - does not check for the same string in different files.
+                -->
+               <module name="MultipleStringLiterals">
+                       <property name="allowedDuplicates" value="1"/>
+               </module>
+               
+               <!-- 
+                       Checks that exceptions are immutable (have only final fields)
+                -->
+               <module name="MutableException"/>
+               
+               <!-- 
+                       A general rule to check for source text tokens that shouldn't be there
+                       see http://checkstyle.sourceforge.net/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html
+                -->
+               <module name="IllegalToken">
+                  <property name="tokens" value="LITERAL_ASSERT"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--           COMPLEXITY           -->
+       <!-- ****************************** -->
+               
+               <!-- 
+                       Restrict the number of number of &&, ||, &, |  and ^ in an expression.
+                       Note that the operators & and | are not only integer bitwise operators, they are also the 
+                       non-shortcut versions of the boolean operators && and ||.
+                -->
+               <module name="BooleanExpressionComplexity">
+                       <property name="max" value="3"/>
+               </module>
+               
+               <!-- 
+                       This metric measures the number of instantiations of other classes within the given class. 
+                       The higher the DAC, the more complex the data structure of the system.
+                -->
+               <module name="ClassDataAbstractionCoupling">
+                       <property name="max" value="7"/>
+               </module>
+               
+               <!-- 
+                       The number of other classes a class relies on. A high number indicates over-complex
+                       class interdependencies that might benefit from refactoring.
+                -->
+               <module name="ClassFanOutComplexity">
+               <property name="max" value="10"/>
+       </module>
+               
+               <!-- 
+                       Checks cyclomatic complexity against a specified limit. The complexity is a measure 
+                       of the minimum number of possible paths through the source and therefore the number of required 
+                       tests. Consider re-factoring if at or above 10.
+                -->
+               <module name="CyclomaticComplexity">
+                       <property name="max" value="15"/>
+               </module>
+               
+               <!-- 
+                       The NPATH metric computes the number of possible execution paths through a function. It takes 
+                       into account the nesting of conditional statements and multi-part boolean expressions 
+                       (e.g., A && B, C || D, etc.).
+                -->
+               <module name="NPathComplexity">
+                       <property name="max" value="200"/>
+               </module>
+
+               <!-- 
+                       Maximum number of throws statements in a method
+                -->
+               <module name="ThrowsCount">
+                       <property name="max" value="2"/>
+               </module>
+               
+               <!-- 
+                       Maximum if-else depth
+                -->
+               <module name="NestedIfDepth">
+                       <property name="max" value="4"/>
+               </module>
+
+               <!-- 
+                       Restricts nested try blocks to a specified depth. 
+                -->
+               <module name="NestedTryDepth">
+                       <property name="max" value="2"/>
+               </module>
+
+       <!-- ****************************** -->
+       <!--              TODO              -->
+       <!-- ****************************** -->
+
+               <!-- 
+                       Checks for uncommented main() methods (debugging leftovers)
+                -->
+               <module name="UncommentedMain"/>
+
+               <!-- 
+                       Check for TODO and similar comments 
+               -->
+               <module name="TodoComment">
+                       <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>
+</module>
diff --git a/utils/checkstyle/import-control.xml b/utils/checkstyle/import-control.xml
new file mode 100644 (file)
index 0000000..b41aab3
--- /dev/null
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE import-control PUBLIC
+    "-//Puppy Crawl//DTD Import Control 1.1//EN"
+    "http://www.puppycrawl.com/dtds/import_control_1_1.dtd">
+    
+    <!--
+       see http://checkstyle.sourceforge.net/config_imports.html#ImportControl
+       allow/disallow rules propagate to sub-packages 
+       unless local-only="true" is specified
+       
+       note this can handle only one top-level package, so ImportControl is
+       suppressed for MCview and vamsas in checkstyle-suppress.xml
+       (all rules are suppressed for com/ext/org/uk)
+    -->
+   <import-control pkg="jalview">
+   
+               <allow pkg="java"/>
+               <allow pkg="jalview"/>
+               <allow pkg="com.stevesoft.pat"/>
+               
+               <subpackage name="appletgui">
+               <disallow pkg="javax.swing"/>
+               <disallow pkg="jalview.gui"/>
+               <disallow pkg="jalview.ws"/>
+               <allow pkg="org.jmol"/>
+               <allow pkg="javajs.awt" class="jalview.appletgui.AppletJmolBinding"/>
+           </subpackage>
+               
+               <subpackage name="bin">
+               <allow pkg="groovy"/>
+               <allow pkg="org.apache.log4j" class="jalview.bin.Cache"/>
+               <allow pkg="javax.swing" class="jalview.bin.Jalview"/>
+               <allow pkg="netscape.javascript" class="jalview.bin.JalviewLite"/>
+           </subpackage>
+               
+               <subpackage name="datamodel">
+               <disallow pkg="jalview.gui"/>
+               <allow pkg="fr.orsay.lri.varna"/>
+                       <subpackage name="xdb">
+                               <subpackage name="embl">
+                               <allow pkg="org.exolab.castor"/>
+                           </subpackage>
+                   </subpackage>
+           </subpackage>
+               
+               <subpackage name="fts">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.ws"/>
+               <allow pkg="org.json"/>
+               <allow pkg="com.sun.jersey"/>
+           </subpackage>
+               
+               <subpackage name="gui">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.help"/>
+               <allow pkg="javax.imageio"/>
+               <allow pkg="ext.edu.ucsf"/>
+               <allow pkg="net.miginfocom"/>
+               <allow pkg="org.jibble"/>
+               <allow pkg="org.jmol"/>
+               <allow pkg="org.openscience"/>
+               <allow pkg="org.exolab.castor" class="jalview.gui.Jalview2XML"/>
+               <allow pkg="org.robsite" class="jalview.gui.BlogReader"/>
+               <allow pkg="org.apache.log4j" class="jalview.gui.Console"/>
+               <allow pkg="org.apache.log4j" class="jalview.gui.JalviewAppender"/>
+               <allow pkg="org.biodas" class="jalview.gui.DasSourceBrowser"/>
+               <allow pkg="compbio.metadata" class="jalview.gui.WsJobParameters"/>
+               <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarna"/>
+               <allow pkg="fr.orsay.lri.varna" class="jalview.gui.AppVarnaBinding"/>
+               <allow pkg="uk.ac.vamsas" class="jalview.gui.VamsasApplication"/>
+           </subpackage>
+               
+               <subpackage name="jbgui">
+               <allow pkg="javax.swing"/>
+               <allow pkg="net.miginfocom"/>
+           </subpackage>
+
+               <subpackage name="httpserver">
+               <allow pkg="javax.servlet"/>
+               <allow pkg="org.eclipse.jetty"/>
+           </subpackage>
+
+               <subpackage name="io">
+               <allow pkg="javax.swing"/>
+               <allow pkg="org.jfree"/>
+               <allow pkg="org.json"/>
+               <allow pkg="org.jsoup"/>
+               <allow pkg="uk.ac.ebi"/>
+               <allow pkg="uk.ac.vamsas"/>
+               <allow pkg="fr.orsay.lri.varna"/>
+               <allow pkg="MCview"/>
+               </subpackage>       
+                               
+               <subpackage name="javascript">
+               <allow pkg="netscape.javascript"/>
+           </subpackage>
+
+               <subpackage name="rest">
+               <allow pkg="javax.servlet"/>
+               </subpackage>
+
+               <subpackage name="structure">
+               <allow pkg="MCview"/>
+               </subpackage>
+
+               <subpackage name="util">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.imageio"/>
+               <allow pkg="org.jfree"/>
+               <allow pkg="org.jibble"/>
+               </subpackage>
+
+               <subpackage name="ws">
+               <allow pkg="javax.swing"/>
+               <allow pkg="javax.xml"/>
+               <allow pkg="ext.vamsas"/>
+               <allow pkg="compbio"/>
+               <allow pkg="MCview"/>
+               <allow pkg="org.apache.http"/>
+               <allow pkg="org.apache.james"/>
+               <allow pkg="org.apache.axis"/>
+               <allow pkg="org.biodas.jdas"/>
+               <allow pkg="org.exolab.castor"/>
+               <allow pkg="uk.ac.ebi"/>
+               <allow pkg="vamsas.objects"/>
+               </subpackage>
+
+   </import-control>
\ No newline at end of file
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");
+    }
+  }
 
 }
index 47c404e..01973d2 100755 (executable)
@@ -19,8 +19,7 @@
         var logger = project.getBuildListeners( ).firstElement( );
         logger.setMessageOutputLevel( 1 );
     </script>
-       <echo message="Missing message labels compared to Messages.properties"/>
-       <foreach target="compareProperties" param="file2">
+       <foreach target="compareBundles" param="file2">
                <path>
                        <fileset dir="${basedir}/resources/lang">
                                <exclude name="Messages.properties" />
        </foreach>
 </target>
 
+<target name="compareBundles" description="compare a properties file with Messages.properties and vice versa">
+       <echo message=" "/>
+       <echo message="Missing message labels in ${file2} compared to Messages.properties"/>
+       <antcall target="compareProperties">
+               <param name="file1" value="resources/lang/Messages.properties"/>
+               <param name="file2" value="${file2}" />
+       </antcall>
+       <echo message=" "/>
+       <echo message="Missing message labels in Messages.properties compare to ${file2}"/>
+       <antcall target="compareProperties">
+               <param name="file2" value="resources/lang/Messages.properties"/>
+               <param name="file1" value="${file2}" />
+       </antcall>
+</target>
+               
 <target name="compareProperties" description="reports missing entries in one message bundle">
-    <loadproperties srcFile="resources/lang/Messages.properties" prefix="prefixfile1"/>
+    <loadproperties srcFile="${file1}" prefix="prefixfile1"/>
     <loadproperties srcFile="${file2}" prefix="prefixfile2"/>
 
     <propertyselector property="file1.list" delimiter="," match="prefixfile1\.(.+)" select="\1"/>
     <propertyselector property="file2.list" delimiter="," match="prefixfile2\.(.+)" select="\1"/>
        
-       <echo message=" "/>
-       <echo message="*** ${file2}:" />
     <for list="${file1.list}" param="file1.property">
         <sequential>
             <if>