Merge branch 'Jalview-JS/develop' into merge_js_develop
authorJim Procter <jprocter@issues.jalview.org>
Mon, 14 Dec 2020 19:58:34 +0000 (19:58 +0000)
committerJim Procter <jprocter@issues.jalview.org>
Mon, 14 Dec 2020 20:28:39 +0000 (20:28 +0000)
also patched new code from JAL-3690 refactorings

330 files changed:
doc/addingWebClient.md [new file with mode: 0644]
examples/groovy/hmmertestimport.groovy [new file with mode: 0644]
examples/testdata/hmmer3/alignment_frag.fa.gz [new file with mode: 0644]
examples/testdata/hmmer3/alignment_res.fa.gz [new file with mode: 0644]
examples/testdata/hmmer3/hit_fragment.json.gz [new file with mode: 0644]
examples/testdata/hmmer3/hmmeresult.json.gz [new file with mode: 0644]
examples/uniref50.hmm [new file with mode: 0644]
help/help/help.jhm
help/help/helpTOC.xml
help/help/html/features/preferences.html
help/help/html/menus/alwhmmer.html [new file with mode: 0644]
j11lib/apache-mime4j-0.6.jar [deleted file]
j11lib/apache-mime4j-core-0.8.3.jar [new file with mode: 0644]
j11lib/apache-mime4j-dom-0.8.3.jar [new file with mode: 0644]
j11lib/httpclient-4.0.3.jar [deleted file]
j11lib/httpclient-4.5.6.jar [new file with mode: 0644]
j11lib/httpcore-4.0.1.jar [deleted file]
j11lib/httpcore-4.4.10.jar [new file with mode: 0644]
j11lib/httpmime-4.0.3.jar [deleted file]
j11lib/httpmime-4.5.6.jar [new file with mode: 0644]
j11lib/java-json.jar [deleted file]
j11lib/json-20180130.jar [new file with mode: 0644]
j11lib/slivka-client.jar [new file with mode: 0644]
j8lib/apache-mime4j-core-0.8.3.jar [new file with mode: 0644]
j8lib/apache-mime4j-dom-0.8.3.jar [new file with mode: 0644]
resources/ProbabilityOfMatch [new file with mode: 0644]
resources/lang/Messages.properties
resources/lang/Messages_es.properties
schemas/jalview.xsd
src/ext/edu/ucsf/rbvi/strucviz2/StructureManager.java
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignmentAnnotationUtils.java
src/jalview/analysis/AlignmentSorter.java
src/jalview/analysis/AlignmentUtils.java
src/jalview/analysis/SeqsetUtils.java
src/jalview/api/AlignCalcListener.java [new file with mode: 0644]
src/jalview/api/AlignCalcManagerI.java
src/jalview/api/AlignCalcManagerI2.java [new file with mode: 0644]
src/jalview/api/AlignCalcWorkerI.java
src/jalview/api/AlignViewportI.java
src/jalview/api/FeatureSettingsModelI.java
src/jalview/api/PollableAlignCalcWorkerI.java [new file with mode: 0644]
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/TitledPanel.java
src/jalview/bin/Jalview.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/AlignmentOrder.java
src/jalview/datamodel/AlignmentView.java
src/jalview/datamodel/AnnotatedCollectionI.java
src/jalview/datamodel/HMMNode.java [new file with mode: 0644]
src/jalview/datamodel/HiddenMarkovModel.java [new file with mode: 0644]
src/jalview/datamodel/ResidueCount.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceCollectionI.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/CalculationChooser.java
src/jalview/gui/Desktop.java
src/jalview/gui/IProgressIndicator.java
src/jalview/gui/JalviewChangeSupport.java
src/jalview/gui/JvSwingUtils.java
src/jalview/gui/OptsAndParamsPage.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PairwiseAlignPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/ProgressBar.java
src/jalview/gui/RestServiceEditorPane.java
src/jalview/gui/SlivkaPreferences.java [new file with mode: 0644]
src/jalview/gui/SplitFrame.java
src/jalview/gui/StructureChooser.java
src/jalview/gui/WebserviceInfo.java
src/jalview/gui/WsJobParameters.java
src/jalview/gui/WsParamSetManager.java
src/jalview/gui/WsPreferences.java
src/jalview/hmmer/HMMAlign.java [new file with mode: 0644]
src/jalview/hmmer/HMMBuild.java [new file with mode: 0644]
src/jalview/hmmer/HMMERParamStore.java [new file with mode: 0644]
src/jalview/hmmer/HMMERPreset.java [new file with mode: 0644]
src/jalview/hmmer/HMMSearch.java [new file with mode: 0644]
src/jalview/hmmer/HmmerCommand.java [new file with mode: 0644]
src/jalview/hmmer/JackHMMER.java [new file with mode: 0644]
src/jalview/hmmer/Search.java [new file with mode: 0644]
src/jalview/io/AlignFile.java
src/jalview/io/CountReader.java [new file with mode: 0644]
src/jalview/io/FileFormat.java
src/jalview/io/FileLoader.java
src/jalview/io/HMMFile.java [new file with mode: 0644]
src/jalview/io/IdentifyFile.java
src/jalview/io/SequenceAnnotationReport.java
src/jalview/io/StockholmFile.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GPreferences.java
src/jalview/jbgui/GRestInputParamEditDialog.java
src/jalview/jbgui/GRestServiceEditorPane.java
src/jalview/project/Jalview2XML.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/ResidueShaderI.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/schemes/FeatureSettingsAdapter.java
src/jalview/schemes/HMMMatchScoreColourScheme.java [new file with mode: 0644]
src/jalview/schemes/HmmerColourScheme.java [new file with mode: 0644]
src/jalview/schemes/HmmerGlobalBackground.java [new file with mode: 0644]
src/jalview/schemes/HmmerLocalBackground.java [new file with mode: 0644]
src/jalview/schemes/JalviewColourScheme.java
src/jalview/schemes/ResidueProperties.java
src/jalview/util/Comparison.java
src/jalview/util/FileUtils.java [new file with mode: 0644]
src/jalview/util/HMMProbabilityDistributionAnalyser.java [new file with mode: 0644]
src/jalview/util/HttpUtils.java
src/jalview/util/MapList.java
src/jalview/util/MappingUtils.java
src/jalview/util/Platform.java
src/jalview/util/ProbabilityAnalyserKickstarter.java [new file with mode: 0644]
src/jalview/util/StringUtils.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/workers/AlignCalcManager.java
src/jalview/workers/AlignCalcManager2.java [new file with mode: 0644]
src/jalview/workers/AlignCalcWorker.java
src/jalview/workers/AnnotationWorker.java
src/jalview/workers/ColumnCounterSetWorker.java
src/jalview/workers/ConsensusThread.java
src/jalview/workers/ConservationThread.java
src/jalview/workers/InformationThread.java [new file with mode: 0644]
src/jalview/workers/StrucConsensusThread.java
src/jalview/ws/AWSThread.java
src/jalview/ws/AWsJob.java
src/jalview/ws/JobStateSummary.java
src/jalview/ws/ServiceChangeListener.java [new file with mode: 0644]
src/jalview/ws/WSClient.java
src/jalview/ws/WSDiscovererI.java [new file with mode: 0644]
src/jalview/ws/api/CancellableI.java [new file with mode: 0644]
src/jalview/ws/api/DistanceMatrixResultI.java [new file with mode: 0644]
src/jalview/ws/api/JalviewServiceEndpointProviderI.java [new file with mode: 0644]
src/jalview/ws/api/JalviewWebServiceI.java [new file with mode: 0644]
src/jalview/ws/api/JobId.java [new file with mode: 0644]
src/jalview/ws/api/MsaI.java [new file with mode: 0644]
src/jalview/ws/api/MsaResultI.java [new file with mode: 0644]
src/jalview/ws/api/MsaWithGuideTreeI.java [new file with mode: 0644]
src/jalview/ws/api/MultipleSequenceAlignmentI.java [new file with mode: 0644]
src/jalview/ws/api/SequenceAnnotationServiceI.java [new file with mode: 0644]
src/jalview/ws/api/ServiceWithParameters.java [new file with mode: 0644]
src/jalview/ws/api/TreeResultI.java [new file with mode: 0644]
src/jalview/ws/api/UIinfo.java [new file with mode: 0644]
src/jalview/ws/api/WSAnnotationCalcManagerI.java [new file with mode: 0644]
src/jalview/ws/ebi/HmmerJSONProcessor.java [new file with mode: 0644]
src/jalview/ws/ebi/hmmerClient.java [new file with mode: 0644]
src/jalview/ws/gui/AnnotationWsJob.java [new file with mode: 0644]
src/jalview/ws/gui/MsaWSJob.java [new file with mode: 0644]
src/jalview/ws/gui/MsaWSThread.java [moved from src/jalview/ws/jws2/MsaWSThread.java with 52% similarity]
src/jalview/ws/gui/WsJob.java [new file with mode: 0644]
src/jalview/ws/io/mime/JalviewMimeContentHandler.java
src/jalview/ws/jws1/Discoverer.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/AAConClient.java [deleted file]
src/jalview/ws/jws2/AADisorderClient.java [deleted file]
src/jalview/ws/jws2/AbstractJabaCalcWorker.java [deleted file]
src/jalview/ws/jws2/JabaParamStore.java
src/jalview/ws/jws2/JabaPreset.java
src/jalview/ws/jws2/JabaWsParamTest.java [new file with mode: 0644]
src/jalview/ws/jws2/JabawsCalcWorker.java [deleted file]
src/jalview/ws/jws2/JabawsMsaInterfaceAlignCalcWorker.java [deleted file]
src/jalview/ws/jws2/Jws2Client.java
src/jalview/ws/jws2/Jws2ClientFactory.java [new file with mode: 0644]
src/jalview/ws/jws2/Jws2Discoverer.java
src/jalview/ws/jws2/MsaWSClient.java
src/jalview/ws/jws2/ParameterUtils.java
src/jalview/ws/jws2/PreferredServiceChangeListener.java [new file with mode: 0644]
src/jalview/ws/jws2/PreferredServiceRegistry.java [new file with mode: 0644]
src/jalview/ws/jws2/SeqAnnotationServiceCalcWorker.java [new file with mode: 0644]
src/jalview/ws/jws2/SequenceAnnotationWSClient.java
src/jalview/ws/jws2/dm/AAConSettings.java
src/jalview/ws/jws2/dm/JabaOption.java
src/jalview/ws/jws2/jabaws2/AAConClient.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/AADisorderClient.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/JabawsAnnotationInstance.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/JabawsMsaInterfaceAlignCalcWorker.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/JabawsServiceInstance.java [new file with mode: 0644]
src/jalview/ws/jws2/jabaws2/Jws2Instance.java
src/jalview/ws/jws2/jabaws2/Jws2InstanceFactory.java
src/jalview/ws/jws2/jabaws2/RNAalifoldClient.java [moved from src/jalview/ws/jws2/RNAalifoldClient.java with 70% similarity]
src/jalview/ws/params/ArgumentI.java
src/jalview/ws/params/AutoCalcSetting.java
src/jalview/ws/params/OptionI.java
src/jalview/ws/params/ValueConstrainI.java
src/jalview/ws/params/simple/BooleanOption.java
src/jalview/ws/params/simple/DoubleParameter.java [new file with mode: 0644]
src/jalview/ws/params/simple/FileParameter.java [new file with mode: 0644]
src/jalview/ws/params/simple/IntegerParameter.java
src/jalview/ws/params/simple/LogarithmicParameter.java [new file with mode: 0644]
src/jalview/ws/params/simple/Option.java
src/jalview/ws/params/simple/Parameter.java [deleted file]
src/jalview/ws/params/simple/RadioChoiceParameter.java [moved from src/jalview/ws/params/simple/StringChoiceParameter.java with 65% similarity]
src/jalview/ws/params/simple/StringParameter.java [new file with mode: 0644]
src/jalview/ws/rest/HttpResultSet.java
src/jalview/ws/rest/InputType.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJobThread.java
src/jalview/ws/rest/RestServiceDescription.java
src/jalview/ws/rest/clientdefs/ShmrRestClient.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaAnnotationServiceInstance.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaDatastore.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaParamSet.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaWSInstance.java [new file with mode: 0644]
src/jalview/ws/uimodel/AlignAnalysisUIText.java
src/jalview/xml/binding/jalview/AlcodonFrame.java
src/jalview/xml/binding/jalview/Annotation.java
src/jalview/xml/binding/jalview/AnnotationColourScheme.java
src/jalview/xml/binding/jalview/AnnotationElement.java
src/jalview/xml/binding/jalview/DoubleMatrix.java
src/jalview/xml/binding/jalview/DoubleVector.java
src/jalview/xml/binding/jalview/Feature.java
src/jalview/xml/binding/jalview/FeatureMatcher.java
src/jalview/xml/binding/jalview/FeatureMatcherSet.java
src/jalview/xml/binding/jalview/FilterBy.java
src/jalview/xml/binding/jalview/JalviewModel.java
src/jalview/xml/binding/jalview/JalviewUserColours.java
src/jalview/xml/binding/jalview/MapListType.java
src/jalview/xml/binding/jalview/Mapping.java
src/jalview/xml/binding/jalview/NoValueColour.java
src/jalview/xml/binding/jalview/ObjectFactory.java
src/jalview/xml/binding/jalview/PcaDataType.java
src/jalview/xml/binding/jalview/Pdbentry.java
src/jalview/xml/binding/jalview/Sequence.java
src/jalview/xml/binding/jalview/SequenceSet.java
src/jalview/xml/binding/jalview/SequenceType.java
src/jalview/xml/binding/jalview/ThresholdType.java
src/jalview/xml/binding/jalview/VAMSAS.java
src/jalview/xml/binding/jalview/WebServiceParameterSet.java
src/jalview/xml/binding/jalview/package-info.java
swingjs/README.txt [deleted file]
swingjs/SwingJS-site.zip
swingjs/timestamp
swingjs/ver/3.2.4/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.4/SwingJS-site.zip [deleted file]
swingjs/ver/3.2.4/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.4/net.sf.j2s.core.jar [deleted file]
swingjs/ver/3.2.4/timestamp [deleted file]
swingjs/ver/3.2.5/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.5/SwingJS-site.zip [deleted file]
swingjs/ver/3.2.5/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.5/net.sf.j2s.core.jar [deleted file]
swingjs/ver/3.2.5/timestamp [deleted file]
swingjs/ver/3.2.7/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.7/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.7/net.sf.j2s.core.jar [deleted file]
swingjs/ver/3.2.7/timestamp [deleted file]
swingjs/ver/3.2.8/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.8/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.8/net.sf.j2s.core.jar [deleted file]
swingjs/ver/3.2.8/timestamp [deleted file]
swingjs/ver/3.2.9-j11/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.9-j11/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.9-j11/net.sf.j2s.core.jar [deleted file]
swingjs/ver/3.2.9/DEV_NOTES.txt [deleted file]
swingjs/ver/3.2.9/_j2sclasslist.txt [deleted file]
swingjs/ver/3.2.9/net.sf.j2s.core-j11.jar [deleted file]
test/jalview/analysis/AAFrequencyTest.java
test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java
test/jalview/datamodel/AlignmentAnnotationTests.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/datamodel/AlignmentViewTest.java
test/jalview/datamodel/HMMNodeTest.java [new file with mode: 0644]
test/jalview/datamodel/HiddenMarkovModelTest.java [new file with mode: 0644]
test/jalview/datamodel/HiddenSequencesTest.java
test/jalview/datamodel/ResidueCountTest.java
test/jalview/datamodel/SequenceGroupTest.java
test/jalview/datamodel/SequenceTest.java
test/jalview/gui/AlignFrameTest.java
test/jalview/gui/AlignViewportTest.java
test/jalview/gui/PairwiseAlignmentPanelTest.java
test/jalview/gui/PopupMenuTest.java
test/jalview/gui/SequenceRendererTest.java
test/jalview/hmmer/HMMERTest.java [new file with mode: 0644]
test/jalview/hmmer/testProps.jvprops [new file with mode: 0644]
test/jalview/io/FileFormatsTest.java
test/jalview/io/FileLoaderTest.java
test/jalview/io/FormatAdapterTest.java
test/jalview/io/HMMAlignmentTest.sto [new file with mode: 0644]
test/jalview/io/HMMAlignmentTestHMM.hmm [new file with mode: 0644]
test/jalview/io/HMMFileTest.java [new file with mode: 0644]
test/jalview/io/StockholmFileTest.java
test/jalview/io/test_MADE1_hmm.txt [new file with mode: 0644]
test/jalview/io/test_PKinase_hmm.txt [new file with mode: 0644]
test/jalview/io/test_fn3_hmm.txt [new file with mode: 0644]
test/jalview/project/Jalview2xmlTests.java
test/jalview/renderer/OverviewResColourFinderTest.java
test/jalview/renderer/ResidueColourFinderTest.java
test/jalview/renderer/ScaleRendererTest.java
test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java
test/jalview/schemes/ClustalxColourSchemeTest.java
test/jalview/schemes/HmmerGlobalBackgroundTest.java [new file with mode: 0644]
test/jalview/schemes/HmmerLocalBackgroundTest.java [new file with mode: 0644]
test/jalview/schemes/PIDColourSchemeTest.java
test/jalview/util/Binned.csv [new file with mode: 0644]
test/jalview/util/FileUtilsTest.java [new file with mode: 0644]
test/jalview/util/HMMProbabilityDistributionAnalyserTest.java [new file with mode: 0644]
test/jalview/util/MapListTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/util/Raw.csv [new file with mode: 0644]
test/jalview/util/StringUtilsTest.java
test/jalview/util/test_Fams_for_probability_analysis [new file with mode: 0644]
test/jalview/util/test_hmms_for_probability_analysis [new file with mode: 0644]
test/jalview/workers/AlignCalcManagerTest.java
test/jalview/ws/ebi/HmmerJSONProcessTest.java [new file with mode: 0644]
test/jalview/ws/gui/Jws2ParamView.java
test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java [new file with mode: 0644]
test/jalview/ws/jabaws/DisorderAnnotExportImport.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/jws2/ParameterUtilsTest.java
test/jalview/ws/rest/ShmmrRSBSService.java
utils/i18nAnt.xml
utils/jalviewjs/libjs/slivka-client-site.zip [new file with mode: 0644]

diff --git a/doc/addingWebClient.md b/doc/addingWebClient.md
new file mode 100644 (file)
index 0000000..0d0ee1d
--- /dev/null
@@ -0,0 +1,68 @@
+# How to add a web service backend to Jalview's web services UI
+
+### Document Status: *Work in progress !*
+
+There are two phases to services.
+
+ *Discovery* threads are started by jalview.gui.Desktop (or other UI components or the CLI if they are headless services accessible via commandline). Your service discovery thread registers discovered instances so they can be accessed by the user.
+
+ *Access* most services are accessed by selecting a menu item, option, or specifying a nickname for the service instance as a Jalview command line parameter. Different access patterns are used for the various services: seqeunce data source, sequence feature annotation source, multiple sequence alignment, multiple alignment annotation source, etc. There should be no need for your code to create UI components (if there is then Jalview's UI needs to be refactored to avoid this).
+
+## Discovery
+
+*jalview.gui.Desktop*
+- start a discovery thread to discover services provided by your framework. The discoverer should generate a list of objects that either implement WsMenuEntryProviderI or provide another mechanism to add themselves to Jalview's menus (via jalview.gui.AlignFrame.BuildWebServiceMenu() below)
+
+*jalview.gui.AlignFrame*
+- BuildWebServiceMenu()
+ This method creates a runnable that's called when the available set of web services changes (e.g. when a discovery thread completes). Add code to the Runnable's run method to create Menu Items in the web services menu via jalview.ws.WSMenuEntryProviderI instances generated by your discoverer. 
+
+
+## Types of service
+
+### Services that create new alignments or windows, optionally with a progress log
+
+The pattern for these services requires a Client that initates a thread which creates, and montors one or more jobs based on input data.
+
+jalview.ws.MsaWSClient -- currently does double duty with Jaba services for alignment analysis and instantiation of alignment services.
+
+jalview.ws.gui.MSAThread -- UI model and controller for a running MSA service. Instantiated with an instance of jalview.ws.MultipleSequenceAlignmentI provided by the service endpoint factory.
+
+
+## Other classes of interest
+
+### jalview.ws.api
+
+Interfaces and base classes to be implemented and used by a service endpoint.
+
+ jalview.ws.api.CancellableI.java - implement if the service is cancellable
+ jalview.ws.api.JalviewWebServiceI.java - base service interface
+ jalview.ws.api.JobId.java - a timestamped job id that can be saved in a Jalview project
+
+#### submission interfaces
+jalview.ws.api.MsaI.java
+jalview.ws.api.MsaWithGuideTreeI.java
+
+
+#### result interfaces
+jalview.ws.api.MsaResultI.java
+jalview.ws.api.TreeResultI.java
+jalview.ws.api.DistanceMatrixResultI.java
+
+
+#### minimal composed interfaces for a complete functional analysis 
+
+jalview.ws.api.MultipleSequenceAlignmentI.java
+
+
+#### base class for a service endpoint instance - to be materialised by service discoverers
+
+jalview.ws.api.UIinfo.java - basic information 
+jalview.ws.api.ServiceWithParameters.java
+
+jalview.ws.api.JalviewServiceEndpointProviderI - implemented by service endpoint factories (typically extended from UIinfo or ServiceWithParameters).
+
+
+## Analysis services
+
+These have not yet been refactored. Feel free to look at how jalview.ws.jws2.AACons and Disorder clients operate and adapt the pattern for your own services. The Groovy example in the help [[help/html/groovy/featuresCounter.html]] for creating custom annotation tracks uses the same basic 'alignment analysis worker' mechanism to provide dynamically executed alignment analysis calculations that result in annotation tracks displayed below the alginment.
diff --git a/examples/groovy/hmmertestimport.groovy b/examples/groovy/hmmertestimport.groovy
new file mode 100644 (file)
index 0000000..88bd0e1
--- /dev/null
@@ -0,0 +1,6 @@
+// def alv = new jalview.io.FileLoader().LoadFileWaitTillLoaded("examples/testdata/hmmer3/alignment_res.fa.gz","File").getViewport();
+def alv = jalview.bin.Jalview.getCurrentAlignFrame().getViewport();
+def al = alv.getAlignment();
+def jproc = new jalview.ws.ebi.HmmerJSONProcessor(al)
+jproc.parseFrom(new jalview.io.FileParse("/Users/jprocter/git/jalview/examples/testdata/hmmer3/hmmeresult.json.gz",jalview.io.DataSourceType.FILE))
+jproc.updateView(alv)
\ No newline at end of file
diff --git a/examples/testdata/hmmer3/alignment_frag.fa.gz b/examples/testdata/hmmer3/alignment_frag.fa.gz
new file mode 100644 (file)
index 0000000..a4e79b2
Binary files /dev/null and b/examples/testdata/hmmer3/alignment_frag.fa.gz differ
diff --git a/examples/testdata/hmmer3/alignment_res.fa.gz b/examples/testdata/hmmer3/alignment_res.fa.gz
new file mode 100644 (file)
index 0000000..03206f4
Binary files /dev/null and b/examples/testdata/hmmer3/alignment_res.fa.gz differ
diff --git a/examples/testdata/hmmer3/hit_fragment.json.gz b/examples/testdata/hmmer3/hit_fragment.json.gz
new file mode 100644 (file)
index 0000000..bbc8405
Binary files /dev/null and b/examples/testdata/hmmer3/hit_fragment.json.gz differ
diff --git a/examples/testdata/hmmer3/hmmeresult.json.gz b/examples/testdata/hmmer3/hmmeresult.json.gz
new file mode 100644 (file)
index 0000000..c3fa9a2
Binary files /dev/null and b/examples/testdata/hmmer3/hmmeresult.json.gz differ
diff --git a/examples/uniref50.hmm b/examples/uniref50.hmm
new file mode 100644 (file)
index 0000000..b07ec14
--- /dev/null
@@ -0,0 +1,466 @@
+HMMER3/f [3.1b2 | February 2015]
+NAME  uniref50
+LENG  148 
+ALPH  amino
+ RF    no
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Mon Jun 12 14:32:05 2017
+NSEQ  15
+EFFN  0.648193
+CKSUM 2563184735
+STATS LOCAL MSV      -10.0682  0.70956
+STATS LOCAL VITERBI  -10.7870  0.70956
+STATS LOCAL FORWARD   -4.6837  0.70956
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   2.40816  3.71583  2.80837  2.63551  3.47092  2.77036  3.85028  2.88279  2.80267  2.53589  3.68425  3.22102  3.34428  3.14560  3.11474  2.53177  2.75990  2.58070  5.00144  3.51101
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.10433  3.97705  2.52157  0.61958  0.77255  0.00000        *
+      1   2.99317  4.53706  4.08224  3.67789  3.22093  3.85692  4.40592  2.39958  3.44433  1.81088  1.32037  3.95163  4.31759  3.82413  3.64608  3.34553  3.29902  2.40928  5.06591  3.83044      1 m - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+      2   0.97044  4.20710  3.49350  3.28598  4.08269  3.03087  4.30444  3.21278  3.30302  3.09300  4.12129  3.42792  3.77296  3.64134  3.55157  2.55705  2.83652  2.86187  5.50678  4.31039      2 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.11955  3.90315  2.38048  0.61958  0.77255  0.55549  0.85282
+      3   1.74035  4.09199  3.34495  3.00819  4.05288  2.91638  4.05509  3.33461  3.01251  3.11462  3.97728  3.20348  3.62940  3.32849  3.32799  1.99191  1.99086  2.89563  5.42641  4.20726      3 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03323  3.81683  4.53917  0.61958  0.77255  0.62561  0.76558
+      4   2.37663  4.18625  3.55838  3.17855  3.75132  3.18264  4.13666  2.64341  3.07328  2.62344  3.69712  3.39774  3.83139  3.44405  3.35689  2.61052  1.64486  2.15973  5.30034  4.05468      4 t - - -
+          2.68617  4.42230  2.77525  2.73129  3.46359  2.40511  3.72500  3.29359  2.67746  2.69350  4.24695  2.90352  2.73719  3.18152  2.89806  2.37885  2.77501  2.98524  4.58482  3.61508
+          0.33937  1.47682  2.82312  0.71438  0.67236  0.50642  0.92294
+      5   1.78828  4.31568  3.18846  2.75366  3.97645  3.11838  3.84000  3.34055  2.67250  3.02453  3.87541  3.10729  3.71676  3.06391  2.67828  2.15246  2.50645  2.96422  5.30410  4.05011      9 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03188  3.85742  4.57976  0.61958  0.77255  0.59400  0.80322
+      6   2.60146  4.34120  4.20318  3.64233  3.23200  4.03946  4.38229  1.91078  3.53317  1.46276  2.80385  3.95250  4.35454  3.78680  3.77614  3.34686  3.12310  1.90138  5.05979  3.90282     10 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03188  3.85742  4.57976  0.61958  0.77255  0.59400  0.80322
+      7   2.51618  4.38929  3.20785  2.68482  3.53842  3.39630  3.71025  2.97988  2.63127  2.66315  3.23915  3.11866  3.35060  2.98059  3.01133  2.11689  2.77574  2.72369  4.95633  3.10650     11 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03188  3.85742  4.57976  0.61958  0.77255  0.59400  0.80322
+      8   1.83112  4.12334  3.20156  2.95461  4.23963  1.79514  4.09699  3.64646  3.07597  3.33878  4.16582  3.16397  3.61350  3.35846  3.40724  1.96001  2.64648  3.10558  5.57497  4.34818     12 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.07518  3.85742  2.97012  0.61958  0.77255  0.59400  0.80322
+      9   2.02467  4.19921  3.47207  3.00878  3.03795  3.27081  3.95597  2.70270  2.96218  2.55248  3.54468  3.31239  3.83177  3.27950  3.28895  2.63385  2.09090  2.46488  5.06606  3.80489     13 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03327  3.81551  4.53786  0.61958  0.77255  0.56041  0.84624
+     10   2.25155  4.19461  3.85704  3.29295  2.92371  3.72128  4.04839  2.07964  3.20853  2.08962  2.71310  3.60847  4.09120  3.47607  3.47945  3.00735  2.74040  2.14097  4.86082  3.65928     14 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03170  3.86316  4.58551  0.61958  0.77255  0.53107  0.88667
+     11   2.97746  4.34766  4.53309  3.96552  2.78843  4.21079  4.53997  1.80103  3.85948  1.59494  2.57669  4.20401  4.48099  4.02954  4.02513  3.53069  3.20806  1.63119  5.03312  3.89134     15 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     12   2.01604  4.15364  3.23013  2.99255  4.26101  2.66741  4.12859  3.66796  3.09383  3.37186  4.20680  3.19709  3.64453  3.39377  3.41395  1.27425  2.68165  3.13093  5.59931  4.36607     16 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     13   2.41396  4.26265  3.40226  2.93569  3.72492  3.24366  3.92462  2.93397  2.83929  2.73560  3.16052  3.25846  3.81309  3.20648  3.16819  2.37913  1.73294  2.65776  5.16309  3.91530     17 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     14   2.06589  4.14828  3.30608  3.02868  4.20053  2.92394  4.12227  3.52677  3.06750  3.27902  4.13704  3.22373  3.65849  3.38850  3.37961  1.31011  2.40891  3.04032  5.55736  4.32788     18 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     15   2.74009  4.29274  3.92243  3.42912  1.74599  3.72053  3.90473  2.32427  3.32349  2.18956  3.31553  3.65797  4.14118  3.57919  3.55745  2.71376  3.01017  2.38146  4.46330  2.97696     19 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     16   2.76094  4.39380  4.31945  3.75589  3.18422  4.12530  4.45889  2.01307  3.63847  1.30728  2.59228  4.05575  4.41925  3.86957  3.85970  3.43754  3.19324  1.94550  5.06650  3.93230     20 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     17   2.70295  4.73637  3.16526  2.68917  4.18427  3.37581  3.71759  3.61851  2.27125  3.18722  4.06871  3.11427  2.39752  2.89725  1.66361  2.77186  2.98335  3.28411  5.34221  4.10051     21 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.07762  3.90315  2.90945  0.61958  0.77255  0.55549  0.85282
+     18   2.49055  4.81399  3.14505  2.59164  4.19520  3.44406  3.60132  3.55142  1.92611  3.12799  3.98038  3.04037  3.86298  2.75679  1.83484  2.76119  2.76042  3.23493  5.31169  4.06564     22 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.06501  3.85742  3.17445  0.61958  0.77255  0.59400  0.80322
+     19   2.43450  4.81939  2.81703  2.39298  4.15804  3.33308  3.59871  3.56807  2.06609  3.14527  3.97247  2.89702  3.36070  2.29211  2.66793  2.54254  2.87166  3.22778  5.35034  4.03520     23 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03294  3.82535  4.54770  0.61958  0.77255  0.61916  0.77305
+     20   2.61608  4.67386  2.79167  2.51004  4.07010  3.23635  3.73836  3.55025  2.48903  3.13320  4.04098  2.97430  2.02723  2.34075  2.83811  2.68076  2.93097  3.21608  5.34739  4.03735     24 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03294  3.82535  4.54770  0.61958  0.77255  0.51069  0.91649
+     21   1.83080  4.22890  3.60014  3.08598  3.61014  3.38577  4.01761  2.55536  3.00939  2.52819  3.20189  3.39791  3.91288  3.33215  3.33591  2.72706  2.41446  2.12040  5.12303  3.89826     25 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     22   2.43845  4.29437  3.39983  3.04145  3.80350  3.19872  4.06195  2.96220  2.98493  2.76612  3.80233  3.32666  1.71751  3.35496  3.29387  2.63325  2.83846  2.21304  5.28839  4.02321     26 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     23   2.55648  4.28453  3.47615  2.92649  3.45346  3.51308  3.86072  2.37030  2.85167  2.40896  2.93550  3.31525  2.97437  3.17776  3.19434  2.79032  2.33896  2.42929  4.94762  3.71651     27 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     24   2.23005  4.31546  3.25841  2.77512  3.78441  3.22479  3.82985  3.12652  2.73582  2.83244  3.03171  3.14960  3.26067  3.07830  3.10838  1.85715  2.73859  2.81468  5.16957  3.91289     28 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     25   2.72216  3.51794  4.14734  3.58168  3.26953  3.85722  4.23682  2.10046  3.47012  1.71220  2.91412  3.83361  4.22096  3.71804  3.68973  3.16541  2.79579  1.71693  4.93656  3.75086     29 l - - -
+          2.68606  4.42227  2.77522  2.73126  3.46337  2.40515  3.72497  3.29356  2.67743  2.69357  4.24692  2.90349  2.73742  3.18149  2.89784  2.37889  2.77522  2.98521  4.58479  3.61506
+          0.31572  1.55442  2.82310  0.27619  1.42159  0.55549  0.85282
+     26   2.06718  4.47388  3.00085  2.59301  4.03403  3.18938  3.75234  3.40130  2.21691  3.06406  3.90876  3.01767  3.74194  2.94856  2.91976  2.09488  2.60568  3.04014  5.32541  4.04568     31 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03205  3.85226  4.57460  0.61958  0.77255  0.52495  0.89548
+     27   2.09937  4.25808  3.35967  2.86682  3.65405  3.28224  3.85971  2.93650  2.81278  2.15397  3.59474  3.22143  3.43624  3.14697  3.16235  2.43009  2.43628  2.66078  5.07593  3.83686     32 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     28   2.56380  4.32380  3.45039  2.92280  3.52453  3.48960  3.88793  2.33272  2.83649  2.29194  3.45598  3.31192  2.56007  3.18425  3.18050  2.78603  2.52825  2.43071  5.02605  3.78340     33 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     29   2.52137  4.41862  3.18708  2.64701  3.24265  3.41116  3.70401  2.99879  2.50849  2.54033  3.56040  3.09794  3.19241  2.94883  3.00442  2.32271  2.53579  2.73855  5.01724  3.74765     34 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     30   2.00013  4.58033  2.94855  2.53646  4.07584  3.24271  3.72285  3.46598  2.50253  3.10366  3.94143  2.28591  3.76727  2.90505  2.65085  2.58556  2.61842  3.10852  5.34830  4.05040     35 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     31   2.38233  4.27978  3.41241  2.86526  3.23400  3.48475  3.81694  2.67786  2.81404  2.37039  3.42629  2.84230  3.90072  3.13098  3.17039  2.75440  2.50322  2.16090  4.92926  3.68461     36 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     32   2.57741  4.71210  2.95136  2.48036  4.10354  2.51445  3.64563  3.50876  2.11219  3.10615  3.93363  2.96219  3.79067  2.80786  2.54902  2.50592  2.51289  3.16566  5.32824  4.02677     37 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     33   2.48649  4.79372  2.91636  2.20828  4.05411  3.38774  3.59403  3.46081  2.32653  3.05709  3.87988  2.78811  3.79502  2.48988  2.50461  2.63652  2.83744  2.71303  5.28703  3.96685     38 e - - -
+          2.68619  4.42226  2.77520  2.73124  3.46338  2.40514  3.72495  3.29355  2.67742  2.69356  4.24691  2.90348  2.73732  3.18147  2.89802  2.37888  2.77520  2.98519  4.58478  3.61504
+          0.07101  2.83445  4.62550  0.63888  0.75053  0.55549  0.85282
+     34   1.61247  4.12982  3.30077  3.01153  4.23531  2.30721  4.11812  3.64225  3.09602  3.33089  4.15414  3.20546  3.63382  3.37908  3.42786  1.71494  2.65404  3.10635  5.57312  4.35188     41 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     35   2.72153  4.23229  3.98871  3.42694  2.97156  3.37228  4.12428  2.11066  3.32720  1.56866  3.14804  3.72158  4.17041  3.58506  3.57523  3.10753  2.96236  2.01957  4.85619  3.63474     42 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     36   2.59948  4.33296  4.13320  3.58598  1.90470  3.92561  4.14661  2.31847  3.46961  1.74381  2.73954  3.84829  4.26638  3.69996  3.68809  3.23462  3.08833  2.27549  4.71854  3.39100     43 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     37   2.58931  4.58161  2.85848  2.66250  4.27569  1.35942  3.92193  3.72667  2.37699  3.36968  4.25453  3.08080  3.80217  3.15095  3.05968  2.68693  2.97358  3.32002  5.50315  4.25822     44 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     38   2.65443  4.41996  3.43781  2.92526  3.49579  3.52457  3.83449  2.83057  2.64507  1.65492  3.47551  3.30970  3.36731  3.12885  2.65176  2.85231  2.91346  2.65496  4.98654  3.73087     45 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     39   2.72350  4.79628  3.09209  2.60253  4.10688  3.43694  3.64699  3.48037  1.53491  2.80300  3.97997  3.05455  3.87955  2.81812  2.48623  2.53142  2.96661  3.17965  5.30004  4.01932     46 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     40   1.82674  4.13179  3.37396  3.04098  4.15468  2.93287  4.10316  3.48191  3.05943  3.22685  4.07364  3.23234  3.65478  3.36800  3.38156  1.54612  2.23418  3.00585  5.51189  4.29184     47 s - - -
+          2.68618  4.42225  2.77520  2.73124  3.46354  2.40513  3.72495  3.29354  2.67741  2.69355  4.24690  2.90347  2.73740  3.18147  2.89801  2.37887  2.77520  2.98508  4.58477  3.61503
+          0.07101  2.83445  4.62550  0.49418  0.94179  0.55549  0.85282
+     41   1.87334  4.14690  3.25058  2.97809  4.26468  2.12605  4.11046  3.68104  3.08263  3.36184  4.18261  3.18779  3.63442  3.36584  3.42015  1.58161  2.66271  3.13490  5.59481  4.36766     49 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.11955  3.90315  2.38048  0.61958  0.77255  0.55549  0.85282
+     42   2.21070  4.25592  3.22113  2.77420  3.85340  3.11965  3.84389  3.18555  2.74438  2.69874  3.77079  3.12117  3.16635  3.08826  3.10948  2.13243  2.17697  2.83916  5.22265  3.97074     50 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03323  3.81683  4.53917  0.61958  0.77255  0.62561  0.76558
+     43   2.34367  4.62113  3.10732  2.54725  3.88271  3.41056  3.61301  3.25335  2.12788  2.89080  3.32993  3.01581  3.81452  2.79680  2.35592  2.55841  2.82420  2.96607  5.15612  3.88260     51 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.07842  3.81683  2.92953  0.61958  0.77255  0.50642  0.92294
+     44   2.82371  4.84862  3.20218  2.72371  4.21308  3.44211  3.65714  3.71157  2.07944  3.25434  4.14899  2.84303  3.91564  2.83614  1.36807  2.87376  3.07618  3.38687  5.31229  4.06004     52 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.12129  3.86316  2.37274  0.61958  0.77255  0.58934  0.80899
+     45   2.50307  4.57358  2.77436  2.48515  4.13002  2.10145  3.72113  3.58708  2.48196  3.19739  4.04544  2.56817  3.72971  2.91621  2.54565  2.57756  2.84032  3.19983  5.38083  4.07634     53 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03462  3.77648  4.49883  0.61958  0.77255  0.55399  0.85485
+     46   2.68547  4.96255  2.09111  2.21584  4.36925  1.97687  3.70446  3.84410  2.62382  3.41713  4.25934  2.75900  3.76266  2.58919  3.12019  2.66938  2.98839  3.45462  5.60805  4.21173     54 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03205  3.85226  4.57460  0.61958  0.77255  0.52495  0.89548
+     47   2.70472  4.70735  3.22145  2.64799  3.96742  3.15410  3.63371  3.33902  2.12091  2.43520  3.82970  3.09240  3.88741  2.81708  1.91192  2.78290  2.92703  3.06076  5.19463  3.94224     55 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     48   2.39251  4.23853  3.75245  3.18839  3.35715  3.69117  4.01036  2.17738  3.07061  2.00722  3.28706  3.53429  4.07078  3.39072  3.07752  2.97399  2.89120  1.85844  4.92824  3.71532     56 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     49   2.56050  4.39105  3.34411  2.78319  3.60155  3.46480  3.77128  2.83822  2.62742  2.58594  3.21262  3.20237  3.88486  3.03059  2.56448  2.73642  2.19035  2.37832  5.02624  3.77891     57 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     50   1.37812  2.80072  3.83498  3.42070  3.87397  2.99921  4.24161  2.96530  3.32256  2.89459  3.81917  3.44880  3.71764  3.60422  3.56604  2.43360  2.40411  2.61888  5.33835  4.15246     58 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.55549  0.85282
+     51   2.74532  4.50724  3.42983  2.95244  3.42568  3.60626  3.88910  2.77026  2.70375  2.22807  1.95486  3.35569  4.02547  2.58121  2.99178  2.94186  2.99694  2.66631  5.01046  3.74777     59 m - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03044  3.90315  4.62550  0.61958  0.77255  0.44450  1.02483
+     52   0.87297  4.24657  3.57075  3.36786  4.15839  3.06811  4.37727  3.29971  3.38685  3.17640  4.19749  3.49040  3.81731  3.71861  3.62959  2.59634  2.88098  2.93600  5.57511  4.38724     60 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     53   1.96298  4.17134  3.43460  3.07855  4.14627  2.98936  4.12481  3.46945  3.08161  3.21642  4.06614  3.27556  3.70074  3.39215  3.40515  1.84467  1.63498  3.01250  5.50977  4.28998     61 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     54   3.40066  4.84720  3.99369  3.74344  2.30278  3.95279  3.67128  3.39553  3.59798  2.82228  4.05988  3.85394  4.42456  3.87882  3.75994  3.52665  3.68805  3.27113  3.95029  0.80817     62 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     55   2.86663  5.06853  2.87640  2.51952  4.45748  3.43879  3.66568  3.89866  1.33937  3.41664  4.27179  2.44223  3.91577  2.81805  2.46217  2.85914  3.10555  3.54515  5.50478  4.21799     63 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     56   2.89101  4.40561  4.26922  3.93641  3.62800  3.83108  4.72052  2.04974  3.80577  2.29743  3.57810  4.10920  4.38636  4.15841  4.00806  3.34183  3.25039  0.90272  5.42983  4.16757     64 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     57   2.78989  4.87427  3.10728  2.66228  4.33471  3.44160  3.70636  3.64306  1.30828  3.25641  4.14609  3.10047  3.92071  2.86764  2.46119  2.83588  2.59339  3.32217  5.44317  4.19498     65 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     58   3.28295  4.64373  4.65267  4.15432  2.12281  4.39226  4.40565  2.30868  4.01063  0.99404  2.96208  4.34589  4.63887  4.13687  4.14117  3.75853  3.51440  2.42033  4.68321  3.26182     66 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     59   3.08248  4.42168  4.72065  4.23378  3.50231  4.37831  4.95293  1.13074  4.10572  1.99571  3.31982  4.46032  4.70821  4.37869  4.30619  3.77127  3.35421  1.44848  5.47660  4.27063     67 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     60   2.47137  4.31634  3.52340  3.28135  4.06362  3.15188  4.29038  3.20358  3.22639  3.06334  4.10788  3.47324  3.86421  3.61618  3.47946  2.67390  1.00625  2.88730  5.49222  4.28053     68 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     61   2.89484  4.63395  3.51346  3.36817  4.35306  3.31558  4.43642  3.92611  3.43456  3.54133  4.59617  3.66397  0.65427  3.82016  3.66760  3.06578  3.34480  3.55944  5.51022  4.47541     69 P - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     62   2.83547  5.32344  1.90710  1.42799  4.63051  3.24198  3.71244  4.09996  2.65068  3.63347  4.46321  2.71732  3.81726  2.86723  3.20067  2.75440  2.81778  3.69487  5.81218  4.35094     70 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     63   2.79923  4.56350  3.49435  3.40744  4.54632  0.58454  4.52062  4.17205  3.60289  3.81287  4.79002  3.65874  3.95796  3.91884  3.82676  2.97427  3.28861  3.68020  5.61312  4.65200     71 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     64   2.69344  5.03834  2.59685  1.78499  4.35492  3.31996  3.63904  3.79867  2.33359  3.34661  4.15382  2.64678  2.71516  2.78054  2.89199  2.67010  2.77928  3.42501  5.53498  4.15652     72 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     65   2.70271  4.40317  3.56325  3.00957  3.45446  3.68235  3.94694  2.18180  2.88182  2.21283  3.37093  3.41883  4.05792  2.33611  3.21378  2.95204  2.94041  2.01647  5.02429  3.78732     73 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     66   3.04481  5.17464  2.53544  0.88540  4.53437  3.34332  3.94029  4.00914  2.83416  3.60986  4.58016  2.99593  3.95313  3.15433  3.25317  3.01711  3.35013  3.68253  5.68627  4.40959     74 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     67   3.05681  4.44153  4.54138  3.99838  1.97987  4.22221  4.40129  2.17878  3.87522  1.45215  3.02589  4.20160  4.50632  4.03401  4.02978  3.55251  3.29207  1.80812  4.80289  3.46847     75 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     68   2.82984  5.35567  1.99168  1.57663  4.64578  3.25717  3.68509  4.14274  2.58330  3.63869  4.45307  2.71724  3.81329  2.22362  3.11653  2.74299  3.09347  3.72626  5.79564  4.33600     76 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     69   2.50977  1.62448  4.23724  3.80750  3.60189  3.40590  4.45756  2.35254  3.63764  2.45765  3.57920  3.82230  4.04603  3.92585  3.81907  2.84633  2.91668  1.82275  5.24689  4.01880     77 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     70   2.77571  5.11398  2.10801  2.05696  4.45701  3.25620  3.72899  3.91339  2.64389  3.48166  4.32027  2.78446  1.86353  2.89484  3.15510  2.73789  3.05806  3.53410  5.67671  4.27030     78 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     71   2.91274  5.42662  1.24765  1.93231  4.73792  3.20738  3.76458  4.24169  2.78531  3.76893  4.62568  2.68636  3.83308  2.93581  3.37349  2.60161  3.20907  3.82383  5.94007  4.44265     79 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     72   2.93000  5.34144  1.08347  2.15883  4.66482  3.19912  3.82811  4.25255  2.88821  3.80850  4.69751  2.51974  3.85217  3.02158  3.46889  2.84580  3.25390  3.83179  5.90365  4.41772     80 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     73   2.89101  4.40561  4.26922  3.93641  3.62800  3.83108  4.72052  2.04974  3.80577  2.29743  3.57810  4.10920  4.38636  4.15841  4.00806  3.34183  3.25039  0.90272  5.42983  4.16757     81 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     74   3.40066  4.84720  3.99369  3.74344  2.30278  3.95279  3.67128  3.39553  3.59798  2.82228  4.05988  3.85394  4.42456  3.87882  3.75994  3.52665  3.68805  3.27113  3.95029  0.80817     82 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     75   3.08173  4.41570  4.73343  4.24332  3.51344  4.38931  4.96241  1.16063  4.11994  2.00857  3.32756  4.46929  4.71466  4.39012  4.32070  3.78014  3.35186  1.39369  5.48545  4.28088     83 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     76   3.27378  4.70553  4.35708  3.99825  3.17780  4.11433  4.62122  2.38848  3.76496  0.75643  3.16963  4.26355  4.53226  4.10824  3.92358  3.69863  3.56359  2.45281  5.09417  3.84135     84 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     77   3.10426  5.24570  0.77891  2.40498  4.63731  3.29196  4.02650  4.24977  3.13093  3.83985  4.82107  2.96628  3.95224  3.26642  3.66070  3.05541  3.44536  3.87811  5.78539  4.49402     85 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     78   2.10165  4.63153  3.04360  2.53313  3.37849  3.42468  3.14974  3.24484  2.48640  2.87927  3.73924  3.02051  3.83549  2.34761  2.89722  2.67591  2.83487  2.96227  5.11406  3.77860     86 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     79   0.87297  4.24657  3.57075  3.36786  4.15839  3.06811  4.37727  3.29971  3.38685  3.17640  4.19749  3.49040  3.81731  3.71861  3.62959  2.59634  2.88098  2.93600  5.57511  4.38724     87 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     80   3.04481  5.17464  2.53544  0.88540  4.53437  3.34332  3.94029  4.00914  2.83416  3.60986  4.58016  2.99593  3.95313  3.15433  3.25317  3.01711  3.35013  3.68253  5.68627  4.40959     88 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     81   3.04481  5.17464  2.53544  0.88540  4.53437  3.34332  3.94029  4.00914  2.83416  3.60986  4.58016  2.99593  3.95313  3.15433  3.25317  3.01711  3.35013  3.68253  5.68627  4.40959     89 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     82   2.02804  4.79412  2.56696  2.04470  4.09359  3.33689  3.67081  3.44631  2.51465  3.10781  3.94410  2.90500  3.80252  2.83547  2.98166  2.64658  2.87169  2.76307  5.37415  4.03168     90 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     83   2.79923  4.56350  3.49435  3.40744  4.54632  0.58454  4.52062  4.17205  3.60289  3.81287  4.79002  3.65874  3.95796  3.91884  3.82676  2.97427  3.28861  3.68020  5.61312  4.65200     91 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     84   2.73428  4.33692  3.73213  3.19478  3.16177  3.72868  2.92126  1.73180  3.00305  2.10225  3.32627  3.53324  4.10443  3.37488  3.27326  3.02489  2.97120  2.37844  4.75364  3.40581     92 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     85   2.98626  5.46880  1.08491  1.97249  4.77077  3.21550  3.81546  4.28421  2.87189  3.82944  4.72170  2.71026  3.86087  3.00007  3.46540  2.87647  3.29141  3.87860  5.96770  4.48798     93 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     86   3.27378  4.70553  4.35708  3.99825  3.17780  4.11433  4.62122  2.38848  3.76496  0.75643  3.16963  4.26355  4.53226  4.10824  3.92358  3.69863  3.56359  2.45281  5.09417  3.84135     94 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     87   2.89484  4.63395  3.51346  3.36817  4.35306  3.31558  4.43642  3.92611  3.43456  3.54133  4.59617  3.66397  0.65427  3.82016  3.66760  3.06578  3.34480  3.55944  5.51022  4.47541     95 P - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     88   3.48726  4.82741  4.35628  4.01269  1.82549  4.23514  3.48811  3.25093  3.87322  2.62544  3.87831  3.93991  4.57991  3.96204  3.99151  3.61127  3.72377  3.16284  3.67256  0.95290     96 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     89   2.36871  4.29005  3.29968  3.12112  4.18153  3.01810  4.22768  3.71868  3.20194  3.43114  4.34903  3.32859  3.76571  3.54324  3.48419  0.94365  2.85682  3.23083  5.54583  4.26583     97 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     90   2.70964  0.75093  4.25205  4.01610  3.98428  3.30982  4.64026  3.14621  3.84384  3.05665  4.18165  3.97525  4.02496  4.18572  3.94943  2.98138  3.18527  2.88356  5.37752  4.27103     98 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     91   3.12574  4.95602  3.62729  3.11760  4.33719  3.59265  3.90370  3.88680  2.28467  3.38377  4.38192  3.46899  4.09078  3.11945  0.82993  3.20529  3.38498  3.60641  5.37824  4.24257     99 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     92   0.87297  4.24657  3.57075  3.36786  4.15839  3.06811  4.37727  3.29971  3.38685  3.17640  4.19749  3.49040  3.81731  3.71861  3.62959  2.59634  2.88098  2.93600  5.57511  4.38724    100 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     93   2.79923  4.56350  3.49435  3.40744  4.54632  0.58454  4.52062  4.17205  3.60289  3.81287  4.79002  3.65874  3.95796  3.91884  3.82676  2.97427  3.28861  3.68020  5.61312  4.65200    101 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     94   2.36871  4.29005  3.29968  3.12112  4.18153  3.01810  4.22768  3.71868  3.20194  3.43114  4.34903  3.32859  3.76571  3.54324  3.48419  0.94365  2.85682  3.23083  5.54583  4.26583    102 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     95   2.70964  0.75093  4.25205  4.01610  3.98428  3.30982  4.64026  3.14621  3.84384  3.05665  4.18165  3.97525  4.02496  4.18572  3.94943  2.98138  3.18527  2.88356  5.37752  4.27103    103 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     96   2.36871  4.29005  3.29968  3.12112  4.18153  3.01810  4.22768  3.71868  3.20194  3.43114  4.34903  3.32859  3.76571  3.54324  3.48419  0.94365  2.85682  3.23083  5.54583  4.26583    104 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     97   2.36871  4.29005  3.29968  3.12112  4.18153  3.01810  4.22768  3.71868  3.20194  3.43114  4.34903  3.32859  3.76571  3.54324  3.48419  0.94365  2.85682  3.23083  5.54583  4.26583    105 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     98   2.70964  0.75093  4.25205  4.01610  3.98428  3.30982  4.64026  3.14621  3.84384  3.05665  4.18165  3.97525  4.02496  4.18572  3.94943  2.98138  3.18527  2.88356  5.37752  4.27103    106 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+     99   0.87297  4.24657  3.57075  3.36786  4.15839  3.06811  4.37727  3.29971  3.38685  3.17640  4.19749  3.49040  3.81731  3.71861  3.62959  2.59634  2.88098  2.93600  5.57511  4.38724    107 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    100   2.79923  4.56350  3.49435  3.40744  4.54632  0.58454  4.52062  4.17205  3.60289  3.81287  4.79002  3.65874  3.95796  3.91884  3.82676  2.97427  3.28861  3.68020  5.61312  4.65200    108 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    101   3.06946  5.03551  3.25229  2.85531  4.44585  3.54670  3.82012  3.88188  0.90373  3.42461  4.38128  3.27486  4.04036  3.00629  2.45564  3.10509  3.31538  3.58407  5.45821  4.28639    109 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    102   3.06247  4.41039  4.65086  4.13598  3.48324  4.35915  4.85935  1.65561  4.00771  1.89605  3.31161  4.38665  4.67296  4.28428  4.22305  3.72759  3.32396  1.08186  5.42132  4.21018    110 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    103   2.33323  4.28075  3.53672  3.04537  3.62455  3.45748  3.98551  2.58410  2.72399  2.59228  3.55231  3.38781  3.95328  3.30102  3.25844  2.79290  2.46624  1.66085  5.10597  3.87716    111 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    104   2.09904  4.31904  3.13967  2.79512  4.23584  2.43802  3.97520  3.66080  2.88605  3.30435  4.12032  2.79615  3.70254  3.18983  3.27753  1.61859  2.49732  3.17574  5.54095  4.27688    112 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    105   2.79923  4.56350  3.49435  3.40744  4.54632  0.58454  4.52062  4.17205  3.60289  3.81287  4.79002  3.65874  3.95796  3.91884  3.82676  2.97427  3.28861  3.68020  5.61312  4.65200    113 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    106   2.34210  4.57052  2.98887  2.43186  3.63497  3.31233  3.71920  3.32573  2.57569  2.97882  3.82112  2.81207  3.79423  2.91349  3.00476  1.86229  2.69145  3.00524  5.25570  3.95436    114 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    107   3.05964  4.41092  4.64145  4.12759  3.48238  4.35054  4.85240  1.66963  3.99735  1.89738  3.31309  4.37857  4.66775  4.27653  4.21363  3.71953  3.32208  1.07763  5.41853  4.20516    115 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    108   2.91005  5.38045  1.25818  2.12941  4.69830  3.20228  3.78776  4.26304  2.81947  3.79137  4.65619  2.14323  3.83796  2.96707  3.40279  2.81725  3.21882  3.83565  5.91563  4.42054    116 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    109   2.96665  4.95377  2.97494  2.73211  4.13599  3.43683  3.89106  3.78353  2.54586  3.27542  4.30113  3.19246  3.99230  1.05904  2.82765  3.01035  3.26391  3.50694  5.38986  4.09082    117 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    110   2.64618  4.90499  2.31134  2.18942  4.30332  3.26131  3.70172  3.73572  2.57300  3.32434  4.14511  2.84177  3.78986  2.86174  3.06104  1.76618  2.63178  3.35922  5.54260  4.16860    118 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    111   3.10426  5.24570  0.77891  2.40498  4.63731  3.29196  4.02650  4.24977  3.13093  3.83985  4.82107  2.96628  3.95224  3.26642  3.66070  3.05541  3.44536  3.87811  5.78539  4.49402    119 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    112   2.73269  4.96873  2.61141  2.26957  4.35491  2.17303  3.70728  3.80016  2.46897  3.36392  4.20366  2.88233  3.83451  1.94009  2.87446  2.73151  3.00866  3.43365  5.54626  4.19876    120 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    113   2.56630  4.67539  2.76483  2.50324  4.25470  3.20379  3.80042  3.71196  2.47872  3.32135  4.15966  2.47516  3.79205  2.98884  3.00841  1.53662  2.90903  3.30833  5.51362  4.18451    121 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    114   3.45422  4.77029  4.46140  4.11213  1.01250  4.26302  3.55945  3.07075  3.96969  2.40922  3.69615  4.01237  4.59409  4.02617  4.05737  3.63979  3.68916  3.02613  3.73517  1.83750    122 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    115   3.27378  4.70553  4.35708  3.99825  3.17780  4.11433  4.62122  2.38848  3.76496  0.75643  3.16963  4.26355  4.53226  4.10824  3.92358  3.69863  3.56359  2.45281  5.09417  3.84135    123 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    116   2.92493  5.35887  1.12201  2.14550  4.68054  3.19834  3.81470  4.26138  2.86788  3.80711  4.68829  2.43062  3.84716  3.00361  3.45124  2.83676  3.24430  3.83759  5.91360  4.42201    124 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02824  3.97705  4.69940  0.61958  0.77255  0.48576  0.95510
+    117   2.99103  5.43832  1.04731  2.03422  4.75036  3.21916  3.83186  4.26509  2.89245  3.82288  4.72422  2.72815  3.86743  3.02108  3.48036  2.88767  3.30065  3.86474  5.95049  4.48470    125 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.05161  3.97705  3.45590  0.61958  0.77255  0.48576  0.95510
+    118   2.86997  5.43069  1.57180  1.74614  4.72729  2.80306  3.71453  4.23943  2.69618  3.73332  4.56237  2.43722  3.80910  2.87126  3.27991  2.76596  3.14983  3.81040  5.89719  4.40314    126 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    119   2.94701  4.93449  2.95833  2.71460  4.11381  3.42085  3.87354  3.75736  2.52981  3.25157  4.27740  3.17495  3.97565  1.09531  2.81227  2.99143  3.24405  3.48203  5.37148  4.07074    127 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    120   2.77849  4.28259  3.99549  3.02221  3.34513  3.89873  4.21017  1.60238  3.32583  1.96055  3.04166  3.76188  4.24121  3.61775  3.59603  3.18793  3.01465  1.89778  5.01613  3.81900    128 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    121   2.05663  4.99383  2.42035  1.95337  4.30142  3.11016  3.64379  3.74448  2.38547  3.30891  4.11909  2.80952  3.78509  2.79112  2.97996  2.54099  2.92358  3.37653  5.51637  4.13250    129 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    122   2.37074  5.20065  2.03752  1.62561  4.52764  2.94012  3.68254  3.99698  2.59389  3.53203  4.34713  2.73405  3.79399  2.83254  3.13133  2.70217  3.03318  3.59496  5.71621  4.27884    130 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    123   2.76891  4.53595  3.45942  3.36936  4.50963  0.61326  4.48439  4.12940  3.56175  3.77320  4.74981  3.62373  3.92970  3.87945  3.78857  2.94321  3.25651  3.64192  5.58291  4.61439    131 G - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    124   3.45280  4.72560  4.55948  4.18538  1.45983  4.27876  3.45556  3.19175  4.01502  2.56322  3.77632  3.99268  4.58568  4.02082  4.06587  3.62371  3.67122  3.09770  1.76510  1.80304    132 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    125   2.87283  4.39315  4.23821  3.90420  3.61058  3.80809  4.69198  2.04849  3.77322  2.28363  3.56364  4.08078  4.36427  4.12727  3.97777  3.31702  3.23254  0.92773  5.40873  4.14528    133 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    126   3.24760  4.68579  4.32075  3.96132  3.16793  4.08580  4.59138  2.37683  3.72825  0.78064  3.16594  4.22883  4.50730  4.07699  3.89079  3.66669  3.53825  2.43535  5.07658  3.81868    134 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    127   2.45786  4.30296  3.50186  3.25812  4.04222  3.13941  4.26905  3.17937  3.20271  3.03994  4.08552  3.45408  3.84975  3.59352  3.45722  2.66008  1.04037  2.86556  5.47283  4.25897    135 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    128   2.68154  0.78852  4.21932  3.97783  3.95068  3.28696  4.60693  3.10838  3.80528  3.02007  4.14415  3.94300  4.00035  4.14805  3.91507  2.95331  3.15521  2.84739  5.34926  4.23772    136 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    129   2.02617  4.29048  3.42265  2.94627  3.54036  3.40652  3.31257  2.77872  2.86355  2.59741  3.53948  3.30371  3.90044  3.21666  3.18816  2.73904  2.82169  1.86270  5.00831  3.74432    137 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    130   0.90195  4.23400  3.54659  3.34205  4.13472  3.05626  4.35430  3.27256  3.36043  3.15035  4.17350  3.47069  3.80326  3.69417  3.60509  2.58374  2.86679  2.91280  5.55371  4.36315    138 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    131   3.44381  4.80306  4.30117  3.95207  1.85364  4.19548  3.48537  3.22033  3.81418  2.60484  3.85318  3.90681  4.54641  3.92239  3.94488  3.57229  3.68268  3.12961  3.68006  0.97942    139 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    132   2.86235  4.60578  3.47842  3.32948  4.31715  3.28867  4.39999  3.88386  3.39382  3.50174  4.55528  3.62780  0.68858  3.78012  3.62986  3.03247  3.31042  3.51987  5.48103  4.43903    140 P - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    133   2.60256  4.60991  3.08123  2.59418  3.90705  3.39886  3.69738  3.25085  2.27951  2.91739  3.78849  3.05676  3.84470  2.63540  2.79735  2.69573  1.94572  2.76699  5.21418  3.93668    141 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    134   2.16968  3.47307  3.59233  3.22260  4.15866  2.47411  4.19438  3.56363  3.18625  3.27458  4.10858  3.32406  3.66022  3.48496  3.48055  1.23700  2.65371  3.05043  5.52336  4.31592    142 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    135   3.07859  5.21813  0.80740  2.38838  4.60638  3.27362  4.00471  4.21341  3.10456  3.80732  4.78755  2.94873  3.93224  3.24424  3.63163  3.03196  3.41903  3.84400  5.75900  4.46621    143 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    136   2.87283  4.39315  4.23821  3.90420  3.61058  3.80809  4.69198  2.04849  3.77322  2.28363  3.56364  4.08078  4.36427  4.12727  3.97777  3.31702  3.23254  0.92773  5.40873  4.14528    144 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    137   2.50102  4.23694  3.76525  3.33965  3.72246  3.37067  4.24809  2.46042  3.23911  2.55924  3.64161  3.56053  3.97799  3.58142  3.52035  2.77764  1.69802  1.75863  5.30971  4.08018    145 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    138   3.09498  4.49149  4.45102  4.07022  3.43002  4.15408  4.78347  0.98199  3.89992  1.99977  3.35310  4.30411  4.57779  4.24002  4.08717  3.65761  3.39284  1.85079  5.33749  4.08258    146 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    139   3.02382  5.15051  2.52384  0.91441  4.50717  3.32764  3.92196  3.97736  2.81286  3.58149  4.55225  2.98104  3.93620  3.13613  3.22992  2.99812  3.32879  3.65289  5.66334  4.38601    147 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    140   2.45786  4.30296  3.50186  3.25812  4.04222  3.13941  4.26905  3.17937  3.20271  3.03994  4.08552  3.45408  3.84975  3.59352  3.45722  2.66008  1.04037  2.86556  5.47283  4.25897    148 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    141   3.08695  4.88934  3.20791  2.97643  3.34377  3.51816  0.98092  3.80251  2.81733  3.28606  4.33566  3.38232  4.07539  3.34383  3.07797  3.15699  3.39324  3.53609  4.80769  3.29239    149 h - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    142   2.99214  5.06805  3.26268  2.74531  4.47846  3.57206  3.65342  3.86981  1.12103  3.36156  4.25702  3.16311  3.99796  2.80635  2.11223  3.00404  3.19554  3.55761  5.42835  4.23089    150 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    143   3.02382  5.15051  2.52384  0.91441  4.50717  3.32764  3.92196  3.97736  2.81286  3.58149  4.55225  2.98104  3.93620  3.13613  3.22992  2.99812  3.32879  3.65289  5.66334  4.38601    151 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    144   2.49167  5.21869  2.13891  1.38935  4.54510  3.23855  3.71342  3.98470  2.64038  3.55288  4.39217  2.73628  3.81159  2.87379  3.17028  2.74234  3.08340  3.59770  5.74876  4.31122    152 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    145   2.67924  5.36825  1.81597  1.42545  4.67130  3.22067  3.71949  4.14895  2.68617  3.67868  4.51726  2.69278  3.81366  2.87890  3.25116  2.76699  3.13943  3.73938  5.85528  4.37934    153 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    146   3.24708  4.60677  4.69416  4.13988  3.08947  4.47063  4.76500  1.92492  3.96672  0.95356  2.71915  4.43331  4.67883  4.15873  4.13317  3.81764  3.47493  2.15974  5.15578  4.04247    154 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02889  3.95434  4.67668  0.61958  0.77255  0.50828  0.92013
+    147   2.69781  4.29649  3.84369  3.29786  3.44437  3.73086  4.15124  2.24231  3.19336  2.10104  3.11890  3.63278  4.14347  3.51043  3.49251  3.03876  2.03846  1.78833  5.07714  3.86271    155 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.18495  3.95434  1.89921  0.61958  0.77255  0.50828  0.92013
+    148   1.44115  4.10304  3.22225  2.99375  4.15355  2.08176  4.10711  3.47540  3.09081  3.24183  4.11431  3.18864  3.61518  3.39097  3.39593  2.35434  2.65737  2.99565  5.50492  4.29375    156 a - - -
+          2.68608  4.42226  2.77520  2.73124  3.46354  2.40513  3.72495  3.29355  2.67741  2.69355  4.24690  2.90347  2.73740  3.18147  2.89801  2.37887  2.77520  2.98519  4.58477  3.61504
+          0.08120  2.55114        *  0.46726  0.98542  0.00000        *
+//
index 99d010d..3b6652f 100755 (executable)
    <mapID target="alwCalc" url="html/menus/alwcalculate.html"/>
    
    <mapID target="wsMenu" url="html/menus/wsmenu.html"/>
+   <mapID target="alwHmmer" url="html/menus/alwhmmer.html"/>
    <mapID target="popMenu" url="html/menus/popupMenu.html"/>
    <mapID target="popMenuAddref" url="html/menus/popupMenu.html#addrefannot"/>
    <mapID target="annotPanelMenu" url="html/menus/alwannotationpanel.html"/>
index a0c7fe6..4c372e0 100755 (executable)
                                <tocitem text="Colour Menu" target="alwColour" />
                                <tocitem text="Calculate Menu" target="alwCalc" />
                                <tocitem text="Web Service Menu" target="wsMenu" />
+                               <tocitem text="HMMER Menu" target="alwHmmer" />
                                <tocitem text="Annotation Panel Menu" target="annotPanelMenu" />
                                <tocitem text="Popup Menu" target="popMenu" />
                        </tocitem>
index 5fda2df..41dae1d 100755 (executable)
@@ -64,6 +64,9 @@
     <li>The <a href="#editing"><strong>&quot;Editing&quot;</strong>
         Preferences</a> tab contains settings affecting behaviour when editing alignments.
     </li>
+    <li>The <a href="#hmmer"><strong>&quot;HMMER&quot;</strong>
+        Preferences</a> tab allows you to configure locally installed HMMER tools.
+    </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>
     <em>Sort with New Tree</em> - When selected, any trees calculated or
     loaded onto the alignment will automatically sort the alignment.
   </p>
+    <p>
+    <a name="hmmer"><strong>&quot;HMMER&quot; Preferences tab</strong></a>
+  </p>
+  <p>If you have installed HMMER tools (available from <a href="http://hmmerorg">hmmer.org</a>),
+  then you should specify on this screen the location of the installation (the path to the folder 
+  containing binary executable programs). Double-click in the input field to open a file browser.</p>
+  <p>When this path is configured, the <a href="../menus/alwhmmer.html">HMMER menu</a> will be
+  enabled in the Alignment window.</p>
   <p>&nbsp;</p>
   <em>Web Services Preferences</em> - documentation for this tab is
   given in the
diff --git a/help/help/html/menus/alwhmmer.html b/help/help/html/menus/alwhmmer.html
new file mode 100644 (file)
index 0000000..ce23c4b
--- /dev/null
@@ -0,0 +1,87 @@
+<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>
+</head>
+<body>
+<p>
+  <strong>HMMER Menu</strong>
+</p>
+<p>This menu is available if hmmbuild tools have been installed and configured in the 
+<a href="../features/preferences.html#hmmer">HMMER Preferences</a> panel.
+  <br><br>
+  
+  <strong>hmmbuild</strong>
+  <br><br>Run hmmbuild to create a Hidden Markov Model profile of your sequence alignment or sub-groups.
+  <br><br>The consensus sequence for the computed profile is inserted as the first sequence of
+  the alignment (or group) for which hmmbuild is run.
+  <br>Jalview also computes and displays an annotation below the alignment, showing
+  the information content of each column.
+  <br>This is calculated as the sum over residue symbols of
+  <pre>
+    match emission probability * log(match emission probability / background frequency) / log(2)
+  </pre>
+  where the background frequencies are taken from (tbc: where? not https://www.ebi.ac.uk/uniprot/TrEMBLstats)
+  <ul>
+  <li>Edit settings and run...
+  <br><br>Choose whether to run hmmbuild for the whole alignment, or all or selected groups, or both 
+  (default is the alignment).
+  <br>Optionally enter a name to give the HMM profile consensus sequence
+  (default is "Alignment" or group name, with "_HMM" appended).
+  <br>Use Reference Annotation: select this option if your alignment has an RF reference annotation,
+  and you wish to constrain the HMM profile to it (hmmbuild option '--hand').
+  <br><br></li>
+  <li>hmmbuild with default settings
+  <br><br>Runs hmmbuild for the whole alignment.</li>
+  </ul>
+  
+  <strong>hmmalign</strong> and <strong>hmmsearch</strong> require an HMM consensus sequence to be selected first.
+  <br><em>To do this, right-click on the name of an HMM sequence added by hmmbuild, and 'Select HMM'.
+  The alignment will be with respect to the HMM profile for the consensus sequence.</em>
+  <br><br>
+  <strong>hmmalign</strong>
+  <br><br>Run hmmalign to align selected sequences (or the whole alignment) to a selected HMM profile.
+  <ul>
+  <li>Edit settings and run...
+  <br><br>Choose whether to 'trim non-matching termini' - hmmalign option '--trim'.
+  <br><br></li>
+  <li>hmmalign with default settings</li>
+  </ul>
+  <strong>hmmsearch</strong>
+  <br><br>Run hmmsearch to use an HMM profile as input to search a sequence database.
+  <ul>
+  <li>Edit settings and run...
+  <ul>
+  <li>tbc: choose database</li>
+  <li>tbc: automatically align</li>
+  <li>tbc: return accessions</li>
+  <li>tbc: number of results</li>
+  <li>tbc: sequence eValue cutoff</li>
+  <li>tbc: domains eValue cutoff</li>
+  </ul>
+  </li>
+  <br><li>hmmsearch with default settings</li>
+  <br><li>Add database
+  <br>Browse to select a local sequence data file to be searched</li>
+  </ul>
+<br>
+</body>
+</html>
diff --git a/j11lib/apache-mime4j-0.6.jar b/j11lib/apache-mime4j-0.6.jar
deleted file mode 100644 (file)
index 1d2282c..0000000
Binary files a/j11lib/apache-mime4j-0.6.jar and /dev/null differ
diff --git a/j11lib/apache-mime4j-core-0.8.3.jar b/j11lib/apache-mime4j-core-0.8.3.jar
new file mode 100644 (file)
index 0000000..448cf92
Binary files /dev/null and b/j11lib/apache-mime4j-core-0.8.3.jar differ
diff --git a/j11lib/apache-mime4j-dom-0.8.3.jar b/j11lib/apache-mime4j-dom-0.8.3.jar
new file mode 100644 (file)
index 0000000..938c215
Binary files /dev/null and b/j11lib/apache-mime4j-dom-0.8.3.jar differ
diff --git a/j11lib/httpclient-4.0.3.jar b/j11lib/httpclient-4.0.3.jar
deleted file mode 100644 (file)
index fd0d377..0000000
Binary files a/j11lib/httpclient-4.0.3.jar and /dev/null differ
diff --git a/j11lib/httpclient-4.5.6.jar b/j11lib/httpclient-4.5.6.jar
new file mode 100644 (file)
index 0000000..56231de
Binary files /dev/null and b/j11lib/httpclient-4.5.6.jar differ
diff --git a/j11lib/httpcore-4.0.1.jar b/j11lib/httpcore-4.0.1.jar
deleted file mode 100644 (file)
index 4aef35e..0000000
Binary files a/j11lib/httpcore-4.0.1.jar and /dev/null differ
diff --git a/j11lib/httpcore-4.4.10.jar b/j11lib/httpcore-4.4.10.jar
new file mode 100644 (file)
index 0000000..dc510f8
Binary files /dev/null and b/j11lib/httpcore-4.4.10.jar differ
diff --git a/j11lib/httpmime-4.0.3.jar b/j11lib/httpmime-4.0.3.jar
deleted file mode 100644 (file)
index 0dfd331..0000000
Binary files a/j11lib/httpmime-4.0.3.jar and /dev/null differ
diff --git a/j11lib/httpmime-4.5.6.jar b/j11lib/httpmime-4.5.6.jar
new file mode 100644 (file)
index 0000000..df5a7d1
Binary files /dev/null and b/j11lib/httpmime-4.5.6.jar differ
diff --git a/j11lib/java-json.jar b/j11lib/java-json.jar
deleted file mode 100755 (executable)
index 2f211e3..0000000
Binary files a/j11lib/java-json.jar and /dev/null differ
diff --git a/j11lib/json-20180130.jar b/j11lib/json-20180130.jar
new file mode 100644 (file)
index 0000000..bc2cd41
Binary files /dev/null and b/j11lib/json-20180130.jar differ
diff --git a/j11lib/slivka-client.jar b/j11lib/slivka-client.jar
new file mode 100644 (file)
index 0000000..34d2de9
Binary files /dev/null and b/j11lib/slivka-client.jar differ
diff --git a/j8lib/apache-mime4j-core-0.8.3.jar b/j8lib/apache-mime4j-core-0.8.3.jar
new file mode 100644 (file)
index 0000000..448cf92
Binary files /dev/null and b/j8lib/apache-mime4j-core-0.8.3.jar differ
diff --git a/j8lib/apache-mime4j-dom-0.8.3.jar b/j8lib/apache-mime4j-dom-0.8.3.jar
new file mode 100644 (file)
index 0000000..938c215
Binary files /dev/null and b/j8lib/apache-mime4j-dom-0.8.3.jar differ
diff --git a/resources/ProbabilityOfMatch b/resources/ProbabilityOfMatch
new file mode 100644 (file)
index 0000000..9e3869f
--- /dev/null
@@ -0,0 +1,261 @@
+0.2
+A
+200, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.20369859505605942, 0.4222571919176904, 0.02232980369562049, 0.026676627662949624, 0.03525533903309387, 0.04787669271298644, 0.05605478196465866, 0.0641749787418314, 0.10286871806399077, 0.12105923035393054, 0.12422338883170829, 0.10304081214854802, 0.10333588151825282, 0.10114320874739426, 0.11812749552768892, 0.15006056120099137, 0.2237625777282616, 0.30253227447901293, 0.388557592836257, 0.43721427997253054, 0.47970928320880174, 0.5289808943443863, 0.5486523348637581, 0.5583247254358412, 0.5484761487937164, 0.5995060657240099, 0.6195991719342547, 0.6227297938639322, 0.6284738072714547, 0.5548992929945823, 0.5416658828311707, 0.5848669247143425, 0.5528051163252368, 0.6785332996776757, 0.5806004778403442, 0.18593167643573633, 0.38318927736500424
+400, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.00538163724710359, 0.050246851326647975, 0.00325623383324987, 0.016089404836314707, 0.004768961434464644, 0.012975554662909325, 0.014612779422905292, 0.036453046922170884, 0.03669851726847946, 0.06053063401623625, 0.07734802668205788, 0.14448615467437756, 0.24953322777140308, 0.34806276783515594, 0.4229567261622065, 0.4873077681738967, 0.5401722415436365, 0.5521510226102508, 0.6000517399892216, 0.6107765515229574, 0.5870927019689605, 0.6298630970573851, 0.6879023365675971, 0.6221611553796009, 0.632263810408655, 0.689461445849211, 0.6390236708841557, 0.7242036199282817, 0.6557168681820945, 0.21069080034931634
+600, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.009258546378795182, 0.022829316518316413, 0.022698074547786367, 0.012736836086937675, 0.016469563173777596, 0.01913720324613999, 0.03173961484046805, 0.04293589176349238, 0.08585848446208531, 0.16926121837954017, 0.293436232527367, 0.3543603601267507, 0.48651755499862337, 0.5103148855367983, 0.5876985421521675, 0.5784255879120095, 0.5938007169568057, 0.5598080715719793, 0.691548146841681, 0.6943388099375437, 0.6996541955589088, 0.7434201980299975, 0.8365119642131629, 0.9095567810750043, 0.5207569176305396, 0.7405911308670332
+800, -2.4, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4
+, 0.008917934185414377, 0.01017895688795886, 0.037528784049424314, 0.02798827469166613, 0.03137703539242772, 0.11784556048768703, 0.11121306048524869, 0.20430912771074103, 0.2598593792958281, 0.4306348256035734, 0.46316119541365697, 0.5405314728294079, 0.539282096838667, 0.42055185929928385, 0.5448818087581953, 0.5997338164946914, 0.62308312092143, 0.7089840268242462, 0.6436353618329662, 0.826552573493094, 0.7908826508888537, 0.6905508284818629, 0.3823632872193804
+1000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2
+, 0.006152180116633862, 0.015427371964555698, 0.02331992788794896, 0.10944473717642993, 0.19333261931256743, 0.2004513811627833, 0.2384363292885486, 0.5272892625055869, 0.5168199037063749, 0.5652991338441917, 0.4397653398451027, 0.46013409044401904, 0.5175981692561336, 0.6704643484850927, 0.7969708452261104, 0.4745152293484279, 0.9101407067992686, 0.9288992619408138, 0.8325611428419273
+10000000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 2.0
+, 0.0013574547186773595, 0.07926513808931503, 0.07102964878743583, 0.0726328476783432, 0.188665578230727, 0.4670863411106134, 0.6080090637275772, 0.44379833749922704, 0.5310140600224029, 0.5931610388683948, 0.4655146952326047, 0.7948299079449878, 0.45438605875039634, 0.7676093316330358, 0.5325662206236474, 0.5570031538223215
+Q
+200, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.8
+, 0.030660402054098843, 0.029515962408728325, 0.01386298123421587, 0.03323790765774019, 0.050077081129415675, 0.029026658778299946, 0.04803400920855964, 0.046080800910896676, 0.05350762941049219, 0.07623076885791424, 0.07766677224262616, 0.12818678386245805, 0.13808429251771162, 0.15976782729500769, 0.18553311032498795, 0.21473885233239454, 0.26862488576858196, 0.3335898147114968, 0.3933292215057105, 0.4471255648270871, 0.5140106474150711, 0.5606446177282451, 0.56645579177951, 0.6187003826533546, 0.6264565231734968, 0.6902587142708823, 0.7310434998635741, 0.7404822151595194, 0.7455970773478046, 0.8194310136729327, 0.754028761152219, 0.6904665436774613, 0.7865490878301985, 0.8251017523682402, 0.25767625767590513, 0.09683794373033726
+400, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.015174619218570292, 0.037092256738479906, 0.02807957626685945, 0.020952215954002592, 0.012490724790011861, 0.015060526993713729, 0.02337051753316606, 0.03585907871833321, 0.04997995343607782, 0.05116995577905059, 0.08421567659761686, 0.11469062311930732, 0.1729106310315939, 0.19279889620933457, 0.2305248874399254, 0.26979519803194807, 0.35005713230775476, 0.442197230272885, 0.5123688583661171, 0.5530137422740864, 0.5569824269831563, 0.5644003448573167, 0.5847125012080069, 0.6854939519416933, 0.7023668672066997, 0.7154562402783202, 0.7676568753108612, 0.8390636087066714, 0.8073438244745248, 0.7137044911123218, 0.7005129526561815, 0.660501122004602, 0.977346670748799
+600, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.06409443044310832, 0.17043537478138396, 0.06708416589502411, 0.04885363429869391, 0.03348033250104629, 0.05051027800044158, 0.027081552065751212, 0.05641650262162609, 0.08745592321636787, 0.13269225526345627, 0.17856051100094275, 0.2604735522213605, 0.2257012643447686, 0.33727227847072533, 0.43694229465002715, 0.47575874028429543, 0.5515806648065332, 0.5766003713260374, 0.5333600150424079, 0.6251127815619932, 0.6323814616237637, 0.7636923593854934, 0.8150120235799707, 0.8554510812808985, 0.8528317416457601, 0.8932737202285638, 0.8996973853124699, 0.7504095750846632, 0.0782035688876777
+800, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.6, 2.8, 3.0, 3.2
+, 0.008569761190854706, 0.01818566336086026, 0.0035886737075778684, 0.019557202027668318, 0.04730700327264522, 0.11713253719294132, 0.11747711101000212, 0.13566131005576462, 0.22173593877845912, 0.23226589196469324, 0.3285201642634684, 0.40175918428239643, 0.514273714962315, 0.6426839325030723, 0.5592607511903168, 0.4484374500207914, 0.4271084024627013, 0.5761775665904221, 0.7207597567939774, 0.8261386365447307, 0.9533012758522402, 0.9546438827372017, 0.9144745505555422, 0.5300797598551829, 0.3222227681422887
+1000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 3.0
+, 0.03406830709780076, 0.059250254494420895, 0.06295161152712787, 0.14778317919449488, 0.2052302207229962, 0.18103793431053206, 0.27419636115330304, 0.43791113182322405, 0.5014274959179482, 0.6332032204767004, 0.4625651540928214, 0.5822609669670592, 0.46439614255985395, 0.5769223811890896, 0.7117235531057876, 0.7830268783073607, 0.7662000487154872, 0.9574188255261584, 0.9791270764706063, 0.3459984609465178
+10000000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.4
+, 0.011375782562223234, 0.015110412493978646, 0.025236652426745946, 0.08429389717841733, 0.14087146909054712, 0.11134410528964563, 0.7012573537893643, 0.6706932505976297, 0.36458107960413166, 0.4313977123835829, 0.5936455596283988, 0.6425632118499391, 0.5015729047474079, 0.692265646351462, 0.8633350923482849, 0.4146853327478658, 0.4854770135494893
+L
+200, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.022694200314865198, 0.04438120468049618, 0.2034621056438575, 0.09596674258314453, 0.0936871324670998, 0.14776469827002428, 0.13802184826675024, 0.13439766666587188, 0.04220458436568829, 0.16944536376489286, 0.11668704319818315, 0.10097026506035328, 0.13321742110406912, 0.1826244747204611, 0.24029848496689793, 0.27293725510554856, 0.3702265782860514, 0.39675970663839577, 0.3865827048643012, 0.4121574468469467, 0.42297029574231776, 0.42374694961798354, 0.45387310170747625, 0.4990958786276845, 0.5249310443913181, 0.5568838889388209, 0.5814034735034034, 0.5874918865708025, 0.544773016253518, 0.5740018578298114, 0.5921713379469711, 0.631807381420908, 0.7064114207808031, 0.7452793584039196, 0.5607075738856433, 0.6177654347620544, 0.2210712700377047, 0.0341445893559449
+400, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.022810154959402515, 0.022810154959402515, 0.007720793314408286, 0.020949129787512125, 0.008085477457937203, 0.025751402801163902, 0.010533333633145176, 0.019532582257393728, 0.02675455267790389, 0.04368701982880921, 0.0642728570843146, 0.09326829811586024, 0.1600825548451298, 0.2628755953431343, 0.33349628915200696, 0.3715599414484014, 0.39048003188172026, 0.3639567373219425, 0.3686159885628984, 0.3815167578493698, 0.4323222079737531, 0.47570929722908906, 0.5414607289365889, 0.5729269739868003, 0.6300711763621937, 0.6385473260853091, 0.6476475561759117, 0.6476414812252087, 0.6798341599008929, 0.7011957467766897, 0.6072402235385015, 0.6366008002469443, 0.28404340538354134
+600, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.004522531317523935, 0.005379331911902031, 0.041373584208902116, 0.06341550713400419, 0.00541136917154892, 0.024970967450366772, 0.01737419159452633, 0.02698710179147721, 0.10931342415377847, 0.16986739364325762, 0.3018235387326877, 0.3955846475210277, 0.36463488371059793, 0.35591519236678093, 0.33945447736638934, 0.3474316317416148, 0.40674510340538544, 0.45543036568909234, 0.5303127712434488, 0.5480395796161592, 0.6182397608837148, 0.6337199392749969, 0.6954318960326403, 0.7741570775389336, 0.7714912509580867, 0.8938303831713577, 0.8447712444019307, 0.6180977910562903, 0.09687554836070501
+800, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0
+, 0.00376740149279639, 0.008994324259810987, 0.011217681458643158, 0.01782829505291646, 0.06663319133607505, 0.10356871471685111, 0.22278722861655195, 0.42553503993613984, 0.36496033595587996, 0.3610925735058211, 0.3820858282736695, 0.4198207783566425, 0.4120354668294257, 0.41931435853443944, 0.3957678881854993, 0.530671191878201, 0.5316696899190078, 0.5311791062303839, 0.5776547205659004, 0.6069486624133318, 0.6843818658889624, 0.6689819508356897, 0.851214696227136
+1000, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8
+, 0.032368973346990515, 0.13969512844032048, 0.2276500581125476, 0.4431061395070267, 0.44559967376517107, 0.4080484956725524, 0.345312870981004, 0.5593329427588312, 0.3453546578106801, 0.39706278392354083, 0.4575762231727116, 0.5177464816296974, 0.47914956650885854, 0.5118580467178341, 0.6401841274969214, 0.6712200329105288, 0.6463117979877456, 0.42810448131912826
+10000000, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6
+, 0.01782272397306565, 0.09395030002738014, 0.28736733981389734, 0.4610503140581492, 0.4504825574929253, 0.5433177175779089, 0.39843618244538137, 0.35264792682742047, 0.2477238149909607, 0.36972491007649827, 0.4492191259986524, 0.4335075346288497, 0.5333388835840573, 0.5258079002931256, 0.4621631821269529, 0.6088093248295579, 0.7590881193363881, 0.7903597389905895
+S
+200, -4.2, -4.0, -3.8, -3.6, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.12438418712700766, 0.017446874253851875, 0.18519360573679758, 0.22124855285421674, 0.059752889119277716, 0.042504821227910966, 0.0663164525876336, 0.029121816870577095, 0.05492112929293922, 0.06720779941392006, 0.08127909407093194, 0.0560348871102672, 0.09659058156200162, 0.10353812840581252, 0.1210800822205396, 0.1562651703452635, 0.20319933061104634, 0.26245317523800094, 0.3369190441521257, 0.4095080052105503, 0.48191521218608413, 0.5284157963491289, 0.5606549634969592, 0.5950347464160363, 0.6187357500970652, 0.6470608094279561, 0.6356898770675693, 0.6714774329043008, 0.6121942241790169, 0.6095743971384333, 0.6564633462830982, 0.8280795031669954, 0.726251886423071, 0.7056292388804567, 0.6339622337745136
+400, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.03629666034518226, 0.010251346587675996, 0.00588376225845094, 0.017103038428544992, 0.014167000294475663, 0.027002831996804307, 0.022073022212184695, 0.03815019381933721, 0.056348100149132954, 0.08949481882232799, 0.11963538365342391, 0.17229156999292647, 0.23102140894642761, 0.30799404180594553, 0.39670138039825537, 0.4994930747566133, 0.5572615383451857, 0.5696161186424068, 0.6158152862031046, 0.6439833627431268, 0.6519249573567936, 0.6333835930691046, 0.6961475696922559, 0.6193005635430306, 0.6552521049455082, 0.7202828580642087, 0.7532262221700042, 0.8334731780932044, 0.2368772002791371
+600, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.013059399423161333, 0.24102871126123523, 0.01585339152122089, 0.028060159218492607, 0.026905462227703764, 0.04927252800462799, 0.03723841497717851, 0.02803294010626132, 0.03829902396434643, 0.06344601230608479, 0.057968769867864034, 0.10541929960012424, 0.19562626406778896, 0.27703475443325176, 0.41179023162123574, 0.5335069983729668, 0.5546150860338063, 0.5747348009876617, 0.5514881911764865, 0.6364965911968703, 0.6801059018570212, 0.6534703205286367, 0.5564196913416785, 0.7302176125008304, 0.8131069350450936, 0.8027519219958231, 0.6085485091562549, 0.8202839094617357, 0.405278218549064
+800, -2.4, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.04216693629487124, 0.0043830307084839195, 0.014462196442335668, 0.01919041673092326, 0.01977825622316669, 0.023712744831969675, 0.055443290493752295, 0.08851448392127609, 0.11455256546377275, 0.2328694553482898, 0.3367326328850246, 0.459317221407433, 0.5879316224828962, 0.6470056873737324, 0.570650862440862, 0.7095801714949331, 0.706462120036267, 0.7170494260774206, 0.6295006361454005, 0.7778910581389612, 0.7148705132619393, 0.7592112207571959, 0.7482104188792188, 0.9522502952396771
+1000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0
+, 0.026214357205221576, 0.04427631406271417, 0.1264935961447764, 0.14077609356326534, 0.2960780435431137, 0.38160536439121107, 0.474947107253397, 0.5727918213213382, 0.6855543310528419, 0.6138913582635468, 0.5778692630210621, 0.6580943515434279, 0.6050444129262045, 0.6168509337333394, 0.8288146290440119, 0.6657847422198185
+10000000, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.2
+, 0.027142096860031932, 0.013757755597518209, 0.0227211975407645, 0.05284974093264248, 0.048659901118917506, 0.16142942336804442, 0.12657774238502886, 0.26692784650029305, 0.3779063407756724, 0.643762567432302, 0.49130042503233945, 0.7242627649143978, 0.6783062480117502, 0.6304716291654356, 0.7038812933324693, 0.9237125448626993, 0.620579612380977, 0.6038819322983577, 0.4726479391294941
+R
+200, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.03207726503553209, 0.005274482832016623, 0.02353481066931443, 0.01858536618468486, 0.029482970704681824, 0.029822145312603715, 0.03156800848371642, 0.030513654789762576, 0.04606365662704011, 0.04081943283545797, 0.05812095484759577, 0.07558217960358522, 0.08275712090661415, 0.09765221787115734, 0.13423340776679776, 0.1489303205649009, 0.2101302968591223, 0.241768086761866, 0.28003078459011693, 0.3620682642630574, 0.41228413694312804, 0.4842228134280171, 0.5208837054055414, 0.5601867659345883, 0.5971129002888642, 0.5931505256179169, 0.6398668937991495, 0.6522501064755667, 0.6681713881294856, 0.6631087700660413, 0.6581604871860909, 0.6224264678321053, 0.6767846770830652, 0.6536296591076727, 0.47393142233152774, 0.6996554390188527, 0.5687643264275022, 0.6981446635867379, 0.4736078327732734
+400, -3.4, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.06120237498398166, 0.041651302875030785, 0.005403336877600516, 0.005329713060580334, 0.014009522483041804, 0.030143197221196488, 0.030445491091082598, 0.029049177244755166, 0.04466300930040355, 0.02959186639672202, 0.07858217329768569, 0.10613250573098461, 0.13756433589801076, 0.1753766185741036, 0.24220992595864874, 0.3379268214752498, 0.43933847181192914, 0.4687608305155847, 0.5219843880663324, 0.5378031723967835, 0.5885073150547451, 0.5790215715229141, 0.6033105062790582, 0.6369385345570912, 0.6367438494487759, 0.6442980558476543, 0.7448119005362304, 0.6787320027676245, 0.7192587968629324, 0.6923730973665412, 0.5134331453351957, 0.5810559726136121, 0.5684926350975337, 0.6125402492396689, 0.9289869625201223
+600, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.1378365503565375, 0.050594717687005665, 0.12781834109421955, 0.08752773884720516, 0.049670070100221224, 0.07664827304436632, 0.046105225891738925, 0.02153118141988729, 0.03233228014945535, 0.0604699995627281, 0.053891025109674896, 0.06548772677419284, 0.15524097503420448, 0.20322318539844983, 0.2685506473941544, 0.3672922083066144, 0.4728367869025848, 0.5215150279053673, 0.5827726312548501, 0.5019429810469788, 0.6236707269413359, 0.6381821952554616, 0.5617610775185542, 0.6050454853873801, 0.6781155911224431, 0.6977041177757346, 0.7921057139590649, 0.6326622936336238, 0.8560845234345356, 0.8638521228076326, 0.9234678570523027, 0.5228541729414256, 0.7057173072099404
+800, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.012317541353916594, 0.006880746923185741, 0.0018860052516560708, 0.09200540112678679, 0.03267249789183022, 0.07654308724863221, 0.13111551917418324, 0.11110315232892057, 0.2858352233385768, 0.3183838804941956, 0.3214764152349552, 0.5381027132381613, 0.5154858992781721, 0.5938759396466544, 0.5317669156056538, 0.474571014220306, 0.6656176259936978, 0.4470667687414132, 0.5694015228099887, 0.5721682279897327, 0.8456605579912806, 0.6845196622874592, 0.701356537506164, 0.9379461680382511, 0.47849324750243555
+1000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.03673099779274436, 0.05975508700856275, 0.11729622266401589, 0.07431155893971492, 0.20129024254078534, 0.4122602456482906, 0.6700041328568925, 0.4307533654784136, 0.43106406500951033, 0.4362086337224014, 0.4358870724581107, 0.5947155769405055, 0.5170772477786677, 0.6550101981782633, 0.42172408225949354, 0.6801152737752161, 0.5717836886325366, 0.8028045185803616, 0.5636513233075834, 0.32157261133978665, 0.7451205510907003, 0.25624149496885484, 0.030797703222132593
+10000000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8
+, 0.0062919463087248335, 0.024701523260601082, 0.2840737382895135, 0.0578473552912253, 0.07021063189568708, 0.436086646036658, 0.5269060018126795, 0.3787509834038887, 0.4402173913043479, 0.578105949559571, 0.6284310137501962, 0.7335907335907337, 0.45416143979928836, 0.7206038447930181, 0.9030250931270212, 0.6380443086325439, 0.7962851491959756, 0.7771192021827078, 0.4714806276492899, 0.3111369584181448, 0.5469497035762096
+E
+200, -4.4, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.8
+, 0.009621440371994583, 0.004146270499067931, 0.027007253515549435, 0.03136727179124811, 0.038744876752604566, 0.016229285222223038, 0.03822370326896233, 0.03570001601652651, 0.04401784840638429, 0.05086975856820555, 0.07644960546391222, 0.06614806173185703, 0.061318793235008814, 0.10185835962162645, 0.1450144368887007, 0.1425492047876539, 0.20799587783194384, 0.19641586610839798, 0.2043744860695266, 0.2275087023393559, 0.2756277828898441, 0.3308814934337169, 0.4129586159308165, 0.48035942769144885, 0.5342480296805483, 0.5657700139485319, 0.6110696594264812, 0.6158626562381674, 0.6120291915122046, 0.6455192674095419, 0.6780413894925083, 0.6495724311929135, 0.6361403433588055, 0.7950927440077705, 0.5949832111286862, 0.37058920504165416, 0.3524209038075929, 0.5271389454687425, 0.7803589040683762, 0.47464831353328946
+400, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.017589676152591112, 0.06683204264988173, 0.01657213629129284, 0.00332003136981703, 0.00930518388267171, 0.005974036257469811, 0.017903762602890994, 0.03761496143931975, 0.03408447798140072, 0.07714241431466798, 0.10029575266470864, 0.09561574949799023, 0.14597655312457017, 0.15454703000082912, 0.17666151890870305, 0.18425024121949826, 0.20492924164637813, 0.27328431284733345, 0.35372364617784047, 0.45535119003288305, 0.5450906270210514, 0.5819563761275088, 0.6164230496799653, 0.6272027332867812, 0.6065517245120872, 0.5779706100641258, 0.6540444997527108, 0.5860082895169939, 0.6757729762046188, 0.5782390265906364, 0.6483029111399775, 0.7238765375054353, 0.8145822355514108, 0.38720430152211993, 0.29944373638984595, 0.26181929584821206
+600, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.053283575664541366, 0.03616471216877128, 0.06326608218206026, 0.011131203387245636, 0.028527095216323052, 0.014063364780183754, 0.045519433969399455, 0.10546598100346138, 0.14949350502179756, 0.15101877591261562, 0.09738810031195794, 0.13481415571820254, 0.14257886566448752, 0.2860309312905558, 0.3680760044864281, 0.4681448135606153, 0.5807334464914079, 0.5840788193716014, 0.5684825986445871, 0.5423637974395175, 0.6322784178809525, 0.5910884453929658, 0.4403967228080618, 0.7715571363898848, 0.6055828711644718, 0.7943209953485183, 0.44098092121701576, 0.8394721618942949, 0.771295161426513, 0.28710576355040146, 0.07682020988610647, 0.011131203387245636
+800, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.03430651347512906, 0.01170316774637141, 0.02172101047389925, 0.006417685703626693, 0.008803131942231902, 0.02558597050998453, 0.07306274568825875, 0.11280115830989065, 0.09350632912488134, 0.19757784784170848, 0.13668996284243146, 0.10109885106932971, 0.21372922331058639, 0.33935195047966055, 0.4835653244772779, 0.5933154629689057, 0.5389606803781795, 0.5486205951197954, 0.6256878350116513, 0.4954150416424488, 0.6982028550061831, 0.7725732080733803, 0.7556245509596634, 0.820419992617725, 0.3871956296488177, 0.21161330536631878
+1000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4
+, 0.007075408536552707, 0.052106342694856415, 0.054267687080583535, 0.11138738604476046, 0.18238487903712933, 0.13756590467213264, 0.20171268632711103, 0.3204675946135979, 0.4939881373188593, 0.48725191860865325, 0.4577231292051552, 0.5029274757637503, 0.5911749097279292, 0.617890908127232, 0.6754028092464903, 0.7538926271666511, 0.7790160448683208, 0.9317881518423954, 0.2815681472036956
+10000000, -1.2, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.05348182058279778, 0.033963789927669706, 0.16707500121047786, 0.16511036477645546, 0.17236127301119492, 0.10153344754105208, 0.5210622228521675, 0.5405779170203302, 0.6467331482363765, 0.5613844499745355, 0.4960746174216681, 0.6196549070937729, 0.5823067577399326, 0.6626260661097897, 0.3857996700919029, 0.2655828409440213, 0.7804169453620828, 0.6799529670918482, 0.14494194369333543
+K
+200, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.8, 4.0
+, 0.006233425622353032, 0.030408921119546396, 0.02093592220185473, 0.03558424628095059, 0.010346048488097845, 0.005378266919520889, 0.03131994736626652, 0.028487448042530204, 0.03379094987238925, 0.024700449398553797, 0.03347424071928632, 0.07302434835089781, 0.073512659195887, 0.09610703764665972, 0.10795809398583348, 0.12494848067773846, 0.15366097022715058, 0.19623704670279507, 0.20948968747096094, 0.24338255490000843, 0.2906241049173688, 0.33876574586758207, 0.4184822248111851, 0.47928225866895335, 0.5290089476862202, 0.5603050017954271, 0.5786006171900762, 0.5901574708056799, 0.6223281637221282, 0.628128623412185, 0.5921857112354082, 0.6140101201683108, 0.5920359569841578, 0.5965921083365542, 0.6087237791828294, 0.4924534069623098, 0.38684136208760095, 0.8267798205668004, 0.052443291913803605, 0.13555614153669435, 0.4949704158969042
+400, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.6
+, 0.020798610371752655, 0.005632200186423676, 0.020798610371752648, 0.017012541269074165, 0.006032073496491691, 0.01364226026152598, 0.021143675648025915, 0.01868251927506294, 0.025685901851698386, 0.05158053569829252, 0.06125362327569112, 0.10431760125648461, 0.11657963235000496, 0.16124223048718866, 0.16595610614723216, 0.20943134871276328, 0.2710357434275307, 0.3346119224884066, 0.4332968718252851, 0.5110259226245114, 0.5749134438517876, 0.6081320558919092, 0.5874087675618509, 0.6035394962722405, 0.6231341763893807, 0.5835358073444723, 0.5961581174202724, 0.5709563638636703, 0.5779902811937659, 0.6074718329071743, 0.659698021432162, 0.5065478271339936, 0.8797381245584289, 0.7417154908480318, 0.44066114867280576, 0.3040791284756775, 0.15208479719465084, 0.0783083282618651
+600, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.08005202718154787, 0.04962009188671522, 0.039406216500345155, 0.002740406190104946, 0.011403405751254717, 0.0028098082516713977, 0.0071633756207432455, 0.03306075603501498, 0.0646831514898025, 0.11569513004064116, 0.13990454263335425, 0.17679877588621143, 0.16262258352799974, 0.1706813596201359, 0.2931339965678484, 0.43799455936872084, 0.5507332991803784, 0.6083433873274956, 0.6506958124282605, 0.5950317952941324, 0.5577837159753122, 0.6396812143891745, 0.6025343792533054, 0.41729136641693454, 0.5159270205746278, 0.550689666206242, 0.6076331037708719, 0.5624524359539496, 0.6696235241307377, 0.8959934752809087, 0.07262822815281679, 0.13051495642939867
+800, -2.2, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.018911760605919804, 0.004795965261657025, 0.045975193728396195, 0.008989657476380065, 0.017318826511208574, 0.025057718947206414, 0.12261710593295176, 0.11213161725895983, 0.19187686131466689, 0.14188715644056538, 0.14546530966094284, 0.31206534648850154, 0.47086768089542014, 0.545789218740381, 0.5885204739595565, 0.5773710383535828, 0.46045973024930353, 0.5908802815580871, 0.626959762836653, 0.6316980119840698, 0.664414162678641, 0.79310547563987, 0.33278822567457084, 0.7061514195583597, 0.15356389927792902, 0.054667562122229715
+1000, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.02052890441228883, 0.04023189215617797, 0.07663031858028652, 0.20025096556556882, 0.18400997644450603, 0.18611930275336508, 0.21527083749750153, 0.3970930399563381, 0.4481132941803083, 0.5686396636354857, 0.5301579703207275, 0.621978803891937, 0.7140332311751852, 0.6286470990555741, 0.6377560435504707, 0.7720935141696131, 0.8320930630399452, 0.3946962688868332
+10000000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.6
+, 0.01260629568849769, 0.01879100107483044, 0.09267256151895265, 0.04568967070994719, 0.09962589275592335, 0.11544315827770806, 0.28789943693289816, 0.2591618348295238, 0.3929734264526971, 0.39127635602768385, 0.5935754756602113, 0.6145883983450332, 0.3876823250131941, 0.6618930447590909, 0.6606724003127443, 0.5138853185066581, 0.5624084011945034
+T
+200, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.008187665742003893, 0.028861201409083426, 0.00980913610487576, 0.1083985994398448, 0.0598706444724795, 0.05947128234147885, 0.16040484993339152, 0.09915598512252316, 0.10446723349172699, 0.1200298989675841, 0.15094705758522858, 0.1328601676913035, 0.07572629791473424, 0.12872358724292082, 0.14537735848143038, 0.18757394078969675, 0.20983017792030184, 0.2754583875906324, 0.3381900390309666, 0.40271265447333354, 0.4729359584475696, 0.5373178412824395, 0.5595641713342255, 0.6104980864110142, 0.6378975434547939, 0.6441654366086963, 0.6732334439933628, 0.666053356346672, 0.6774517895349775, 0.6637156928572294, 0.606772055426944, 0.6491227745638032, 0.6968486954506264, 0.6098259501108972, 0.6265547114255277
+400, -3.0, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.0027025687608381557, 0.004064194112156794, 0.0016032875228119338, 0.009757997483425634, 0.007868980509490626, 0.007607238389344213, 0.02595046601655586, 0.01905911002852271, 0.031882814581105576, 0.04062653475175, 0.08168889317790175, 0.1302149726190696, 0.17840065319707346, 0.2606656745972047, 0.39450792466149653, 0.4911094546024143, 0.5585520055189517, 0.5923224948870527, 0.6302384579809271, 0.6457682162071837, 0.6946071862394861, 0.7185853742529493, 0.7454414752360349, 0.618499419222971, 0.7074628958097988, 0.7352779958711105, 0.6955516339755666, 0.726348989935302, 0.31671773573998374, 0.40958798265579704
+600, -2.8, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.052328852070039164, 0.026867396031232334, 0.16837658222176605, 0.024245798575350842, 0.0262292817988048, 0.12130083036303745, 0.0613620195234056, 0.060587459883910885, 0.05055444507030803, 0.07451277195194778, 0.07160801588372659, 0.09814403889181059, 0.23180293729028179, 0.37716308908081375, 0.5000132531217487, 0.5844300853732715, 0.588706451584414, 0.6364889102697228, 0.6447154143653666, 0.6571490187910064, 0.7745048328842353, 0.6898685260527815, 0.5933031009014547, 0.8136253894039864, 0.737081747390056, 0.612229773163282, 0.8993016606028706, 0.17838061372014036
+800, -2.6, -2.2, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.8
+, 0.021818989702759535, 0.021818989702759535, 0.026069027674035287, 0.01465256116221214, 0.029619466548546323, 0.011029824666793777, 0.019680030570921273, 0.03947987072242306, 0.0986257950403479, 0.18456806333044862, 0.3139427691570446, 0.4815565268749844, 0.6261430195281782, 0.5140415380874448, 0.5665602405952214, 0.5992870215665328, 0.6250365102046636, 0.8048492147720124, 0.6377275954637704, 0.5701006015265965, 0.8557024286413152, 0.9530038501783763, 0.8085467849780019, 0.27882798691668526
+1000, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.4
+, 0.009332428725528, 0.04925965308388099, 0.07181890841950693, 0.1406860776336484, 0.259162393696497, 0.601915813203475, 0.5614990245451659, 0.5400938444987884, 0.6009355243934302, 0.5240251717766059, 0.5904347159672351, 0.7086467981563515, 0.6532544497183701, 0.7830103565979136, 0.8442480557193919, 0.6152519207547671
+10000000, -1.4, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.2
+, 0.017400075652502834, 0.013968671710909226, 0.016258931051023752, 0.02276972220938904, 0.07144236497729933, 0.25014108242074024, 0.6377278912714578, 0.6213497886400078, 0.8644058949419727, 0.43810672452330535, 0.5254430132270977, 0.8481163148765324, 0.3798431831480397, 0.7667171569008974, 0.8092008618156888, 0.5447444189442937
+N
+200, -4.2, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.0712065157005121, 0.13294638271304174, 0.024918407202641813, 0.3991956150411048, 0.0953625460996715, 0.022620790870142397, 0.07653812401707984, 0.04013908322757407, 0.06637157555040195, 0.08790716077730971, 0.06987895197872204, 0.11594595731928202, 0.09469654486442684, 0.1055032820197743, 0.11677327019941976, 0.1383930868361456, 0.17556655708200233, 0.21274981636519386, 0.24681031402251496, 0.275707492383167, 0.343676483955714, 0.41361073312621865, 0.49954020026571794, 0.5289597425675846, 0.5644353295028, 0.594018016380281, 0.6394736076806113, 0.664612890069819, 0.6676529289997108, 0.6609569315008057, 0.7241923463576184, 0.6799056719677031, 0.6618977735500067, 0.7626413640672547, 0.5363488878232969, 0.7741958263705373, 0.6860956762633909, 0.7969009695833165, 0.7827637598777691
+400, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.001128461356220943, 0.007744997057307509, 0.007104165781121, 0.012715233504607883, 0.01992997097665505, 0.010023506476345678, 0.008734440583315614, 0.012766891527232208, 0.037250387032780934, 0.03554618185109885, 0.0641277000435746, 0.10383126855713888, 0.15817420705543073, 0.1590150077356472, 0.19733501123405667, 0.2655449837641665, 0.33774475148059496, 0.42156779664100374, 0.49403682221432815, 0.5567834425997928, 0.5869474638861647, 0.598529564395528, 0.6427745755499635, 0.6511468650484329, 0.656275764390928, 0.7339886223828026, 0.7133697636691161, 0.7833908369222597, 0.7814001135653762, 0.6921926967996985, 0.6930677127575958, 0.8719006330411663, 0.6993407299981116, 0.7520194008570942
+600, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.012861627109688046, 0.05731785655357574, 0.07991944732610307, 0.08479562252863253, 0.08630884538516512, 0.06730490514845179, 0.008611336673529002, 0.024364202282699095, 0.04027411837341045, 0.05638279176751919, 0.07866817897417579, 0.07014008024714515, 0.1488228079108204, 0.21117858715982965, 0.22492604700759586, 0.3527511628371557, 0.4612776292791651, 0.508376750438461, 0.5978425447842742, 0.6169494954975383, 0.5870009692193582, 0.6834443025176401, 0.7503292713151367, 0.6041252831156599, 0.7114403688322494, 0.7942233006410815, 0.8025344848026892, 0.480061963819044, 0.8510863288832535, 0.4311453569540338, 0.4549099721194074, 0.8294748061125389, 0.3232898151906798
+800, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.019989818428644154, 0.023892261719647902, 0.0029054710661450957, 0.004062937593554483, 0.008984136668700427, 0.010308406280718847, 0.08691527710437, 0.10361026893347543, 0.04789619477114294, 0.16745026833775423, 0.21747643195160038, 0.20845806212626344, 0.32694891534008996, 0.47723349576907653, 0.5295067551508112, 0.5770392423901299, 0.5730686049665393, 0.5894890079270304, 0.6047381214895978, 0.6682541217110526, 0.7311441820863821, 0.652518439576027, 0.8361938939030221, 0.4820988922476904, 0.7577299982101305, 0.5925855581398125, 0.12158342006740268, 0.9351822615425827, 0.12598320331575102
+1000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.08803701255783213, 0.09574103749053965, 0.08474819481634101, 0.17517515123980776, 0.26799302520655116, 0.28439407716762816, 0.41648646362717917, 0.5455595697137675, 0.5615697118402637, 0.6793471491223992, 0.6046007911293165, 0.5491817816902066, 0.49692743170413184, 0.7221889848936341, 0.5269348636773619, 0.7588655952688864, 0.47213759827611784, 0.4709761521355724, 0.643696648197198, 0.20472622478386168
+10000000, -1.4, -1.2, -1.0, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 2.0, 2.2, 2.4
+, 0.011076077289999191, 0.021909483447944987, 0.019761832256823684, 0.1397123465907093, 0.42129914368169563, 0.0812885393899792, 0.40490640849438697, 0.445164695597671, 0.5457577680850202, 0.6138506965124918, 0.499762804469091, 0.6076612903225806, 0.6718496818294005, 0.36172655263459996, 0.30939476061427285, 0.7177078765779696, 0.6569729941950139, 0.7172609072522392
+G
+200, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0
+, 0.04980271364834668, 0.08033718293586467, 0.02137202174972912, 0.23924182209704178, 0.04290368826652217, 0.10995998186386532, 0.09077215489621959, 0.020063069662946225, 0.05199866894271401, 0.09869248618709753, 0.05755910536963877, 0.07335095177942563, 0.07836111992160895, 0.10947432785061317, 0.1829574600664543, 0.19644932151930236, 0.2475476355976773, 0.28047029664287276, 0.3663585502825831, 0.41381370184743865, 0.45028476809894513, 0.49271429268477074, 0.5257516371642744, 0.5380569146271968, 0.5816939874640986, 0.569518767778985, 0.5743891432518737, 0.5686338321658405, 0.6140459068175762, 0.5643093026733956, 0.6011486020284298, 0.573474665378709, 0.5168116740045788, 0.5321248352677072, 0.5278162040229152, 0.4301895642957476, 0.4371969736562028, 0.28501611757799006, 0.6434525427174271, 0.28996678413494487, 0.08989837533651014, 0.2567539583435563, 0.04184963224881832
+400, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.013901301934598695, 0.004289024917785121, 0.013437974346902313, 0.007368860439472664, 0.01073447463708951, 0.02777219816300249, 0.017735008916501906, 0.03167632189935238, 0.065395714271814, 0.08023970903915105, 0.11154164414214832, 0.2022512296813042, 0.25545491618906413, 0.3536476783862624, 0.42363655299206915, 0.4684936278546968, 0.4921050743779281, 0.5494874471369424, 0.558926685575915, 0.5687086639940497, 0.6215795839689724, 0.6083484928768131, 0.6314576358198148, 0.6230514702472063, 0.5920065807809958, 0.626983997044515, 0.6050340178513397, 0.5291775304616348, 0.49878218646796507, 0.47333053527490554, 0.5819171331727555, 0.5436606285875814, 0.7368953451348795, 0.21159919104802896, 0.2423277350632243
+600, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.004262592522543604, 0.009609989324161305, 0.040722908138649094, 0.017614076524928034, 0.0093627162404978, 0.015355034655796965, 0.024755600324803256, 0.020194055025720813, 0.026706288439159422, 0.08077741729614026, 0.12928457280333558, 0.2529615159130915, 0.34196845700567596, 0.45149860216958276, 0.40996695404314654, 0.42578108033137246, 0.4803786191950474, 0.5843776520341477, 0.5586147764363851, 0.617306728496986, 0.6227856958198603, 0.6671398928615958, 0.6500952347555135, 0.6889882325738811, 0.6256734694615649, 0.5995168124878059, 0.7490707491628702, 0.5011582262180214, 0.5080490865168124, 0.28843898542192936, 0.6652919608969325, 0.7408142102868135
+800, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.0020230132774187795, 0.023747698329704935, 0.028075380703131567, 0.015626043218693486, 0.04235468455893636, 0.09197490603136489, 0.18883534980280212, 0.27670832943186874, 0.4442895339785569, 0.36389293680452, 0.5494049531835955, 0.4340033509928248, 0.6029975424434239, 0.5363372195839183, 0.574020584323784, 0.5723823552003017, 0.668482030254807, 0.4580004693100662, 0.7116840257389728, 0.5822536180791649, 0.4377759423870536, 0.6468675879501711, 0.7183741297796663, 0.6254979951414307, 0.5158137378302833, 0.7279496888294327, 0.2627362326894526
+1000, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.006489542114188809, 0.006949859307726209, 0.022534370804249342, 0.04516393000377678, 0.1136821257633273, 0.5110285116517171, 0.46770290612880394, 0.3659219700856653, 0.4583001142462624, 0.41336563823768924, 0.397921392614628, 0.39534194552429375, 0.4342297564398891, 0.5579332833345442, 0.6046583720178514, 0.41123271903157327, 0.6403926457323382, 0.6698778696734571, 0.5480418899094861, 0.7586576713030415, 0.7548134802193488, 0.6548685078706759, 0.9440873569829723, 0.7717038041572167, 0.23724929693196156
+10000000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2
+, 0.021380286118534823, 0.027108017567662453, 0.1482481505468543, 0.600664441493963, 0.6398889295975626, 0.37057797159012834, 0.7850458683916712, 0.614502459890595, 0.3122958193267364, 0.8122341869514071, 0.5943585978600379, 0.7604878736966307, 0.5587283184181798, 0.6866167554855552, 0.4973986404656242, 0.780872442534018, 0.7371014288730907, 0.30209092437916923
+M
+200, -3.4, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.02845963128097755, 0.006327814220719094, 0.03532321766363078, 0.02785817915545463, 0.06305230492182508, 0.06525558678224297, 0.06920333364821739, 0.09663310690550701, 0.09168272875852655, 0.10444060917510496, 0.14161496195972897, 0.18760094354688894, 0.27340880409079077, 0.3140034341765975, 0.3341867951289014, 0.3632541277201427, 0.39668565401586187, 0.43522081815108804, 0.47207835629148115, 0.5026342064038121, 0.5554008469913351, 0.5833574566458571, 0.6008099311783961, 0.6450861919646963, 0.6497380418171971, 0.7249028494100742, 0.7645552091301733, 0.7775959306800271, 0.7826666371582449, 0.7687189766034876, 0.7377750773840379, 0.8546113117648433, 0.7309510025155838, 0.5922461289520015
+400, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.038170835425479464, 0.01826291926366975, 0.008627909268057714, 0.005990921954905756, 0.007691489978484118, 0.020392739300842774, 0.04472291093102174, 0.060316255940233786, 0.06302004459220394, 0.1541038418593209, 0.22685507146016778, 0.2784664330885808, 0.29825937959171117, 0.3196733796620143, 0.3640325566040108, 0.40625749304857856, 0.4479345337346429, 0.5468608319197934, 0.5597030539512597, 0.6165686331561653, 0.6632688548164488, 0.6959674881486, 0.7903394987481768, 0.7268668913376479, 0.8235451001308638, 0.8275484601484625, 0.8098358326580584, 0.8637631783068633, 0.7737756627826707, 0.8647890997855323, 0.6977375511994904, 0.5247504661744165
+600, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.005736237861731748, 0.009523975244624639, 0.023891194668858876, 0.025234750802993748, 0.02552717930757656, 0.056254640669280716, 0.20941928914694077, 0.19788347655830058, 0.29589811372140384, 0.29852413139321216, 0.2897028729418557, 0.39073179258287705, 0.4552629356841357, 0.5593966833420538, 0.5750394291646366, 0.585085568055378, 0.7318672657089549, 0.6941092464581831, 0.8819680496498116, 0.8406532752846406, 0.8451650670206011, 0.9416795740780045, 0.893085997768151, 0.9110602722058794, 0.7163256112121613, 0.7174375236482226
+800, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.4, 3.8
+, 0.004674108580720676, 0.0035096825949236417, 0.02573551674322442, 0.08020943690055882, 0.2141222710358276, 0.3552257946322249, 0.323221883037281, 0.334294250957123, 0.2829357833432641, 0.43434992803525485, 0.5808355469054186, 0.6241893673747914, 0.6931880921298325, 0.5795185281057724, 0.5509178962895578, 0.8197337451110486, 0.736948316454277, 0.7846023423062995, 0.6580624097643196, 0.9191076830846109, 0.9023948888700153, 0.9474981632934666, 0.016170424235835836, 0.21365134335027647
+1000, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 3.4, 3.8
+, 0.0395955810122565, 0.20251297074083224, 0.2515696605044113, 0.23118137403932495, 0.31920693493675995, 0.32386507072905335, 0.5120874998766078, 0.5880070517335512, 0.7408938081106, 0.6469459262991496, 0.40303988237456356, 0.8411104193700822, 0.9040742300533903, 0.7482458141989218, 0.7670674781862866, 0.9574210199417486, 0.23437245866088377, 0.1630415456646714
+10000000, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.2
+, 0.005278592375366569, 0.02483900643974241, 0.21079571893904142, 0.25278114329772, 0.24822695035460993, 0.39404962972586727, 0.8361985706007341, 0.5839568257083283, 0.5340659340659342, 0.7478816708785491, 0.435701214440193, 0.7346019028542814, 0.5848733325174398, 0.5098265895953757
+W
+200, -4.0, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0
+, 0.010053137251715156, 0.03614107661201093, 0.07513752318069507, 0.06232763609362001, 0.04090719053394041, 0.03012721074281631, 0.01999689051399049, 0.020024382749013706, 0.035560145033910834, 0.041624797523196214, 0.06142487113870969, 0.07038694508427773, 0.0874141479196364, 0.14373224227628087, 0.1930317693688374, 0.17608850960040795, 0.2837591992712456, 0.31751427975693, 0.37402457119572285, 0.3767044103235768, 0.3875467674943792, 0.5162805569385304, 0.5513809807468663, 0.43645713565312544, 0.5295897770124752, 0.5509452638284295, 0.6355399448481385, 0.6292792289200955, 0.6154280980913217, 0.5862191648292456, 0.692729444731882, 0.6933688155617883, 0.6525897180760073, 0.6862900638687898, 0.6206267900753528, 0.7227963137333674, 0.6563610741001843, 0.6541491631508591, 0.6862278523667734, 0.5173986502301023, 0.6254962352564359, 0.2376686434766528, 0.2850520026378816, 0.32445331851643955, 0.1545443294828597
+400, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.2
+, 0.003936305168090178, 0.002892443565021887, 0.008130955780809584, 0.012686225767031701, 0.025774402091606103, 0.04458131185056105, 0.05957848834895015, 0.09030918669627554, 0.1253577531298458, 0.1762117242340049, 0.18978784602769633, 0.2613781994982344, 0.3479702350864556, 0.38339977058667163, 0.38746151324205624, 0.4143832977912655, 0.4326335523770048, 0.48109640926677794, 0.5253077885613805, 0.5436337693892012, 0.5957468274559441, 0.6066920552022064, 0.5856318907005583, 0.7405960813443107, 0.6556337756952331, 0.7700481180232187, 0.6123487455485063, 0.716084361648064, 0.5946136429487322, 0.7631646331908402, 0.7287205565301803, 0.7089736280501816, 0.7458023147425407, 0.800312812064102, 0.7905807458117725, 0.7524453487016617, 0.6904598548976143, 0.09244951222078437, 0.8853441973001723, 0.22803862653375243
+600, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8
+, 0.015941116115818707, 0.016594307129943656, 0.010924353018042558, 0.014218984649465553, 0.02534885725861216, 0.06771148595573359, 0.06116471271630187, 0.058466868227181355, 0.11369094282044122, 0.10028915633745711, 0.09713241672842075, 0.23121690042026713, 0.21175385468088415, 0.28462241635242436, 0.31685345966888984, 0.34243553290584766, 0.3967943463270171, 0.5322292663560987, 0.46053074781033976, 0.46756551159626847, 0.5093913642584738, 0.46665721497662693, 0.5872387559719567, 0.5295263318218335, 0.6679207002526416, 0.633194898204035, 0.8205977787023934, 0.6778801000144382, 0.6386241437433336, 0.7474959665347901, 0.7280984639756457, 0.792440375474518, 0.8269539563283489, 0.914446352387371, 0.6292990018576369, 0.9002209011938572, 0.8814371535125446, 0.9569213613893796, 0.5613551803722755, 0.15303410010373106
+800, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0
+, 0.0224761653850587, 0.06897795528325656, 0.043964184488533876, 0.05426990516042012, 0.10593446276907946, 0.11088933395600369, 0.11131403251399657, 0.41212081201518397, 0.252185523895901, 0.5131779640168599, 0.4970442274474704, 0.3753445990025042, 0.4454367118169079, 0.43641127627008697, 0.5375555342059549, 0.582743847296434, 0.700875716747453, 0.3693056263810981, 0.5166424534068959, 0.5938453539126746, 0.5650094444620126, 0.7110946731164166, 0.6077794715264038, 0.797757938175236, 0.5455658878175588, 0.673111514092521, 0.7037020400243812, 0.6435682203777798, 0.604048928630185, 0.8674003285619997, 0.2236593996887986, 0.928303029180713
+1000, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.6
+, 0.05041657765434737, 0.02326957207651351, 0.03004073319755601, 0.19675712971481144, 0.3266965127238455, 0.22095951443145867, 0.36550759392486015, 0.7630891680139287, 0.6041852181656279, 0.8423339540657977, 0.6174986823281381, 0.39799453053783046, 0.7304563141139018, 0.6849573328041277, 0.3470302731161567, 0.3593023674822529, 0.4835460460460461, 0.7854439789160697, 0.6272501956691886, 0.6353194544149319, 0.8131345333267939, 0.6726479627242986, 0.9429828499595941, 0.7991883202445581, 0.6992572398895678, 0.5080599505378266, 0.8768982229402262, 0.4046968016124748, 0.8114981199287552, 0.3381969775924961
+10000000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.4, 0.6, 0.8, 1.0, 3.0, 4.0, 4.2
+, 0.0021122338299937207, 0.1448140900195695, 0.07805907172995782, 0.28139773895169584, 0.22224694104560624, 0.16373639516804211, 0.3721264367816092, 0.3226118969192017, 0.33218720152817577, 0.0726298477372805, 0.4892249251223611, 0.8037608756665732
+D
+200, -4.6, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8
+, 0.018626895228895723, 0.11728080320078006, 0.5937426667262748, 0.03927533862645874, 0.05974671976524982, 0.0917149470704997, 0.06046434414289128, 0.04459964351175079, 0.03891584428680007, 0.05454776436988832, 0.05760795314793352, 0.06520214434682021, 0.08441878992655659, 0.10554307834242026, 0.13156414894978147, 0.14638211055267963, 0.17598859363160593, 0.17217531685054885, 0.18463737353117532, 0.20794269423656211, 0.27808363911099476, 0.3642544766197776, 0.42615125908706963, 0.5026779437159384, 0.5381913735877556, 0.5448344936741886, 0.5736658815321012, 0.5728175734848698, 0.5772159313301718, 0.5935206601384001, 0.5785927893804083, 0.5803030006598179, 0.634696992284186, 0.6632184597205736, 0.5725772600179964, 0.5806805560809384, 0.6456153291100302, 0.4008137326056845, 0.5142766154383125, 0.594144624446019, 0.9480860255395239, 0.7891323212963747
+400, -3.8, -3.6, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8
+, 0.017526022053705452, 0.010090662246000215, 0.005911072408159453, 0.0094242912522625, 0.00483203212764107, 0.014840210378253412, 0.035251055138788005, 0.03010333597027076, 0.05707110978001972, 0.06806654215390828, 0.10122954326734433, 0.13770152403508962, 0.1251534611085536, 0.15864699520014003, 0.12863271934388903, 0.17303911256916327, 0.23872337803608437, 0.3438374233682127, 0.4471077553553215, 0.5299235923012301, 0.5563624942893748, 0.5662502058564726, 0.5721638839165779, 0.6129871191897227, 0.5660340347563402, 0.6308606276684164, 0.632643587440431, 0.5798265428394158, 0.5711256183324998, 0.6104867833858457, 0.5477759251339209, 0.5034780015525244, 0.28633253697579686, 0.6019606099741027, 0.41753839461241327, 0.34898716933495605, 0.1753443010109411, 0.4937170887940028
+600, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.07572055697912322, 0.04685137919874146, 0.013470059859080275, 0.016120642626666723, 0.025934741332931405, 0.013470059859080279, 0.01047103161086878, 0.043184882720677706, 0.07524094553614041, 0.057131662342132405, 0.07555065450499734, 0.09094351900345422, 0.07943708440995989, 0.14120981974737906, 0.15889063869132145, 0.18288901171356836, 0.2994462254923587, 0.455922970640683, 0.470865053294829, 0.555923147176361, 0.5744394407250271, 0.5983652427055746, 0.6451298402584105, 0.6144094316369362, 0.5638708071261487, 0.5817023571301216, 0.7382954315694873, 0.6415137553013202, 0.6027798778331301, 0.5498240561188864, 0.3129098587277003, 0.5853527174502478, 0.6417674076529638, 0.34646976044148603, 0.8892401221593547, 0.06589683307979534
+800, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 3.0, 3.2
+, 0.008510660029390252, 0.053999319540527856, 0.029166739590808066, 0.11008787306416677, 0.06867749030405805, 0.10487922755985372, 0.08441754322657907, 0.13927445001053515, 0.1262502840915484, 0.1581350088904876, 0.37032405294594306, 0.47112296199708115, 0.5059968009083806, 0.5667473589508149, 0.5662007078489808, 0.5036665508717231, 0.5685524410133438, 0.5021030771387083, 0.46777863494735494, 0.6249417586714079, 0.6570922695616377, 0.7799387736421073, 0.7624247583463559, 0.364603814519136, 0.8518129178326466, 0.33007532508626103, 0.2808647177027291
+1000, -2.0, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.03099074564389641, 0.03526188187699943, 0.0601183779288754, 0.10708870906841245, 0.14124632869365342, 0.07858307490648676, 0.16099733636085756, 0.11251951702527954, 0.31888428435752014, 0.3845687605484582, 0.47978895233223035, 0.5356864443869647, 0.5760458574570188, 0.5243609252477301, 0.44676271680565494, 0.5517489421762919, 0.40731563845050217, 0.5530463031664227, 0.7056189995435903, 0.6602700897805741, 0.7555583244746631, 0.43490969602040125, 0.9630958463140022
+10000000, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.4, 2.6
+, 0.0014151021012620737, 0.01120977596741344, 0.04853957951178213, 0.06924634213674427, 0.2242589254898953, 0.3488169966199903, 0.4214279585474444, 0.5540891613841836, 0.6191275770879868, 0.5765505268784041, 0.7524044757887831, 0.70228140959197, 0.36758525047113005, 0.6752083232984923, 0.8562413388764525, 0.4384222653499529, 0.2229776446185757, 0.7973201791445547, 0.13059610618454792, 0.0663917127836773
+H
+200, -4.0, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0
+, 0.03366143791073794, 0.12229579473890749, 0.0023965874294210304, 0.11142894439620184, 0.0598821754984208, 0.035073646976856346, 0.030033608637588124, 0.042770531837719, 0.07436799354604083, 0.06192889876940986, 0.07501889297412434, 0.07651922461089912, 0.10236657357048272, 0.13008490869476172, 0.17570521982550932, 0.19562570288549183, 0.2402717212537774, 0.34894741760751985, 0.3926314534309388, 0.463459973122341, 0.4872892573845177, 0.5656076053978417, 0.5702410891638474, 0.5842610000246314, 0.6401215021032886, 0.6635057656919326, 0.6858272882551264, 0.7036437455064729, 0.6900683507603625, 0.7912016521539376, 0.6256905279756557, 0.6551663451279496, 0.6442387019495477, 0.5154430296772594, 0.610714922104654, 0.47655815437182536, 0.5038680884987706, 0.331638615368125, 0.16532032785248002
+400, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0
+, 0.024983509456821706, 0.0023065782730348084, 0.02498350945682171, 0.03938325596225074, 0.01924885711675501, 0.017001918349411307, 0.004532697766235948, 0.01672786076537002, 0.030488464144219574, 0.04246194666294303, 0.05482530743289866, 0.09453774664211397, 0.15068238595070957, 0.22043514025408253, 0.30862698998080434, 0.40606922105192056, 0.4635111004362203, 0.5490011391057846, 0.5896936531471226, 0.6012522032441759, 0.6334213044527051, 0.6530489917577715, 0.6816836432220428, 0.7235863198736988, 0.6104989855312881, 0.744281538492875, 0.6437700766365099, 0.6596101401847652, 0.6237587050584414, 0.4909123749450153, 0.4754536332396059, 0.5319185585373064, 0.5738471453688846, 0.5770204247077545, 0.3974957524720365, 0.12628946646351794
+600, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8
+, 0.003375360767234541, 0.02315851530668037, 0.007713013203962888, 0.020489809218885796, 0.02789797627428184, 0.05670945810086781, 0.08172911385087334, 0.10354699727263074, 0.20946023963686963, 0.3485166802620737, 0.4135052949447255, 0.5048283954868971, 0.5810659272872755, 0.6252028870513755, 0.49276922092287434, 0.6972373542165986, 0.598283244541968, 0.7060471943352125, 0.6335714820846869, 0.8409656287721421, 0.8713022883991768, 0.7548429339870076, 0.7731077709300429, 0.6286562667563377, 0.7416134578437232, 0.7973583875768113, 0.6246797630480752, 0.44839283867200974, 0.618207741949151
+800, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.004332254797836343, 0.008517472428799602, 0.02801288412634691, 0.04042976376212141, 0.05638253860440923, 0.1485878639312434, 0.45494966839303996, 0.5364218471499814, 0.6019752585827106, 0.6468967344018158, 0.7291083814949837, 0.5541234821386483, 0.44092351636485544, 0.5412120458980819, 0.5492062498043022, 0.6146558441172213, 0.46263676380203994, 0.8097888157180061, 0.8253314552869299, 0.9025689021252576, 0.3065145430410163, 0.887952826612005, 0.7349291853455371, 0.6930569512214189, 0.7189787433389939
+1000, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 3.0, 3.2, 3.4
+, 0.016726572227312234, 0.044336969269249515, 0.06230922176482117, 0.2733652504290111, 0.3606353085893688, 0.4154854412512842, 0.4931667421477475, 0.5421469025922283, 0.5483236455497511, 0.569378907839295, 0.43122599932991407, 0.506119714597294, 0.4286583086215133, 0.6048992306603105, 0.45424657023908194, 0.6333345687706163, 0.5822196798974196, 0.8918964292632531, 0.9422988109598484, 0.8579332348997845
+10000000, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 2.0, 2.4, 3.0, 3.4
+, 0.026043125175021, 0.28627129078596353, 0.2006741486957521, 0.3602109329490757, 0.5126121076233183, 0.7521644636049453, 0.7345747319418476, 0.4402735868034601, 0.7231112172597723, 0.4617557163307154, 0.4887361728712654, 0.6417756720568545, 0.36683051156016755, 0.3773720014321518, 0.6682563906905762
+F
+200, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.8
+, 0.0118796572796037, 0.0014672582394740575, 0.03743998420606895, 0.027945978849726678, 0.042221213889387516, 0.010801552826949386, 0.04139522496607944, 0.03999191502135917, 0.05211549995458061, 0.060297109638310954, 0.10129384648254204, 0.15616351789120644, 0.21318276089539578, 0.25042509461225854, 0.29299384438800996, 0.30431199722184266, 0.31474465593677153, 0.3215608071222106, 0.34933410952686794, 0.4013372334166951, 0.4132461627252968, 0.4735993600214136, 0.5137798275706204, 0.5240892505076316, 0.5732127691892553, 0.5728471386016757, 0.587424087598907, 0.6378341853871199, 0.6652131586082336, 0.6434091755890186, 0.6811145001725185, 0.6778946461924046, 0.6531231489646425, 0.622114029030299, 0.7027944481835392, 0.6544984744633467, 0.6768972298187619, 0.7649999212127353, 0.17747727606580532, 0.03200371938741867
+400, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.004521502078034196, 0.011294546197758165, 0.01902181455153136, 0.028453600912992427, 0.045494587204780265, 0.075636622645322, 0.1346817828927533, 0.1858370410511906, 0.21145461364683354, 0.22993300300255923, 0.24758097664369763, 0.2503946720700768, 0.2893435384653396, 0.33294847977837494, 0.3801325469321394, 0.4218741104610451, 0.4797481604447298, 0.511808478587414, 0.5974117622187544, 0.5834704269428962, 0.6578279478883984, 0.6933440994726486, 0.7200687227206225, 0.6742670559283108, 0.7199198750632219, 0.7264408323450363, 0.7378516949019436, 0.8038271425512616, 0.8296853580700081, 0.8243729580366167, 0.779678703055898, 0.7171620329790568
+600, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.04225844325367724, 0.02996073852825442, 0.0033279267524589365, 0.010538147174194904, 0.0055842967220071866, 0.023707193295361365, 0.03287914981492101, 0.055581517092584964, 0.12205147623150721, 0.18674255469804368, 0.21228362626337297, 0.19176664697425205, 0.192771021747899, 0.2738504396168108, 0.2706484536269102, 0.3113119235107976, 0.3768631860175106, 0.4286865380951811, 0.4674373782473765, 0.4470173830795746, 0.5654578562715549, 0.6089083108990303, 0.6950018580809499, 0.754745539388691, 0.6729932052759504, 0.6466101067600745, 0.7630081242628347, 0.7653017355343918, 0.7660715915354379, 0.9006582480689912, 0.8613792472553212, 0.9183691145965688
+800, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.0025284892240452768, 0.0013041538615920674, 0.02322344999575436, 0.06274762646486995, 0.14440845571763275, 0.3574106974338475, 0.26027269066425, 0.2629704658055164, 0.24533138237707777, 0.26347140721903634, 0.3022788001575987, 0.29989143373704513, 0.4442104934598845, 0.5365972904585126, 0.4221062978051718, 0.5554972868238451, 0.5400155429805876, 0.6527242876757253, 0.47262603008218756, 0.6000342893579687, 0.8297108914342853, 0.5432571765506535, 0.6164512733317686, 0.659729845987438, 0.878226507885687, 0.8293156239699597, 0.39935167691260115
+1000, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.06957581181214641, 0.11727576980179334, 0.19879724787180408, 0.15514564994465022, 0.15335563242078185, 0.2029411563067941, 0.33025361900905537, 0.4179908587644115, 0.4428200805838054, 0.5634100755177667, 0.5680939840623824, 0.41520905829955296, 0.5753449870929177, 0.48414588902396805, 0.5913147768147112, 0.4648190251829891, 0.6358734895010334, 0.8449506822406887, 0.5716931289884855, 0.6013880377634973, 0.7021165582108326, 0.7605031088714594, 0.8316368363163683
+10000000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.08665812891997504, 0.1893325561060915, 0.392884167636787, 0.7103372143883693, 0.1713556511117511, 0.12470072279692956, 0.2383403904279098, 0.4472355817003856, 0.3084458638141755, 0.3922429804435704, 0.5098120423323317, 0.4048967889635629, 0.4046453884579675, 0.45231916560612523, 0.578670933838637, 0.527791925571288, 0.9204796267282687, 0.9253331472075768, 0.8919738382028523, 0.8766760073779796, 0.8865785578260142
+Y
+200, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0
+, 0.009286499266584609, 0.04190994220311158, 0.005673267516690456, 0.011282526243736116, 0.041909942203111575, 0.05957785566189, 0.04749864096985896, 0.05803797548561103, 0.07284698771143527, 0.04867312515561958, 0.0837839451245465, 0.08136844795311347, 0.1196284938247924, 0.13488330074785607, 0.1859103414172193, 0.22494333273362108, 0.2845607850383266, 0.34148624354154694, 0.3537330507841197, 0.4303267700378927, 0.4596981968135125, 0.5043265158898462, 0.5722032966248287, 0.591132260747033, 0.5615672359144327, 0.6433527557582447, 0.6200821169061512, 0.6866199534656023, 0.6409420681507526, 0.6377669951160809, 0.6475917264147603, 0.5867402271820585, 0.6081464300418282, 0.5855598936277712, 0.703751153709795, 0.5335558858652032, 0.5718292411383575, 0.7868125143340565, 0.5943859446876695, 0.2531795538962151
+400, -3.0, -2.8, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8
+, 0.0024631904120060435, 0.014599337728464305, 0.0019080473895611095, 0.0034467235991527422, 0.007898872470056247, 0.02454940809416175, 0.02767901585092433, 0.060144475081240587, 0.10182673535143302, 0.1402223895256354, 0.2159272947456956, 0.2474628127234784, 0.30672796698809546, 0.3701837946270894, 0.4281630341544478, 0.4900105528169095, 0.49672558077846896, 0.5458230184672949, 0.5822237283945346, 0.6232035400297948, 0.6309651873689367, 0.6650089068472502, 0.6906883232556257, 0.719070120561808, 0.5861318306017409, 0.6939528630753063, 0.644733589945717, 0.7557826365261244, 0.7868872016335692, 0.8077101821427416, 0.785137848061695, 0.7007336361374807, 0.7907789335787568, 0.9314640234622172
+600, -3.2, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8
+, 0.0678339420637355, 0.03132907113746549, 0.19521471211245917, 0.0790468441438464, 0.04504147115901855, 0.03621970390869113, 0.03736078959794541, 0.0702121913978338, 0.07678045932576472, 0.10633802477667664, 0.11960413292539095, 0.19900688668929817, 0.19847870369671886, 0.35052340230366474, 0.4182620478260756, 0.49334638007139636, 0.4139336918612302, 0.4758803364739189, 0.48058197497143446, 0.5325837123233392, 0.6764738640938338, 0.5824113213410999, 0.6854925565305252, 0.716699831685794, 0.6913247110998257, 0.7364537742437196, 0.6973151529206393, 0.6640017089879244, 0.7535147537884177, 0.8736524217431264, 0.8883154079240142, 0.9086524895242979, 0.3364614429341759, 0.8892455486542443, 0.516276512630574
+800, -2.4, -2.2, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.12499249996999987, 0.017542677750980205, 0.004183814710350362, 0.04049577780196881, 0.01945394480279348, 0.05981555656515628, 0.1662287133765109, 0.2470726136520115, 0.2279836885745909, 0.3405906596146762, 0.39304167365159454, 0.5479494843905584, 0.5776797970134353, 0.4969350548999451, 0.554976031602476, 0.6111452872519451, 0.5933613225870421, 0.6503765957046587, 0.6459187382843162, 0.47697114639093807, 0.4439174984783494, 0.5898786001485177, 0.6521583574634947, 0.699411044781371, 0.8755290078823845, 0.6892194962693724, 0.5956513541689771, 0.4191972780617089, 0.6859665367471306
+1000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.01513420581891473, 0.04710716529773664, 0.08675346730823665, 0.2536586494224809, 0.34051794477036007, 0.4949352227554531, 0.3744979625153848, 0.3885763166955366, 0.47500620176957165, 0.6732234245582497, 0.5916145874535242, 0.6141509220860845, 0.7235237614799357, 0.8444622025111802, 0.5840380724187212, 0.37117416203862574, 0.6845523703789804, 0.7343493349470799, 0.6147306746541727, 0.836192015818726, 0.6897855770617488, 0.7497181598163127, 0.3071472030349666, 0.1919103374866947
+10000000, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 2.0, 2.2, 2.6, 2.8, 3.0, 3.2
+, 0.0708645474792468, 0.17151110308719983, 0.2570225856067352, 0.11678972600342932, 0.14007308160779536, 0.5103673933918981, 0.7576957600718095, 0.7229533929002657, 0.7098140887820918, 0.6723469072042269, 0.6112883643448062, 0.6166996129966311, 0.893002867868218, 0.8895255061508461, 0.8001654763978401, 0.30475369142377656, 0.6623003900213408, 0.7044407947702315, 0.6821802063854838
+C
+200, -4.4, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8
+, 0.00552600427650797, 0.03485954094930549, 0.03838810402982251, 0.025715627803848534, 0.025488221431905482, 0.04343408489770449, 0.07142970187382498, 0.061574074307699386, 0.07314774143241341, 0.0645623004653657, 0.08295448119612607, 0.11583376897861364, 0.10923780472615427, 0.15872284777216678, 0.18960300191746962, 0.21632285501348175, 0.2689843145563964, 0.317374224275957, 0.3630447998094276, 0.47533324924738357, 0.47607691305922323, 0.5079450745840531, 0.5277576798975776, 0.5628057172760719, 0.575051710042101, 0.5593880195311266, 0.6755090738783593, 0.5934386213582137, 0.6382467809460037, 0.46977743056505733, 0.49332782901573397, 0.433919671579876, 0.4787946054736947, 0.5285187386448856, 0.5192055844835611, 0.5418864058012781, 0.4974690811553878, 0.6669903566100355, 0.5635741644172909, 0.5631278587090643, 0.4509635087812499, 0.41102196954637915, 0.5675101424562242, 0.3858209367335479, 0.7158058178212813, 0.8441831930348846, 0.917028268187617
+400, -2.8, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.2
+, 0.010395396838634843, 0.021361460299502484, 0.02165535066430582, 0.015159525108778021, 0.05264200337595036, 0.09707983819746174, 0.09731511297628698, 0.14129374581890802, 0.20022262624150677, 0.1899999623811763, 0.24177069784075372, 0.2794320762962471, 0.3349563341527679, 0.39941588667848116, 0.37542427668497114, 0.4413948575311084, 0.4994511731980783, 0.5229578236619977, 0.517824249985961, 0.5986188278934524, 0.55649711734287, 0.6546467413270598, 0.7295136272915, 0.6635498671850562, 0.6708303778437357, 0.6854662728780426, 0.7366769816589981, 0.6804239212899574, 0.8020315025334613, 0.648248800129263, 0.4883801068027809, 0.5457865193156772, 0.7435757599432814, 0.3888378116158756, 0.8142396988934587, 0.35653604110313064, 0.9515094757412567, 0.8683671258886828, 0.43063122020040623, 0.20134832264371375
+600, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2, 4.4
+, 0.014640944089221617, 0.047190998499466535, 0.016131092675076904, 0.05393342938205346, 0.03794117361550069, 0.14801529752994014, 0.12649865136882416, 0.12425487801283724, 0.18258838145967776, 0.17401252442552514, 0.24820371537628083, 0.2723009495881132, 0.31076828090971514, 0.4228592493350921, 0.4833419854280797, 0.48225822549606906, 0.6096979060194508, 0.6813975348841623, 0.6390568469900091, 0.6423882998985359, 0.6933120557029364, 0.7437104177397691, 0.7344965946599342, 0.5339314985180899, 0.76693091389901, 0.7860009499083788, 0.9485711375084455, 0.7614620936289629, 0.7922335003939941, 0.8140234673530409, 0.9905994173641781, 0.7496322833936753, 0.5402660706005019, 0.18423883691036483
+800, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 4.0, 4.2, 4.4
+, 0.1676606183648437, 0.1676606183648437, 0.07743155394424302, 0.07659036520366225, 0.040008410782623315, 0.06504823840581023, 0.1572369829786188, 0.20637862095592702, 0.26511828078110244, 0.26880018429549696, 0.7715955945577099, 0.5608321221346089, 0.5723698356275932, 0.5774648391346796, 0.5310722977083755, 0.5139787601877006, 0.6388370807266754, 0.5159175246850328, 0.4037730013428791, 0.6462677917648109, 0.6914477449297176, 0.7064353719025876, 0.6496598105159759, 0.8061020949745134, 0.9114250135029706, 0.805807135371541, 0.7069698372603644, 0.5579972241756949, 0.9707483336999887, 0.2521582668435688, 0.6737025368927209
+1000, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.6
+, 0.020481263776634836, 0.03747584236618773, 0.07963219211712719, 0.42117945879058266, 0.40087635526094045, 0.4186096119797778, 0.7519767441860465, 0.6969740019889189, 0.6769121710047986, 0.5095117468832265, 0.49996377012356535, 0.42357137893493324, 0.3704784074335224, 0.5022112276689343, 0.5377495655874323, 0.9377135348226019, 0.518641826827345, 0.6148997981190606, 0.925832429274806, 0.9306706710610997, 0.5275370793684547
+10000000, -0.6, 0.2, 0.6, 1.0, 1.2, 1.4, 2.2, 2.6, 2.8, 3.6
+, 0.2450956648098813, 0.34003811136989204, 0.5689392891716222, 0.5240494732020156, 0.4197691734921817, 0.6071833648393195, 0.47977746870653687, 0.1474288840262582, 0.2158490566037736, 0.059728506787330306
+I
+200, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6
+, 0.010246568324761396, 0.023586419611002423, 0.07326453667116309, 0.02266434565723754, 0.19125014334998405, 0.049215674536650926, 0.08042765604892763, 0.11504040934022898, 0.09190473758714221, 0.07884776581058621, 0.13204286686172295, 0.17339014874279796, 0.14738531701866997, 0.1925666588813994, 0.2798288367649437, 0.30356530000018567, 0.37802490411090917, 0.3891635072532392, 0.4188735667360788, 0.4130451708923584, 0.4090566074203953, 0.4005398324769401, 0.43727658014390886, 0.4525658021391098, 0.49469453336259855, 0.5364548074114078, 0.5487359041804901, 0.5589759259605349, 0.5600275134828192, 0.5857561779201617, 0.5950991838931297, 0.6171171951409766, 0.6208158282379346, 0.5341821673007862, 0.5911918922048982, 0.47767207984960436, 0.6016175443003301, 0.453017422332317, 0.009829615646825916, 0.011933949374280328
+400, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8
+, 0.009424041651289006, 0.005248090853102813, 0.020104435812286, 0.008380660947748239, 0.011633543757944554, 0.031233862457621414, 0.03796795304800285, 0.05304879411403409, 0.09428391079887828, 0.1957080355293911, 0.26417738982917194, 0.33722314135736386, 0.3835329367560942, 0.38791379723365044, 0.3469048845284936, 0.33981871326454166, 0.3718334747259479, 0.3744119941355528, 0.4371801106903041, 0.4742278199477808, 0.5467307808120919, 0.5889710925569661, 0.6003132839102469, 0.6282891377294968, 0.6667994100593078, 0.7149791981213757, 0.7165443100481403, 0.7648169965214152, 0.7931588888124155, 0.849697960723633, 0.5985009755051228
+600, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6
+, 0.01177149197646163, 0.019466387676539337, 0.009179617714196748, 0.021002809412977955, 0.012304705104874294, 0.01742489800381316, 0.09673996824968178, 0.20818513532059035, 0.24902690941466604, 0.3201033911616928, 0.3968527717263692, 0.32677150095038016, 0.2956502311222198, 0.3521918640702484, 0.34323878987875367, 0.41238085067793995, 0.4528202043089073, 0.4946606714015018, 0.60916176112803, 0.586244459052103, 0.731691655254136, 0.7615547888406847, 0.7532320282223522, 0.8256747853564931, 0.8227885041950739, 0.9414977098583945, 0.8707420724568614
+800, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4
+, 0.004884508436313263, 0.008895670331354973, 0.04738253012569462, 0.15700893886749803, 0.2720568723512916, 0.29754465051552165, 0.3529009205231974, 0.33901402505796213, 0.33151291774566327, 0.3171419785124146, 0.39610993206239475, 0.42435592249318754, 0.4284240846602554, 0.48610410052424313, 0.5011209748404598, 0.5923040805122267, 0.6801122435468188, 0.6003811302269592, 0.6886824799977288, 0.6536244005652843, 0.7340922067541863, 0.9749464234875972
+1000, -2.0, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2
+, 0.04006366374589266, 0.016420176967562962, 0.10541928765426886, 0.1842196914154018, 0.33370157870353867, 0.4140144214086954, 0.37627524716443256, 0.376828275689411, 0.350294020866546, 0.29056694294813423, 0.428977185963412, 0.4437891708347922, 0.4040640317539013, 0.5436759732095426, 0.6396942795183248, 0.699574241911313, 0.6264500766775059, 0.6958787809288652, 0.6647049856983595, 0.9007007532728866
+10000000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0
+, 0.05928374933750602, 0.2840734480639214, 0.355188042763727, 0.4981825035676783, 0.522066931657905, 0.687219937903835, 0.4285758086769892, 0.26404535582320265, 0.4070341937448583, 0.31549829407614327, 0.3522842812258061, 0.41463591162408975, 0.44042322850815757, 0.8108811576260953, 0.6660499661785326, 0.6714949448238751, 0.6945054584794939, 0.9471616054797473
+P
+200, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.2
+, 0.09462093250004656, 0.06513499980673217, 0.25836149525869284, 0.003590843571806108, 0.08011419031573228, 0.03750805525576047, 0.0574609648224664, 0.021046661598639223, 0.03965651331683649, 0.03233547498093971, 0.05244949461037999, 0.059239211279768764, 0.08658427873468452, 0.11641077018764909, 0.17102302987730567, 0.21557776345358962, 0.3488992728757439, 0.38412126513874806, 0.4717518589355339, 0.48086303211958253, 0.5349972443434652, 0.5523284345890979, 0.5139727330404497, 0.5737275580736053, 0.646507295963126, 0.6177418767988746, 0.5913879649161384, 0.6113435859450091, 0.6248086488637173, 0.6177495838258914, 0.5915088103951179, 0.5390155146848349, 0.5544234138321293, 0.4961989976316854, 0.5910782276103086, 0.575955804525867, 0.8040228012576552, 0.2552364547730815, 0.1539699424587969, 0.6105382318958665, 0.6920195597291678
+400, -3.2, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 4.0, 4.2
+, 0.027678544003005952, 0.0017759936101448578, 0.01563976484987035, 0.02662887534696838, 0.010267917113890223, 0.014499665143659572, 0.027299347695871414, 0.045885094521211214, 0.04395609633506502, 0.07075355873801675, 0.11122160543559785, 0.19482765066850968, 0.3102447121351171, 0.4323382675846813, 0.5049196275808877, 0.5340408301827624, 0.5699327744168944, 0.5646308086676382, 0.5898440411347238, 0.5960532705788892, 0.6456568185067169, 0.6761301863788893, 0.6705221804706994, 0.6794427710153623, 0.6560926262495437, 0.6670270517403344, 0.6415870485838746, 0.4940385904199614, 0.5459239564924565, 0.47599332002445893, 0.409220079384302, 0.42847584927258375, 0.827666355527503, 0.6427397436884055, 0.3387975859228055, 0.6658481930242676
+600, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4
+, 0.054115861337130235, 0.046296087292164195, 0.056336173545012996, 0.005138426504631574, 0.03016715284976033, 0.02195661225379361, 0.035469037639700524, 0.043213639799410224, 0.07923069137404684, 0.1892981614814477, 0.24008662810215636, 0.4542352013348483, 0.5155927001365727, 0.6227024593529396, 0.6069408758206023, 0.5689367573494439, 0.6173067228915726, 0.6507688014522729, 0.5604747283213789, 0.7005841663886421, 0.6021972001890809, 0.7322327525953377, 0.6256764860648757, 0.6644107146326537, 0.6404289926815111, 0.5798792570169877, 0.48913332794575626, 0.4739894981973522, 0.6169184160982089, 0.6311019946564094, 0.9162938262863316
+800, -2.4, -2.2, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2
+, 0.00625109691006886, 0.0036866050811829405, 0.010821473610371099, 0.034581709047270474, 0.052505947010089406, 0.04046046640914797, 0.0715445762534076, 0.19387348265185214, 0.3024834157149413, 0.4407693068754491, 0.5501948550333603, 0.4344640358714685, 0.4429962655179792, 0.4559017802592965, 0.4550889515888062, 0.562065860749629, 0.5872819382503642, 0.5031074411074145, 0.549570630011202, 0.7331689607663807, 0.637804892388616, 0.7508243979930967, 0.6847389871555631, 0.6837776185382219, 0.7089342805159007, 0.7548686754100637, 0.6858453269953747, 0.737874223470343
+1000, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.09319850573232, 0.10979172199248835, 0.06948530038214824, 0.07586792624252905, 0.1989606990626378, 0.3974041167469781, 0.4836987107065937, 0.43529270200348963, 0.5872083609038189, 0.4748060743676909, 0.4782649923500425, 0.47660581529267176, 0.40493349371783804, 0.4729478286637323, 0.5031491548381056, 0.4918696117603916, 0.474799166651737, 0.7606885434541573, 0.6515931714096899, 0.8523660209056383, 0.6549542201339508, 0.49738075923608915, 0.37358200278550074, 0.9102043744992286, 0.30461699146099175
+10000000, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.2, 0.4, 0.6, 0.8, 1.0, 1.4, 1.6, 1.8, 2.0, 2.4, 2.8, 3.0
+, 0.002034225211333397, 0.03213966868366234, 0.1254929577464789, 0.22886329058900245, 0.5338868536424239, 0.30411880078453357, 0.7558683600047184, 0.8943652386947497, 0.5068308181096108, 0.8747794169548951, 0.808677163898561, 0.6541717723070068, 0.520123659549802, 0.8308427892277724, 0.75944364805703, 0.46422176679969807, 0.11903193440828615, 0.9246754822273444
+V
+200, -4.2, -4.0, -3.8, -3.6, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0
+, 0.3013177924972648, 0.0670576962538446, 0.027947536968587417, 0.025471567022443797, 0.17738326284128084, 0.10698026054520915, 0.027192326456929903, 0.04736489830728461, 0.15565145058718088, 0.08889759595104872, 0.0901815261535527, 0.12890229680120277, 0.17640442149470179, 0.20057478536198106, 0.25497736014857153, 0.2845496101729879, 0.3387008081814645, 0.36859541367677057, 0.408859593377653, 0.42852982770728926, 0.43491545736005727, 0.4437173153173867, 0.4307511980475097, 0.4688229717283917, 0.5041690529385188, 0.5206150940885195, 0.5504178549950146, 0.604449454781223, 0.5852695922917379, 0.5892740759521515, 0.5821242214118382, 0.611738803380447, 0.5748701424067844, 0.5470664583475426, 0.4366875437443472, 0.2990467205099567, 0.17194313586429896
+400, -3.4, -3.2, -3.0, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 3.0
+, 0.007630710431630884, 0.05643138079149608, 0.0019464106682222882, 0.00495914554400256, 0.008471384625919275, 0.022434103491537804, 0.040253776825090605, 0.025356097618350212, 0.048630164072312, 0.06994433785325964, 0.10054807768512329, 0.17714681726250375, 0.262931751831555, 0.34550802640469575, 0.3781959689270546, 0.43546932456834325, 0.4111227842326892, 0.39342474726021504, 0.40754351242412284, 0.460087545031051, 0.4784670790288331, 0.5272787211953236, 0.5658096821582352, 0.6095502530391147, 0.6572364343932448, 0.6458428060835956, 0.699498928622632, 0.7675563268175648, 0.7165153170099512, 0.5393942384511748, 0.5587490608280018, 0.7684784086894817
+600, -2.8, -2.6, -2.4, -2.2, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4
+, 0.061032997065434115, 0.18533639985747144, 0.0145577041202563, 0.010942786101539745, 0.07387934237880509, 0.037536176376309634, 0.02763024311231824, 0.02265328277135838, 0.09520478453610436, 0.1595129075059143, 0.22597260291075094, 0.37063686634929416, 0.4028000965396746, 0.40189585160555535, 0.32174279329124866, 0.37195239626061044, 0.4539851836669101, 0.4666124404448917, 0.5233672984387059, 0.5443786020355682, 0.670588238862655, 0.6746727393780464, 0.774273657653073, 0.8059482440811514, 0.7534118409082837, 0.933769318652744, 0.9199396810574295
+800, -2.0, -1.8, -1.6, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4
+, 0.008536139445826405, 0.010647452272946844, 0.003065442904427912, 0.004083085051204419, 0.017935306813610788, 0.09716361787367706, 0.19725368574759128, 0.3505081624049802, 0.4204715759928817, 0.45469008403510625, 0.388999422485893, 0.32305500994632613, 0.39140601027418337, 0.48052658276599364, 0.421967881355336, 0.5799579944888391, 0.619119965966238, 0.619504925624972, 0.6769064254531707, 0.7778709874558832, 0.771651999854801, 0.7479361219585633, 0.5246872402663989
+1000, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2
+, 0.03892955516942246, 0.12043398243351962, 0.2645304545541721, 0.4365200127998329, 0.437088025611357, 0.35702064605615885, 0.4010590154472944, 0.36781079834103564, 0.4587836912312046, 0.39663279275577046, 0.6365005914806564, 0.5655098255829267, 0.593426197811947, 0.6692760067022221, 0.8622693278223753, 0.7184982472426565, 0.7060497525545142
+10000000, -1.4, -1.2, -1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 2.0
+, 0.017728944142882157, 0.007167824432547233, 0.08493880095308559, 0.2528489732042521, 0.4813898894916351, 0.36070591557949294, 0.39824076805492237, 0.3119042195275812, 0.32650985724376896, 0.49659876345439163, 0.5211131565504622, 0.4260184611915101, 0.5637321616051639, 0.5428210040346628, 0.7687209074612477, 0.7000895494459963, 0.8891690518938169
index 1762a06..bf9cc18 100644 (file)
@@ -11,6 +11,7 @@ action.paste = Paste
 action.show_html_source = Show HTML Source
 action.print = Print...
 action.web_service = Web Service
+action.hmmer = HMMER
 action.cancel_job = Cancel Job
 action.start_job = Start Job
 action.revert = Revert
@@ -59,6 +60,8 @@ action.boxes = Boxes
 action.text = Text
 action.by_pairwise_id = By Pairwise Identity
 action.by_id = By Id
+action.by_evalue = By E-Value
+action.by_bit_score = By Bit Score
 action.by_length = By Length
 action.by_group = By Group
 action.unmark_as_reference = Unmark as Reference 
@@ -98,6 +101,7 @@ action.edit_group = Edit Group
 action.border_colour = Border colour
 action.edit_new_group = Edit New Group
 action.hide_sequences = Hide Sequences
+action.add_background_frequencies = Add Background Frequencies
 action.sequences = Sequences
 action.ids = IDS
 action.ids_sequences = IDS and sequences
@@ -131,6 +135,8 @@ action.select_highlighted_columns = Select Highlighted Columns
 tooltip.select_highlighted_columns = Press B to mark highlighted columns, Ctrl-(or Cmd)-B to toggle, and Alt-B to mark all but highlighted columns 
 action.deselect_all = Deselect all
 action.invert_selection = Invert selection
+action.filter_by_evalue = Filter by E-Value
+action.filter_by_score = Filter by Score
 action.using_jmol = Using Jmol
 action.undo_changes_to_feature_settings = Undo all unapplied changes to feature settings
 action.undo_changes_to_feature_settings_and_close_the_dialog = Undo all pending changes and close the feature settings dialog
@@ -200,6 +206,9 @@ label.colourScheme_turnpropensity = Turn Propensity
 label.colourScheme_buriedindex = Buried Index
 label.colourScheme_purine/pyrimidine = Purine/Pyrimidine
 label.colourScheme_nucleotide = Nucleotide
+label.colourScheme_hmmer-uniprot = HMMER profile v global background
+label.colourScheme_hmmer-alignment = HMMER profile v alignment background
+label.colourScheme_hmm_match_score = HMM Match Score
 label.colourScheme_t-coffeescores = T-Coffee Scores
 label.colourScheme_rnahelices = By RNA Helices
 label.colourScheme_sequenceid = Sequence ID Colour
@@ -810,8 +819,8 @@ label.fetch_retrieve_from_all_sources = Retrieve from all {0} sources in {1}<br>
 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
-label.opt_and_params_show_brief_desc_image_link = <html>Click to show brief description<br><img src="{0}"/> Right click for further information.</html> 
-label.opt_and_params_show_brief_desc = <html>Click to show brief description<br></html>
+label.opt_and_params_show_brief_desc_image_link = Click to show brief description<br><img src="{0}"/> Right click for further information. 
+label.opt_and_params_show_brief_desc = Click to show brief description<br>
 label.adjusts_width_generated_eps_png = <html>Adjusts the width of the generated EPS or PNG file to ensure even the longest sequence ID or annotation label is displayed</html>
 label.manually_specify_width_left_column = <html>Manually specify the width of the left hand column where sequence IDs and annotation labels will be rendered in exported alignment figures. This setting will be ignored if 'Automatically set ID width' is set</html>
 label.job_created_when_checked = <html>When checked, a job is created for every sequence in the current selection.</html>
@@ -946,7 +955,6 @@ label.groovy_support_failed = Jalview Groovy Support Failed
 label.couldnt_create_groovy_shell = Couldn't create the groovy Shell. Check the error log for the details of what went wrong.
 error.unsupported_version_calcIdparam = Unsupported Version for calcIdparam {0}
 error.implementation_error_cant_reorder_tree = Implementation Error: Can't reorder this tree. Not DefaultMutableTreeNode.
-error.invalid_value_for_option = Invalid value {0} for option {1}
 error.implementation_error_cannot_import_vamsas_doc = Implementation Error - cannot import existing vamsas document into an existing session, Yet!
 label.vamsas_doc_couldnt_be_opened_as_new_session = VAMSAS Document could not be opened as a new session - please choose another
 error.implementation_error_vamsas_operation_not_init = Impementation error! Vamsas Operations when client not initialised and connected
@@ -1054,6 +1062,7 @@ exception.ranml_couldnt_process_data = Couldn't process data as RNAML file ({0})
 exception.ranml_invalid_file = Invalid RNAML file ({0})
 exception.ranml_problem_parsing_data = Problem parsing data as RNAML ({0})
 exception.pfam_no_sequences_found = No sequences found (PFAM input)
+exception.hmmer_no_valid_sequences_found = No valid sequences found
 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.unknown_annotation_detected = Unknown annotation detected: {0} {1}
@@ -1125,6 +1134,9 @@ status.loading_cached_pdb_entries = Loading Cached PDB Entries
 status.searching_for_pdb_structures = Searching for PDB Structures
 status.opening_file_for = opening file for
 status.colouring_chimera = Colouring Chimera
+status.running_hmmbuild = Building Hidden Markov Model
+status.running_hmmalign = Creating alignment with Hidden Markov Model
+status.running_search = Searching for matching sequences
 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
 label.error_loading_file_params = Error loading file {0}
@@ -1341,6 +1353,79 @@ label.alignment = alignment
 label.pca = PCA
 label.create_image_of = Create {0} image of {1}
 label.click_to_edit = Click to edit, right-click for menu
+label.hmmalign = hmmalign
+label.use_hmm = HMM profile to use
+label.use_sequence = Sequence to use
+label.hmmbuild = hmmbuild
+label.hmmsearch = hmmsearch
+label.jackhmmer = jackhmmer
+label.installation = Installation
+label.hmmer_location = HMMER Binaries Installation Location
+label.cygwin_location = Cygwin Binaries Installation Location (Windows)
+label.information_annotation = Information Annotation
+label.ignore_below_background_frequency = Ignore Below Background Frequency
+label.information_description = Information content, measured in bits
+warn.no_hmm = No Hidden Markov model found.\nRun hmmbuild or load an HMM file first.
+label.no_sequences_found = No matching sequences, or an error occurred.
+label.hmmer = HMMER
+label.trim_termini = Trim Non-Matching Termini
+label.trim_termini_desc = If true, non-matching regions on either end of the resulting alignment are removed.
+label.no_of_sequences = Number of sequences returned
+label.reporting_cutoff = Reporting Cut-off
+label.inclusion_threshold = Inlcusion Threshold
+label.freq_alignment = Use alignment background frequencies
+label.freq_uniprot = Use Uniprot background frequencies
+label.hmmalign_options = hmmalign options
+label.hmmsearch_options = hmmsearch options
+label.jackhmmer_options = jackhmmer options
+label.executable_not_found = The ''{0}'' executable file was not found
+warn.command_failed = {0} failed
+label.invalid_folder = Invalid Folder
+label.number_of_results = Number of Results to Return
+label.number_of_iterations = Number of jackhmmer Iterations
+label.auto_align_seqs = Automatically Align Fetched Sequences
+label.new_returned = new sequences returned
+label.use_accessions = Return Accessions
+label.check_for_new_sequences = Return Number of New Sequences
+label.evalue = E-Value
+label.reporting_seq_evalue = Reporting Sequence E-value Cut-off
+label.reporting_seq_score = Reporting Sequence Score Threshold
+label.reporting_dom_evalue = Reporting Domain E-value Cut-off
+label.reporting_dom_score = Reporting Domain Score Threshold
+label.inclusion_seq_evalue = Inclusion Sequence E-value Cut-off
+label.inclusion_seq_score = Inclusion Sequence Score Threshold
+label.inclusion_dom_evalue = Inclusion Domain E-value Cut-off
+label.inclusion_dom_score = Inclusion Domain Score Threshold
+label.number_of_results_desc = The maximum number of hmmsearch results to display
+label.number_of_iterations_desc = The number of iterations jackhmmer will complete when searching for new sequences
+label.auto_align_seqs_desc = If true, all fetched sequences will be aligned to the hidden Markov model with which the search was performed
+label.check_for_new_sequences_desc = Display number of new sequences returned from hmmsearch compared to the previous alignment 
+label.use_accessions_desc = If true, the accession number of each sequence is returned, rather than that sequence's name
+label.reporting_seq_e_value_desc = The E-value cutoff for returned sequences 
+label.reporting_seq_score_desc = The score threshold for returned sequences 
+label.reporting_dom_e_value_desc = The E-value cutoff for returned domains 
+label.reporting_dom_score_desc = The score threshold for returned domains 
+label.inclusion_seq_e_value_desc = Sequences with an E-value less than this cut-off are classed as significant
+label.inclusion_seq_score_desc = Sequences with a bit score greater than this threshold are classed as significant
+label.inclusion_dom_e_value_desc = Domains with an E-value less than this cut-off are classed as significant
+label.inclusion_dom_score_desc = Domains with a bit score greater than this threshold are classed as significant
+label.add_database = Add Database
+label.this_alignment = This alignment
+warn.invalid_format = This is not a valid database file format. The current supported formats are Fasta, Stockholm and Pfam.
+label.database_for_hmmsearch = The database hmmsearch will search through
+label.use_reference = Use Reference Annotation
+label.use_reference_desc = If true, hmmbuild will keep all columns defined as a reference position by the reference annotation
+label.hmm_name = Alignment HMM Name
+label.hmm_name_desc = The name given to the HMM for the alignment
+warn.no_reference_annotation = No reference annotation found
+label.hmmbuild_for = Build HMM for
+label.hmmbuild_for_desc = Build an HMM for the selected sets of sequences
+label.alignment = Alignment
+label.groups_and_alignment = All groups and alignment
+label.groups = All groups
+label.selected_group = Selected group
+label.use_info_for_height = Use Information Content as Letter Height
+action.search = Search
 label.backupfiles_confirm_delete = Confirm delete
 label.backupfiles_confirm_delete_old_files = Delete the following older backup files? (see the Backups tab in Preferences for more options)
 label.backupfiles_confirm_save_file = Confirm save file
@@ -1413,3 +1498,4 @@ label.include_linked_features = Include {0} features
 label.include_linked_tooltip = Include visible {0} features<br>converted to local sequence coordinates
 label.features_not_shown = {0} feature(s) not shown
 label.no_features_to_sort_by = No features to sort by
+
index d3c3355..0dee36d 100644 (file)
@@ -865,7 +865,6 @@ label.groovy_support_failed = El soporte Groovy de Jalview ha fallado
 label.couldnt_create_groovy_shell = No es posible crear el shell de Groovy. Compruebe el fichero de log para conocer los detalles.
 error.unsupported_version_calcIdparam = Versión no soportada de {0}
 error.implementation_error_cant_reorder_tree = Error de implementación: no es posible reordenar este Ã¡rbol. No DefaultMutableTreeNode.
-error.invalid_value_for_option = Valor no válido de {0} para la opción {1}
 error.implementation_error_cannot_import_vamsas_doc = Error de implementación - todavía no es posible importar el documento VAMSAS existente en una sesión existente.
 label.vamsas_doc_couldnt_be_opened_as_new_session = El documento VAMSAS no ha podido abrirse como una nueva sesión. Por favor, escoja otra.
 error.implementation_error_vamsas_operation_not_init = Â¡Error de implementación! Operaciones VAMSAS cuando el cliente no estaba inicializado ni conectado
@@ -1337,6 +1336,7 @@ label.alignment = alineamiento
 label.pca = ACP
 label.create_image_of = Crear imagen {0} de {1}
 label.click_to_edit = Haga clic para editar, clic en el botón derecho para ver el menú  
+action.search = Buscar
 label.backupfiles_confirm_delete = Confirmar borrar
 label.backupfiles_confirm_delete_old_files = Â¿Borrar los siguientes archivos? (ver la pestaña 'Copias' de la ventana de Preferencias para más opciones)
 label.backupfiles_confirm_save_file = Confirmar guardar archivo
index 1d2235e..c21721b 100755 (executable)
                                                                        </xs:attribute>
                                                                </xs:complexType>
                                                        </xs:element>
+                                                       <xs:element name="hmmerProfile" minOccurs="0" type="xs:string">
+                                                               <xs:annotation>
+                                                                       <xs:documentation>name of the project jar entry that holds the HMM file with the profile for the sequence</xs:documentation>
+                                                               </xs:annotation>
+                                                       </xs:element>
                                                </xs:sequence>
                                                <xs:attribute name="colour" type="xs:int" use="optional" />
                                                <xs:attribute name="start" type="xs:int" use="required" />
index 4378457..c1d04c4 100644 (file)
@@ -34,6 +34,7 @@ package ext.edu.ucsf.rbvi.strucviz2;
 
 import jalview.bin.Cache;
 import jalview.gui.Preferences;
+import jalview.util.FileUtils;
 import jalview.util.Platform;
 
 import java.io.File;
@@ -936,18 +937,16 @@ public class StructureManager
     }
     else if (os.startsWith("Windows"))
     {
-      for (String root : new String[] { "\\Program Files",
-          "C:\\Program Files", "\\Program Files (x86)",
-          "C:\\Program Files (x86)" })
-      {
-        for (String version : new String[] { "1.11", "1.11.1", "1.11.2",
-            "1.12", "1.12.1", "1.12.2", "1.13" })
-        {
-          pathList.add(root + "\\Chimera " + version + "\\bin\\chimera");
-          pathList.add(
-                  root + "\\Chimera " + version + "\\bin\\chimera.exe");
-        }
-      }
+      /*
+       * typical Windows installation path is
+       * C:\Program Files\Chimera 1.12\bin\chimera.exe
+       */
+      // current drive:
+      pathList.addAll(FileUtils.findMatches("\\",
+              "Program Files*/Chimera*/bin/{chimera,chimera.exe}"));
+      // C: drive (note may add as duplicates)
+      pathList.addAll(FileUtils.findMatches("C:\\",
+              "Program Files*/Chimera*/bin/{chimera,chimera.exe}"));
     }
     else if (os.startsWith("Mac"))
     {
index 52dedcf..4e53484 100755 (executable)
@@ -24,6 +24,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.Profile;
 import jalview.datamodel.ProfileI;
 import jalview.datamodel.Profiles;
@@ -32,6 +33,7 @@ import jalview.datamodel.ResidueCount;
 import jalview.datamodel.ResidueCount.SymbolCounts;
 import jalview.datamodel.SequenceI;
 import jalview.ext.android.SparseIntArray;
+import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.Format;
 import jalview.util.MappingUtils;
@@ -48,25 +50,12 @@ import java.util.List;
  * This class is used extensively in calculating alignment colourschemes that
  * depend on the amount of conservation in each alignment column.
  * 
- * @author $author$
- * @version $Revision$
  */
 public class AAFrequency
 {
-  public static final String PROFILE = "P";
-
-  /*
-   * Quick look-up of String value of char 'A' to 'Z'
-   */
-  private static final String[] CHARS = new String['Z' - 'A' + 1];
+  private static final double LOG2 = Math.log(2);
 
-  static
-  {
-    for (char c = 'A'; c <= 'Z'; c++)
-    {
-      CHARS[c - 'A'] = String.valueOf(c);
-    }
-  }
+  public static final String PROFILE = "P";
 
   public static final ProfilesI calculate(List<SequenceI> list, int start,
           int end)
@@ -192,6 +181,52 @@ public class AAFrequency
   }
 
   /**
+   * Returns the full set of profiles for a hidden Markov model. The underlying
+   * data is the raw probabilities of a residue being emitted at each node,
+   * however the profiles returned by this function contain the percentage
+   * chance of a residue emission.
+   * 
+   * @param hmm
+   * @param width
+   *          The width of the Profile array (Profiles) to be returned.
+   * @param start
+   *          The alignment column on which the first profile is based.
+   * @param end
+   *          The alignment column on which the last profile is based.
+   * @param removeBelowBackground
+   *          if true, symbols with a match emission probability less than
+   *          background frequency are ignored
+   * @return
+   */
+  public static ProfilesI calculateHMMProfiles(final HiddenMarkovModel hmm,
+          int width, int start, int end, boolean removeBelowBackground,
+          boolean infoLetterHeight)
+  {
+    ProfileI[] result = new ProfileI[width];
+    char[] symbols = hmm.getSymbols().toCharArray();
+    int symbolCount = symbols.length;
+    for (int column = start; column < end; column++)
+    {
+      ResidueCount counts = new ResidueCount();
+      for (char symbol : symbols)
+      {
+        int value = getAnalogueCount(hmm, column, symbol,
+                removeBelowBackground, infoLetterHeight);
+        counts.put(symbol, value);
+      }
+      int maxCount = counts.getModalCount();
+      String maxResidue = counts.getResiduesForCount(maxCount);
+      int gapCount = counts.getGapCount();
+      ProfileI profile = new Profile(symbolCount, gapCount, maxCount,
+              maxResidue);
+      profile.setCounts(counts);
+
+      result[column] = profile;
+    }
+    return new Profiles(result);
+  }
+
+  /**
    * 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
@@ -289,9 +324,80 @@ public class AAFrequency
   }
 
   /**
-   * Derive the gap count annotation row.
+   * Derive the information 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 'ignore below background frequency',
+   * which may in turn result in a change in the derived values.
+   * 
+   * @param information
+   *          the annotation row to add annotations to
+   * @param profiles
+   *          the source information data
+   * @param startCol
+   *          start column (inclusive)
+   * @param endCol
+   *          end column (exclusive)
+   * @param ignoreGaps
+   *          if true, normalise residue percentages
+   * @param showSequenceLogo
+   *          if true include all information symbols, else just show modal
+   *          residue
+   */
+  public static float completeInformation(AlignmentAnnotation information,
+          ProfilesI profiles, int startCol, int endCol)
+  {
+    // long now = System.currentTimeMillis();
+    if (information == null || information.annotations == null)
+    {
+      /*
+       * called with a bad alignment annotation row 
+       * wait for it to be initialised properly
+       */
+      return 0;
+    }
+
+    float max = 0f;
+    SequenceI hmmSeq = information.sequenceRef;
+
+    int seqLength = hmmSeq.getLength();
+    if (information.annotations.length < seqLength)
+    {
+      return 0;
+    }
+
+    HiddenMarkovModel hmm = hmmSeq.getHMM();
+
+    for (int column = startCol; column < endCol; column++)
+    {
+      if (column >= seqLength)
+      {
+        // hmm consensus sequence is shorter than the alignment
+        break;
+      }
+      
+      float value = hmm.getInformationContent(column);
+      boolean isNaN = Float.isNaN(value);
+      if (!isNaN)
+      {
+        max = Math.max(max, value);
+      }
+
+      String description = isNaN ? null
+              : String.format("%.4f bits", value);
+      information.annotations[column] = new Annotation(
+              Character.toString(
+                      Character.toUpperCase(hmmSeq.getCharAt(column))),
+              description, ' ', value);
+    }
+
+    information.graphMax = max;
+    return max;
+  }
+
+  /**
+   * Derive the occupancy count annotation
    * 
-   * @param gaprow
+   * @param occupancy
    *          the annotation row to add annotations to
    * @param profiles
    *          the source consensus data
@@ -300,11 +406,11 @@ public class AAFrequency
    * @param endCol
    *          end column (exclusive)
    */
-  public static void completeGapAnnot(AlignmentAnnotation gaprow,
+  public static void completeGapAnnot(AlignmentAnnotation occupancy,
           ProfilesI profiles, int startCol, int endCol, long nseq)
   {
-    if (gaprow == null || gaprow.annotations == null
-            || gaprow.annotations.length < endCol)
+    if (occupancy == null || occupancy.annotations == null
+            || occupancy.annotations.length < endCol)
     {
       /*
        * called with a bad alignment annotation row 
@@ -313,8 +419,8 @@ public class AAFrequency
       return;
     }
     // always set ranges again
-    gaprow.graphMax = nseq;
-    gaprow.graphMin = 0;
+    occupancy.graphMax = nseq;
+    occupancy.graphMin = 0;
     double scale = 0.8 / nseq;
     for (int i = startCol; i < endCol; i++)
     {
@@ -325,7 +431,7 @@ public class AAFrequency
          * happens if sequences calculated over were 
          * shorter than alignment width
          */
-        gaprow.annotations[i] = null;
+        occupancy.annotations[i] = null;
         return;
       }
 
@@ -333,7 +439,8 @@ public class AAFrequency
 
       String description = "" + gapped;
 
-      gaprow.annotations[i] = new Annotation("", description, '\0', gapped,
+      occupancy.annotations[i] = new Annotation("", description, '\0',
+              gapped,
               jalview.util.ColorUtils.bleachColour(Color.DARK_GRAY,
                       (float) scale * gapped));
     }
@@ -470,6 +577,7 @@ public class AAFrequency
     return result;
   }
 
+
   /**
    * Extract a sorted extract of cDNA codon profile data. The returned array
    * contains
@@ -749,4 +857,118 @@ public class AAFrequency
     }
     return scale;
   }
+
+  /**
+   * Returns the sorted HMM profile for the given column of the alignment. The
+   * returned array contains
+   * 
+   * <pre>
+   *    [profileType=0, numberOfValues, 100, charValue1, percentage1, charValue2, percentage2, ...]
+   * in descending order of percentage value
+   * </pre>
+   * 
+   * @param hmm
+   * @param column
+   * @param removeBelowBackground
+   *          if true, ignores residues with probability less than their
+   *          background frequency
+   * @param infoHeight
+   *          if true, uses the log ratio 'information' measure to scale the
+   *          value
+   * @return
+   */
+  public static int[] extractHMMProfile(HiddenMarkovModel hmm, int column,
+          boolean removeBelowBackground, boolean infoHeight)
+  {
+    if (hmm == null)
+    {
+      return null;
+    }
+    String alphabet = hmm.getSymbols();
+    int size = alphabet.length();
+    char symbols[] = new char[size];
+    int values[] = new int[size];
+    int totalCount = 0;
+
+    for (int i = 0; i < size; i++)
+    {
+      char symbol = alphabet.charAt(i);
+      symbols[i] = symbol;
+      int value = getAnalogueCount(hmm, column, symbol,
+              removeBelowBackground, infoHeight);
+      values[i] = value;
+      totalCount += value;
+    }
+
+    /*
+     * sort symbols by increasing emission probability
+     */
+    QuickSort.sort(values, symbols);
+
+    int[] profile = new int[3 + size * 2];
+
+    profile[0] = AlignmentAnnotation.SEQUENCE_PROFILE;
+    profile[1] = size;
+    profile[2] = 100;
+
+    /*
+     * order symbol/count profile by decreasing emission probability
+     */
+    if (totalCount != 0)
+    {
+      int arrayPos = 3;
+      for (int k = size - 1; k >= 0; k--)
+      {
+        Float percentage;
+        int value = values[k];
+        if (removeBelowBackground)
+        {
+          percentage = ((float) value) / totalCount * 100f;
+        }
+        else
+        {
+          percentage = value / 100f;
+        }
+        int intPercent = Math.round(percentage);
+        profile[arrayPos] = symbols[k];
+        profile[arrayPos + 1] = intPercent;
+        arrayPos += 2;
+      }
+    }
+    return profile;
+  }
+
+  /**
+   * Converts the emission probability of a residue at a column in the alignment
+   * to a 'count', suitable for rendering as an annotation value
+   * 
+   * @param hmm
+   * @param column
+   * @param symbol
+   * @param removeBelowBackground
+   *          if true, returns 0 for any symbol with a match emission
+   *          probability less than the background frequency
+   * @infoHeight if true, uses the log ratio 'information content' to scale the
+   *             value
+   * @return
+   */
+  static int getAnalogueCount(HiddenMarkovModel hmm, int column,
+          char symbol, boolean removeBelowBackground, boolean infoHeight)
+  {
+    double value = hmm.getMatchEmissionProbability(column, symbol);
+    double freq = ResidueProperties.backgroundFrequencies
+            .get(hmm.getAlphabetType()).get(symbol);
+    if (value < freq && removeBelowBackground)
+    {
+      return 0;
+    }
+
+    if (infoHeight)
+    {
+      value = value * (Math.log(value / freq) / LOG2);
+    }
+
+    value = value * 10000d;
+    return Math.round((float) value);
+  }
 }
index f5626ce..5c2d936 100644 (file)
@@ -75,11 +75,11 @@ public class AlignmentAnnotationUtils
      * Build a lookup, by calcId (annotation source), of all annotation types in
      * each graph group.
      */
-    Map<String, Map<Integer, List<String>>> groupLabels = new HashMap<String, Map<Integer, List<String>>>();
+    Map<String, Map<Integer, List<String>>> groupLabels = new HashMap<>();
 
     // trackers for which calcId!label combinations we have dealt with
-    List<String> addedToShown = new ArrayList<String>();
-    List<String> addedToHidden = new ArrayList<String>();
+    List<String> addedToShown = new ArrayList<>();
+    List<String> addedToHidden = new ArrayList<>();
 
     for (AlignmentAnnotation aa : annotations)
     {
@@ -99,7 +99,7 @@ public class AlignmentAnnotationUtils
         /*
          * Build a 'composite label' for types in line graph groups.
          */
-        final List<String> labelAsList = new ArrayList<String>();
+        final List<String> labelAsList = new ArrayList<>();
         final String displayLabel = aa.label;
         labelAsList.add(displayLabel);
         if (aa.graph == AlignmentAnnotation.LINE_GRAPH
@@ -239,4 +239,42 @@ public class AlignmentAnnotationUtils
     return (anns == null ? Collections.<AlignmentAnnotation> emptyList()
             : Arrays.asList(anns));
   }
+
+  /**
+   * replace an existing sequence associated annotation with another, creating
+   * association as necessary.
+   * 
+   * @param newAnnot
+   *          - annotation row associated with a sequence to be propagated to
+   *          its reference annotation
+   * @param typeName
+   *          - label used to match existing row
+   * @param calcId
+   *          - calcId for existing row
+   */
+  public static void replaceAnnotationOnAlignmentWith(
+          AlignmentAnnotation newAnnot, String typeName, String calcId)
+  {
+    if (newAnnot.sequenceRef != null)
+    {
+      SequenceI dsseq = newAnnot.sequenceRef;
+      while (dsseq.getDatasetSequence() != null)
+      {
+        dsseq = dsseq.getDatasetSequence();
+      }
+      // look for same annotation on dataset and lift this one over
+      List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
+              typeName);
+      if (dsan != null && dsan.size() > 0)
+      {
+        for (AlignmentAnnotation dssan : dsan)
+        {
+          dsseq.removeAlignmentAnnotation(dssan);
+        }
+      }
+      AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
+      dsseq.addAlignmentAnnotation(dssan);
+      dssan.adjustForAlignment();
+    }
+  }
 }
index af7db0a..f2b2222 100755 (executable)
@@ -113,6 +113,10 @@ public class AlignmentSorter implements ApplicationSingletonI
 
   private boolean sortLengthAscending;
 
+  private static boolean sortEValueAscending;
+
+  private static boolean sortBitScoreAscending;
+
   /**
    * Sorts sequences in the alignment by Percentage Identity with the given
    * reference sequence, sorting the highest identity to the top
@@ -196,6 +200,90 @@ public class AlignmentSorter implements ApplicationSingletonI
   }
 
   /**
+   * Sorts by sequence evalue. Currently moves all sequences without an evalue to
+   * the top of the alignment.
+   * 
+   * @param align
+   *                The alignment object to sort
+   */
+  public static void sortByEValue(AlignmentI align)
+  {
+    int nSeq = align.getHeight();
+
+    double[] evalue = new double[nSeq];
+    SequenceI[] seqs = new SequenceI[nSeq];
+
+    for (int i = 0; i < nSeq; i++)
+    {
+      seqs[i] = align.getSequenceAt(i);
+      AlignmentAnnotation[] ann = seqs[i].getAnnotation("Search Scores");
+      if (ann != null)
+      {
+        evalue[i] = ann[0].getEValue();
+      }
+      else
+      {
+        evalue[i] = -1;
+      }
+    }
+
+    QuickSort.sort(evalue, seqs);
+
+    if (sortEValueAscending)
+    {
+      setReverseOrder(align, seqs);
+    }
+    else
+    {
+      setOrder(align, seqs);
+    }
+
+    sortEValueAscending = !sortEValueAscending;
+  }
+
+  /**
+   * Sorts by sequence bit score. Currently moves all sequences without a bit
+   * score to the top of the alignment
+   * 
+   * @param align
+   *                The alignment object to sort
+   */
+  public static void sortByBitScore(AlignmentI align)
+  {
+    int nSeq = align.getHeight();
+
+    double[] score = new double[nSeq];
+    SequenceI[] seqs = new SequenceI[nSeq];
+
+    for (int i = 0; i < nSeq; i++)
+    {
+      seqs[i] = align.getSequenceAt(i);
+      AlignmentAnnotation[] ann = seqs[i].getAnnotation("Search Scores");
+      if (ann != null)
+      {
+        score[i] = ann[0].getEValue();
+      }
+      else
+      {
+        score[i] = -1;
+      }
+    }
+
+    QuickSort.sort(score, seqs);
+
+    if (sortBitScoreAscending)
+    {
+      setReverseOrder(align, seqs);
+    }
+    else
+    {
+      setOrder(align, seqs);
+    }
+
+    sortBitScoreAscending = !sortBitScoreAscending;
+  }
+
+  /**
    * Sorts the alignment by size of group. <br>
    * Maintains the order of sequences in each group by order in given alignment
    * object.
index 0c40873..be2739f 100644 (file)
@@ -1459,28 +1459,31 @@ public class AlignmentUtils
       final List<AlignmentAnnotation> result = new ArrayList<>();
       for (AlignmentAnnotation dsann : datasetAnnotations)
       {
-        /*
-         * Find matching annotations on the alignment. If none is found, then
-         * add this annotation to the list of 'addable' annotations for this
-         * sequence.
-         */
-        final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
-                .findAnnotations(seq, dsann.getCalcId(), dsann.label);
-        if (!matchedAlignmentAnnotations.iterator().hasNext())
+        if (dsann.annotations != null) // ignore non-positional annotation
         {
-          result.add(dsann);
-          if (labelForCalcId != null)
+          /*
+           * Find matching annotations on the alignment. If none is found, then
+           * add this annotation to the list of 'addable' annotations for this
+           * sequence.
+           */
+          final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
+                  .findAnnotations(seq, dsann.getCalcId(), dsann.label);
+          if (!matchedAlignmentAnnotations.iterator().hasNext())
           {
-            labelForCalcId.put(dsann.getCalcId(), dsann.label);
+            result.add(dsann);
+            if (labelForCalcId != null)
+            {
+              labelForCalcId.put(dsann.getCalcId(), dsann.label);
+            }
           }
         }
-      }
-      /*
-       * Save any addable annotations for this sequence
-       */
-      if (!result.isEmpty())
-      {
-        candidates.put(seq, result);
+        /*
+         * Save any addable annotations for this sequence
+         */
+        if (!result.isEmpty())
+        {
+          candidates.put(seq, result);
+        }
       }
     }
   }
index fdca89d..61fc747 100755 (executable)
@@ -20,6 +20,8 @@
  */
 package jalview.analysis;
 
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -35,7 +37,7 @@ public class SeqsetUtils
 
   /**
    * Store essential properties of a sequence in a hashtable for later recovery
-   * Keys are Name, Start, End, SeqFeatures, PdbId
+   * Keys are Name, Start, End, SeqFeatures, PdbId, HMM
    * 
    * @param seq
    *          SequenceI
@@ -52,7 +54,7 @@ public class SeqsetUtils
       sqinfo.put("Description", seq.getDescription());
     }
 
-    Vector<SequenceFeature> sfeat = new Vector<SequenceFeature>();
+    Vector<SequenceFeature> sfeat = new Vector<>();
     List<SequenceFeature> sfs = seq.getFeatures().getAllFeatures();
     sfeat.addAll(sfs);
 
@@ -69,6 +71,16 @@ public class SeqsetUtils
               (seq.getDatasetSequence() != null) ? seq.getDatasetSequence()
                       : new Sequence("THISISAPLACEHOLDER", ""));
     }
+    if (seq.hasHMMProfile())
+    {
+      sqinfo.put("HMM", seq.getHMM());
+    }
+
+    if (seq.getAnnotation("Search Scores") != null)
+    {
+      sqinfo.put("Score", seq.getAnnotation("Search Scores"));
+    }
+
     return sqinfo;
   }
 
@@ -97,6 +109,10 @@ public class SeqsetUtils
     Vector<PDBEntry> pdbid = (Vector<PDBEntry>) sqinfo.get("PdbId");
     String description = (String) sqinfo.get("Description");
     Sequence seqds = (Sequence) sqinfo.get("datasetSequence");
+    HiddenMarkovModel hmm = (HiddenMarkovModel) sqinfo.get("HMM");
+    AlignmentAnnotation[] scores = (AlignmentAnnotation[]) sqinfo
+            .get("Score");
+
     if (oldname == null)
     {
       namePresent = false;
@@ -135,6 +151,18 @@ public class SeqsetUtils
       sq.setDatasetSequence(seqds);
     }
 
+    if (hmm != null)
+    {
+      sq.setHMM(new HiddenMarkovModel(hmm, sq));
+    }
+
+    if (scores != null)
+    {
+      for (AlignmentAnnotation score : scores)
+      {
+        sq.addAlignmentAnnotation(score);
+      }
+    }
     return namePresent;
   }
 
diff --git a/src/jalview/api/AlignCalcListener.java b/src/jalview/api/AlignCalcListener.java
new file mode 100644 (file)
index 0000000..9ce385d
--- /dev/null
@@ -0,0 +1,39 @@
+package jalview.api;
+
+import java.util.EventListener;
+
+/**
+ * A listener class which receives state updates of {@link AlignCalcWorkerI}.
+ * It can be registered with an {@link AlignCalcManagerI2}.
+ * 
+ * @author mmwarowny
+ *
+ */
+public interface AlignCalcListener extends EventListener
+{
+  /**
+   * Called when the worker is scheduler for execution with
+   * {@link AlignCalcManagerI2#startWorker(AlignCalcWorkerI)}.
+   */
+  default void workerQueued(AlignCalcWorkerI worker) {}
+  
+  /**
+   * Called when the worker starts calculations.
+   */
+  default void workerStarted(AlignCalcWorkerI worker) {}
+  
+  /**
+   * Called when the worker finishes successfully.
+   */
+  default void workerCompleted(AlignCalcWorkerI worker) {}
+  
+  /**
+   * Called when the worker is cancelled.
+   */
+  default void workerCancelled(AlignCalcWorkerI worker) {}
+  
+  /**
+   * Called when the worker finishes with an exception.
+   */
+  default void workerExceptional(AlignCalcWorkerI worker, Throwable throwable) {}
+}
index 18605b8..005ecd7 100644 (file)
@@ -32,7 +32,7 @@ public interface AlignCalcManagerI
    * 
    * @param worker
    */
-  void notifyStart(AlignCalcWorkerI worker);
+  void notifyStarted(AlignCalcWorkerI worker);
 
   /**
    * tell manager that a thread running worker's run() loop is ready to start
@@ -150,7 +150,7 @@ public interface AlignCalcManagerI
    * 
    * @param typeToRemove
    */
-  void removeRegisteredWorkersOfClass(
+  void removeWorkersOfClass(
           Class<? extends AlignCalcWorkerI> typeToRemove);
 
   /**
diff --git a/src/jalview/api/AlignCalcManagerI2.java b/src/jalview/api/AlignCalcManagerI2.java
new file mode 100644 (file)
index 0000000..22b4832
--- /dev/null
@@ -0,0 +1,120 @@
+package jalview.api;
+
+import java.util.List;
+
+import jalview.datamodel.AlignmentAnnotation;
+
+/**
+ * An abstract manager which controls the execution of interactive jobs.
+ * There is always one instance of AlignCancManager per AlignmenViewport
+ * which runs the jobs, notifies observers and ensures no race conditions.
+ * 
+ * @author mmwarowny
+ *
+ */
+public interface AlignCalcManagerI2
+{
+  /**
+   * Registers the worker with the manager and immediately schedules it
+   * for execution.
+   */
+  void registerWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Returns the list of all registered workers or an empty list if 
+   * there are none
+   */
+  List<AlignCalcWorkerI> getWorkers();
+  
+  /**
+   * Returns the list of all workers of a given class or an empty list
+   * if there are none. The classes are compared using 
+   * {@ink Class#equals(Object)} rather than {@code instanceof}.
+   */
+  List<AlignCalcWorkerI> getWorkersOfClass(Class<? extends AlignCalcWorkerI> cls);
+  
+  /**
+   * Removes the worker from the scheduler. It does not cancel workers
+   * already scheduled for execution.
+   */
+  void removeWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Removes all workers which are involved with the given annotation.
+   */
+  void removeWorkerForAnnotation(AlignmentAnnotation annot);
+  
+  /**
+   * Removes all workers of a given class. The classes are compared using
+   * {@link Class#equals(Object)}. 
+   */
+  void removeWorkersOfClass(Class<? extends AlignCalcWorkerI> cls);
+  
+  /**
+   * Disables a worker so it won't be run during the following restarts.
+   */
+  void disableWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Restores the previously disabled worker back to operation.
+   */
+  void enableWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Checks whether the worker is disabled either due to failure or
+   * disabling it manually.
+   */
+  boolean isDisabled(AlignCalcWorkerI worker);
+  
+  /**
+   * Checks whether the given worker is currently running.
+   */
+  boolean isWorking(AlignCalcWorkerI worker);
+  
+  /**
+   * Checks whether the currently running worker (if any) is processing
+   * the given annotation.
+   */
+  boolean isWorkingWithAnnotation(AlignmentAnnotation annot);
+  
+  /**
+   * Checks whether this manager is running a worker.
+   */
+  boolean isWorking();
+  
+  /**
+   * Scheduler the worker for one-time execution. The worker does not need
+   * to be registered with this manager and will be scheduler regardless
+   * of being disabled. If the worker has already been scheduled, the
+   * previous one will be cancelled.
+   */
+  void startWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Schedules all registered and not-disabled workers for next execution.
+   */
+  void restartWorkers();
+  
+  /**
+   * Cancels the execution of the worker. Note, if the worker is already
+   * running, this method may, but doesn't have to, interrupt it in
+   * the middle of the work.
+   */
+  void cancelWorker(AlignCalcWorkerI worker);
+  
+  /**
+   * Connect the listener of the worker state changes.
+   */
+  void addAlignCalcListener(AlignCalcListener listener);
+  
+  /**
+   * Remove previously registered worker listener.
+   */
+  void removeAlignCalcListener(AlignCalcListener listener);
+  
+  /**
+   * Stops the manager from running new jobs and cleans-up all
+   * resources such as threads and thread pools.
+   */
+  void shutdown();
+}
index 85157c4..b51b94e 100644 (file)
  */
 package jalview.api;
 
+import java.util.concurrent.Callable;
+
 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
+public interface AlignCalcWorkerI
 {
   /**
    * Answers true if this worker updates the given annotation (regardless of its
@@ -39,8 +41,8 @@ public interface AlignCalcWorkerI extends Runnable
 
   /**
    * Updates the display of calculated annotation values (does not recalculate
-   * the values). This allows ÃŸquick redraw of annotations when display settings
-   * are changed.
+   * the values). This allows a quick redraw of annotations when display
+   * settings are changed.
    */
   void updateAnnotation();
 
@@ -48,7 +50,13 @@ public interface AlignCalcWorkerI extends Runnable
    * Removes any annotation(s) managed by this worker from the alignment
    */
   void removeAnnotation();
-
+  
+  /**
+   * The main calculation happens here
+   * @throws Throwable 
+   */
+  public void run() throws Throwable;
+  
   /**
    * 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
index 065be75..2f992a6 100644 (file)
@@ -55,7 +55,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return
    */
-  public ViewportRanges getRanges();
+  ViewportRanges getRanges();
 
   /**
    * calculate the height for visible annotation, revalidating bounds where
@@ -63,7 +63,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return total height of annotation
    */
-  public int calcPanelHeight();
+  int calcPanelHeight();
 
   /**
    * Answers true if the viewport has at least one column selected
@@ -87,6 +87,12 @@ public interface AlignViewportI extends ViewStyleI
 
   boolean isNormaliseSequenceLogo();
 
+  boolean isShowInformationHistogram();
+
+  boolean isShowHMMSequenceLogo();
+
+  boolean isNormaliseHMMSequenceLogo();
+
   ColourSchemeI getGlobalColourScheme();
 
   /**
@@ -114,6 +120,8 @@ public interface AlignViewportI extends ViewStyleI
 
   boolean isIgnoreGapsConsensus();
 
+  boolean isIgnoreBelowBackground();
+
   boolean isCalculationInProgress(AlignmentAnnotation alignmentAnnotation);
 
   AlignmentAnnotation getAlignmentQualityAnnot();
@@ -158,7 +166,7 @@ public interface AlignViewportI extends ViewStyleI
    * 
    * @return
    */
-  AlignCalcManagerI getCalcManager();
+  AlignCalcManagerI2 getCalcManager();
 
   /**
    * get the percentage gaps allowed in a conservation calculation
@@ -499,9 +507,21 @@ public interface AlignViewportI extends ViewStyleI
   @Override
   void setProteinFontAsCdna(boolean b);
 
-  TreeModel getCurrentTree();
+  void setHmmProfiles(ProfilesI info);
 
-  void setCurrentTree(TreeModel tree);
+  ProfilesI getHmmProfiles();
+
+  /**
+   * Registers and starts a worker thread to calculate Information Content
+   * annotation, if it is not already registered
+   * 
+   * @param ap
+   */
+  void initInformationWorker(AlignmentViewPanel ap);
+
+  boolean isInfoLetterHeight();
+
+  public abstract TreeModel getCurrentTree();
 
   /**
    * Answers a data bean containing data for export as configured by the
@@ -512,6 +532,8 @@ public interface AlignViewportI extends ViewStyleI
    */
   AlignmentExportData getAlignExportData(AlignExportSettingsI options);
 
+  public abstract void setCurrentTree(TreeModel tree);
+
   /**
    * @param update
    *          - set the flag for updating structures on next repaint
index c0fc523..5e910dc 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.api;
 
+import jalview.datamodel.features.FeatureMatcherSetI;
+
 import java.util.Comparator;
 
 /**
@@ -60,6 +62,15 @@ public interface FeatureSettingsModelI extends Comparator<String>
   FeatureColourI getFeatureColour(String type);
 
   /**
+   * Returns any filters defined for the feature type, or null if not known
+   * 
+   * @param type
+   * @return
+   */
+
+  FeatureMatcherSetI getFeatureFilters(String type);
+
+  /**
    * Returns the transparency value, from 0 (fully transparent) to 1 (fully
    * opaque)
    * 
diff --git a/src/jalview/api/PollableAlignCalcWorkerI.java b/src/jalview/api/PollableAlignCalcWorkerI.java
new file mode 100644 (file)
index 0000000..25074ec
--- /dev/null
@@ -0,0 +1,18 @@
+package jalview.api;
+
+public interface PollableAlignCalcWorkerI extends AlignCalcWorkerI
+{
+  @Override
+  public default void run() throws Throwable
+  {
+    startUp();
+  }
+  
+  public void startUp() throws Throwable;
+  
+  public boolean poll() throws Throwable;
+  
+  public void cancel();
+  
+  public void done();
+}
index fc1f26d..063e949 100644 (file)
@@ -236,6 +236,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
             alignPanel);
     viewport.updateConservation(alignPanel);
     viewport.updateConsensus(alignPanel);
+    viewport.initInformationWorker(alignPanel);
 
     displayNonconservedMenuItem.setState(viewport.getShowUnconserved());
     followMouseOverFlag.setState(viewport.isFollowHighlight());
@@ -1324,6 +1325,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       sortGroupMenuItem_actionPerformed();
     }
+    else if (source == sortEValueMenuItem)
+    {
+      sortEValueMenuItem_actionPerformed();
+    }
+    else if (source == sortBitScoreMenuItem)
+    {
+      sortBitScoreMenuItem_actionPerformed();
+    }
     else if (source == removeRedundancyMenuItem)
     {
       removeRedundancyMenuItem_actionPerformed();
@@ -2770,6 +2779,26 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   }
 
+  public void sortEValueMenuItem_actionPerformed()
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByEValue(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+
+  public void sortBitScoreMenuItem_actionPerformed()
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByBitScore(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+
   public void removeRedundancyMenuItem_actionPerformed()
   {
     new RedundancyPanel(alignPanel);
@@ -3120,6 +3149,10 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   MenuItem sortGroupMenuItem = new MenuItem();
 
+  MenuItem sortEValueMenuItem = new MenuItem();
+
+  MenuItem sortBitScoreMenuItem = new MenuItem();
+
   MenuItem removeRedundancyMenuItem = new MenuItem();
 
   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
index b379c2d..e2eebfc 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
  * 
  * This file is part of Jalview.
  * 
@@ -54,10 +54,16 @@ public class AlignViewport extends AlignmentViewport
 
   private AnnotationColumnChooser annotationColumnSelectionState;
 
+  java.awt.Frame nullFrame;
+
+  protected FeatureSettings featureSettings = null;
+
+  private float heightScale = 1, widthScale = 1;
+
   public AlignViewport(AlignmentI al, JalviewLite applet)
   {
     super(al);
-    calculator = new jalview.workers.AlignCalcManager();
+    calculator = new jalview.workers.AlignCalcManager2();
     this.applet = applet;
 
     // we always pad gaps
@@ -197,7 +203,7 @@ public class AlignViewport extends AlignmentViewport
                         colour));
         if (residueShading != null)
         {
-          residueShading.setConsensus(hconsensus);
+          residueShading.setConsensus(consensusProfiles);
         }
       }
 
@@ -208,15 +214,8 @@ public class AlignViewport extends AlignmentViewport
       }
     }
     initAutoAnnotation();
-
   }
 
-  java.awt.Frame nullFrame;
-
-  protected FeatureSettings featureSettings = null;
-
-  private float heightScale = 1, widthScale = 1;
-
   /**
    * {@inheritDoc}
    */
@@ -296,17 +295,6 @@ public class AlignViewport extends AlignmentViewport
             .getStructureSelectionManager(applet);
   }
 
-  @Override
-  public boolean isNormaliseSequenceLogo()
-  {
-    return normaliseSequenceLogo;
-  }
-
-  public void setNormaliseSequenceLogo(boolean state)
-  {
-    normaliseSequenceLogo = state;
-  }
-
   /**
    * 
    * @return true if alignment characters should be displayed
index 58569cd..3d74aa2 100644 (file)
@@ -555,8 +555,8 @@ public class AlignmentPanel extends Panel
     // this is called after loading new annotation onto alignment
     if (alignFrame.getSize().height == 0)
     {
-      System.out.println(
-              "adjustAnnotationHeight frame size zero NEEDS FIXING");
+      // panel not laid out yet?
+      return;
     }
     fontChanged();
     validateAnnotationDimensions(true);
index a0102b9..9cd2b51 100755 (executable)
@@ -534,7 +534,7 @@ public class AnnotationLabels extends Panel
                     MessageManager.getString("label.ignore_gaps_consensus"),
                     (aa[selectedRow].groupRef != null)
                             ? aa[selectedRow].groupRef
-                                    .getIgnoreGapsConsensus()
+                                                                                               .getIgnoreGapsConsensus()
                             : ap.av.isIgnoreGapsConsensus());
             final AlignmentAnnotation aaa = aa[selectedRow];
             cbmi.addItemListener(new ItemListener()
index f89b67c..aa08e79 100755 (executable)
  */
 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 jalview.viewmodel.ViewportListenerI;
+import jalview.viewmodel.ViewportRanges;
+
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
index 9cbdd36..f4603b5 100755 (executable)
@@ -71,7 +71,7 @@ public class OverviewPanel extends Panel implements Runnable,
 
     od = new OverviewDimensionsShowHidden(av.getRanges(),
             (av.isShowAnnotation()
-                    && av.getSequenceConsensusHash() != null));
+                                               && av.getSequenceConsensusHash() != null));
 
     oviewCanvas = new OverviewCanvas(od, av);
     setLayout(new BorderLayout());
index dec6573..8c72f64 100644 (file)
@@ -23,6 +23,8 @@ package jalview.appletgui;
 import java.awt.Graphics;
 import java.awt.Insets;
 import java.awt.Panel;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 
 public class TitledPanel extends Panel
 {
index 70aaa42..75504be 100755 (executable)
@@ -186,8 +186,8 @@ public class Jalview implements ApplicationSingletonI
   class FeatureFetcher
   {
     /*
-     * TODO: generalise to track all jalview events to orchestrate batch processing
-     * events.
+     * TODO: generalise to track all jalview events to orchestrate batch
+     * processing events.
      */
 
     private int queued = 0;
@@ -461,7 +461,12 @@ public class Jalview implements ApplicationSingletonI
         System.out.println("Error setting Taskbar: " + t.getMessage());
       }
       desktop.setVisible(true);
-
+      if (Platform.isJS())
+        Cache.setProperty("SHOW_JWS2_SERVICES", "false");
+      if (allowServices)
+      {
+        desktop.startServiceDiscovery();
+      }
       if (!isJS)
       /**
        * Java only
@@ -469,8 +474,6 @@ public class Jalview implements ApplicationSingletonI
        * @j2sIgnore
        */
       {
-        if (allowServices)
-          desktop.startServiceDiscovery();
         if (!aparser.contains("nousagestats"))
         {
           startUsageStats(desktop);
@@ -763,6 +766,10 @@ public class Jalview implements ApplicationSingletonI
           createOutputFiles(aparser, format);
         }
       }
+      if (headless)
+      {
+        af.getViewport().getCalcManager().shutdown();
+      }
     }
     // extract groovy arguments before anything else.
     // Once all other stuff is done, execute any groovy scripts (in order)
index 8d81a34..3a79ac6 100755 (executable)
@@ -292,6 +292,32 @@ public class Alignment implements AlignmentI, AutoCloseable
   }
 
   /**
+   * Inserts a sequence at a point in the alignment.
+   * 
+   * @param i
+   *          the index of the position the sequence is to be inserted in.
+   */
+  @Override
+  public void insertSequenceAt(int i, SequenceI snew)
+  {
+    synchronized (sequences)
+    {
+      if (sequences.size() > i)
+      {
+        sequences.add(i, snew);
+        return;
+
+      }
+      else
+      {
+        sequences.add(snew);
+        hiddenSequences.adjustHeightSequenceAdded();
+      }
+      return;
+    }
+  }
+
+  /**
    * DOCUMENT ME!
    * 
    * @return DOCUMENT ME!
@@ -1606,34 +1632,50 @@ public class Alignment implements AlignmentI, AutoCloseable
           String calcId, boolean autoCalc, SequenceI seqRef,
           SequenceGroup groupRef)
   {
-    if (annotations != null)
+    AlignmentAnnotation annot = annotations == null ? null
+            : AlignmentAnnotation.findFirstAnnotation(
+              Arrays.asList(getAlignmentAnnotation()), name, calcId,
+              autoCalc, seqRef, groupRef);
+
+    if (annot == null)
     {
-      for (AlignmentAnnotation annot : getAlignmentAnnotation())
+
+      annot = new AlignmentAnnotation(name, name, new Annotation[1], 0f, 0f,
+              AlignmentAnnotation.BAR_GRAPH);
+      annot.hasText = false;
+      if (calcId != null)
       {
-        if (annot.autoCalculated == autoCalc && (name.equals(annot.label))
-                && (calcId == null || annot.getCalcId().equals(calcId))
-                && annot.sequenceRef == seqRef
-                && annot.groupRef == groupRef)
-        {
-          return annot;
-        }
+        annot.setCalcId(calcId);
       }
+      annot.autoCalculated = autoCalc;
+      if (seqRef != null)
+      {
+        annot.setSequenceRef(seqRef);
+      }
+      annot.groupRef = groupRef;
+      addAnnotation(annot);
     }
-    AlignmentAnnotation annot = new AlignmentAnnotation(name, name,
-            new Annotation[1], 0f, 0f, AlignmentAnnotation.BAR_GRAPH);
-    annot.hasText = false;
-    if (calcId != null)
+    return annot;
+  }
+
+
+  @Override
+  public AlignmentAnnotation updateFromOrCopyAnnotation(
+          AlignmentAnnotation ala)
+  {
+    AlignmentAnnotation annot = AlignmentAnnotation.findFirstAnnotation(
+            Arrays.asList(getAlignmentAnnotation()), ala.label, ala.calcId,
+            ala.autoCalculated, ala.sequenceRef, ala.groupRef);
+    if (annot == null)
     {
-      annot.setCalcId(new String(calcId));
+      annot = new AlignmentAnnotation(ala);
+      addAnnotation(annot);
     }
-    annot.autoCalculated = autoCalc;
-    if (seqRef != null)
+    else
     {
-      annot.setSequenceRef(seqRef);
+      annot.updateAlignmentAnnotationFrom(ala);
     }
-    annot.groupRef = groupRef;
-    addAnnotation(annot);
-
+    validateAnnotation(annot);
     return annot;
   }
 
@@ -2033,4 +2075,18 @@ public class Alignment implements AlignmentI, AutoCloseable
     }
   }
 
+  @Override
+  public List<SequenceI> getHmmSequences()
+  {
+    List<SequenceI> result = new ArrayList<>();
+    for (int i = 0; i < sequences.size(); i++)
+    {
+      SequenceI seq = sequences.get(i);
+      if (seq.hasHMMProfile())
+      {
+        result.add(seq);
+      }
+    }
+    return result;
+  }
 }
index 2ee4503..4ba0ac4 100755 (executable)
@@ -94,6 +94,10 @@ public class AlignmentAnnotation
    */
   private long invalidrnastruc = -2;
 
+  private double bitScore;
+
+  private double eValue;
+
   /**
    * Updates the _rnasecstr field Determines the positions that base pair and
    * the positions of helices based on secondary structure from a Stockholm file
@@ -584,7 +588,7 @@ public class AlignmentAnnotation
     }
     return null;
   }
-
+  
   /**
    * Creates a new AlignmentAnnotation object.
    * 
@@ -696,7 +700,7 @@ public class AlignmentAnnotation
       }
     }
   }
-
+  
   /**
    * Copy constructor creates a new independent annotation row with the same
    * associated sequenceRef
@@ -706,6 +710,17 @@ public class AlignmentAnnotation
   public AlignmentAnnotation(AlignmentAnnotation annotation)
   {
     setAnnotationId();
+    updateAlignmentAnnotationFrom(annotation);
+  }
+
+  /**
+   * copy attributes and annotation from an existing annotation (used by copy
+   * constructor). This method does not update the unique annotationId
+   * 
+   * @param annotation
+   */
+  public void updateAlignmentAnnotationFrom(AlignmentAnnotation annotation)
+  {
     this.label = new String(annotation.label);
     if (annotation.description != null)
     {
@@ -729,6 +744,9 @@ public class AlignmentAnnotation
     this.scaleColLabel = annotation.scaleColLabel;
     this.showAllColLabels = annotation.showAllColLabels;
     this.calcId = annotation.calcId;
+    this.bitScore = annotation.bitScore;
+    this.eValue = annotation.eValue;
+
     if (annotation.properties != null)
     {
       properties = new HashMap<>();
@@ -960,6 +978,7 @@ public class AlignmentAnnotation
    * @param seqRef
    * @param startRes
    * @param alreadyMapped
+   *          - annotation are at aligned columns
    */
   public void createSequenceMapping(SequenceI seqRef, int startRes,
           boolean alreadyMapped)
@@ -1161,7 +1180,7 @@ public class AlignmentAnnotation
   {
     return hasScore || !Double.isNaN(score);
   }
-
+  
   /**
    * Score only annotation
    * 
@@ -1192,6 +1211,7 @@ public class AlignmentAnnotation
     makeVisibleAnnotation(hidden);
   }
 
+
   public void setPadGaps(boolean padgaps, char gapchar)
   {
     this.padGaps = padgaps;
@@ -1651,7 +1671,6 @@ public class AlignmentAnnotation
           Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
           String label)
   {
-
     ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
     for (AlignmentAnnotation ann : list)
     {
@@ -1696,7 +1715,6 @@ public class AlignmentAnnotation
   public static Iterable<AlignmentAnnotation> findAnnotation(
           List<AlignmentAnnotation> list, String calcId)
   {
-
     List<AlignmentAnnotation> aa = new ArrayList<>();
     if (calcId == null)
     {
@@ -1714,4 +1732,42 @@ public class AlignmentAnnotation
     return aa;
   }
 
+  public double getBitScore()
+  {
+    return bitScore;
+  }
+
+  public void setBitScore(double bitScore)
+  {
+    this.bitScore = bitScore;
+  }
+
+  public double getEValue()
+  {
+    return eValue;
+  }
+
+  public void setEValue(double eValue)
+  {
+    this.eValue = eValue;
+  }
+
+  public static AlignmentAnnotation findFirstAnnotation(
+          Iterable<AlignmentAnnotation> alignmentAnnotation, String name,
+          String calcId, boolean autoCalc, SequenceI seqRef,
+          SequenceGroup groupRef)
+  {
+
+    for (AlignmentAnnotation annot : alignmentAnnotation)
+    {
+      if (annot.autoCalculated == autoCalc && (name.equals(annot.label))
+              && (calcId == null || annot.getCalcId().equals(calcId))
+              && annot.sequenceRef == seqRef && annot.groupRef == groupRef)
+      {
+        return annot;
+      }
+    }
+    return null;
+  }
+
 }
index 93a2456..cea1c5b 100755 (executable)
@@ -518,8 +518,6 @@ public interface AlignmentI extends AnnotatedCollectionI
    *          - null or specific sequence reference
    * @param groupRef
    *          - null or specific group reference
-   * @param method
-   *          - CalcId for the annotation (must match)
    * 
    * @return existing annotation matching the given attributes
    */
@@ -527,6 +525,17 @@ public interface AlignmentI extends AnnotatedCollectionI
           boolean autoCalc, SequenceI seqRef, SequenceGroup groupRef);
 
   /**
+   * like findOrCreateAnnotation - looks for an existing alignment annotation
+   * row with matching name, calcId, sequenceRef, groupRef and autoCalculated
+   * flag and updates it from the annotation. If none is found the annotation is
+   * added directly.
+   * 
+   * @param ala
+   * @return ala or the annotation row that was updated.
+   */
+  AlignmentAnnotation updateFromOrCopyAnnotation(AlignmentAnnotation ala);
+
+  /**
    * move the given group up or down in the alignment by the given number of
    * rows. Implementor assumes given group is already present on alignment - no
    * recalculations are triggered.
@@ -604,6 +613,16 @@ public interface AlignmentI extends AnnotatedCollectionI
   public boolean setHiddenColumns(HiddenColumns cols);
 
   /**
+   * Insert a sequence at a position in an alignment
+   * 
+   * @param i
+   *          The index of the position.
+   * @param snew
+   *          The new sequence.
+   */
+  void insertSequenceAt(int i, SequenceI snew);
+
+  /**
    * Set the first sequence as representative and hide its insertions. Typically
    * used when loading JPred files.
    */
@@ -623,5 +642,4 @@ public interface AlignmentI extends AnnotatedCollectionI
    */
   public HiddenColumns propagateInsertions(SequenceI profileseq,
           AlignmentView input);
-
 }
index 6d09145..ef46d79 100755 (executable)
@@ -80,7 +80,7 @@ public class AlignmentOrder
    */
   public AlignmentOrder(AlignmentI orderFrom)
   {
-    Order = new ArrayList<SequenceI>();
+    Order = new ArrayList<>();
 
     for (SequenceI seq : orderFrom.getSequences())
     {
@@ -96,7 +96,7 @@ public class AlignmentOrder
    */
   public AlignmentOrder(SequenceI[] orderFrom)
   {
-    Order = new ArrayList<SequenceI>(Arrays.asList(orderFrom));
+    Order = new ArrayList<>(Arrays.asList(orderFrom));
   }
 
   /**
index e6604d1..c00f0b1 100644 (file)
@@ -25,6 +25,7 @@ import jalview.util.ShiftList;
 
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -114,6 +115,16 @@ public class AlignmentView
     {
       return seqs.size();
     }
+
+    public SequenceGroup getNewSequenceGroup(char c)
+    {
+      SequenceGroup newsg = new SequenceGroup(sg);
+      for (SeqCigar seq : seqs)
+      {
+        newsg.addSequence(seq.getSeq(c), false);
+      }
+      return newsg;
+    }
   }
 
   /**
@@ -1237,4 +1248,21 @@ public class AlignmentView
     }
 
   }
+
+  /**
+   * return pruned visible sequences in each group in alignment view
+   * 
+   * @param c
+   * @return
+   */
+  public Collection<? extends AnnotatedCollectionI> getVisibleGroups(char c)
+  {
+    ArrayList<SequenceGroup> groups = new ArrayList<>();
+    for (ScGroup sc : scGroups)
+    {
+      SequenceGroup sg = sc.getNewSequenceGroup(c);
+      groups.add(sg);
+    }
+    return groups;
+  }
 }
index 2963fd5..878f22a 100644 (file)
@@ -61,4 +61,6 @@ public interface AnnotatedCollectionI extends SequenceCollectionI
    *         alignment, parent group).
    */
   AnnotatedCollectionI getContext();
+
+  
 }
diff --git a/src/jalview/datamodel/HMMNode.java b/src/jalview/datamodel/HMMNode.java
new file mode 100644 (file)
index 0000000..b646eee
--- /dev/null
@@ -0,0 +1,148 @@
+package jalview.datamodel;
+
+/**
+ * stores data for each node in the hmm model
+ * @author TZVanaalten
+ *
+ */
+public class HMMNode
+{
+  //contains the match emissions for each symbol 
+  double[] matchEmissions;
+
+  //contains the insert emissions for each symbol 
+  double[] insertEmissions;
+
+  // contains the state transitions for each possible transition. These are mm,
+  // mi, md, im, ii, dm and dd in order
+  double[] stateTransitions;
+  
+  //annotations
+  int residueNumber;
+  char consensusResidue;
+  char referenceAnnotation;
+  char maskValue;
+  char consensusStructure;
+
+  /**
+   * Constructor
+   */
+  public HMMNode()
+  {
+  }
+
+  public double[] getMatchEmissions()
+  {
+    return matchEmissions;
+  }
+
+  double getMatchEmission(int symbolIndex)
+  {
+    return matchEmissions[symbolIndex];
+  }
+
+  public void setMatchEmissions(double[] matches)
+  {
+    this.matchEmissions = matches;
+  }
+
+  public double[] getInsertEmissions()
+  {
+    return insertEmissions;
+  }
+
+  double getInsertEmission(int symbolIndex)
+  {
+    return insertEmissions[symbolIndex];
+  }
+
+  public void setInsertEmissions(double[] insertEmissionsL)
+  {
+    this.insertEmissions = insertEmissionsL;
+  }
+
+  public double[] getStateTransitions()
+  {
+    return stateTransitions;
+  }
+
+  double getStateTransition(int transition)
+  {
+    return stateTransitions[transition];
+  }
+
+  public void setStateTransitions(double[] stateTransitionsM)
+  {
+    this.stateTransitions = stateTransitionsM;
+  }
+
+  int getResidueNumber()
+  {
+    return residueNumber;
+  }
+  public void setResidueNumber(int resNo)
+  {
+    this.residueNumber = resNo;
+  }
+
+  char getConsensusResidue()
+  {
+    return consensusResidue;
+  }
+  public void setConsensusResidue(char consensusResidue)
+  {
+    this.consensusResidue = consensusResidue;
+  }
+
+  char getReferenceAnnotation()
+  {
+    return referenceAnnotation;
+  }
+  public void setReferenceAnnotation(char referenceAnnotation)
+  {
+    this.referenceAnnotation = referenceAnnotation;
+  }
+
+  char getMaskValue()
+  {
+    return maskValue;
+  }
+  public void setMaskValue(char maskValue)
+  {
+    this.maskValue = maskValue;
+  }
+
+  char getConsensusStructure()
+  {
+    return consensusStructure;
+  }
+  public void setConsensusStructure(char consensusStructure)
+  {
+    this.consensusStructure = consensusStructure;
+  }
+
+  /**
+   * Answers the symbol index of the symbol with the highest match emission
+   * probability (first symbol in case of a tie). Note this object stores
+   * probabilities, not the negative logarithms as in the HMM file.
+   * 
+   * @return
+   */
+  int getMaxMatchEmissionIndex()
+  {
+    int maxIndex = 0;
+    double max = 0D;
+
+    for (int i = 0; i < matchEmissions.length; i++)
+    {
+      if (matchEmissions[i] > max)
+      {
+        max = matchEmissions[i];
+        maxIndex = i;
+      }
+    }
+    return maxIndex;
+  }
+}
+   
+  
diff --git a/src/jalview/datamodel/HiddenMarkovModel.java b/src/jalview/datamodel/HiddenMarkovModel.java
new file mode 100644 (file)
index 0000000..6b8b095
--- /dev/null
@@ -0,0 +1,672 @@
+package jalview.datamodel;
+
+import jalview.io.HMMFile;
+import jalview.schemes.ResidueProperties;
+import jalview.util.Comparison;
+import jalview.util.MapList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Data structure which stores a hidden Markov model
+ * 
+ * @author TZVanaalten
+ * 
+ */
+public class HiddenMarkovModel
+{
+  private static final char GAP_DASH = '-';
+
+  public final static String YES = "yes";
+
+  public final static String NO = "no";
+
+  public static final int MATCHTOMATCH = 0;
+
+  public static final int MATCHTOINSERT = 1;
+
+  public static final int MATCHTODELETE = 2;
+
+  public static final int INSERTTOMATCH = 3;
+
+  public static final int INSERTTOINSERT = 4;
+
+  public static final int DELETETOMATCH = 5;
+
+  public static final int DELETETODELETE = 6;
+
+  private static final double LOG2 = Math.log(2);
+
+  /*
+   * properties read from HMM file header lines
+   */
+  private Map<String, String> fileProperties = new HashMap<>();
+
+  private String fileHeader;
+  
+  /*
+   * the symbols used in this model e.g. "ACGT"
+   */
+  private String alphabet;
+
+  /*
+   * symbol lookup index into the alphabet for 'A' to 'Z'
+   */
+  private int[] symbolIndexLookup = new int['Z' - 'A' + 1];
+
+  /*
+   * Nodes in the model. The begin node is at index 0, and contains 
+   * average emission probabilities for each symbol.
+   */
+  private List<HMMNode> nodes = new ArrayList<>();
+
+  /*
+   * the aligned HMM consensus sequence extracted from the HMM profile
+   */
+  private SequenceI hmmSeq;
+
+  /*
+   * mapping from HMM nodes to residues of the hmm consensus sequence
+   */
+  private Mapping mapToHmmConsensus;
+
+  // stores background frequencies of alignment from which this model came
+  private Map<Character, Float> backgroundFrequencies;
+
+  /**
+   * Constructor
+   */
+  public HiddenMarkovModel()
+  {
+  }
+
+  /**
+   * Copy constructor given a new aligned sequence with which to associate the
+   * HMM profile
+   * 
+   * @param hmm
+   * @param sq
+   */
+  public HiddenMarkovModel(HiddenMarkovModel hmm, SequenceI sq)
+  {
+    super();
+    this.fileProperties = new HashMap<>(hmm.fileProperties);
+    this.alphabet = hmm.alphabet;
+    this.nodes = new ArrayList<>(hmm.nodes);
+    this.symbolIndexLookup = hmm.symbolIndexLookup;
+    this.fileHeader = new String(hmm.fileHeader);
+    this.hmmSeq = sq;
+    this.backgroundFrequencies = hmm.getBackgroundFrequencies();
+    if (sq.getDatasetSequence() == hmm.mapToHmmConsensus.getTo())
+    {
+      // same dataset sequence e.g. after realigning search results
+      this.mapToHmmConsensus = hmm.mapToHmmConsensus;
+    }
+    else
+    {
+      // different dataset sequence e.g. after loading HMM from project
+      this.mapToHmmConsensus = new Mapping(sq.getDatasetSequence(),
+              hmm.mapToHmmConsensus.getMap());
+    }
+  }
+
+  /**
+   * Returns the information content at a specified column, calculated as the
+   * sum (over possible symbols) of the log ratio
+   * 
+   * <pre>
+   *  log(emission probability / background probability) / log(2)
+   * </pre>
+   * 
+   * @param column
+   *          column position (base 0)
+   * @return
+   */
+  public float getInformationContent(int column)
+  {
+    float informationContent = 0f;
+
+    for (char symbol : getSymbols().toCharArray())
+    {
+      float freq = ResidueProperties.backgroundFrequencies
+              .get(getAlphabetType()).get(symbol);
+      float prob = (float) getMatchEmissionProbability(column, symbol);
+      informationContent += prob * Math.log(prob / freq);
+    }
+
+    informationContent = informationContent / (float) LOG2;
+
+    return informationContent;
+  }
+
+  /**
+   * Gets the file header of the .hmm file this model came from
+   * 
+   * @return
+   */
+  public String getFileHeader()
+  {
+    return fileHeader;
+  }
+
+  /**
+   * Sets the file header of this model.
+   * 
+   * @param header
+   */
+  public void setFileHeader(String header)
+  {
+    fileHeader = header;
+  }
+
+  /**
+   * Returns the symbols used in this hidden Markov model
+   * 
+   * @return
+   */
+  public String getSymbols()
+  {
+    return alphabet;
+  }
+  
+  /**
+   * Gets the node in the hidden Markov model at the specified position.
+   * 
+   * @param nodeIndex
+   *          The index of the node requested. Node 0 optionally contains the
+   *          average match emission probabilities across the entire model, and
+   *          always contains the insert emission probabilities and state
+   *          transition probabilities for the begin node. Node 1 contains the
+   *          first node in the HMM that can correspond to a column in the
+   *          alignment.
+   * @return
+   */
+  public HMMNode getNode(int nodeIndex)
+  {
+    return nodes.get(nodeIndex);
+  }
+
+  /**
+   * Returns the name of the sequence alignment on which the HMM is based.
+   * 
+   * @return
+   */
+  public String getName()
+  {
+    return fileProperties.get(HMMFile.NAME);
+  }
+  
+  /**
+   * Answers the string value of the property (parsed from an HMM file) for the
+   * given key, or null if the property is not present
+   * 
+   * @param key
+   * @return
+   */
+  public String getProperty(String key)
+  {
+    return fileProperties.get(key);
+  }
+
+  /**
+   * Answers true if the property with the given key is present with a value of
+   * "yes" (not case-sensitive), else false
+   * 
+   * @param key
+   * @return
+   */
+  public boolean getBooleanProperty(String key)
+  {
+    return YES.equalsIgnoreCase(fileProperties.get(key));
+  }
+
+  /**
+   * Returns the length of the hidden Markov model. The value returned is the
+   * LENG property if specified, else the number of nodes, excluding the begin
+   * node (which should be the same thing).
+   * 
+   * @return
+   */
+  public int getLength()
+  {
+    if (fileProperties.get(HMMFile.LENGTH) == null)
+    {
+      return nodes.size() - 1; // not counting BEGIN node
+    }
+    return Integer.parseInt(fileProperties.get(HMMFile.LENGTH));
+  }
+
+  /**
+   * Returns the value of mandatory property "ALPH" - "amino", "DNA", "RNA" are
+   * the options. Other alphabets may be added.
+   * 
+   * @return
+   */
+  public String getAlphabetType()
+  {
+    return fileProperties.get(HMMFile.ALPHABET);
+  }
+
+  /**
+   * Sets the model alphabet to the symbols in the given string (ignoring any
+   * whitespace), and returns the number of symbols
+   * 
+   * @param symbols
+   */
+  public int setAlphabet(String symbols)
+  {
+    String trimmed = symbols.toUpperCase().replaceAll("\\s", "");
+    int count = trimmed.length();
+    alphabet = trimmed;
+    symbolIndexLookup = new int['Z' - 'A' + 1];
+    Arrays.fill(symbolIndexLookup, -1);
+    int ignored = 0;
+
+    /*
+     * save the symbols in order, and a quick lookup of symbol position
+     */
+    for (short i = 0; i < count; i++)
+    {
+      char symbol = trimmed.charAt(i);
+      if (symbol >= 'A' && symbol <= 'Z'
+              && symbolIndexLookup[symbol - 'A'] == -1)
+      {
+        symbolIndexLookup[symbol - 'A'] = i;
+      }
+      else
+      {
+        System.err
+                .println(
+                        "Unexpected or duplicated character in HMM ALPHabet: "
+                                + symbol);
+        ignored++;
+      }
+    }
+    return count - ignored;
+  }
+
+  /**
+   * Answers the node of the model corresponding to an aligned column position
+   * (0...), or null if there is no such node
+   * 
+   * @param column
+   * @return
+   */
+  HMMNode getNodeForColumn(int column)
+  {
+    /*
+     * if the hmm consensus is gapped at the column,
+     * there is no corresponding node
+     */
+    if (Comparison.isGap(hmmSeq.getCharAt(column)))
+    {
+      return null;
+    }
+
+    /*
+     * find the node (if any) that is mapped to the
+     * consensus sequence residue position at the column
+     */
+    int seqPos = hmmSeq.findPosition(column);
+    int[] nodeNo = mapToHmmConsensus.getMap().locateInFrom(seqPos, seqPos);
+    if (nodeNo != null)
+    {
+      return getNode(nodeNo[0]);
+    }
+    return null;
+  }
+
+  /**
+   * Gets the match emission probability for a given symbol at a column in the
+   * alignment.
+   * 
+   * @param alignColumn
+   *          The index of the alignment column, starting at index 0. Index 0
+   *          usually corresponds to index 1 in the HMM.
+   * @param symbol
+   *          The symbol for which the desired probability is being requested.
+   * @return
+   * 
+   */
+  public double getMatchEmissionProbability(int alignColumn, char symbol)
+  {
+    HMMNode node = getNodeForColumn(alignColumn);
+    int symbolIndex = getSymbolIndex(symbol);
+    if (node != null && symbolIndex != -1)
+    {
+      return node.getMatchEmission(symbolIndex);
+    }
+    return 0D;
+  }
+
+  /**
+   * Gets the insert emission probability for a given symbol at a column in the
+   * alignment.
+   * 
+   * @param alignColumn
+   *          The index of the alignment column, starting at index 0. Index 0
+   *          usually corresponds to index 1 in the HMM.
+   * @param symbol
+   *          The symbol for which the desired probability is being requested.
+   * @return
+   * 
+   */
+  public double getInsertEmissionProbability(int alignColumn, char symbol)
+  {
+    HMMNode node = getNodeForColumn(alignColumn);
+    int symbolIndex = getSymbolIndex(symbol);
+    if (node != null && symbolIndex != -1)
+    {
+      return node.getInsertEmission(symbolIndex);
+    }
+    return 0D;
+  }
+  
+  /**
+   * Gets the state transition probability for a given symbol at a column in the
+   * alignment.
+   * 
+   * @param alignColumn
+   *          The index of the alignment column, starting at index 0. Index 0
+   *          usually corresponds to index 1 in the HMM.
+   * @param symbol
+   *          The symbol for which the desired probability is being requested.
+   * @return
+   * 
+   */
+  public double getStateTransitionProbability(int alignColumn,
+          int transition)
+  {
+    HMMNode node = getNodeForColumn(alignColumn);
+    if (node != null)
+    {
+      return node.getStateTransition(transition);
+    }
+    return 0D;
+  }
+  
+  /**
+   * Returns the sequence position linked to the node at the given index. This
+   * corresponds to an aligned column position (counting from 1).
+   * 
+   * @param nodeIndex
+   *          The index of the node, starting from index 1. Index 0 is the begin
+   *          node, which does not correspond to a column in the alignment.
+   * @return
+   */
+  public int getNodeMapPosition(int nodeIndex)
+  {
+    return nodes.get(nodeIndex).getResidueNumber();
+  }
+  
+  /**
+   * Returns the consensus residue at the specified node.
+   * 
+   * @param nodeIndex
+   *          The index of the specified node.
+   * @return
+   */
+  public char getConsensusResidue(int nodeIndex)
+  {
+   char value = nodes.get(nodeIndex).getConsensusResidue();
+   return value;
+  }
+  
+  /**
+   * Returns the reference annotation at the specified node.
+   * 
+   * @param nodeIndex
+   *          The index of the specified node.
+   * @return
+   */
+  public char getReferenceAnnotation(int nodeIndex)
+  {
+   char value = nodes.get(nodeIndex).getReferenceAnnotation();
+   return value;
+  }
+  
+  /**
+   * Returns the mask value at the specified node.
+   * 
+   * @param nodeIndex
+   *          The index of the specified node.
+   * @return
+   */
+  public char getMaskedValue(int nodeIndex)
+  {
+   char value = nodes.get(nodeIndex).getMaskValue();
+   return value;
+  }
+  
+  /**
+   * Returns the consensus structure at the specified node.
+   * 
+   * @param nodeIndex
+   *          The index of the specified node.
+   * @return
+   */
+  public char getConsensusStructure(int nodeIndex)
+  {
+   char value = nodes.get(nodeIndex).getConsensusStructure();
+   return value;
+  }
+  
+  /**
+   * Sets a property read from an HMM file
+   * 
+   * @param key
+   * @param value
+   */
+  public void setProperty(String key, String value)
+  {
+    fileProperties.put(key, value);
+  }
+
+  /**
+   * Temporary implementation, should not be used.
+   * 
+   * @return
+   */
+  public String getViterbi()
+  {
+    String value;
+    value = fileProperties.get(HMMFile.VITERBI);
+    return value;
+  }
+
+  /**
+   * Temporary implementation, should not be used.
+   * 
+   * @return
+   */
+  public String getMSV()
+  {
+    String value;
+    value = fileProperties.get(HMMFile.MSV);
+    return value;
+  }
+
+  /**
+   * Temporary implementation, should not be used.
+   * 
+   * @return
+   */
+  public String getForward()
+  {
+    String value;
+    value = fileProperties.get(HMMFile.FORWARD);
+    return value;
+  }
+
+  /**
+   * Constructs the consensus sequence based on the most probable symbol at each
+   * position. Gap characters are inserted for discontinuities in the node map
+   * numbering (if provided), else an ungapped sequence is generated.
+   * <p>
+   * A mapping between the HMM nodes and residue positions of the sequence is
+   * also built and saved.
+   * 
+   * @return
+   */
+  void buildConsensusSequence()
+  {
+    List<int[]> toResidues = new ArrayList<>();
+
+    /*
+     * if the HMM provided a map to sequence, use those start/end values,
+     * else just treat it as for a contiguous sequence numbered from 1
+     */
+    boolean hasMap = getBooleanProperty(HMMFile.MAP);
+    int start = hasMap ? getNode(1).getResidueNumber() : 1;
+    int endResNo = hasMap ? getNode(nodes.size() - 1).getResidueNumber()
+            : (start + getLength() - 1);
+    char[] sequence = new char[endResNo];
+
+    int lastResNo = start - 1;
+    int seqOffset = -1;
+    int gapCount = 0;
+
+
+    for (int seqN = 0; seqN < start; seqN++)
+    {
+      sequence[seqN] = GAP_DASH;
+      seqOffset++;
+    }
+    
+    for (int nodeNo = 1; nodeNo < nodes.size(); nodeNo++)
+    {
+      HMMNode node = nodes.get(nodeNo);
+      final int resNo = hasMap ? node.getResidueNumber() : lastResNo + 1;
+
+      /*
+       * insert gaps if map numbering is not continuous
+       */
+      while (resNo > lastResNo + 1)
+      {
+        sequence[seqOffset++] = GAP_DASH;
+        lastResNo++;
+        gapCount++;
+      }
+      char consensusResidue = node.getConsensusResidue();
+      if (GAP_DASH == consensusResidue)
+      {
+        /*
+         * no residue annotation in HMM - scan for the symbol
+         * with the highest match emission probability
+         */
+        int symbolIndex = node.getMaxMatchEmissionIndex();
+        consensusResidue = alphabet.charAt(symbolIndex);
+        if (node.getMatchEmission(symbolIndex) < 0.5D)
+        {
+          // follow convention of lower case if match emission prob < 0.5
+          consensusResidue = Character.toLowerCase(consensusResidue);
+        }
+      }
+      sequence[seqOffset++] = consensusResidue;
+      lastResNo = resNo;
+    }
+
+    Sequence seq = new Sequence(getName(), sequence, start,
+            lastResNo - gapCount);
+    seq.createDatasetSequence();
+    seq.setHMM(this);
+    this.hmmSeq = seq;
+
+    /*
+     * construct and store Mapping of nodes to residues
+     * note as constructed this is just an identity mapping, 
+     * but it allows for greater flexibility in future
+     */
+    List<int[]> fromNodes = new ArrayList<>();
+    fromNodes.add(new int[] { 1, getLength() });
+    toResidues.add(new int[] { seq.getStart(), seq.getEnd() });
+    MapList mapList = new MapList(fromNodes, toResidues, 1, 1);
+    mapToHmmConsensus = new Mapping(seq.getDatasetSequence(), mapList);
+  }
+
+
+  /**
+   * Answers the aligned consensus sequence for the profile. Note this will
+   * return null if called before <code>setNodes</code> has been called.
+   * 
+   * @return
+   */
+  public SequenceI getConsensusSequence()
+  {
+    return hmmSeq;
+  }
+
+  /**
+   * Answers the index position (0...) of the given symbol, or -1 if not a valid
+   * symbol for this HMM
+   * 
+   * @param symbol
+   * @return
+   */
+  private int getSymbolIndex(char symbol)
+  {
+    /*
+     * symbolIndexLookup holds the index for 'A' to 'Z'
+     */
+    char c = Character.toUpperCase(symbol);
+    if ('A' <= c && c <= 'Z')
+    {
+      return symbolIndexLookup[c - 'A'];
+    }
+    return -1;
+  }
+
+  /**
+   * Sets the nodes of this HMM, and also extracts the HMM consensus sequence
+   * and a mapping between node numbers and sequence positions
+   * 
+   * @param nodeList
+   */
+  public void setNodes(List<HMMNode> nodeList)
+  {
+    nodes = nodeList;
+    if (nodes.size() > 1)
+    {
+      buildConsensusSequence();
+    }
+  }
+
+  /**
+   * Sets the aligned consensus sequence this HMM is the model for
+   * 
+   * @param hmmSeq
+   */
+  public void setHmmSeq(SequenceI hmmSeq)
+  {
+    this.hmmSeq = hmmSeq;
+  }
+
+  public void setBackgroundFrequencies(Map<Character, Float> bkgdFreqs)
+  {
+    backgroundFrequencies = bkgdFreqs;
+  }
+
+  public void setBackgroundFrequencies(ResidueCount bkgdFreqs)
+  {
+    backgroundFrequencies = new HashMap<>();
+
+    int total = bkgdFreqs.getTotalResidueCount();
+
+    for (char c : bkgdFreqs.getSymbolCounts().symbols)
+    {
+      backgroundFrequencies.put(c, bkgdFreqs.getCount(c) * 1f / total);
+    }
+
+  }
+
+  public Map<Character, Float> getBackgroundFrequencies()
+  {
+    return backgroundFrequencies;
+  }
+
+}
+
index 74eb887..047b7e7 100644 (file)
@@ -25,6 +25,8 @@ import jalview.util.Format;
 import jalview.util.QuickSort;
 import jalview.util.SparseCount;
 
+import java.util.List;
+
 /**
  * A class to count occurrences of residues in a profile, optimised for speed
  * and memory footprint.
@@ -148,6 +150,24 @@ public class ResidueCount
   }
 
   /**
+   * A constructor that counts frequency of all symbols (including gaps) in the
+   * sequences (not case-sensitive)
+   * 
+   * @param sequences
+   */
+  public ResidueCount(List<SequenceI> sequences)
+  {
+    this();
+    for (SequenceI seq : sequences)
+    {
+      for (int i = 0; i < seq.getLength(); i++)
+      {
+        add(seq.getCharAt(i));
+      }
+    }
+  }
+
+  /**
    * 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.
@@ -640,4 +660,19 @@ public class ResidueCount
     sb.append("]");
     return sb.toString();
   }
+
+  /**
+   * Answers the total count for all symbols (excluding gaps)
+   * 
+   * @return
+   */
+  public int getTotalResidueCount()
+  {
+    int total = 0;
+    for (char symbol : this.getSymbolCounts().symbols)
+    {
+      total += getCount(symbol);
+    }
+    return total;
+  }
 }
index 552349f..009a290 100755 (executable)
@@ -27,6 +27,7 @@ import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 import jalview.util.StringUtils;
+import jalview.workers.InformationThread;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -82,6 +83,10 @@ public class Sequence extends ASequence implements SequenceI
 
   private String vamsasId;
 
+  HiddenMarkovModel hmm;
+
+  boolean isHMMConsensusSequence = false;
+
   private DBModList<DBRefEntry> dbrefs; // controlled access
 
   /**
@@ -361,6 +366,11 @@ public class Sequence extends ASequence implements SequenceI
         this.addPDBId(new PDBEntry(pdb));
       }
     }
+    if (seq.getHMM() != null)
+    {
+      this.hmm = new HiddenMarkovModel(seq.getHMM(), this);
+    }
+
   }
 
   @Override
@@ -1069,7 +1079,8 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public ContiguousI findPositions(int fromColumn, int toColumn)
   {
-    if (toColumn < fromColumn || fromColumn < 1)
+    fromColumn = Math.max(fromColumn, 1);
+    if (toColumn < fromColumn)
     {
       return null;
     }
@@ -1804,7 +1815,8 @@ public class Sequence extends ASequence implements SequenceI
     {
       for (AlignmentAnnotation ann : annotation)
       {
-        if (ann.calcId != null && ann.calcId.equals(calcId)
+        String id = ann.getCalcId();
+        if (id != null && id.equals(calcId)
                 && ann.label != null && ann.label.equals(label))
         {
           result.add(ann);
@@ -1924,6 +1936,34 @@ public class Sequence extends ASequence implements SequenceI
     }
   }
 
+  @Override
+  public HiddenMarkovModel getHMM()
+  {
+    return hmm;
+  }
+
+  @Override
+  public void setHMM(HiddenMarkovModel hmm)
+  {
+    this.hmm = hmm;
+  }
+
+  @Override
+  public boolean hasHMMAnnotation()
+  {
+    if (this.annotation == null) {
+      return false;
+    }
+    for (AlignmentAnnotation ann : annotation)
+    {
+      if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * {@inheritDoc}
    */
@@ -2088,4 +2128,10 @@ public class Sequence extends ASequence implements SequenceI
     // otherwise, sequence was completely hidden
     return 0;
   }
+
+  @Override
+  public boolean hasHMMProfile()
+  {
+    return hmm != null;
+  }
 }
index e2bb5a6..aa15d1f 100644 (file)
@@ -83,4 +83,12 @@ public interface SequenceCollectionI
    * @return
    */
   boolean isNucleotide();
+
+  /**
+   * Returns the (possibly empty) list of HMM consensus sequences in the
+   * collection
+   * 
+   * @return
+   */
+  List<SequenceI> getHmmSequences();
 }
index 861595c..0431708 100755 (executable)
@@ -25,6 +25,8 @@ import jalview.analysis.Conservation;
 import jalview.renderer.ResidueShader;
 import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
+import jalview.util.MessageManager;
+import jalview.workers.InformationThread;
 
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
@@ -43,11 +45,10 @@ import java.util.Map;
 public class SequenceGroup implements AnnotatedCollectionI
 {
   // TODO ideally this event notification functionality should be separated into
-  // a
-  // subclass of ViewportProperties similarly to ViewportRanges. Done here as
-  // quick fix for JAL-2665
+  // a subclass of ViewportProperties similarly to ViewportRanges.
+  // Done here as a quick fix for JAL-2665
   public static final String SEQ_GROUP_CHANGED = "Sequence group changed";
-
+  
   protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
@@ -65,40 +66,46 @@ public class SequenceGroup implements AnnotatedCollectionI
   String groupName;
 
   String description;
-
+  
   Conservation conserve;
 
+  Conservation conservationData;
+
+  ProfilesI consensusProfiles;
+
+  ProfilesI hmmProfiles;
+
   boolean displayBoxes = true;
 
   boolean displayText = true;
 
   boolean colourText = false;
 
-  /**
-   * True if the group is defined as a group on the alignment, false if it is
-   * just a selection.
+  /*
+   * true if the group is defined as a group on the alignment, false if it is
+   * just a selection
    */
   boolean isDefined = false;
 
-  /**
+  /*
    * after Olivier's non-conserved only character display
    */
   boolean showNonconserved = false;
 
-  /**
-   * group members
+  /*
+   * sequences in the group
    */
   private List<SequenceI> sequences;
 
-  /**
+  /*
    * representative sequence for this group (if any)
    */
   private SequenceI seqrep = null;
 
   int width = -1;
 
-  /**
-   * Colourscheme applied to group if any
+  /*
+   * colour scheme applied to group if any
    */
   public ResidueShaderI cs;
 
@@ -122,22 +129,29 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   public Color textColour2 = Color.white;
 
-  /**
-   * consensus calculation property
+  /*
+   * properties for consensus annotation
    */
   private boolean ignoreGapsInConsensus = true;
 
-  /**
-   * consensus calculation property
-   */
   private boolean showSequenceLogo = false;
 
-  /**
-   * flag indicating if logo should be rendered normalised
-   */
   private boolean normaliseSequenceLogo;
 
   /*
+   * properties for HMM information annotation
+   */
+  private boolean hmmIgnoreBelowBackground = true;
+
+  private boolean hmmUseInfoLetterHeight;
+
+  private boolean hmmShowSequenceLogo;
+
+  private boolean hmmNormaliseSequenceLogo;
+
+  private boolean hmmShowHistogram;
+
+  /*
    * visibility of rows or represented rows covered by group
    */
   private boolean hidereps = false;
@@ -145,18 +159,22 @@ public class SequenceGroup implements AnnotatedCollectionI
   /*
    * visibility of columns intersecting this group
    */
-  private boolean hidecols = false;
+  private boolean hidecols;
 
   AlignmentAnnotation consensus = null;
 
   AlignmentAnnotation conservation = null;
 
+  private AlignmentAnnotation hmmInformation;
+  
   private boolean showConsensusHistogram;
-
+  
   private AnnotatedCollectionI context;
 
+
   /**
-   * Creates a new SequenceGroup object.
+   * Constructor, assigning a generated default name of "JGroup:" with object
+   * hashcode appended
    */
   public SequenceGroup()
   {
@@ -199,10 +217,13 @@ public class SequenceGroup implements AnnotatedCollectionI
    * copy constructor
    * 
    * @param seqsel
+   * @param keepsequences
+   *          if false do not add sequences from seqsel to new instance
    */
   public SequenceGroup(SequenceGroup seqsel)
   {
     this();
+
     if (seqsel != null)
     {
       sequences = new ArrayList<>();
@@ -228,6 +249,9 @@ public class SequenceGroup implements AnnotatedCollectionI
       showSequenceLogo = seqsel.showSequenceLogo;
       normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
       showConsensusHistogram = seqsel.showConsensusHistogram;
+      hmmShowSequenceLogo = seqsel.hmmShowSequenceLogo;
+      hmmNormaliseSequenceLogo = seqsel.hmmNormaliseSequenceLogo;
+      hmmShowHistogram = seqsel.hmmShowHistogram;
       idColour = seqsel.idColour;
       outlineColour = seqsel.outlineColour;
       seqrep = seqsel.seqrep;
@@ -236,8 +260,12 @@ public class SequenceGroup implements AnnotatedCollectionI
       thresholdTextColour = seqsel.thresholdTextColour;
       width = seqsel.width;
       ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus;
+      hmmIgnoreBelowBackground = seqsel.hmmIgnoreBelowBackground;
+      hmmUseInfoLetterHeight = seqsel.hmmUseInfoLetterHeight;
       if (seqsel.conserve != null)
       {
+        // todo avoid doing this if we don't actually want derived calculations
+        // !
         recalcConservation(); // safer than
         // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ??
       }
@@ -580,8 +608,9 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * calculate residue conservation for group - but only if necessary. returns
-   * true if the calculation resulted in a visible change to group
+   * Recalculates column consensus, conservation, and HMM annotation for the
+   * group (as applicable). Returns true if the calculation resulted in a
+   * visible change to group.
    * 
    * @param defer
    *          when set, colourschemes for this group are not refreshed after
@@ -589,7 +618,8 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public boolean recalcConservation(boolean defer)
   {
-    if (cs == null && consensus == null && conservation == null)
+    if (cs == null && consensus == null && conservation == null
+            && hmmInformation == null)
     {
       return false;
     }
@@ -600,6 +630,16 @@ public class SequenceGroup implements AnnotatedCollectionI
     {
       ProfilesI cnsns = AAFrequency.calculate(sequences, startRes,
               endRes + 1, showSequenceLogo);
+      if (hmmInformation != null)
+      {
+        HiddenMarkovModel hmm = hmmInformation.sequenceRef.getHMM();
+
+        ProfilesI info = AAFrequency.calculateHMMProfiles(hmm,
+                (endRes + 1) - startRes, startRes, endRes + 1,
+                hmmIgnoreBelowBackground, hmmUseInfoLetterHeight);
+        _updateInformationRow(info);
+        upd = true;
+      }
       if (consensus != null)
       {
         _updateConsensusRow(cnsns, sequences.size());
@@ -700,6 +740,33 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
+   * Recalculates the information content on the HMM annotation
+   * 
+   * @param cnsns
+   */
+  private void _updateInformationRow(ProfilesI cnsns)
+  {
+    if (hmmInformation == null)
+    {
+      createInformationAnnotation();
+    }
+    hmmInformation.description = MessageManager
+            .getString("label.information_description");
+    setHmmProfiles(cnsns);
+    // preserve width if already set
+    int aWidth = (hmmInformation.annotations != null)
+            ? (endRes < hmmInformation.annotations.length
+                    ? hmmInformation.annotations.length : endRes + 1)
+            : endRes + 1;
+    hmmInformation.annotations = null;
+    hmmInformation.annotations = new Annotation[aWidth]; // should be alignment
+                                                      // width
+    hmmInformation.setCalcId(InformationThread.HMM_CALC_ID);
+    AAFrequency.completeInformation(hmmInformation, cnsns, startRes,
+            endRes + 1);
+  }
+
+  /**
    * @param s
    *          sequence to either add or remove from group
    * @param recalc
@@ -1156,6 +1223,22 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
+   * Creates the Hidden Markov Model annotation for this group
+   */
+  void createInformationAnnotation()
+  {
+    hmmInformation = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+            6.25f, AlignmentAnnotation.BAR_GRAPH);
+    hmmInformation.hasText = true;
+    hmmInformation.autoCalculated = false;
+    hmmInformation.groupRef = this;
+    hmmInformation.label = getName();
+    hmmInformation.description = MessageManager
+            .getString("label.information_description");
+    hmmInformation.setCalcId(InformationThread.HMM_CALC_ID);
+  }
+
+  /**
    * set this alignmentAnnotation object as the one used to render consensus
    * annotation
    * 
@@ -1242,6 +1325,26 @@ public class SequenceGroup implements AnnotatedCollectionI
     return ignoreGapsInConsensus;
   }
 
+  public void setIgnoreBelowBackground(boolean state)
+  {
+    hmmIgnoreBelowBackground = state;
+  }
+
+  public boolean isIgnoreBelowBackground()
+  {
+    return hmmIgnoreBelowBackground;
+  }
+
+  public void setInfoLetterHeight(boolean state)
+  {
+    hmmUseInfoLetterHeight = state;
+  }
+
+  public boolean isUseInfoLetterHeight()
+  {
+    return hmmUseInfoLetterHeight;
+  }
+
   /**
    * @param showSequenceLogo
    *          indicates if a sequence logo is shown for consensus annotation
@@ -1485,4 +1588,70 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
   }
+
+  public boolean isShowInformationHistogram()
+  {
+    return hmmShowHistogram;
+  }
+
+  public void setShowInformationHistogram(boolean state)
+  {
+    if (hmmShowHistogram != state && hmmInformation != null)
+    {
+      this.hmmShowHistogram = state;
+      // recalcConservation(); TODO don't know what to do here next
+    }
+    this.hmmShowHistogram = state;
+  }
+
+  public boolean isShowHMMSequenceLogo()
+  {
+    return hmmShowSequenceLogo;
+  }
+
+  public void setShowHMMSequenceLogo(boolean state)
+  {
+    hmmShowSequenceLogo = state;
+  }
+
+  public boolean isNormaliseHMMSequenceLogo()
+  {
+    return hmmNormaliseSequenceLogo;
+  }
+
+  public void setNormaliseHMMSequenceLogo(boolean state)
+  {
+    hmmNormaliseSequenceLogo = state;
+  }
+
+  public ProfilesI getConsensusData()
+  {
+    return consensusProfiles;
+  }
+
+  public ProfilesI getHmmProfiles()
+  {
+    return hmmProfiles;
+  }
+
+  public void setHmmProfiles(ProfilesI hmmProfiles)
+  {
+    this.hmmProfiles = hmmProfiles;
+  }
+
+  @Override
+  public List<SequenceI> getHmmSequences()
+  {
+    List<SequenceI> result = new ArrayList<>();
+    for (int i = 0; i < sequences.size(); i++)
+    {
+      SequenceI seq = sequences.get(i);
+      if (seq.hasHMMProfile())
+      {
+        result.add(seq);
+      }
+    }
+    return result;
+  }
+
 }
index 933f332..72ce22c 100755 (executable)
@@ -48,6 +48,10 @@ public interface SequenceI extends ASequenceI
    */
   public void setName(String name);
 
+  public HiddenMarkovModel getHMM();
+
+  public void setHMM(HiddenMarkovModel hmm);
+
   /**
    * Get the display name
    */
@@ -215,10 +219,10 @@ public interface SequenceI extends ASequenceI
    * from 1), or null if no residues are included in the range
    * 
    * @param fromColum
-   *          - first column base 1
+   *          - first column base 1. (0 and negative positions are rounded up)
    * @param toColumn
    *          - last column, base 1
-   * @return
+   * @return null if fromColum>toColumn
    */
   public ContiguousI findPositions(int fromColum, int toColumn);
 
@@ -506,6 +510,12 @@ public interface SequenceI extends ASequenceI
   public List<DBRefEntry> getPrimaryDBRefs();
 
   /**
+   * Answers true if the sequence has annotation for Hidden Markov Model
+   * information content, else false
+   */
+  boolean hasHMMAnnotation();
+
+  /**
    * Returns a (possibly empty) list of sequence features that overlap the given
    * alignment column range, optionally restricted to one or more specified
    * feature types. If the range is all gaps, then features which enclose it are
@@ -542,7 +552,7 @@ public interface SequenceI extends ASequenceI
    * @param c1
    * @param c2
    */
-  public int replace(char c1, char c2);
+  int replace(char c1, char c2);
 
   /**
    * Answers the GeneLociI, or null if not known
@@ -572,7 +582,7 @@ public interface SequenceI extends ASequenceI
    *          the iterator to use
    * @return a String corresponding to the sequence
    */
-  public String getSequenceStringFromIterator(Iterator<int[]> it);
+  String getSequenceStringFromIterator(Iterator<int[]> it);
 
   /**
    * Locate the first position in this sequence which is not contained in an
@@ -582,8 +592,15 @@ public interface SequenceI extends ASequenceI
    *          iterator over regions
    * @return first residue not contained in regions
    */
+
   public int firstResidueOutsideIterator(Iterator<int[]> it);
 
 
+  /**
+   * Answers true if this sequence has an associated Hidden Markov Model
+   * 
+   * @return
+   */
+  boolean hasHMMProfile();
 }
 
index 5f7d0d4..9d8407a 100644 (file)
@@ -64,6 +64,13 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.ColourMenuHelper.ColourChangeListener;
 import jalview.gui.ViewSelectionMenu.ViewSetProvider;
+import jalview.hmmer.HMMAlign;
+import jalview.hmmer.HMMBuild;
+import jalview.hmmer.HMMERParamStore;
+import jalview.hmmer.HMMERPreset;
+import jalview.hmmer.HMMSearch;
+import jalview.hmmer.HmmerCommand;
+import jalview.hmmer.JackHMMER;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
 import jalview.io.BackupFiles;
@@ -98,10 +105,23 @@ import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.ServiceChangeListener;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.jws2.PreferredServiceRegistry;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
 import jalview.ws.seqfetcher.DbSourceProxy;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -130,12 +150,14 @@ import java.awt.event.MouseEvent;
 import java.awt.print.PageFormat;
 import java.awt.print.PrinterJob;
 import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.PrintWriter;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Deque;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -154,6 +176,8 @@ import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
 
 import ext.vamsas.ServiceHandle;
 
@@ -164,8 +188,9 @@ import ext.vamsas.ServiceHandle;
  * @version $Revision$
  */
 @SuppressWarnings("serial")
-public class AlignFrame extends GAlignFrame implements DropTargetListener,
-        IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener
+public class AlignFrame extends GAlignFrame
+        implements DropTargetListener, IProgressIndicator,
+        AlignViewControllerGuiI, ColourChangeListener, ServiceChangeListener
 {
 
   public static int frameCount;
@@ -195,6 +220,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   String fileName = null;
 
+  /**
+   * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping
+   */
   File fileObject;
 
   private int id;
@@ -357,7 +385,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   void init()
   {
-
     boolean newPanel = (alignPanel == null);
     viewport.setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
     if (newPanel)
@@ -434,9 +461,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (Desktop.getDesktopPane() != null)
     {
       this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
+      addServiceListeners();
       if (!Platform.isJS())
       {
-        addServiceListeners();
       }
       setGUINucleotide();
     }
@@ -855,6 +882,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         ap.av.updateConservation(ap);
         ap.av.updateConsensus(ap);
         ap.av.updateStrucConsensus(ap);
+        ap.av.initInformationWorker(ap);
       }
     }
   }
@@ -874,58 +902,43 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return viewport;
   }
 
+  @Override
+  public void servicesChanged(WSDiscovererI discoverer,
+          Collection<? extends ServiceWithParameters> services)
+  {
+    buildWebServicesMenu();
+  }
+
   /* Set up intrinsic listeners for dynamically generated GUI bits. */
   private void addServiceListeners()
   {
-    final java.beans.PropertyChangeListener thisListener;
-    Desktop.getInstance().addJalviewPropertyChangeListener("services",
-            thisListener = new java.beans.PropertyChangeListener()
-            {
-
-              @Override
-              public void propertyChange(PropertyChangeEvent evt)
-              {
-                // // System.out.println("Discoverer property change.");
-                // if (evt.getPropertyName().equals("services"))
-                {
-                  SwingUtilities.invokeLater(new Runnable()
-                  {
-
-                    @Override
-                    public void run()
-                    {
-                      System.err.println(
-                              "Rebuild WS Menu for service change");
-                      BuildWebServiceMenu();
-                    }
-
-                  });
-                }
-              }
-            });
-    addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+    if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
     {
-
+      WSDiscovererI discoverer = SlivkaWSDiscoverer.getInstance();
+      discoverer.addServiceChangeListener(this);
+    }
+    if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
+    {
+      WSDiscovererI discoverer = Jws2Discoverer.getInstance();
+      discoverer.addServiceChangeListener(this);
+    }
+    // legacy event listener for compatibility with jws1
+    PropertyChangeListener legacyListener = (changeEvent) -> {
+      buildWebServicesMenu();
+    };
+    Desktop.getInstance().addJalviewPropertyChangeListener("services",legacyListener);
+    
+    addInternalFrameListener(new InternalFrameAdapter() {
       @Override
-      public void internalFrameClosed(
-              javax.swing.event.InternalFrameEvent evt)
-      {
-        // System.out.println("deregistering discoverer listener");
-        Desktop.getInstance().removeJalviewPropertyChangeListener(
-                "services", thisListener);
+      public void internalFrameClosed(InternalFrameEvent e) {
+        System.out.println("deregistering discoverer listener");
+        SlivkaWSDiscoverer.getInstance().removeServiceChangeListener(AlignFrame.this);
+        Jws2Discoverer.getInstance().removeServiceChangeListener(AlignFrame.this);
+        Desktop.getInstance().removeJalviewPropertyChangeListener("services", legacyListener);
         closeMenuItem_actionPerformed(true);
       }
     });
-    // Finally, build the menu once to get current service state
-    new Thread(new Runnable()
-    {
-
-      @Override
-      public void run()
-      {
-        BuildWebServiceMenu();
-      }
-    }).start();
+    buildWebServicesMenu();
   }
 
   /**
@@ -999,6 +1012,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     showConsensusHistogram.setSelected(av.isShowConsensusHistogram());
     showSequenceLogo.setSelected(av.isShowSequenceLogo());
     normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo());
+    showInformationHistogram.setSelected(av.isShowInformationHistogram());
+    showHMMSequenceLogo.setSelected(av.isShowHMMSequenceLogo());
+    normaliseHMMSequenceLogo.setSelected(av.isNormaliseHMMSequenceLogo());
 
     ColourMenuHelper.setColourSelected(colourMenu,
             av.getGlobalColourScheme());
@@ -1043,6 +1059,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     progressBar.setProgressBar(message, id);
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    progressBar.removeProgressBar(id);
+  }
 
   @Override
   public void registerHandler(final long id,
@@ -1101,6 +1123,257 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
+  public void hmmBuild_actionPerformed(boolean withDefaults)
+  {
+    if (!alignmentIsSufficient(1))
+    {
+      return;
+    }
+
+    /*
+     * get default parameters, and optionally show a dialog
+     * to allow them to be modified
+     */
+    ParamDatastoreI store = HMMERParamStore.forBuild(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
+    {
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
+    }
+    new Thread(new HMMBuild(this, args)).start();
+  }
+
+  @Override
+  public void hmmAlign_actionPerformed(boolean withDefaults)
+  {
+    if (!(checkForHMM() && alignmentIsSufficient(2)))
+    {
+      return;
+    }
+
+    /*
+     * get default parameters, and optionally show a dialog
+     * to allow them to be modified
+     */
+    ParamDatastoreI store = HMMERParamStore.forAlign(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
+    {
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
+    }
+    new Thread(new HMMAlign(this, args)).start();
+  }
+
+  @Override
+  public void hmmSearch_actionPerformed(boolean withDefaults)
+  {
+    if (!checkForHMM())
+    {
+      return;
+    }
+
+    /*
+     * get default parameters, and (if requested) show 
+     * dialog to allow modification
+     */
+    ParamDatastoreI store = HMMERParamStore.forSearch(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
+    {
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
+    }
+    new Thread(new HMMSearch(this, args)).start();
+    alignPanel.repaint();
+  }
+
+  @Override
+  public void jackhmmer_actionPerformed(boolean withDefaults)
+  {
+
+    /*
+     * get default parameters, and (if requested) show 
+     * dialog to allow modification
+     */
+
+    ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
+    {
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
+    }
+    new Thread(new JackHMMER(this, args)).start();
+    alignPanel.repaint();
+
+  }
+
+  /**
+   * Checks if the alignment has at least one hidden Markov model, if not shows
+   * a dialog advising to run hmmbuild or load an HMM profile
+   * 
+   * @return
+   */
+  private boolean checkForHMM()
+  {
+    if (viewport.getAlignment().getHmmSequences().isEmpty())
+    {
+      JOptionPane.showMessageDialog(this,
+              MessageManager.getString("warn.no_hmm"));
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  protected void filterByEValue_actionPerformed()
+  {
+    viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff"));
+  }
+
+  @Override
+  protected void filterByScore_actionPerformed()
+  {
+    viewport.filterByScore(inputDouble("Enter Bit Score Threshold"));
+  }
+
+  private double inputDouble(String message)
+  {
+    String str = null;
+    Double d = null;
+    while (d == null || d <= 0)
+    {
+      str = JOptionPane.showInputDialog(this.alignPanel, message);
+      try
+      {
+        d = Double.valueOf(str);
+      } catch (NumberFormatException e)
+      {
+      }
+    }
+    return d;
+  }
+
+  /**
+   * Checks if the alignment contains the required number of sequences.
+   * 
+   * @param required
+   * @return
+   */
+  public boolean alignmentIsSufficient(int required)
+  {
+    if (getViewport().getSequenceSelection().length < required)
+    {
+      JOptionPane.showMessageDialog(this,
+              MessageManager.getString("label.not_enough_sequences"));
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Opens a file browser and adds the selected file, if in Fasta, Stockholm or
+   * Pfam format, to the list held under preference key "HMMSEARCH_DBS" (as a
+   * comma-separated list)
+   */
+  @Override
+  public void addDatabase_actionPerformed() throws IOException
+  {
+    if (Cache.getProperty(Preferences.HMMSEARCH_DBS) == null)
+    {
+      Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
+    }
+
+    String path = openFileChooser(false);
+    if (path != null && new File(path).exists())
+    {
+      IdentifyFile identifier = new IdentifyFile();
+      FileFormatI format = identifier.identify(path, DataSourceType.FILE);
+      if (format == FileFormat.Fasta || format == FileFormat.Stockholm
+              || format == FileFormat.Pfam)
+      {
+        String currentDbPaths = Cache
+                .getProperty(Preferences.HMMSEARCH_DBS);
+        currentDbPaths += Preferences.COMMA + path;
+        Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths);
+      }
+      else
+      {
+        JOptionPane.showMessageDialog(this,
+                MessageManager.getString("warn.invalid_format"));
+      }
+    }
+  }
+
+  /**
+   * Opens a file chooser, optionally restricted to selecting folders
+   * (directories) only. Answers the path to the selected file or folder, or
+   * null if none is chosen.
+   * 
+   * @param
+   * @return
+   */
+  protected String openFileChooser(boolean forFolder)
+  {
+    // TODO duplicates GPreferences method - relocate to JalviewFileChooser?
+    String choice = null;
+    JFileChooser chooser = new JFileChooser();
+    if (forFolder)
+    {
+      chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+    }
+    chooser.setDialogTitle(
+            MessageManager.getString("label.open_local_file"));
+    chooser.setToolTipText(MessageManager.getString("action.open"));
+
+    int value = chooser.showOpenDialog(this);
+
+    if (value == JFileChooser.APPROVE_OPTION)
+    {
+      choice = chooser.getSelectedFile().getPath();
+    }
+    return choice;
+  }
+
+  @Override
   public void reload_actionPerformed(ActionEvent e)
   {
     if (fileName == null && fileObject == null)
@@ -1570,6 +1843,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   @Override
   public void associatedData_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
     final JalviewFileChooser chooser = new JalviewFileChooser(
             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
@@ -2070,10 +2344,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param e
    *          DOCUMENT ME!
+   * @throws InterruptedException
+   * @throws IOException
    */
 
   @Override
   protected void pasteNew_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
     paste(true);
   }
@@ -2083,10 +2360,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param e
    *          DOCUMENT ME!
+   * @throws InterruptedException
+   * @throws IOException
    */
 
   @Override
   protected void pasteThis_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
     paste(false);
   }
@@ -2096,9 +2376,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param newAlignment
    *          true to paste to a new alignment, otherwise add to this.
+   * @throws InterruptedException
+   * @throws IOException
    */
-
-  void paste(boolean newAlignment)
+  void paste(boolean newAlignment) throws IOException, InterruptedException
   {
     boolean externalPaste = true;
     try
@@ -2427,7 +2708,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       System.out.println("Exception whilst pasting: " + ex);
       // could be anything being pasted in here
     }
-
   }
 
   @Override
@@ -3794,6 +4074,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignPanel.paintAlignment(true, false);
   }
 
+  @Override
+  public void sortEValueMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByEValue(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+
+  @Override
+  public void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByBitScore(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+
   /**
    * DOCUMENT ME!
    * 
@@ -4015,34 +4317,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
     if (viewport.getAlignment().getAlignmentAnnotation()
-            .hashCode() != _annotationScoreVectorHash)
+            .hashCode() == _annotationScoreVectorHash)
+    {
+      return;
+    }
+
+    sortByAnnotScore.removeAll();
+    Set<String> scoreSorts = new HashSet<>();
+    for (SequenceI sqa : viewport.getAlignment().getSequences())
     {
-      sortByAnnotScore.removeAll();
-      // almost certainly a quicker way to do this - but we keep it simple
-      Hashtable<String, String> scoreSorts = new Hashtable<>();
-      AlignmentAnnotation aann[];
-      for (SequenceI sqa : viewport.getAlignment().getSequences())
+      AlignmentAnnotation[] anns = sqa.getAnnotation();
+      for (int i = 0; anns != null && i < anns.length; i++)
       {
-        aann = sqa.getAnnotation();
-        for (int i = 0; aann != null && i < aann.length; i++)
+        AlignmentAnnotation aa = anns[i];
+        if (aa != null && aa.hasScore() && aa.sequenceRef != null)
         {
-          if (aann[i].hasScore() && aann[i].sequenceRef != null)
-          {
-            scoreSorts.put(aann[i].label, aann[i].label);
-          }
+          scoreSorts.add(aa.label);
         }
       }
-      Enumeration<String> labels = scoreSorts.keys();
-      while (labels.hasMoreElements())
-      {
-        addSortByAnnotScoreMenuItem(sortByAnnotScore, labels.nextElement());
-      }
-      sortByAnnotScore.setVisible(scoreSorts.size() > 0);
-      scoreSorts.clear();
-
-      _annotationScoreVectorHash = viewport.getAlignment()
-              .getAlignmentAnnotation().hashCode();
     }
+    for (String label : scoreSorts)
+    {
+      addSortByAnnotScoreMenuItem(sortByAnnotScore, label);
+    }
+    sortByAnnotScore.setVisible(!scoreSorts.isEmpty());
+
+    _annotationScoreVectorHash = viewport.getAlignment()
+            .getAlignmentAnnotation().hashCode();
   }
 
   /**
@@ -4324,185 +4625,80 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return tp;
   }
 
-  private boolean buildingMenu = false;
-
   /**
-   * Generates menu items and listener event actions for web service clients
-   * 
+   * Schedule the web services menu rebuild to the event dispatch thread.
    */
-
-  public void BuildWebServiceMenu()
+  public void buildWebServicesMenu()
   {
-    while (buildingMenu)
-    {
-      try
+    SwingUtilities.invokeLater(() -> {
+      Cache.log.info("Rebuiling WS menu");
+      webService.removeAll();
+      if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
       {
-        System.err.println("Waiting for building menu to finish.");
-        Thread.sleep(10);
-      } catch (Exception e)
+        Cache.log.info("Building web service menu for slivka");
+        SlivkaWSDiscoverer discoverer = SlivkaWSDiscoverer.getInstance();
+        JMenu submenu = new JMenu("Slivka");
+        buildWebServicesMenu(discoverer, submenu);
+        webService.add(submenu);
+      }
+      if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
       {
+        WSDiscovererI jws2servs = Jws2Discoverer.getInstance();
+        JMenu submenu = new JMenu("JABAWS");
+        buildLegacyWebServicesMenu(submenu);
+        buildWebServicesMenu(jws2servs, submenu);
+        webService.add(submenu);
       }
-    }
-    final AlignFrame me = this;
-    buildingMenu = true;
-    new Thread(new Runnable()
-    {
+    });
+  }
 
-      @Override
-      public void run()
+  private void buildLegacyWebServicesMenu(JMenu menu)
+  {
+    JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
+    if (Discoverer.getServices() != null && Discoverer.getServices().size() > 0) 
+    {
+      var secstrpred = Discoverer.getServices().get("SecStrPred");
+      if (secstrpred != null) 
       {
-        final List<JMenuItem> legacyItems = new ArrayList<>();
-        try
-        {
-          // System.err.println("Building ws menu again "
-          // + Thread.currentThread());
-          // TODO: add support for context dependent disabling of services based
-          // on
-          // alignment and current selection
-          // TODO: add additional serviceHandle parameter to specify abstract
-          // handler
-          // class independently of AbstractName
-          // TODO: add in rediscovery GUI function to restart discoverer
-          // TODO: group services by location as well as function and/or
-          // introduce
-          // object broker mechanism.
-          final Vector<JMenu> wsmenu = new Vector<>();
-          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");
-          // JAL-940 - only show secondary structure prediction services from
-          // the legacy server
-          Hashtable<String, Vector<ServiceHandle>> ds = Discoverer
-                  .getInstance().getServices();
-          if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
-              // &&
-          ds != null && (ds.size() > 0))
-          {
-            // TODO: refactor to allow list of AbstractName/Handler bindings to
-            // be
-            // stored or retrieved from elsewhere
-            // No MSAWS used any more:
-            // Vector msaws = null; // (Vector)
-            // Discoverer.services.get("MsaWS");
-            Vector<ServiceHandle> secstrpr = ds.get("SecStrPred");
-            if (secstrpr != null)
-            {
-              // Add any secondary structure prediction services
-              for (int i = 0, j = secstrpr.size(); i < j; i++)
-              {
-                final ext.vamsas.ServiceHandle sh = secstrpr.get(i);
-                jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
-                        .getServiceClient(sh);
-                int p = secstrmenu.getItemCount();
-                impl.attachWSMenuEntry(secstrmenu, me);
-                int q = secstrmenu.getItemCount();
-                for (int litm = p; litm < q; litm++)
-                {
-                  legacyItems.add(secstrmenu.getItem(litm));
-                }
-              }
-            }
-          }
-
-          // Add all submenus in the order they should appear on the web
-          // services menu
-          wsmenu.add(msawsmenu);
-          wsmenu.add(secstrmenu);
-          wsmenu.add(dismenu);
-          wsmenu.add(analymenu);
-          // No search services yet
-          // wsmenu.add(seqsrchmenu);
-
-          javax.swing.SwingUtilities.invokeLater(new Runnable()
-          {
-
-            @Override
-            public void run()
-            {
-              try
-              {
-                webService.removeAll();
-                // first, add discovered services onto the webservices menu
-                if (wsmenu.size() > 0)
-                {
-                  for (int i = 0, j = wsmenu.size(); i < j; i++)
-                  {
-                    webService.add(wsmenu.get(i));
-                  }
-                }
-                else
-                {
-                  webService.add(me.webServiceNoServices);
-                }
-                // TODO: move into separate menu builder class.
-                // boolean new_sspred = false;
-                if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
-                {
-                  Jws2Discoverer jws2servs = Jws2Discoverer.getInstance();
-                  if (jws2servs != null)
-                  {
-                    if (jws2servs.hasServices())
-                    {
-                      jws2servs.attachWSMenuEntry(webService, me);
-                      for (Jws2Instance sv : jws2servs.getServices())
-                      {
-                        if (sv.description.toLowerCase().contains("jpred"))
-                        {
-                          for (JMenuItem jmi : legacyItems)
-                          {
-                            jmi.setVisible(false);
-                          }
-                        }
-                      }
-
-                    }
-                    if (jws2servs.isRunning())
-                    {
-                      JMenuItem tm = new JMenuItem(
-                              "Still discovering JABA Services");
-                      tm.setEnabled(false);
-                      webService.add(tm);
-                    }
-                  }
-                }
-                build_urlServiceMenu(me.webService);
-                build_fetchdbmenu(webService);
-                for (JMenu item : wsmenu)
-                {
-                  if (item.getItemCount() == 0)
-                  {
-                    item.setEnabled(false);
-                  }
-                  else
-                  {
-                    item.setEnabled(true);
-                  }
-                }
-              } catch (Exception e)
-              {
-                Cache.log.debug(
-                        "Exception during web service menu building process.",
-                        e);
-              }
-            }
-          });
-        } catch (Exception e)
+        for (ext.vamsas.ServiceHandle sh : secstrpred) 
         {
+          var menuProvider = Discoverer.getServiceClient(sh);
+          menuProvider.attachWSMenuEntry(secstrmenu, this);
         }
-        buildingMenu = false;
       }
-    }).start();
+    }
+    menu.add(secstrmenu);
+  }
 
+  /**
+   * Constructs the web services menu for the given discoverer under the
+   * specified menu. This method must be called on the EDT
+   * 
+   * @param discoverer
+   *          the discoverer used to build the menu
+   * @param menu
+   *          parent component which the elements will be attached to
+   */
+  private void buildWebServicesMenu(WSDiscovererI discoverer, JMenu menu)
+  {
+    if (discoverer.hasServices())
+    {
+      PreferredServiceRegistry.getRegistry().populateWSMenuEntry(
+              discoverer.getServices(), sv -> buildWebServicesMenu(), menu,
+              this, null);
+    }
+    if (discoverer.isRunning())
+    {
+      JMenuItem item = new JMenuItem("Service discovery in progress.");
+      item.setEnabled(false);
+      menu.add(item);
+    }
+    else if (!discoverer.hasServices())
+    {
+      JMenuItem item = new JMenuItem("No services available.");
+      item.setEnabled(false);
+      menu.add(item);
+    }
   }
 
   /**
@@ -4943,6 +5139,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param file
    *          either a filename or a URL string.
+   * @throws InterruptedException
+   * @throws IOException
    */
 
   public void loadJalviewDataFile(Object file, DataSourceType sourceType,
@@ -6079,6 +6277,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
   }
 
+  /**
+   * Sets the status of the HMMER menu
+   */
+  public void updateHMMERStatus()
+  {
+    hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
+  }
+
   @Override
   protected void loadVcf_actionPerformed()
   {
index 7ab84ad..dca9047 100644 (file)
@@ -39,6 +39,7 @@ import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.renderer.ResidueShader;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
@@ -264,14 +265,13 @@ f   */
 
     setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true);
 
-    alignment
-            .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
+               alignment.setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
 
     // We must set conservation and consensus before setting colour,
     // as Blosum and Clustal require this to be done
-    if (hconsensus == null && !isDataset)
+               if (hconsensus == null && !isDataset)
     {
-      if (!alignment.isNucleotide())
+                       if (!alignment.isNucleotide())
       {
         showConservation = Cache.getDefault("SHOW_CONSERVATION", true);
         showQuality = Cache.getDefault("SHOW_QUALITY", true);
@@ -283,13 +283,19 @@ f   */
       showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
       normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
               false);
+      // for now, use consensus options for Information till it gets its own
+      setShowHMMSequenceLogo(showSequenceLogo);
+      setNormaliseHMMSequenceLogo(normaliseSequenceLogo);
+      setShowInformationHistogram(showConsensusHistogram);
       showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
       showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
 
       showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
     }
     initAutoAnnotation();
-    String colourProperty = alignment.isNucleotide()
+    // initInformation();
+
+               String colourProperty = alignment.isNucleotide()
             ? Preferences.DEFAULT_COLOUR_NUC
             : Preferences.DEFAULT_COLOUR_PROT;
     String schemeName = Cache.getProperty(colourProperty);
@@ -312,11 +318,11 @@ f   */
 
     if (residueShading != null)
     {
-      residueShading.setConsensus(hconsensus);
+                       residueShading.setConsensus(hconsensus);
     }
     setColourAppliesToAllGroups(true);
   }
-
+  
   boolean validCharWidth;
 
   /**
@@ -401,7 +407,7 @@ f   */
     /*
      * replace mappings on our alignment
      */
-    if (alignment != null && align != null)
+               if (alignment != null && align != null)
     {
       alignment.setCodonFrames(align.getCodonFrames());
     }
@@ -454,7 +460,7 @@ f   */
   }
 
   /**
-   * returns the visible column regions of the alignment
+   * Returns an iterator over the visible column regions of the alignment
    * 
    * @param selectedRegionOnly
    *          true to just return the contigs intersecting with the selected
@@ -474,8 +480,9 @@ f   */
     {
       end = alignment.getWidth();
     }
-    return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
-            false));
+
+    return (alignment.getHiddenColumns().getVisContigsIterator(start,
+            end, false));
   }
 
   /**
@@ -525,7 +532,7 @@ f   */
   }
 
   public boolean followSelection = true;
-
+  
   /**
    * @return true if view selection should always follow the selections
    *         broadcast by other selection sources
@@ -590,18 +597,20 @@ f   */
     return StructureSelectionManager
             .getStructureSelectionManager(Desktop.getInstance());
   }
-
+  
   @Override
   public boolean isNormaliseSequenceLogo()
   {
     return normaliseSequenceLogo;
   }
 
-  public void setNormaliseSequenceLogo(boolean state)
+  @Override
+public void setNormaliseSequenceLogo(boolean state)
   {
     normaliseSequenceLogo = state;
   }
 
+
   /**
    * 
    * @return true if alignment characters should be displayed
@@ -611,7 +620,7 @@ f   */
   {
     return validCharWidth;
   }
-
+  
   private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<>();
 
   public AutoCalcSetting getCalcIdSettingsFor(String calcId)
@@ -1091,6 +1100,9 @@ f   */
     {
       FeatureColourI preferredColour = featureSettings
               .getFeatureColour(type);
+      FeatureMatcherSetI preferredFilters = featureSettings
+              .getFeatureFilters(type);
+
       FeatureColourI origColour = fr.getFeatureStyle(type);
       if (!mergeOnly || (!origRenderOrder.contains(type)
               || origColour == null
@@ -1105,6 +1117,11 @@ f   */
         {
           fr.setColour(type, preferredColour);
         }
+        if (preferredFilters != null
+                && (!mergeOnly || fr.getFeatureFilter(type) != null))
+        {
+          fr.setFeatureFilter(type, preferredFilters);
+        }
         if (featureSettings.isFeatureDisplayed(type))
         {
           displayed.setVisible(type);
index c843f37..673f04d 100755 (executable)
@@ -61,6 +61,7 @@ import jalview.io.FormatAdapter;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.workers.InformationThread;
 
 /**
  * The panel that holds the labels for alignment annotations, providing
@@ -352,6 +353,10 @@ public class AnnotationLabels extends JPanel
       pop.show(this, evt.getX(), evt.getY());
       return;
     }
+
+    final AlignmentAnnotation ann = aa[selectedRow];
+    final boolean isSequenceAnnotation = ann.sequenceRef != null;
+
     item = new JMenuItem(EDITNAME);
     item.addActionListener(this);
     pop.add(item);
@@ -399,7 +404,8 @@ public class AnnotationLabels extends JPanel
     if (selectedRow < aa.length)
     {
       final String label = aa[selectedRow].label;
-      if (!aa[selectedRow].autoCalculated)
+      if (!(aa[selectedRow].autoCalculated)
+              && !(InformationThread.HMM_CALC_ID.equals(ann.getCalcId())))
       {
         if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
         {
@@ -407,7 +413,7 @@ public class AnnotationLabels extends JPanel
           pop.addSeparator();
           // av and sequencegroup need to implement same interface for
           item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
-                  aa[selectedRow].scaleColLabel);
+                         aa[selectedRow].scaleColLabel);
           item.addActionListener(this);
           pop.add(item);
         }
@@ -420,11 +426,169 @@ public class AnnotationLabels extends JPanel
         consclipbrd.addActionListener(this);
         pop.add(consclipbrd);
       }
+      else if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
+      {
+        addHmmerMenu(pop, ann);
+      }
     }
     pop.show(this, evt.getX(), evt.getY());
   }
 
   /**
+   * Adds context menu options for (alignment or group) Hmmer annotation
+   * 
+   * @param pop
+   * @param ann
+   */
+  protected void addHmmerMenu(JPopupMenu pop, final AlignmentAnnotation ann)
+  {
+    final boolean isGroupAnnotation = ann.groupRef != null;
+    pop.addSeparator();
+    final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
+            MessageManager.getString(
+                    "label.ignore_below_background_frequency"),
+            isGroupAnnotation
+                    ? ann.groupRef
+                            .isIgnoreBelowBackground()
+                    : ap.av.isIgnoreBelowBackground());
+    cbmi.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        if (isGroupAnnotation)
+        {
+          if (!ann.groupRef.isUseInfoLetterHeight())
+          {
+            ann.groupRef.setIgnoreBelowBackground(cbmi.getState());
+            // todo and recompute group annotation
+          }
+        }
+        else if (!ap.av.isInfoLetterHeight())
+        {
+          ap.av.setIgnoreBelowBackground(cbmi.getState(), ap);
+          // todo and recompute annotation
+        }
+        ap.alignmentChanged(); // todo not like this
+      }
+    });
+    pop.add(cbmi);
+    final JCheckBoxMenuItem letterHeight = new JCheckBoxMenuItem(
+            MessageManager.getString("label.use_info_for_height"),
+            isGroupAnnotation ? ann.groupRef.isUseInfoLetterHeight()
+                    : ap.av.isInfoLetterHeight());
+    letterHeight.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        if (isGroupAnnotation)
+        {
+          ann.groupRef.setInfoLetterHeight((letterHeight.getState()));
+          ann.groupRef.setIgnoreBelowBackground(true);
+          // todo and recompute group annotation
+        }
+        else
+        {
+          ap.av.setInfoLetterHeight(letterHeight.getState(), ap);
+          ap.av.setIgnoreBelowBackground(true, ap);
+          // todo and recompute annotation
+        }
+        ap.alignmentChanged();
+      }
+    });
+    pop.add(letterHeight);
+    if (isGroupAnnotation)
+    {
+      final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_group_histogram"),
+              ann.groupRef.isShowInformationHistogram());
+      chist.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          ann.groupRef.setShowInformationHistogram(chist.getState());
+          ap.repaint();
+        }
+      });
+      pop.add(chist);
+      final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_group_logo"),
+              ann.groupRef.isShowHMMSequenceLogo());
+      cprofl.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          ann.groupRef.setShowHMMSequenceLogo(cprofl.getState());
+          ap.repaint();
+        }
+      });
+      pop.add(cprofl);
+      final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
+              MessageManager.getString("label.normalise_group_logo"),
+              ann.groupRef.isNormaliseHMMSequenceLogo());
+      cproflnorm.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          ann.groupRef
+                  .setNormaliseHMMSequenceLogo(cproflnorm.getState());
+          // automatically enable logo display if we're clicked
+          ann.groupRef.setShowHMMSequenceLogo(true);
+          ap.repaint();
+        }
+      });
+      pop.add(cproflnorm);
+    }
+    else
+    {
+      final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_histogram"),
+              av.isShowInformationHistogram());
+      chist.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowInformationHistogram(chist.getState());
+          ap.repaint();
+        }
+      });
+      pop.add(chist);
+      final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
+              MessageManager.getString("label.show_logo"),
+              av.isShowHMMSequenceLogo());
+      cprof.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowHMMSequenceLogo(cprof.getState());
+          ap.repaint();
+        }
+      });
+      pop.add(cprof);
+      final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
+              MessageManager.getString("label.normalise_logo"),
+              av.isNormaliseHMMSequenceLogo());
+      cprofnorm.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          av.setShowHMMSequenceLogo(true);
+          av.setNormaliseHMMSequenceLogo(cprofnorm.getState());
+          ap.repaint();
+        }
+      });
+      pop.add(cprofnorm);
+    }
+  }
+
+  /**
    * A helper method that adds menu options for calculation and visualisation of
    * group and/or alignment consensus annotation to a popup menu. This is
    * designed to be reusable for either unwrapped mode (popup menu is shown on
@@ -926,7 +1090,6 @@ public class AnnotationLabels extends JPanel
             PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
             ap.av.sendSelection();
           }
-
         }
       }
       return;
@@ -990,7 +1153,6 @@ public class AnnotationLabels extends JPanel
   @Override
   public void paintComponent(Graphics g)
   {
-
     int width = getWidth();
     if (width == 0)
     {
@@ -1005,7 +1167,6 @@ public class AnnotationLabels extends JPanel
     }
 
     drawComponent(g2, true, width);
-
   }
 
   /**
index c69d0a8..46d02f7 100644 (file)
@@ -23,12 +23,12 @@ package jalview.gui;
 import jalview.analysis.TreeBuilder;
 import jalview.analysis.scoremodels.ScoreModels;
 import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.AlignViewportI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.bin.Cache;
 import jalview.datamodel.SequenceGroup;
 import jalview.util.MessageManager;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -643,7 +643,7 @@ public class CalculationChooser extends JPanel
      * gui validation shouldn't allow insufficient sequences here, but leave
      * this check in in case this method gets exposed programmatically in future
      */
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
     SequenceGroup sg = viewport.getSelectionGroup();
     if (sg != null && sg.getSize() < MIN_TREE_SELECTION)
     {
@@ -671,8 +671,7 @@ public class CalculationChooser extends JPanel
   public static Object openPcaPanel(AlignFrame af, String modelName,
           SimilarityParamsI params)
   {
-
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
 
     /*
      * gui validation shouldn't allow insufficient sequences here, but leave
index bbd38ec..88c94f6 100644 (file)
@@ -59,8 +59,11 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Vector;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 import java.util.concurrent.Semaphore;
 
 import javax.swing.AbstractAction;
@@ -123,6 +126,7 @@ import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.UrlConstants;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.WSDiscovererI;
 import jalview.ws.params.ParamManager;
 import jalview.ws.utils.UrlDownloadClient;
 
@@ -162,6 +166,7 @@ public class Desktop extends GDesktop
 
   public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
 
+  @SuppressWarnings("deprecation")
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
 
   /**
@@ -175,6 +180,7 @@ public class Desktop extends GDesktop
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
    */
+  @Deprecated
   public void addJalviewPropertyChangeListener(
           PropertyChangeListener listener)
   {
@@ -187,6 +193,7 @@ public class Desktop extends GDesktop
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
+  @Deprecated
   public void addJalviewPropertyChangeListener(String propertyName,
           PropertyChangeListener listener)
   {
@@ -199,6 +206,7 @@ public class Desktop extends GDesktop
    * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
+  @Deprecated
   public void removeJalviewPropertyChangeListener(String propertyName,
           PropertyChangeListener listener)
   {
@@ -1607,7 +1615,8 @@ public class Desktop extends GDesktop
       return;
     }
 
-    AlignmentViewport source = null, target = null;
+    AlignViewportI source = null;
+    AlignViewportI target = null;
     if (frames[0] instanceof AlignFrame)
     {
       source = ((AlignFrame) frames[0]).getCurrentView();
@@ -2573,6 +2582,13 @@ public class Desktop extends GDesktop
       progressBars.put(Long.valueOf(id), addProgressPanel(message));
     }
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    //TODO
+    throw new UnsupportedOperationException("not implemented");
+  }
 
   /*
    * (non-Javadoc)
@@ -2692,10 +2708,13 @@ public class Desktop extends GDesktop
 
   public void startServiceDiscovery(boolean blocking)
   {
-    boolean alive = true;
-    Thread t0 = null, t1 = null, t2 = null;
+    System.out.println("Starting service discovery");
+    var tasks = new ArrayList<Future<?>>();
     // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
-    if (true)
+
+    System.out.println("loading services");
+    
+    /** @j2sIgnore */
     {
       // todo: changesupport handlers need to be transferred
       if (discoverer == null)
@@ -2706,31 +2725,30 @@ public class Desktop extends GDesktop
       }
       // JAL-940 - disabled JWS1 service configuration - always start discoverer
       // until we phase out completely
-      (t0 = new Thread(discoverer)).start();
+      var f = new FutureTask<Void>(discoverer, null);
+      new Thread(f).start();
+      tasks.add(f);
     }
 
     if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
     {
-      t2 = jalview.ws.jws2.Jws2Discoverer.getInstance()
-              .startDiscoverer(changeSupport);
+      tasks.add(jalview.ws.jws2.Jws2Discoverer.getInstance().startDiscoverer());
     }
-    Thread t3 = null;
+    if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
     {
-      // TODO: do rest service discovery
+      tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer());
     }
     if (blocking)
     {
-      while (alive)
-      {
+      for (Future<?> task : tasks) {
         try
         {
-          Thread.sleep(15);
+          // block until all discovery tasks are done
+          task.get();
         } catch (Exception e)
         {
+          e.printStackTrace();
         }
-        alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
-                || (t3 != null && t3.isAlive())
-                || (t0 != null && t0.isAlive());
       }
     }
   }
@@ -2744,8 +2762,10 @@ public class Desktop extends GDesktop
   {
     if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
     {
-      final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
-              .getErrorMessages();
+      final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer
+          .getInstance();
+      final String ermsg = discoverer.getErrorMessages();
+      // CONFLICT:ALT:?     final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
       if (ermsg != null)
       {
         if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
index 35bd871..c250aca 100644 (file)
@@ -56,4 +56,11 @@ public interface IProgressIndicator
    */
   boolean operationInProgress();
 
+  /**
+   * Remove progress bar with a given id from the panel.
+   * 
+   * @param id
+   */
+  void removeProgressBar(long id);
+
 }
index 784e6c1..21c1af0 100644 (file)
@@ -23,6 +23,7 @@ package jalview.gui;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 
+@Deprecated
 public class JalviewChangeSupport implements PropertyChangeListener
 {
   public void propertyChange(PropertyChangeEvent evt)
index f23dcf8..8a735ed 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Font;
-import java.awt.GridLayout;
-import java.awt.Rectangle;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -37,10 +35,8 @@ import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
-import javax.swing.JLabel;
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
-import javax.swing.JPanel;
 import javax.swing.JScrollBar;
 import javax.swing.SwingConstants;
 import javax.swing.border.Border;
@@ -156,54 +152,23 @@ public final class JvSwingUtils
   }
 
   /**
+   * A convenience method that that adds a component with label to a container,
+   * sets a tooltip on both component and label, and optionally specifies layout
+   * constraints for the added component (but not the label)
    * 
-   * @param panel
+   * @param container
    * @param tooltip
    * @param label
-   * @param valBox
-   * @return the GUI element created that was added to the layout so it's
-   *         attributes can be changed.
+   * @param comp
+   * @param constraints
    */
-  public static JPanel addtoLayout(JPanel panel, String tooltip,
-          JComponent label, JComponent valBox)
-  {
-    JPanel laypanel = new JPanel(new GridLayout(1, 2));
-    JPanel labPanel = new JPanel(new BorderLayout());
-    JPanel valPanel = new JPanel();
-    labPanel.setBounds(new Rectangle(7, 7, 158, 23));
-    valPanel.setBounds(new Rectangle(172, 7, 270, 23));
-    labPanel.add(label, BorderLayout.WEST);
-    valPanel.add(valBox);
-    laypanel.add(labPanel);
-    laypanel.add(valPanel);
-    valPanel.setToolTipText(tooltip);
-    labPanel.setToolTipText(tooltip);
-    valBox.setToolTipText(tooltip);
-    panel.add(laypanel);
-    panel.validate();
-    return laypanel;
-  }
-
-  public static void mgAddtoLayout(JPanel cpanel, String tooltip,
-          JLabel jLabel, JComponent name)
+  public static void addtoLayout(Container container, String tooltip,
+          JComponent label, JComponent comp, String constraints)
   {
-    mgAddtoLayout(cpanel, tooltip, jLabel, name, null);
-  }
-
-  public static void mgAddtoLayout(JPanel cpanel, String tooltip,
-          JLabel jLabel, JComponent name, String params)
-  {
-    cpanel.add(jLabel);
-    if (params == null)
-    {
-      cpanel.add(name);
-    }
-    else
-    {
-      cpanel.add(name, params);
-    }
-    name.setToolTipText(tooltip);
-    jLabel.setToolTipText(tooltip);
+    container.add(label);
+    container.add(comp, constraints);
+    comp.setToolTipText(tooltip); // this doesn't seem to show?
+    label.setToolTipText(tooltip);
   }
 
   /**
@@ -368,7 +333,7 @@ public final class JvSwingUtils
 
   /**
    * Adds a titled border to the component in the default font and position (top
-   * left), optionally witht italic text
+   * left), optionally with italic text
    * 
    * @param comp
    * @param title
index 5342c90..046eb81 100644 (file)
  */
 package jalview.gui;
 
+import jalview.bin.Cache;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
 import jalview.util.MessageManager;
+import jalview.ws.jws2.dm.JabaOption;
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.OptionI;
 import jalview.ws.params.ParameterI;
 import jalview.ws.params.ValueConstrainI;
 import jalview.ws.params.ValueConstrainI.ValueType;
+import jalview.ws.params.simple.FileParameter;
+import jalview.ws.params.simple.LogarithmicParameter;
+import jalview.ws.params.simple.RadioChoiceParameter;
+import jalview.ws.params.simple.StringParameter;
 
 import java.awt.BorderLayout;
+import java.awt.Color;
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.awt.Font;
-import java.awt.GridLayout;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
+import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
@@ -52,6 +68,7 @@ import javax.swing.JLabel;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
+import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
 import javax.swing.JTextArea;
@@ -71,15 +88,33 @@ import net.miginfocom.swing.MigLayout;
  */
 public class OptsAndParamsPage
 {
-  /**
+  public static final int PARAM_WIDTH = 340;
+
+  public static final int PARAM_HEIGHT = 150;
+
+  public static final int PARAM_CLOSEDHEIGHT = 80;
+
+  URL linkImageURL = getClass().getResource("/images/link.gif");
+
+  Map<String, OptionBox> optSet = new LinkedHashMap<>();
+
+  Map<String, ParamBox> paramSet = new LinkedHashMap<>();
+
+  /*
    * compact or verbose style parameters
    */
   boolean compact = false;
 
+  OptsParametersContainerI poparent;
+
+  /**
+   * A class that models a panel rendering a single option (checkbox or choice
+   * list)
+   */
   public class OptionBox extends JPanel
           implements MouseListener, ActionListener
   {
-    JCheckBox enabled = new JCheckBox();
+    JCheckBox enabled;
 
     final URL finfo;
 
@@ -91,57 +126,89 @@ public class OptsAndParamsPage
 
     OptionI option;
 
-    JLabel optlabel = new JLabel();
-
-    JComboBox val = new JComboBox();
+    JComboBox<Object> val;
 
+    /**
+     * Constructs and adds labels and controls to the panel for one Option
+     * 
+     * @param opt
+     */
     public OptionBox(OptionI opt)
     {
       option = opt;
-      setLayout(new BorderLayout());
-      enabled.setSelected(opt.isRequired()); // TODO: lock required options
+      setLayout(new FlowLayout(FlowLayout.LEFT));
+      enabled = new JCheckBox(opt.getLabel());
+      enabled.setSelected(opt.isRequired());
+
+      /*
+       * If option is required, show a label, if optional a checkbox
+       * (but not for Jabaws pending JWS-126 resolution)
+       */
+      if (opt.isRequired() && !(opt instanceof JabaOption))
+      {
+        finfo = null;
+        add(new JLabel(opt.getLabel()));
+      }
+      else
+      {
+        finfo = option.getFurtherDetails();
+        configureCheckbox(opt);
+        add(enabled);
+      }
+
+      /*
+       * construct the choice box with possible values, 
+       * or their display names if provided
+       */
+      val = buildComboBox(opt);
+      val.setSelectedItem(opt.getValue());
+
+      /*
+       * only show the choicebox if there is more than one option,
+       * or the option is mandatory
+       */
+      if (opt.getPossibleValues().size() > 1 || opt.isRequired())
+      {
+        val.addActionListener(this);
+        add(val);
+      }
+
+      setInitialValue();
+    }
+
+    /**
+     * Configures the checkbox that controls whether or not the option is
+     * selected
+     * 
+     * @param opt
+     */
+    protected void configureCheckbox(OptionI opt)
+    {
       enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
-      enabled.setText("");
-      enabled.setText(opt.getName());
       enabled.addActionListener(this);
-      finfo = option.getFurtherDetails();
-      String desc = opt.getDescription();
+      final String desc = opt.getDescription();
       if (finfo != null)
       {
         hasLink = true;
-
-        enabled.setToolTipText(JvSwingUtils.wrapTooltip(true,
-                ((desc == null || desc.trim().length() == 0)
-                        ? MessageManager.getString(
-                                "label.opt_and_params_further_details")
-                        : desc) + "<br><img src=\"" + linkImageURL
-                        + "\"/>"));
-        enabled.addMouseListener(this);
+        String description = desc;
+        if (desc == null || desc.trim().isEmpty())
+        {
+          description = MessageManager
+                  .getString("label.opt_and_params_further_details");
+        }
+        description = description + "<br><img src=\"" + linkImageURL
+                + "\"/>";
+        String text = JvSwingUtils.wrapTooltip(true, description);
+        enabled.setToolTipText(text);
+        enabled.addMouseListener(this); // for popup menu to show link
       }
       else
       {
         if (desc != null && desc.trim().length() > 0)
         {
-          enabled.setToolTipText(
-                  JvSwingUtils.wrapTooltip(true, opt.getDescription()));
+          enabled.setToolTipText(JvSwingUtils.wrapTooltip(true, desc));
         }
       }
-      add(enabled, BorderLayout.NORTH);
-      for (Object str : opt.getPossibleValues())
-      {
-        val.addItem(str);
-      }
-      val.setSelectedItem(opt.getValue());
-      if (opt.getPossibleValues().size() > 1)
-      {
-        setLayout(new GridLayout(1, 2));
-        val.addActionListener(this);
-        add(val, BorderLayout.SOUTH);
-      }
-      // TODO: add actionListeners for popup (to open further info),
-      // and to update list of parameters if an option is enabled
-      // that takes a value. JBPNote: is this TODO still valid ?
-      setInitialValue();
     }
 
     @Override
@@ -178,31 +245,21 @@ public class OptsAndParamsPage
       poparent.argSetModified(this, !notmod);
     }
 
-    public OptionI getOptionIfEnabled()
+    /**
+     * Answers null if the option is not selected, else a new Option holding the
+     * selected value
+     * 
+     * @return
+     */
+    public ArgumentI getSelectedOption()
     {
       if (!enabled.isSelected())
       {
         return null;
       }
+      String value = getSelectedValue(option, val.getSelectedIndex());
       OptionI opt = option.copy();
-      if (opt.getPossibleValues() != null
-              && opt.getPossibleValues().size() == 1)
-      {
-        // Hack to make sure the default value for an enabled option with only
-        // one value is actually returned
-        opt.setValue(opt.getPossibleValues().get(0));
-      }
-      if (val.getSelectedItem() != null)
-      {
-        opt.setValue((String) val.getSelectedItem());
-      }
-      else
-      {
-        if (option.getValue() != null)
-        {
-          opt.setValue(option.getValue());
-        }
-      }
+      opt.setValue(value);
       return opt;
     }
 
@@ -218,15 +275,11 @@ public class OptsAndParamsPage
     @Override
     public void mouseEntered(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     @Override
     public void mouseExited(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -268,27 +321,57 @@ public class OptsAndParamsPage
       }
     }
 
+    /**
+     * toString representation for identification in the debugger only
+     */
+    @Override
+    public String toString()
+    {
+      return option == null ? super.toString() : option.toString();
+    }
+
   }
 
+  /**
+   * A class that models a panel rendering a single parameter
+   */
   public class ParamBox extends JPanel
           implements ChangeListener, ActionListener, MouseListener
   {
-    boolean adjusting = false;
+    /*
+     * parameter values (or their logs) are multiplied by this
+     * scaling factor to ensure an integer range for the slider
+     */
+    private int sliderScaleFactor = 1;
+
+    boolean isLogarithmicParameter;
+
+    boolean isChoiceParameter;
+
+    boolean isIntegerParameter;
 
-    boolean choice = false;
+    boolean isStringParameter;
 
-    JComboBox choicebox;
+    boolean adjusting;
 
-    JPanel controlPanel = new JPanel();
+    /*
+     * drop-down list of choice options (if applicable)
+     */
+    JComboBox<Object> choicebox;
 
-    boolean descisvisible = false;
+    /*
+     * radio buttons as an alternative to combo box
+     */
+    ButtonGroup buttonGroup;
+
+    JPanel controlsPanel = new JPanel();
+
+    boolean descriptionIsVisible = false;
 
     JScrollPane descPanel = new JScrollPane();
 
     final URL finfo;
 
-    boolean integ = false;
-
     Object lastVal;
 
     ParameterI parameter;
@@ -297,58 +380,82 @@ public class OptsAndParamsPage
 
     JPanel settingPanel = new JPanel();
 
-    JButton showDesc = new JButton();
+    JSlider slider;
 
-    JSlider slider = null;
+    JTextArea descriptionText = new JTextArea();
 
-    JTextArea string = new JTextArea();
+    ValueConstrainI validator;
 
-    ValueConstrainI validator = null;
+    JTextField valueField;
 
-    JTextField valueField = null;
+    private String descTooltip;
 
-    public ParamBox(final OptsParametersContainerI pmlayout,
+    public ParamBox(final OptsParametersContainerI paramContainer,
             ParameterI parm)
     {
-      pmdialogbox = pmlayout;
+      pmdialogbox = paramContainer;
       finfo = parm.getFurtherDetails();
       validator = parm.getValidValue();
       parameter = parm;
+
+      isLogarithmicParameter = parm instanceof LogarithmicParameter;
+
       if (validator != null)
       {
-        integ = validator.getType() == ValueType.Integer;
-      }
-      else
-      {
-        if (parameter.getPossibleValues() != null)
+        ValueType type = validator.getType();
+        isIntegerParameter = type == ValueType.Integer;
+        isStringParameter = type == ValueType.String
+                || type == ValueType.File;
+
+        /*
+         * ensure slider has an integer range corresponding to
+         * the min-max range of the parameter
+         */
+        if (validator.getMin() != null && validator.getMax() != null
+        // && !isIntegerParameter
+                && !isStringParameter)
         {
-          choice = true;
+          double min = validator.getMin().doubleValue();
+          double max = validator.getMax().doubleValue();
+          if (isLogarithmicParameter)
+          {
+            min = Math.log(min);
+            max = Math.log(max);
+          }
+          sliderScaleFactor = (int) (1000000 / (max - min));
+          // todo scaleMin, scaleMax could also be final fields
         }
       }
 
-      if (!compact)
+      List<String> possibleValues = parameter.getPossibleValues();
+      isChoiceParameter = possibleValues != null
+              && !possibleValues.isEmpty();
+
+      if (compact)
       {
-        makeExpanderParam(parm);
+        addCompactParameter(parm);
       }
       else
       {
-        makeCompactParam(parm);
-
+        addExpandableParam(parm);
       }
     }
 
-    private void makeCompactParam(ParameterI parm)
+    /**
+     * Adds a 'compact' format parameter, with any help text shown as a tooltip
+     * 
+     * @param parm
+     */
+    private void addCompactParameter(ParameterI parm)
     {
       setLayout(new MigLayout("", "[][grow]"));
-
       String ttipText = null;
 
-      controlPanel.setLayout(new BorderLayout());
+      controlsPanel.setLayout(new BorderLayout());
 
       if (parm.getDescription() != null
               && parm.getDescription().trim().length() > 0)
       {
-        // Only create description boxes if there actually is a description.
         ttipText = (JvSwingUtils.wrapTooltip(true,
                 parm.getDescription() + (finfo != null ? "<br><img src=\""
                         + linkImageURL + "\"/>"
@@ -357,91 +464,57 @@ public class OptsAndParamsPage
                         : "")));
       }
 
-      JvSwingUtils.mgAddtoLayout(this, ttipText, new JLabel(parm.getName()),
-              controlPanel, "");
+      JvSwingUtils.addtoLayout(this, ttipText, new JLabel(parm.getName()),
+              controlsPanel, "");
       updateControls(parm);
       validate();
     }
 
-    private void makeExpanderParam(ParameterI parm)
+    /**
+     * Adds an 'expanded' format parameter, with any help shown in a panel that
+     * may be shown or hidden
+     * 
+     * @param parm
+     */
+    private void addExpandableParam(ParameterI parm)
     {
       setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
       setBorder(new TitledBorder(parm.getName()));
       setLayout(null);
-      showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
-      showDesc.setText("+");
-      string.setFont(new Font("Verdana", Font.PLAIN, 11));
-      string.setBackground(getBackground());
+      descriptionText.setFont(new Font("Verdana", Font.PLAIN, 11));
+      descriptionText.setBackground(getBackground());
 
-      string.setEditable(false);
-      descPanel.getViewport().setView(string);
+      descriptionText.setEditable(false);
+      descPanel.getViewport().setView(descriptionText);
 
       descPanel.setVisible(false);
 
       JPanel firstrow = new JPanel();
       firstrow.setLayout(null);
-      controlPanel.setLayout(new BorderLayout());
-      controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
+      controlsPanel.setLayout(new BorderLayout());
+      controlsPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
               PARAM_CLOSEDHEIGHT - 50));
-      firstrow.add(controlPanel);
+      firstrow.add(controlsPanel);
       firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
               PARAM_CLOSEDHEIGHT - 30));
 
-      final ParamBox me = this;
-
       if (parm.getDescription() != null
               && parm.getDescription().trim().length() > 0)
       {
-        // Only create description boxes if there actually is a description.
-        if (finfo != null)
-        {
-          showDesc.setToolTipText(JvSwingUtils.wrapTooltip(true,
-                  MessageManager.formatMessage(
-                          "label.opt_and_params_show_brief_desc_image_link",
-                          new String[]
-                          { linkImageURL.toExternalForm() })));
-          showDesc.addMouseListener(this);
-        }
-        else
-        {
-          showDesc.setToolTipText(
-                  JvSwingUtils.wrapTooltip(true, MessageManager.getString(
-                          "label.opt_and_params_show_brief_desc")));
-        }
-        showDesc.addActionListener(new ActionListener()
-        {
-
-          @Override
-          public void actionPerformed(ActionEvent e)
-          {
-            descisvisible = !descisvisible;
-            descPanel.setVisible(descisvisible);
-            descPanel.getVerticalScrollBar().setValue(0);
-            me.setPreferredSize(new Dimension(PARAM_WIDTH,
-                    (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
-            me.validate();
-            pmdialogbox.refreshParamLayout();
-          }
-        });
-        string.setWrapStyleWord(true);
-        string.setLineWrap(true);
-        string.setColumns(32);
-        string.setText(parm.getDescription());
-        showDesc.setBounds(new Rectangle(10, 10, 16, 16));
-        firstrow.add(showDesc);
+        addExpandableHelp(firstrow, parm);
       }
       add(firstrow);
       validator = parm.getValidValue();
       parameter = parm;
       if (validator != null)
       {
-        integ = validator.getType() == ValueType.Integer;
+        isIntegerParameter = validator.getType() == ValueType.Integer;
       }
       else
       {
         if (parameter.getPossibleValues() != null)
         {
-          choice = true;
+          isChoiceParameter = true;
         }
       }
       updateControls(parm);
@@ -451,6 +524,57 @@ public class OptsAndParamsPage
       validate();
     }
 
+    /**
+     * Adds a button which can be clicked to show or hide help text
+     * 
+     * @param container
+     * @param param
+     */
+    protected void addExpandableHelp(JPanel container, ParameterI param)
+    {
+      JButton showDescBtn = new JButton("+");
+      showDescBtn.setFont(new Font("Verdana", Font.PLAIN, 8));
+      if (finfo != null)
+      {
+        descTooltip = JvSwingUtils.wrapTooltip(true,
+                MessageManager.formatMessage(
+                        "label.opt_and_params_show_brief_desc_image_link",
+                        new String[]
+                        { linkImageURL.toExternalForm() }));
+        showDescBtn.addMouseListener(this);
+      }
+      else
+      {
+        descTooltip = JvSwingUtils.wrapTooltip(true, MessageManager
+                .getString("label.opt_and_params_show_brief_desc"));
+      }
+      showDescBtn.setToolTipText(descTooltip);
+      showDescBtn.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          descriptionIsVisible = !descriptionIsVisible;
+          showDescBtn.setText(descriptionIsVisible ? "-" : "+");
+          showDescBtn.setToolTipText(
+                  descriptionIsVisible ? null : descTooltip);
+          descPanel.setVisible(descriptionIsVisible);
+          descPanel.getVerticalScrollBar().setValue(0);
+          ParamBox.this.setPreferredSize(new Dimension(PARAM_WIDTH,
+                  (descriptionIsVisible) ? PARAM_HEIGHT
+                          : PARAM_CLOSEDHEIGHT));
+          ParamBox.this.validate();
+          pmdialogbox.refreshParamLayout();
+        }
+      });
+      descriptionText.setWrapStyleWord(true);
+      descriptionText.setLineWrap(true);
+      descriptionText.setColumns(32);
+      descriptionText.setText(param.getDescription());
+      showDescBtn.setBounds(new Rectangle(10, 10, 16, 16));
+      container.add(showDescBtn);
+    }
+
     @Override
     public void actionPerformed(ActionEvent e)
     {
@@ -458,33 +582,22 @@ public class OptsAndParamsPage
       {
         return;
       }
-      if (!choice)
-      {
-        updateSliderFromValueField();
-      }
       checkIfModified();
     }
 
+    /**
+     * Checks whether the value of this parameter has been changed and notifies
+     * the parent page accordingly
+     */
     private void checkIfModified()
     {
-      Object cstate = updateSliderFromValueField();
-      boolean notmod = false;
-      if (cstate.getClass() == lastVal.getClass())
+      Object newValue = updateSliderFromValueField();
+      boolean modified = true;
+      if (newValue.getClass() == lastVal.getClass())
       {
-        if (cstate instanceof int[])
-        {
-          notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
-        }
-        else if (cstate instanceof float[])
-        {
-          notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
-        }
-        else if (cstate instanceof String[])
-        {
-          notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
-        }
+        modified = !newValue.equals(lastVal);
       }
-      pmdialogbox.argSetModified(this, !notmod);
+      pmdialogbox.argSetModified(this, modified);
     }
 
     @Override
@@ -502,22 +615,30 @@ public class OptsAndParamsPage
       return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
     }
 
-    public int getBoxHeight()
-    {
-      return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
-    }
-
-    public ParameterI getParameter()
+    /**
+     * Answers an argument holding the value entered or selected in the dialog
+     * 
+     * @return
+     */
+    public ArgumentI getParameter()
     {
       ParameterI prm = parameter.copy();
-      if (choice)
+      String value = null;
+      if (parameter instanceof RadioChoiceParameter)
+      {
+        value = buttonGroup.getSelection().getActionCommand();
+      }
+      else if (isChoiceParameter)
       {
-        prm.setValue((String) choicebox.getSelectedItem());
+        value = getSelectedValue(this.parameter,
+                choicebox.getSelectedIndex());
       }
       else
       {
-        prm.setValue(valueField.getText());
+        value = valueField.getText();
       }
+      prm.setValue(value);
+
       return prm;
     }
 
@@ -539,15 +660,11 @@ public class OptsAndParamsPage
     @Override
     public void mouseEntered(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     @Override
     public void mouseExited(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -562,52 +679,98 @@ public class OptsAndParamsPage
     @Override
     public void mouseReleased(MouseEvent e)
     {
-      // TODO Auto-generated method stub
-
     }
 
     @Override
     public void stateChanged(ChangeEvent e)
     {
-      if (!adjusting)
+      if (adjusting)
       {
-        valueField.setText("" + ((integ) ? ("" + slider.getValue())
-                : ("" + slider.getValue() / 1000f)));
+        return;
+      }
+      try
+      {
+        adjusting = true;
+        if (!isLogarithmicParameter)
+        {
+          /*
+           * set (int or float formatted) text field value
+           */
+          valueField.setText(isIntegerParameter
+                  ? String.valueOf(slider.getValue())
+                  : formatDouble(
+                          slider.getValue() / (float) sliderScaleFactor));
+        }
+        else
+        {
+          double value = Math.pow(Math.E,
+                  slider.getValue() / (double) sliderScaleFactor);
+          valueField.setText(formatDouble(value));
+        }
         checkIfModified();
+      } finally
+      {
+        adjusting = false;
       }
+    }
+
+    /**
+     * Answers the value formatted as a string to 3 decimal places - in
+     * scientific notation if the value is less than 0.001
+     * 
+     * @param value
+     * @return
+     */
+    String formatDouble(double value)
+    {
+      String format = value < 0.001 ? "%3.1E" : "%3.3f";
+      return String.format(format, value);
+    }
 
+    /**
+     * Formats a number as integer or float (3dp) or scientific notation (1dp)
+     * 
+     * @param n
+     * @return
+     */
+    String formatNumber(Number n)
+    {
+      return n instanceof Integer ? String.valueOf(n.intValue())
+              : formatDouble(n.doubleValue());
     }
 
-    public void updateControls(ParameterI parm)
+    void updateControls(ParameterI parm)
     {
       adjusting = true;
-      boolean init = (choicebox == null && valueField == null);
+      boolean init = (choicebox == null && valueField == null
+              && buttonGroup == null);
       if (init)
       {
-        if (choice)
+        if (parm instanceof RadioChoiceParameter)
+        {
+          buttonGroup = addRadioButtons(parameter, controlsPanel);
+        }
+        else if (isChoiceParameter)
         {
-          choicebox = new JComboBox();
+          choicebox = buildComboBox(parm);
           choicebox.addActionListener(this);
-          controlPanel.add(choicebox, BorderLayout.CENTER);
+          controlsPanel.add(choicebox, BorderLayout.CENTER);
         }
         else
         {
           slider = new JSlider();
           slider.addChangeListener(this);
-          valueField = new JTextField();
+          int cols = parm instanceof StringParameter ? 20 : 0;
+          valueField = new JTextField(cols);
           valueField.addActionListener(this);
-          valueField.addKeyListener(new KeyListener()
+          valueField.addKeyListener(new KeyAdapter()
           {
-
-            @Override
-            public void keyTyped(KeyEvent e)
-            {
-            }
-
             @Override
             public void keyReleased(KeyEvent e)
             {
-              if (e.isActionKey())
+              int keyCode = e.getKeyCode();
+              if (e.isActionKey() && keyCode != KeyEvent.VK_LEFT
+                      && keyCode != KeyEvent.VK_RIGHT)
               {
                 if (valueField.getText().trim().length() > 0)
                 {
@@ -615,161 +778,251 @@ public class OptsAndParamsPage
                 }
               }
             }
-
-            @Override
-            public void keyPressed(KeyEvent e)
-            {
-            }
           });
-          valueField.setPreferredSize(new Dimension(60, 25));
-          controlPanel.add(slider, BorderLayout.WEST);
-          controlPanel.add(valueField, BorderLayout.EAST);
-
+          valueField.setPreferredSize(new Dimension(65, 25));
+          if (parm instanceof FileParameter)
+          {
+            valueField.setToolTipText(MessageManager
+                    .getString("label.double_click_to_browse"));
+            valueField.addMouseListener(new MouseAdapter()
+            {
+              @Override
+              public void mouseClicked(MouseEvent e)
+              {
+                if (e.getClickCount() == 2)
+                {
+                  String dir = Cache.getProperty("LAST_DIRECTORY");
+                  JalviewFileChooser chooser = new JalviewFileChooser(dir);
+                  chooser.setFileView(new JalviewFileView());
+                  chooser.setDialogTitle(
+                          MessageManager.getString("action.select_ddbb"));
+
+                  int val = chooser.showOpenDialog(ParamBox.this);
+                  if (val == JalviewFileChooser.APPROVE_OPTION)
+                  {
+                    File choice = chooser.getSelectedFile();
+                    String path = choice.getPath();
+                    valueField.setText(path);
+                    Cache.setProperty("LAST_DIRECTORY", choice.getParent());
+                    FileLoader.updateRecentlyOpened(path,
+                            DataSourceType.FILE);
+                  }
+                }
+              }
+            });
+          }
+          
+          controlsPanel.add(slider, BorderLayout.WEST);
+          controlsPanel.add(valueField, BorderLayout.EAST);
         }
       }
 
-      if (parm != null)
+      String value = parm.getValue();
+      if (value != null)
       {
-        if (choice)
+        if (isChoiceParameter)
         {
-          if (init)
-          {
-            List vals = parm.getPossibleValues();
-            for (Object val : vals)
-            {
-              choicebox.addItem(val);
-            }
-          }
-
-          if (parm.getValue() != null)
+          if (!(parm instanceof RadioChoiceParameter))
           {
-            choicebox.setSelectedItem(parm.getValue());
+            choicebox.setSelectedItem(value);
           }
         }
         else
         {
-          valueField.setText(parm.getValue());
+          valueField.setText(value);
         }
       }
       lastVal = updateSliderFromValueField();
       adjusting = false;
     }
 
-    public Object updateSliderFromValueField()
+    /**
+     * Adds a panel to comp, containing a label and radio buttons for the choice
+     * of values of the given option. Returns a ButtonGroup whose members are
+     * the added radio buttons.
+     * 
+     * @param option
+     * @param comp
+     * 
+     * @return
+     */
+    protected ButtonGroup addRadioButtons(OptionI option, Container comp)
     {
-      int iVal;
-      float fVal;
-      if (validator != null)
+      ButtonGroup bg = new ButtonGroup();
+      JPanel radioPanel = new JPanel();
+      radioPanel.add(new JLabel(option.getDescription()));
+
+      String value = option.getValue();
+
+      for (String opt : option.getPossibleValues())
+      {
+        JRadioButton btn = new JRadioButton(opt);
+        btn.setActionCommand(opt);
+        boolean selected = opt.equals(value);
+        btn.setSelected(selected);
+        btn.addActionListener(this);
+        bg.add(btn);
+        radioPanel.add(btn);
+      }
+      comp.add(radioPanel);
+
+      return bg;
+    }
+
+    /**
+     * Action depends on the type of the input parameter:
+     * <ul>
+     * <li>if a text input, returns the trimmed value</li>
+     * <li>if a choice list or radio button, returns the selected value</li>
+     * <li>if a value slider and input field, sets the value of the slider from
+     * the value in the text field, limiting it to any defined min-max
+     * range.</li>
+     * </ul>
+     * Answers the (possibly modified) input value, as a String, Integer, Float
+     * or Double.
+     * 
+     * @return
+     */
+    Object updateSliderFromValueField()
+    {
+      if (validator == null || isStringParameter)
       {
-        if (integ)
+        if (isChoiceParameter)
         {
-          iVal = 0;
-          try
-          {
-            valueField.setText(valueField.getText().trim());
-            iVal = Integer.valueOf(valueField.getText());
-            if (validator.getMin() != null
-                    && validator.getMin().intValue() > iVal)
-            {
-              iVal = validator.getMin().intValue();
-              // TODO: provide visual indication that hard limit was reached for
-              // this parameter
-            }
-            if (validator.getMax() != null
-                    && validator.getMax().intValue() < iVal)
-            {
-              iVal = validator.getMax().intValue();
-              // TODO: provide visual indication that hard limit was reached for
-              // this parameter
-            }
-          } catch (Exception e)
+          if (parameter instanceof RadioChoiceParameter)
           {
-          }
-          ;
-          // update value field to reflect any bound checking we performed.
-          valueField.setText("" + iVal);
-          if (validator.getMin() != null && validator.getMax() != null)
-          {
-            slider.getModel().setRangeProperties(iVal, 1,
-                    validator.getMin().intValue(),
-                    validator.getMax().intValue() + 1, true);
+            return buttonGroup.getSelection().getActionCommand();
           }
           else
           {
-            slider.setVisible(false);
+            return getSelectedValue(this.parameter,
+                    choicebox.getSelectedIndex());
           }
-          return new int[] { iVal };
         }
-        else
+        slider.setVisible(false);
+        return valueField.getText().trim();
+      }
+
+      if (validator.getMin() == null || validator.getMax() == null)
+      {
+        slider.setVisible(false);
+      }
+
+      valueField.setText(valueField.getText().trim());
+
+      /*
+       * ensure not outside min-max range
+       * TODO: provide some visual indicator if limit reached
+       */
+      try
+      {
+        valueField.setBackground(Color.WHITE);
+        double d = Double.parseDouble(valueField.getText());
+        if (validator.getMin() != null
+                && validator.getMin().doubleValue() > d)
         {
-          fVal = 0f;
-          try
-          {
-            valueField.setText(valueField.getText().trim());
-            fVal = Float.valueOf(valueField.getText());
-            if (validator.getMin() != null
-                    && validator.getMin().floatValue() > fVal)
-            {
-              fVal = validator.getMin().floatValue();
-              // TODO: provide visual indication that hard limit was reached for
-              // this parameter
-              // update value field to reflect any bound checking we performed.
-              valueField.setText("" + fVal);
-            }
-            if (validator.getMax() != null
-                    && validator.getMax().floatValue() < fVal)
-            {
-              fVal = validator.getMax().floatValue();
-              // TODO: provide visual indication that hard limit was reached for
-              // this parameter
-              // update value field to reflect any bound checking we performed.
-              valueField.setText("" + fVal);
-            }
-          } catch (Exception e)
-          {
-          }
-          ;
-          if (validator.getMin() != null && validator.getMax() != null)
-          {
-            slider.getModel().setRangeProperties((int) (fVal * 1000f), 1,
-                    (int) (validator.getMin().floatValue() * 1000f),
-                    1 + (int) (validator.getMax().floatValue() * 1000f),
-                    true);
-          }
-          else
-          {
-            slider.setVisible(false);
-          }
-          return new float[] { fVal };
+          valueField.setText(formatNumber(validator.getMin()));
+        }
+        if (validator.getMax() != null
+                && validator.getMax().doubleValue() < d)
+        {
+          valueField.setText(formatNumber(validator.getMax()));
         }
+      } catch (NumberFormatException e)
+      {
+        valueField.setBackground(Color.yellow);
+        return Float.NaN;
       }
-      else
+
+      if (isIntegerParameter)
       {
-        if (!choice)
+        int iVal = 0;
+        try
+        {
+          iVal = Integer.valueOf(valueField.getText());
+        } catch (Exception e)
+        {
+          valueField.setBackground(Color.yellow);
+          return Integer.valueOf(0);
+        }
+
+        if (validator.getMin() != null && validator.getMax() != null)
+        {
+          slider.getModel().setRangeProperties(iVal, 1,
+                  validator.getMin().intValue(),
+                  validator.getMax().intValue() + 1, true);
+        }
+        else
         {
           slider.setVisible(false);
-          return new String[] { valueField.getText().trim() };
+        }
+        return Integer.valueOf(iVal);
+      }
+
+      if (isLogarithmicParameter)
+      {
+        double dVal = 0d;
+        try
+        {
+          double eValue = Double.valueOf(valueField.getText());
+          dVal = Math.log(eValue);
+        } catch (Exception e)
+        {
+          // shouldn't be possible here
+          valueField.setBackground(Color.yellow);
+          return Double.NaN;
+        }
+        if (validator.getMin() != null && validator.getMax() != null)
+        {
+          double scaleMin = Math.log(validator.getMin().doubleValue())
+                  * sliderScaleFactor;
+          double scaleMax = Math.log(validator.getMax().doubleValue())
+                  * sliderScaleFactor;
+          slider.getModel().setRangeProperties(
+                  (int) (sliderScaleFactor * dVal), 1,
+                  (int) scaleMin, 1 + (int) scaleMax, true);
         }
         else
         {
-          return new String[] { (String) choicebox.getSelectedItem() };
+          slider.setVisible(false);
         }
+        return Double.valueOf(dVal);
       }
 
+      float fVal = 0f;
+      try
+      {
+        fVal = Float.valueOf(valueField.getText());
+      } catch (Exception e)
+      {
+        return Float.valueOf(0f); // shouldn't happen
+      }
+      if (validator.getMin() != null && validator.getMax() != null)
+      {
+        float scaleMin = validator.getMin().floatValue()
+                * sliderScaleFactor;
+        float scaleMax = validator.getMax().floatValue()
+                * sliderScaleFactor;
+        slider.getModel().setRangeProperties(
+                (int) (fVal * sliderScaleFactor), 1, (int) scaleMin,
+                1 + (int) scaleMax, true);
+      }
+      else
+      {
+        slider.setVisible(false);
+      }
+      return Float.valueOf(fVal);
     }
   }
 
-  public static final int PARAM_WIDTH = 340;
-
-  public static final int PARAM_HEIGHT = 150;
-
-  public static final int PARAM_CLOSEDHEIGHT = 80;
-
-  public OptsAndParamsPage(OptsParametersContainerI paramContainer)
-  {
-    this(paramContainer, false);
-  }
-
+  /**
+   * Constructor with the option to show 'compact' format (parameter description
+   * as tooltip) or 'expanded' format (parameter description in a textbox which
+   * may be opened or closed). Use compact for simple description text, expanded
+   * for more wordy or formatted text.
+   * 
+   * @param paramContainer
+   */
   public OptsAndParamsPage(OptsParametersContainerI paramContainer,
           boolean compact)
   {
@@ -799,12 +1052,6 @@ public class OptsAndParamsPage
     mnu.show(invoker, x, y);
   }
 
-  URL linkImageURL = getClass().getResource("/images/link.gif");
-
-  Map<String, OptionBox> optSet = new java.util.LinkedHashMap<String, OptionBox>();
-
-  Map<String, ParamBox> paramSet = new java.util.LinkedHashMap<String, ParamBox>();
-
   public Map<String, OptionBox> getOptSet()
   {
     return optSet;
@@ -825,8 +1072,6 @@ public class OptsAndParamsPage
     this.paramSet = paramSet;
   }
 
-  OptsParametersContainerI poparent;
-
   OptionBox addOption(OptionI opt)
   {
     OptionBox cb = optSet.get(opt.getName());
@@ -870,11 +1115,9 @@ public class OptsAndParamsPage
       }
       else
       {
-        throw new Error(MessageManager.formatMessage(
-                "error.invalid_value_for_option", new String[]
-                { string, option.getName() }));
+        throw new Error(String.format("Invalid value '%s' for option '%s'",
+                string, option.getName()));
       }
-
     }
     if (option.isRequired() && !cb.enabled.isSelected())
     {
@@ -898,16 +1141,18 @@ public class OptsAndParamsPage
   }
 
   /**
-   * recover options and parameters from GUI
+   * Answers a list of arguments representing all the options and arguments
+   * selected on the dialog, holding their chosen or input values. Optional
+   * parameters which were not selected are not included.
    * 
    * @return
    */
   public List<ArgumentI> getCurrentSettings()
   {
-    List<ArgumentI> argSet = new ArrayList<ArgumentI>();
+    List<ArgumentI> argSet = new ArrayList<>();
     for (OptionBox opts : getOptSet().values())
     {
-      OptionI opt = opts.getOptionIfEnabled();
+      ArgumentI opt = opts.getSelectedOption();
       if (opt != null)
       {
         argSet.add(opt);
@@ -915,7 +1160,7 @@ public class OptsAndParamsPage
     }
     for (ParamBox parambox : getParamSet().values())
     {
-      ParameterI parm = parambox.getParameter();
+      ArgumentI parm = parambox.getParameter();
       if (parm != null)
       {
         argSet.add(parm);
@@ -925,4 +1170,57 @@ public class OptsAndParamsPage
     return argSet;
   }
 
+  /**
+   * A helper method that constructs and returns a CombBox for choice of the
+   * possible option values. If display names are provided, then these are added
+   * as options, otherwise the actual values are added.
+   * 
+   * @param opt
+   * @return
+   */
+  protected static JComboBox<Object> buildComboBox(OptionI opt)
+  {
+    JComboBox<Object> cb = null;
+    List<String> displayNames = opt.getDisplayNames();
+    if (displayNames != null)
+    {
+      List<Object> displayNamesObjects = new ArrayList<>();
+      displayNamesObjects.addAll(displayNames);
+      cb = JvSwingUtils.buildComboWithTooltips(displayNamesObjects,
+              opt.getPossibleValues());
+    }
+    else
+    {
+      cb = new JComboBox<>();
+      for (String v : opt.getPossibleValues())
+      {
+        cb.addItem(v);
+      }
+    }
+    return cb;
+  }
+
+  /**
+   * Answers the value corresponding to the selected item in the choice combo
+   * box. Note that this returns the underlying value even if a different
+   * display name is used in the combo box.
+   * 
+   * @return
+   */
+  protected static String getSelectedValue(OptionI opt, int sel)
+  {
+    List<String> possibleValues = opt.getPossibleValues();
+    String value = null;
+    if (possibleValues != null && possibleValues.size() == 1)
+    {
+      // Hack to make sure the default value for an enabled option with only
+      // one value is actually returned even if this.val is not displayed
+      value = possibleValues.get(0);
+    }
+    else if (sel >= 0 && sel < possibleValues.size())
+    {
+      value = possibleValues.get(sel);
+    }
+    return value;
+  }
 }
index cf15aa1..4b6d79b 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
 import jalview.bin.Cache;
 import jalview.renderer.OverviewRenderer;
 import jalview.util.MessageManager;
@@ -63,7 +64,7 @@ public class OverviewPanel extends JPanel
 
   private OverviewCanvas oviewCanvas;
 
-  protected AlignViewport av;
+  private AlignViewportI av;
 
   private AlignmentPanel ap;
 
index 5eca00f..c0d57a6 100644 (file)
@@ -607,6 +607,12 @@ public class PCAPanel extends GPCAPanel
     // // setMenusForViewport();
     // validate();
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    progressBar.removeProgressBar(id);
+  }
 
   @Override
   public void registerHandler(final long id,
index d081794..e736a11 100755 (executable)
 package jalview.gui;
 
 import jalview.analysis.AlignSeq;
+import jalview.api.AlignViewportI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.jbgui.GPairwiseAlignPanel;
 import jalview.util.MessageManager;
-import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.event.ActionEvent;
 import java.util.Vector;
@@ -43,7 +43,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
 
   private static final String DASHES = "---------------------\n";
 
-  AlignmentViewport av;
+  AlignViewportI av;
 
   Vector<SequenceI> sequences;
 
@@ -51,14 +51,13 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
    * Creates a new PairwiseAlignPanel object.
    * 
    * @param viewport
-   *          DOCUMENT ME!
    */
-  public PairwiseAlignPanel(AlignmentViewport viewport)
+  public PairwiseAlignPanel(AlignViewportI viewport)
   {
     super();
     this.av = viewport;
 
-    sequences = new Vector<SequenceI>();
+    sequences = new Vector<>();
 
     SequenceGroup selectionGroup = viewport.getSelectionGroup();
     boolean isSelection = selectionGroup != null
index 4469b43..f46bd4e 100644 (file)
@@ -64,11 +64,13 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.MappedFeatures;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.ResidueCount;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.ColourMenuHelper.ColourChangeListener;
 import jalview.gui.JalviewColourChooser.ColourChooserListener;
+import jalview.io.CountReader;
 import jalview.io.FileFormatI;
 import jalview.io.FileFormats;
 import jalview.io.FormatAdapter;
@@ -87,6 +89,9 @@ import jalview.util.StringUtils;
 import jalview.util.UrlLink;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
+import java.io.IOException;
+import java.net.MalformedURLException;
+
 /**
  * The popup menu that is displayed on right-click on a sequence id, or in the
  * sequence alignment.
@@ -545,6 +550,36 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         }
       }
 
+      if (seq.hasHMMProfile())
+      {
+        menuItem = new JMenuItem(MessageManager
+                .getString("action.add_background_frequencies"));
+        menuItem.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            try
+            {
+              ResidueCount counts = CountReader.getBackgroundFrequencies(ap,
+                      seq);
+              if (counts != null)
+              {
+                seq.getHMM().setBackgroundFrequencies(counts);
+                ap.alignFrame.buildColourMenu();
+              }
+            } catch (MalformedURLException e1)
+            {
+              e1.printStackTrace();
+            } catch (IOException e1)
+            {
+              e1.printStackTrace();
+            }
+          }
+        });
+        add(menuItem);
+      }
+
       menuItem = new JMenuItem(
               MessageManager.getString("action.hide_sequences"));
       menuItem.addActionListener(new ActionListener()
@@ -669,7 +704,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
         buildGroupURLMenu(sg, groupLinks);
       }
       // Add a 'show all structures' for the current selection
-      Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
+      Hashtable<String, PDBEntry> pdbe = new Hashtable<>();
+      Hashtable<String, PDBEntry> reppdb = new Hashtable<>();
 
       SequenceI sqass = null;
       for (SequenceI sq : alignPanel.av.getSequenceSelection())
index 4030afa..04851e8 100755 (executable)
@@ -27,6 +27,8 @@ import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
 import java.awt.event.MouseEvent;
 import java.io.File;
 import java.util.ArrayList;
@@ -37,6 +39,7 @@ import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JInternalFrame;
 import javax.swing.JPanel;
+import javax.swing.JTextField;
 import javax.swing.ListSelectionModel;
 import javax.swing.RowFilter;
 import javax.swing.RowSorter;
@@ -50,6 +53,9 @@ import javax.swing.table.TableColumn;
 import javax.swing.table.TableModel;
 import javax.swing.table.TableRowSorter;
 
+import jalview.hmmer.HmmerCommand;
+import jalview.util.FileUtils;
+
 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.bin.Cache;
@@ -82,6 +88,14 @@ import jalview.ws.sifts.SiftsSettings;
  */
 public class Preferences extends GPreferences
 {
+  // suggested list delimiter character
+  public static final String COMMA = ",";
+
+  public static final String HMMSEARCH_SEQCOUNT = "HMMSEARCH_SEQCOUNT";
+
+  public static final String HMMINFO_GLOBAL_BACKGROUND = "HMMINFO_GLOBAL_BACKGROUND";
+
+  public static final String HMMALIGN_TRIM_TERMINI = "HMMALIGN_TRIM_TERMINI";
   
   public static final String ADD_SS_ANN = "ADD_SS_ANN";
 
@@ -126,6 +140,12 @@ public class Preferences extends GPreferences
   public static final String FONT_SIZE = "FONT_SIZE";
 
   public static final String FONT_STYLE = "FONT_STYLE";
+  
+  public static final String HMMER_PATH = "HMMER_PATH";
+
+  public static final String CYGWIN_PATH = "CYGWIN_PATH";
+
+  public static final String HMMSEARCH_DBS = "HMMSEARCH_DBS";
 
   public static final String GAP_COLOUR = "GAP_COLOUR";
 
@@ -269,6 +289,8 @@ public class Preferences extends GPreferences
 
   private WsPreferences wsPrefs;
 
+  private SlivkaPreferences slivkaPrefs;
+
   private OptionsParam promptEachTimeOpt = new OptionsParam(
           MessageManager.getString("label.prompt_each_time"),
           "Prompt each time");
@@ -296,6 +318,8 @@ public class Preferences extends GPreferences
     {
       wsPrefs = new WsPreferences();
       wsTab.add(wsPrefs, BorderLayout.CENTER);
+      slivkaPrefs = new SlivkaPreferences();
+      slivkaTab.add(slivkaPrefs, BorderLayout.CENTER);
     }
     int width = 500, height = 450;
     if (Platform.isAMacAndNotJS())
@@ -309,6 +333,63 @@ public class Preferences extends GPreferences
     frame.setMinimumSize(new Dimension(width, height));
 
     /*
+     * Set HMMER tab defaults
+     */
+    hmmrTrimTermini.setSelected(Cache.getDefault(HMMALIGN_TRIM_TERMINI, false));
+    if (Cache.getDefault(HMMINFO_GLOBAL_BACKGROUND, false))
+    {
+      hmmerBackgroundUniprot.setSelected(true);
+    }
+    else
+    {
+      hmmerBackgroundAlignment.setSelected(true);
+    }
+    hmmerSequenceCount
+            .setText(Cache.getProperty(HMMSEARCH_SEQCOUNT));
+    hmmerPath.setText(Cache.getProperty(HMMER_PATH));
+    hmmerPath.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        validateHmmerPath();
+      }
+    });
+    hmmerPath.addFocusListener(new FocusAdapter()
+    {
+      @Override
+      public void focusLost(FocusEvent e)
+      {
+        validateHmmerPath();
+      }
+    });
+    if (cygwinPath != null)
+    {
+      String path = Cache.getProperty(CYGWIN_PATH);
+      if (path == null)
+      {
+        path = FileUtils.getPathTo("bash");
+      }
+      cygwinPath.setText(path);
+      cygwinPath.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          validateCygwinPath();
+        }
+      });
+      cygwinPath.addFocusListener(new FocusAdapter()
+      {
+        @Override
+        public void focusLost(FocusEvent e)
+        {
+          validateCygwinPath();
+        }
+      });
+    }
+
+    /*
      * Set Visual tab defaults
      */
     seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true));
@@ -331,6 +412,9 @@ public class Preferences extends GPreferences
             Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true));
     showConsensLogo
             .setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO", false));
+    showInformationHistogram.setSelected(
+            Cache.getDefault("SHOW_INFORMATION_HISTOGRAM", true));
+    showHMMLogo.setSelected(Cache.getDefault("SHOW_HMM_LOGO", false));
     showNpTooltip
             .setSelected(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true));
     showDbRefTooltip
@@ -509,7 +593,7 @@ public class Preferences extends GPreferences
     doReset.addActionListener(onReset);
 
     // filter to display only custom urls
-    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
+    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<>()
     {
       @Override
       public boolean include(
@@ -741,6 +825,10 @@ public class Preferences extends GPreferences
             Boolean.toString(showConsensHistogram.isSelected()));
     Cache.setPropertyNoSave("SHOW_CONSENSUS_LOGO",
             Boolean.toString(showConsensLogo.isSelected()));
+    Cache.setPropertyNoSave("SHOW_INFORMATION_HISTOGRAM",
+            Boolean.toString(showConsensHistogram.isSelected()));
+    Cache.setPropertyNoSave("SHOW_HMM_LOGO",
+            Boolean.toString(showHMMLogo.isSelected()));
     Cache.setPropertyNoSave("ANTI_ALIAS",
             Boolean.toString(smoothFont.isSelected()));
     Cache.setPropertyNoSave(SCALE_PROTEIN_TO_CDNA,
@@ -787,6 +875,42 @@ public class Preferences extends GPreferences
             maxColour.getBackground());
 
     /*
+     * Save HMMER settings
+     */
+    Cache.setPropertyNoSave(HMMALIGN_TRIM_TERMINI,
+            Boolean.toString(hmmrTrimTermini.isSelected()));
+    Cache.setPropertyNoSave(HMMINFO_GLOBAL_BACKGROUND,
+            Boolean.toString(hmmerBackgroundUniprot.isSelected()));
+    Cache.setPropertyNoSave(HMMSEARCH_SEQCOUNT,
+            hmmerSequenceCount.getText());
+    Cache.setOrRemove(HMMER_PATH, hmmerPath.getText());
+    if (cygwinPath != null)
+    {
+      Cache.setOrRemove(CYGWIN_PATH, cygwinPath.getText());
+    }
+    AlignFrame[] frames = Desktop.getAlignFrames();
+    if (frames != null && frames.length > 0)
+    {
+      for (AlignFrame f : frames)
+      {
+        f.updateHMMERStatus();
+      }
+    }
+    
+    hmmrTrimTermini.setSelected(Cache.getDefault(HMMALIGN_TRIM_TERMINI, false));
+    if (Cache.getDefault(HMMINFO_GLOBAL_BACKGROUND, false))
+    {
+      hmmerBackgroundUniprot.setSelected(true);
+    }
+    else
+    {
+      hmmerBackgroundAlignment.setSelected(true);
+    }
+    hmmerSequenceCount
+            .setText(Cache.getProperty(HMMSEARCH_SEQCOUNT));
+    hmmerPath.setText(Cache.getProperty(HMMER_PATH));
+
+    /*
      * Save Overview settings
      */
     Cache.setColourPropertyNoSave(GAP_COLOUR, gapColour.getBackground());
@@ -1101,6 +1225,8 @@ public class Preferences extends GPreferences
             && (identity.isSelected() || showGroupConsensus.isSelected()));
     showConsensLogo.setEnabled(annotations.isSelected()
             && (identity.isSelected() || showGroupConsensus.isSelected()));
+    showInformationHistogram.setEnabled(annotations.isSelected());
+    showHMMLogo.setEnabled(annotations.isSelected());
   }
 
   @Override
@@ -1370,6 +1496,57 @@ public class Preferences extends GPreferences
     }
     return true;
   }
+  
+  /**
+   * Returns true if the given text field contains a path to a folder that
+   * contains an executable with the given name, else false (after showing a
+   * warning dialog). The executable name will be tried with .exe appended if not
+   * found.
+   * 
+   * @param textField
+   * @param executable
+   */
+  protected boolean validateExecutablePath(JTextField textField, String executable)
+  {
+    String folder = textField.getText().trim();
+
+    if (FileUtils.getExecutable(executable, folder) != null)
+    {
+      return true;
+    }
+    if (folder.length() > 0)
+    {
+      JvOptionPane.showInternalMessageDialog(Desktop.getInstance(),
+              MessageManager.formatMessage("label.executable_not_found",
+                      executable),
+              MessageManager.getString("label.invalid_folder"),
+              JvOptionPane.ERROR_MESSAGE);
+    }
+    return false;
+  }
+
+  /**
+   * Checks if a file can be executed
+   * 
+   * @param path
+   *          the path to the file
+   * @return
+   */
+  public boolean canExecute(String path)
+  {
+    File file = new File(path);
+    if (!file.canExecute())
+    {
+      file = new File(path + ".exe");
+      {
+        if (!file.canExecute())
+        {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
 
   /**
    * If Chimera is selected, check it can be found on default or user-specified
@@ -1418,6 +1595,18 @@ public class Preferences extends GPreferences
     }
   }
 
+  @Override
+  protected void validateHmmerPath()
+  {
+    validateExecutablePath(hmmerPath, HmmerCommand.HMMBUILD);
+  }
+
+  @Override
+  protected void validateCygwinPath()
+  {
+    validateExecutablePath(cygwinPath, "run");
+  }
+
   public class OptionsParam
   {
     private String name;
index 011d810..abf096f 100644 (file)
@@ -166,6 +166,23 @@ public class ProgressBar implements IProgressIndicator
     });
 
   }
+  
+  @Override
+  public void removeProgressBar(final long id)
+  {
+    SwingUtilities.invokeLater(() -> {
+      JPanel progressPanel = progressBars.get(id);
+      if (progressPanel != null)
+      {
+        progressBars.remove(id);
+        if (progressBarHandlers.containsKey(id))
+        {
+          progressBarHandlers.remove(id);
+        }
+        removeRow(progressPanel);
+      }
+    });
+  }
 
   /**
    * Lays out progress bar container hierarchy
index cda76d9..213a979 100644 (file)
@@ -476,10 +476,13 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
             final Thread runner = Thread.currentThread();
             JFrame df = new JFrame();
             df.getContentPane().setLayout(new BorderLayout());
-            df.getContentPane().add((nulserv = !nulserv)
-                    ? new RestServiceEditorPane(jalview.ws.rest.RestClient
-                            .makeShmmrRestClient().getRestDescription())
-                    : new RestServiceEditorPane(), BorderLayout.CENTER);
+            df.getContentPane().add(
+                    (nulserv = !nulserv) ? new RestServiceEditorPane(
+                            jalview.ws.rest.clientdefs.ShmrRestClient
+                                    .makeShmmrRestClient()
+                                    .getRestDescription())
+                            : new RestServiceEditorPane(),
+                    BorderLayout.CENTER);
             df.setBounds(100, 100, 600, 400);
             df.addComponentListener(new ComponentListener()
             {
diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java
new file mode 100644 (file)
index 0000000..6c365b9
--- /dev/null
@@ -0,0 +1,368 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+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 java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+
+@SuppressWarnings("serial")
+public class SlivkaPreferences extends JPanel
+{
+  {
+    setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+    setPreferredSize(new Dimension(500, 450));
+  }
+
+  WSDiscovererI discoverer;
+
+  private final ArrayList<String> urls = new ArrayList<>();
+
+  private final ArrayList<Integer> statuses = new ArrayList<>();
+
+  private final AbstractTableModel urlTableModel = new AbstractTableModel()
+  {
+    final String[] columnNames = { "Service URL", "Status" };
+
+    @Override
+    public String getColumnName(int col)
+    {
+      return columnNames[col];
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex)
+    {
+      switch (columnIndex)
+      {
+      case 0:
+        return urls.get(rowIndex);
+      case 1:
+        return statuses.get(rowIndex);
+      default:
+        throw new NoSuchElementException();
+      }
+    }
+
+    @Override
+    public int getRowCount()
+    {
+      return urls.size();
+    }
+
+    @Override
+    public int getColumnCount()
+    {
+      return 2;
+    }
+  };
+
+  private class WSStatusCellRenderer extends DefaultTableCellRenderer
+  {
+    @Override
+    public Component getTableCellRendererComponent(JTable table,
+        Object value, boolean isSelected, boolean hasFocus, int row,
+        int column)
+    {
+      setHorizontalAlignment(CENTER);
+      super.getTableCellRendererComponent(table, "\u25CF", isSelected,
+          hasFocus, row, column);
+      switch ((Integer) value)
+      {
+      case WSDiscovererI.STATUS_NO_SERVICES:
+        setForeground(Color.ORANGE);
+        break;
+      case WSDiscovererI.STATUS_OK:
+        setForeground(Color.GREEN);
+        break;
+      case WSDiscovererI.STATUS_INVALID:
+        setForeground(Color.RED);
+        break;
+      case WSDiscovererI.STATUS_UNKNOWN:
+      default:
+        setForeground(Color.LIGHT_GRAY);
+      }
+      return this;
+    }
+  }
+
+  private JTable urlListTable = new JTable(urlTableModel);
+  {
+    urlListTable.getColumnModel().getColumn(1).setMaxWidth(60);
+    urlListTable.getColumnModel().getColumn(1)
+        .setCellRenderer(new WSStatusCellRenderer());
+  }
+
+  // URL control panel buttons
+  JButton newWsUrl = new JButton(
+      MessageManager.getString("label.new_service_url"));
+
+  JButton editWsUrl = new JButton(
+      MessageManager.getString("label.edit_service_url"));
+
+  JButton deleteWsUrl = new JButton(
+      MessageManager.getString("label.delete_service_url"));
+
+  JButton moveUrlUp = new JButton(
+      MessageManager.getString("action.move_up"));
+
+  JButton moveUrlDown = new JButton(
+      MessageManager.getString("action.move_down"));
+
+  private String showEditUrlDialog(String oldUrl)
+  {
+    String input = (String) JvOptionPane
+        .showInternalInputDialog(
+            this, 
+            MessageManager.getString("label.url:"),
+            UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()),
+            JOptionPane.QUESTION_MESSAGE,
+            null,
+            null,
+            oldUrl);
+    if (input == null)
+    {
+      return null;
+    }
+    try
+    {
+      new URL(input);
+    } catch (MalformedURLException ex)
+    {
+      JvOptionPane.showInternalMessageDialog(this,
+          MessageManager.getString("label.invalid_url"),
+          UIManager.getString("OptionPane.messageDialogTitle",
+              MessageManager.getLocale()),
+          JOptionPane.WARNING_MESSAGE);
+      return null;
+    }
+    return input;
+  }
+
+  // Button Action Listeners
+  private ActionListener newUrlAction = (ActionEvent e) -> {
+    final String input = showEditUrlDialog("");
+    if (input != null)
+    {
+      urls.add(input);
+      statuses.add(discoverer.getServerStatusFor(input));
+      urlTableModel.fireTableRowsInserted(urls.size(), urls.size());
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener editUrlAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i >= 0)
+    {
+      final String input = showEditUrlDialog(urls.get(i));
+      if (input != null)
+      {
+        urls.set(i, input);
+        statuses.set(i, discoverer.getServerStatusFor(input));
+        urlTableModel.fireTableRowsUpdated(i, i);
+        discoverer.setServiceUrls(urls);
+      }
+    }
+  };
+
+  private ActionListener deleteUrlAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i >= 0)
+    {
+      urls.remove(i);
+      statuses.remove(i);
+      urlTableModel.fireTableRowsDeleted(i, i);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener moveUrlUpAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i > 0)
+    {
+      moveTableRow(i, i - 1);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private ActionListener moveUrlDownAction = (ActionEvent e) -> {
+    final int i = urlListTable.getSelectedRow();
+    if (i >= 0 && i < urls.size() - 1)
+    {
+      moveTableRow(i, i + 1);
+      discoverer.setServiceUrls(urls);
+    }
+  };
+
+  private MouseListener tableClickListener = new MouseAdapter()
+  {
+    final ActionEvent actionEvent = new ActionEvent(urlListTable,
+        ActionEvent.ACTION_PERFORMED, "edit");
+
+    @Override
+    public void mouseClicked(MouseEvent e)
+    {
+      if (e.getClickCount() > 1)
+      {
+        editUrlAction.actionPerformed(actionEvent);
+      }
+    }
+  };
+
+  // Setting up URL list Pane
+  {
+    Font font = new Font("Verdana", Font.PLAIN, 10);
+    JPanel urlPaneContainer = new JPanel(new BorderLayout(5, 5));
+    urlPaneContainer.setBorder(BorderFactory.createCompoundBorder(
+        BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
+            "Slivka Web Services"),
+        BorderFactory.createEmptyBorder(10, 5, 5, 5)));
+
+    newWsUrl.setFont(font);
+    editWsUrl.setFont(font);
+    deleteWsUrl.setFont(font);
+    moveUrlUp.setFont(font);
+    moveUrlDown.setFont(font);
+    JPanel editContainer = new JPanel();
+    editContainer.add(newWsUrl);
+    editContainer.add(editWsUrl);
+    editContainer.add(deleteWsUrl);
+    urlPaneContainer.add(editContainer, BorderLayout.PAGE_END);
+
+    JPanel moveContainer = new JPanel();
+    moveContainer
+        .setLayout(new BoxLayout(moveContainer, BoxLayout.PAGE_AXIS));
+    moveContainer.add(moveUrlUp);
+    moveContainer.add(Box.createRigidArea(new Dimension(0, 5)));
+    moveContainer.add(moveUrlDown);
+    urlPaneContainer.add(moveContainer, BorderLayout.LINE_START);
+
+    urlPaneContainer.add(new JScrollPane(urlListTable),
+        BorderLayout.CENTER);
+    this.add(urlPaneContainer);
+
+    // Connecting action listeners
+    urlListTable.addMouseListener(tableClickListener);
+    newWsUrl.addActionListener(newUrlAction);
+    editWsUrl.addActionListener(editUrlAction);
+    deleteWsUrl.addActionListener(deleteUrlAction);
+    moveUrlUp.addActionListener(moveUrlUpAction);
+    moveUrlDown.addActionListener(moveUrlDownAction);
+  }
+
+  private void moveTableRow(int fromIndex, int toIndex)
+  {
+    String url = urls.get(fromIndex);
+    int status = statuses.get(fromIndex);
+    urls.set(fromIndex, urls.get(toIndex));
+    statuses.set(fromIndex, statuses.get(toIndex));
+    urls.set(toIndex, url);
+    statuses.set(toIndex, status);
+    if (urlListTable.getSelectedRow() == fromIndex)
+    {
+      urlListTable.setRowSelectionInterval(toIndex, toIndex);
+    }
+    int firstRow = Math.min(toIndex, fromIndex);
+    int lastRow = Math.max(fromIndex, toIndex);
+    urlTableModel.fireTableRowsUpdated(firstRow, lastRow);
+  }
+
+  // Discoverer reloading buttons
+  JButton refreshServices = new JButton(
+      MessageManager.getString("action.refresh_services"));
+
+  JButton resetServices = new JButton(
+      MessageManager.getString("action.reset_services"));
+
+  JProgressBar progressBar = new JProgressBar();
+
+  // Discoverer buttons action listeners
+  private ActionListener refreshServicesAction = (ActionEvent e) -> {
+    progressBar.setVisible(true);
+    Cache.log.info("Requesting service reload");
+    discoverer.startDiscoverer().handle((_discoverer, exception) -> {
+      if (exception == null)
+      {
+        Cache.log.info("Reloading done");
+      }
+      else
+      {
+        Cache.log.error("Reloading failed", exception);
+      }
+      SwingUtilities.invokeLater(() -> progressBar.setVisible(false));
+      return null;
+    });
+  };
+
+  private ActionListener resetServicesAction = (ActionEvent e) -> {
+    discoverer.setServiceUrls(null);
+    urls.clear();
+    statuses.clear();
+    urls.addAll(discoverer.getServiceUrls());
+    for (String url : urls)
+    {
+      statuses.add(discoverer.getServerStatusFor(url));
+    }
+    urlTableModel.fireTableDataChanged();
+  };
+
+  {
+    Font font = new Font("Verdana", Font.PLAIN, 11);
+    refreshServices.setFont(font);
+    resetServices.setFont(font);
+    JPanel container = new JPanel();
+    container.add(refreshServices);
+    container.add(resetServices);
+    this.add(container);
+
+    // Connecting action listeners
+    refreshServices.addActionListener(refreshServicesAction);
+    resetServices.addActionListener(resetServicesAction);
+  }
+
+  {
+    progressBar.setVisible(false);
+    progressBar.setIndeterminate(true);
+    add(progressBar);
+  }
+
+  SlivkaPreferences()
+  {
+    // Initial URLs loading
+    discoverer = SlivkaWSDiscoverer.getInstance();
+    urls.addAll(discoverer.getServiceUrls());
+    for (String url : urls)
+    {
+      statuses.add(discoverer.getServerStatusFor(url));
+    }
+  }
+}
index 953755f..c4b47a0 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
+import jalview.api.AlignViewControllerGuiI;
+import jalview.api.FeatureSettingsControllerI;
+import jalview.api.SplitContainerI;
+import jalview.controller.FeatureSettingsControllerGuiI;
+import jalview.datamodel.AlignmentI;
+import jalview.jbgui.GAlignFrame;
+import jalview.jbgui.GSplitFrame;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.AlignmentViewport;
+
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -49,18 +62,6 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
-import jalview.api.AlignViewControllerGuiI;
-import jalview.api.FeatureSettingsControllerI;
-import jalview.api.SplitContainerI;
-import jalview.controller.FeatureSettingsControllerGuiI;
-import jalview.datamodel.AlignmentI;
-import jalview.jbgui.GAlignFrame;
-import jalview.jbgui.GSplitFrame;
-import jalview.structure.StructureSelectionManager;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.viewmodel.AlignmentViewport;
-
 /**
  * An internal frame on the desktop that hosts a horizontally split view of
  * linked DNA and Protein alignments. Additional views can be created in linked
@@ -230,8 +231,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     topFrame.alignPanel.adjustAnnotationHeight();
     bottomFrame.alignPanel.adjustAnnotationHeight();
 
-    final AlignViewport topViewport = topFrame.viewport;
-    final AlignViewport bottomViewport = bottomFrame.viewport;
+    final AlignViewportI topViewport = topFrame.viewport;
+    final AlignViewportI bottomViewport = bottomFrame.viewport;
     final AlignmentI topAlignment = topViewport.getAlignment();
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     boolean topAnnotations = topViewport.isShowAnnotation();
@@ -1100,4 +1101,4 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
   {
     return featureSettingsUI != null && !featureSettingsUI.isClosed();
   }
-}
\ No newline at end of file
+}
index 47c9a00..97b0cfb 100644 (file)
@@ -1283,6 +1283,12 @@ public class StructureChooser extends GStructureChooser
   {
     progressBar.setProgressBar(message, id);
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    progressBar.removeProgressBar(id);
+  }
 
   @Override
   public void registerHandler(long id, IProgressIndicatorHandler handler)
index ab9444e..b88102e 100644 (file)
@@ -929,6 +929,12 @@ public void hyperlinkUpdate(HyperlinkEvent e)
   {
     progressBar.setProgressBar(message, id);
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    progressBar.removeProgressBar(id);
+  }
 
   @Override
   public void registerHandler(final long id,
index 45822a3..719b7d9 100644 (file)
@@ -23,10 +23,7 @@ package jalview.gui;
 import jalview.gui.OptsAndParamsPage.OptionBox;
 import jalview.gui.OptsAndParamsPage.ParamBox;
 import jalview.util.MessageManager;
-import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.JabaPreset;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.api.UIinfo;
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.OptionI;
 import jalview.ws.params.ParamDatastoreI;
@@ -48,33 +45,21 @@ import java.awt.event.HierarchyBoundsListener;
 import java.awt.event.HierarchyEvent;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
-import java.net.URL;
 import java.util.Hashtable;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
 
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JDialog;
-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.border.TitledBorder;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 
-import compbio.metadata.Argument;
-import compbio.metadata.Option;
-import compbio.metadata.Parameter;
-import compbio.metadata.Preset;
-import compbio.metadata.PresetManager;
-import compbio.metadata.RunnerConfig;
 import net.miginfocom.swing.MigLayout;
 
 /**
@@ -95,36 +80,35 @@ import net.miginfocom.swing.MigLayout;
 public class WsJobParameters extends JPanel implements ItemListener,
         ActionListener, DocumentListener, OptsParametersContainerI
 {
-  URL linkImageURL = getClass().getResource("/images/link.gif");
+  private static final int PREFERRED_WIDTH = 540;
 
-  private static final String SVC_DEF = "Defaults"; // this is the null
-                                                    // parameter set as shown to
-                                                    // user
+  private static final int DEFAULT_HEIGHT = 640;
+
+  // the default parameter set shown to the user
+  private static final String SVC_DEF = "Defaults";
+
+  private int maxOptWidth = 200;
+
+  // URL linkImageURL = getClass().getResource("/images/link.gif");
+
+  // TODO ABSRACT FROM JABAWS CLASSES
 
   /**
    * manager for options and parameters.
    */
-  OptsAndParamsPage opanp = new OptsAndParamsPage(this);
+  OptsAndParamsPage opanp;
 
-  /**
+  /*
    * panel containing job options
    */
-  JPanel jobOptions = new JPanel();
+  JPanel optionsPanel = new JPanel();
 
-  /**
+  /*
    * panel containing job parameters
    */
-  JPanel paramList = new JPanel();
-
-  JPanel SetNamePanel = new JPanel();
-
-  JPanel setDetails = new JPanel();
-
-  JSplitPane settingsPanel = new JSplitPane();
-
-  JPanel jobPanel = new JPanel();
+  JPanel paramsPanel = new JPanel();
 
-  JScrollPane jobOptionsPane = new JScrollPane();
+  JPanel setNamePanel = new JPanel();
 
   JButton createpref = new JButton();
 
@@ -134,81 +118,80 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   JButton updatepref = new JButton();
 
-  JButton startjob = new JButton();
-
-  JButton canceljob = new JButton();
-
-  JComboBox setName = new JComboBox();
+  JComboBox<String> setName = new JComboBox<>();
 
   JTextArea setDescr = new JTextArea();
 
   JScrollPane paramPane = new JScrollPane();
 
-  // ScrollablePanel optsAndparams = new ScrollablePanel();
-  JPanel optsAndparams = new JPanel();
-
-  RunnerConfig serviceOptions;
-
   ParamDatastoreI paramStore;
 
-  private int MAX_OPTWIDTH = 200;
+  // set true when 'Start Job' is clicked
+  boolean startJob = false;
 
-  WsJobParameters(Jws2Instance service)
-  {
-    this(service, null);
-  }
+  JDialog frame = null;
 
-  public WsJobParameters(Jws2Instance service, WsParamSetI preset)
-  {
-    this(null, service, preset, null);
-  }
+  UIinfo service;
 
-  /**
-   * 
-   * @param desktop
-   *          - if null, create new JFrame outside of desktop
-   * @param service
-   * @param preset
+  /*
+   * list of service presets in the gui
+   */
+  Hashtable<String, String> servicePresets = null;
+
+  /*
+   * set if dialog is being set - so handlers will avoid spurious events
    */
-  public WsJobParameters(JFrame parent, Jws2Instance service,
-          WsParamSetI preset, List<Argument> jobArgset)
+  boolean settingDialog = false;
+
+  private Hashtable<Object, Object> modifiedElements = new Hashtable<>();
+
+  String lastParmSet = null;
+
+  public WsJobParameters(ParamDatastoreI store, WsParamSetI preset,
+          List<ArgumentI> args)
   {
-    this(parent, null, service, preset, jobArgset);
+    super();
+
+    // parameters dialog in 'compact' format (help as tooltips)
+    opanp = new OptsAndParamsPage(this, true);
+    jbInit();
+    this.paramStore = store;
+    this.service = null;
+    init(preset, args);
+    validate();
   }
 
   /**
+   * Constructor given a set of parameters and presets, a service to be invoked,
+   * and a list of (Jabaws client) arguments
    * 
-   * @param parent
    * @param paramStorei
    * @param service
    * @param preset
    * @param jobArgset
    */
-  public WsJobParameters(JFrame parent, ParamDatastoreI paramStorei,
-          Jws2Instance service, WsParamSetI preset,
-          List<Argument> jobArgset)
+  public WsJobParameters(ParamDatastoreI paramStorei, UIinfo service,
+          WsParamSetI preset, List<ArgumentI> jobArgset)
   {
     super();
+
+    // parameters dialog in 'expanded' format (help text boxes)
+    opanp = new OptsAndParamsPage(this, false);
+
     jbInit();
     this.paramStore = paramStorei;
-    if (paramStore == null)
+    if (paramStore == null && service != null)
     {
       paramStore = service.getParamStore();
     }
     this.service = service;
-    // argSetModified(false);
-    // populate parameter table
-    initForService(service, preset, jobArgset);
-    // display in new JFrame attached to parent.
+    initForService(preset, jobArgset);
     validate();
   }
 
-  int response = -1;
-
-  JDialog frame = null;
-
   /**
-   * shows a modal dialog containing the parameters.
+   * Shows a modal dialog containing the parameters and Start or Cancel options.
+   * Answers true if the job is started, false if cancelled.
    * 
    * @return
    */
@@ -216,7 +199,12 @@ public class WsJobParameters extends JPanel implements ItemListener,
   {
 
     frame = new JDialog(Desktop.getInstance(), true);
-
+    if (service != null)
+    {
+      frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
+              new String[]
+      { service.getActionText() }));
+    }
     frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
             new String[]
             { service.getActionText() }));
@@ -242,11 +230,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     });
     frame.setVisible(true);
 
-    if (response > 0)
-    {
-      return true;
-    }
-    return false;
+    return startJob;
   }
 
   private void jbInit()
@@ -276,7 +260,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                update_actionPerformed(e);
+                update_actionPerformed();
               }
             });
     deletepref = JvSwingUtils.makeButton(
@@ -288,7 +272,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                delete_actionPerformed(e);
+                delete_actionPerformed();
               }
             });
     createpref = JvSwingUtils.makeButton(
@@ -300,7 +284,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                create_actionPerformed(e);
+                create_actionPerformed();
               }
             });
     revertpref = JvSwingUtils.makeButton(
@@ -313,10 +297,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                revert_actionPerformed(e);
+                revert_actionPerformed();
               }
             });
-    startjob = JvSwingUtils.makeButton(
+
+    JButton startjob = JvSwingUtils.makeButton(
             MessageManager.getString("action.start_job"),
             MessageManager.getString("label.start_job_current_settings"),
             new ActionListener()
@@ -324,10 +309,10 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                startjob_actionPerformed(e);
+                startjob_actionPerformed();
               }
             });
-    canceljob = JvSwingUtils.makeButton(
+    JButton canceljob = JvSwingUtils.makeButton(
             MessageManager.getString("action.cancel_job"),
             MessageManager.getString("label.cancel_job_close_dialog"),
             new ActionListener()
@@ -335,10 +320,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
               @Override
               public void actionPerformed(ActionEvent e)
               {
-                canceljob_actionPerformed(e);
+                canceljob_actionPerformed();
               }
             });
 
+    JPanel setDetails = new JPanel();
     setDetails.setBorder(
             new TitledBorder(MessageManager.getString("label.details")));
     setDetails.setLayout(new BorderLayout());
@@ -357,7 +343,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     setName.getEditor().addActionListener(this);
     JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
     GridBagLayout gbl = new GridBagLayout();
-    SetNamePanel.setLayout(gbl);
+    setNamePanel.setLayout(gbl);
 
     JLabel setNameLabel = new JLabel(
             MessageManager.getString("label.current_parameter_set_name"));
@@ -372,9 +358,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     revertpref.setVisible(false);
     createpref.setVisible(false);
     JPanel setsavebuts = new JPanel();
-    setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT)); // GridLayout(1,2));
-    ((FlowLayout) setsavebuts.getLayout()).setHgap(10);
-    ((FlowLayout) setsavebuts.getLayout()).setVgap(0);
+    setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); // GridLayout(1,2));
     JPanel spacer = new JPanel();
     spacer.setPreferredSize(new Dimension(2, 30));
     setsavebuts.add(spacer);
@@ -385,11 +369,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
     // setsavebuts.setSize(new Dimension(150, 30));
     JPanel buttonArea = new JPanel(new GridLayout(1, 1));
     buttonArea.add(setsavebuts);
-    SetNamePanel.add(setNameInfo);
+    setNamePanel.add(setNameInfo);
     GridBagConstraints gbc = new GridBagConstraints();
     gbc.gridheight = 2;
     gbl.setConstraints(setNameInfo, gbc);
-    SetNamePanel.add(buttonArea);
+    setNamePanel.add(buttonArea);
     gbc = new GridBagConstraints();
     gbc.gridx = 0;
     gbc.gridy = 2;
@@ -399,36 +383,33 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
     // paramPane.setPreferredSize(new Dimension(360, 400));
     // paramPane.setPreferredSize(null);
-    jobOptions.setBorder(
+    optionsPanel.setBorder(
             new TitledBorder(MessageManager.getString("label.options")));
-    jobOptions.setOpaque(true);
-    paramList.setBorder(
+    optionsPanel.setOpaque(true);
+    paramsPanel.setBorder(
             new TitledBorder(MessageManager.getString("label.parameters")));
-    paramList.setOpaque(true);
-    JPanel bjo = new JPanel(new BorderLayout()),
-            bjp = new JPanel(new BorderLayout());
-    bjo.add(jobOptions, BorderLayout.CENTER);
-    bjp.add(paramList, BorderLayout.CENTER);
-    bjp.setOpaque(true);
-    bjo.setOpaque(true);
+    paramsPanel.setOpaque(true);
     // optsAndparams.setScrollableWidth(ScrollableSizeHint.FIT);
     // optsAndparams.setScrollableHeight(ScrollableSizeHint.NONE);
     // optsAndparams.setLayout(new BorderLayout());
+    JPanel optsAndparams = new JPanel();
     optsAndparams.setLayout(new BorderLayout());
-    optsAndparams.add(jobOptions, BorderLayout.NORTH);
-    optsAndparams.add(paramList, BorderLayout.CENTER);
+    optsAndparams.add(optionsPanel, BorderLayout.NORTH);
+    optsAndparams.add(paramsPanel, BorderLayout.CENTER);
     JPanel jp = new JPanel(new BorderLayout());
     jp.add(optsAndparams, BorderLayout.CENTER);
     paramPane.getViewport().setView(jp);
     paramPane.setBorder(null);
     setLayout(new BorderLayout());
+
+    JPanel jobPanel = new JPanel();
     jobPanel.setPreferredSize(null);
     jobPanel.setLayout(new BorderLayout());
     jobPanel.add(setDetails, BorderLayout.NORTH);
     jobPanel.add(paramPane, BorderLayout.CENTER);
     // jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
 
-    add(SetNamePanel, BorderLayout.NORTH);
+    add(setNamePanel, BorderLayout.NORTH);
     add(jobPanel, BorderLayout.CENTER);
 
     JPanel dialogpanel = new JPanel();
@@ -436,20 +417,20 @@ public class WsJobParameters extends JPanel implements ItemListener,
     dialogpanel.add(canceljob);
     // JAL-1580: setMaximumSize() doesn't work, so just size for the worst case:
     // check for null is for JUnit usage
-    final int windowHeight = Desktop.getInstance() == null ? 540
+    final int windowHeight = Desktop.getInstance() == null ? DEFAULT_HEIGHT
             : Desktop.getInstance().getHeight();
     setPreferredSize(new Dimension(540, windowHeight));
     add(dialogpanel, BorderLayout.SOUTH);
     validate();
   }
 
-  protected void revert_actionPerformed(ActionEvent e)
+  protected void revert_actionPerformed()
   {
     reInitDialog(lastParmSet);
     updateWebServiceMenus();
   }
 
-  protected void update_actionPerformed(ActionEvent e)
+  protected void update_actionPerformed()
   {
     if (isUserPreset)
     {
@@ -467,7 +448,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     paramStore.deletePreset(lastParmSet2);
   }
 
-  protected void delete_actionPerformed(ActionEvent e)
+  protected void delete_actionPerformed()
   {
     if (isUserPreset)
     {
@@ -478,7 +459,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     updateWebServiceMenus();
   }
 
-  protected void create_actionPerformed(ActionEvent e)
+  protected void create_actionPerformed()
   {
     String curname = ((String) setName.getSelectedItem()).trim();
     if (curname.length() > 0)
@@ -497,55 +478,40 @@ public class WsJobParameters extends JPanel implements ItemListener,
     }
   }
 
-  protected void canceljob_actionPerformed(ActionEvent e)
+  protected void canceljob_actionPerformed()
   {
-    response = 0;
+    startJob = false;
     if (frame != null)
     {
       frame.setVisible(false);
     }
   }
 
-  protected void startjob_actionPerformed(ActionEvent e)
+  protected void startjob_actionPerformed()
   {
-    response = 1;
+    startJob = true;
     if (frame != null)
     {
       frame.setVisible(false);
     }
   }
 
-  Jws2Instance service;
+  void initForService(WsParamSetI paramSet, List<ArgumentI> jobArgset)
+  {
+    settingDialog = true;
 
-  /**
-   * list of service presets in the gui
-   */
-  Hashtable servicePresets = null;
+    init(paramSet, jobArgset);
 
-  /**
-   * set if dialog is being set - so handlers will avoid spurious events
-   */
-  boolean settingDialog = false;
+  }
 
-  void initForService(Jws2Instance service, WsParamSetI jabap,
-          List<Argument> jabajobArgset)
+  void init(WsParamSetI p, List<ArgumentI> jobArgset)
   {
-    WsParamSetI p = null;
-    List<ArgumentI> jobArgset = null;
-    settingDialog = true;
-    { // instantiate the abstract proxy for Jaba objects
-      jobArgset = jabajobArgset == null ? null
-              : JabaParamStore.getJwsArgsfromJaba(jabajobArgset);
-      p = jabap; // (jabap != null) ? paramStore.getPreset(jabap.getName()) :
-                 // null;
-    }
-
-    Hashtable exnames = new Hashtable();
+    Hashtable<String, String> exnames = new Hashtable<>();
     for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
     {
       exnames.put(setName.getItemAt(i), setName.getItemAt(i));
     }
-    servicePresets = new Hashtable();
+    servicePresets = new Hashtable<>();
     // Add the default entry - if not present already.
     if (!exnames.contains(SVC_DEF))
     {
@@ -553,7 +519,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
       exnames.put(SVC_DEF, SVC_DEF);
       servicePresets.put(SVC_DEF, SVC_DEF);
     }
-    String curname = (p == null ? "" : p.getName());
+
+    // String curname = (p == null ? "" : p.getName());
     for (WsParamSetI pr : paramStore.getPresets())
     {
       if (!pr.isModifiable())
@@ -593,10 +560,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
       }
     }
     settingDialog = false;
-
   }
 
-  @SuppressWarnings("unchecked")
   private void updateTable(WsParamSetI p, List<ArgumentI> jobArgset)
   {
     boolean setDefaultParams = false;
@@ -633,9 +598,9 @@ public class WsJobParameters extends JPanel implements ItemListener,
             OptionI opt = (OptionI) myarg;
             OptionBox ob = opanp.addOption(opt);
             ob.resetToDefault(setDefaultParams);
-            if (MAX_OPTWIDTH < ob.getPreferredSize().width)
+            if (maxOptWidth < ob.getPreferredSize().width)
             {
-              MAX_OPTWIDTH = ob.getPreferredSize().width;
+              maxOptWidth = ob.getPreferredSize().width;
             }
             ob.validate();
             cw += ob.getPreferredSize().width + 5;
@@ -704,8 +669,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
     return modifiedElements.size() > 0;
   }
 
-  private Hashtable modifiedElements = new Hashtable();
-
   /**
    * reset gui and modification state settings
    */
@@ -770,7 +733,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     if (b && modifiedElements.size() > 0)
     {
       makeSetNameValid(!isUserPreset);
-      SetNamePanel.revalidate();
+      setNamePanel.revalidate();
     }
     updateButtonDisplay();
   }
@@ -817,7 +780,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     // sync the gui with the preset database
     for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
     {
-      String snm = (String) setName.getItemAt(i);
+      String snm = setName.getItemAt(i);
       if (snm.equals(nm))
       {
         makeupdate = true;
@@ -837,96 +800,88 @@ public class WsJobParameters extends JPanel implements ItemListener,
     settingDialog = stn;
   }
 
+  /**
+   * Rebuilds the Options and Parameters panels
+   */
   @Override
   public void refreshParamLayout()
   {
-    // optsAndparams.setPreferredSize(null);
-    FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
-    int sep = fl.getVgap();
-    boolean fh = true;
-    int os = 0,
-            s = jobOptions.getBorder().getBorderInsets(jobOptions).bottom
-                    + jobOptions.getBorder().getBorderInsets(jobOptions).top
-                    + 2 * sep;
-    /**
-     * final height for viewport
-     */
-    int finalh = s;
-    int panewidth = paramPane.getViewport().getSize().width - 120
-            - jobOptions.getBorder().getBorderInsets(jobOptions).left
-            + jobOptions.getBorder().getBorderInsets(jobOptions).right;
-
-    int w = 2 * fl.getHgap()
-            + (MAX_OPTWIDTH > OptsAndParamsPage.PARAM_WIDTH ? MAX_OPTWIDTH
-                    : OptsAndParamsPage.PARAM_WIDTH);
-    int hgap = fl.getHgap(), cw = hgap;
+    final int rightMargin = 40;
+    final int availableWidth = paramPane.getViewport().getSize().width
+            - rightMargin
+            - optionsPanel.getBorder().getBorderInsets(optionsPanel).left
+            + optionsPanel.getBorder().getBorderInsets(optionsPanel).right;
 
     if (opanp.getOptSet().size() > 0)
     {
+      int hgap = 5;
+      int currentWidth = hgap;
 
-      jobOptions.setLayout(new MigLayout("", "", ""));
-      jobOptions.removeAll();
+      /*
+       * layout constraint 'nogrid' prevents vertical column alignment,
+       * allowing controls to flow without extra space inserted to align
+       */
+      optionsPanel.setLayout(new MigLayout("nogrid", "", ""));
+      optionsPanel.removeAll();
+      JPanel lastAdded = null;
 
+      /*
+       * add each control in turn; if adding would overflow the right margin,
+       * remove and re-add the previous parameter with "wrap" (after) 
+       * in order to start a new row
+       */
       for (OptionBox pbox : opanp.getOptSet().values())
       {
         pbox.validate();
-        cw += pbox.getSize().width + hgap;
-        if (cw + 120 > panewidth)
-        {
-          jobOptions.add(pbox, "wrap");
-          // System.out.println("Wrap on "+pbox.option.getName());
-          cw = hgap + pbox.getSize().width;
-          fh = true;
-        }
-        else
-        {
-          jobOptions.add(pbox);
-        }
-        if (fh)
+        int boxWidth = pbox.getSize().width;
+        currentWidth += boxWidth + hgap;
+        boolean wrapAfterLast = currentWidth > availableWidth
+                && lastAdded != null;
+        // System.out.println(String.format(
+        // "%s width=%d, paneWidth=%d, currentWidth=%d, wrapAfterLast=%s",
+        // pbox.toString(), boxWidth, panewidth, currentWidth,
+        // wrapAfterLast));
+        if (wrapAfterLast)
         {
-          finalh += pbox.getSize().height + fl.getVgap();
-          fh = false;
+          optionsPanel.remove(lastAdded);
+          optionsPanel.add(lastAdded, "wrap");
+          currentWidth = hgap + boxWidth;
         }
+        optionsPanel.add(pbox);
+        lastAdded = pbox;
       }
-      jobOptions.revalidate();
+      optionsPanel.revalidate();
     }
     else
     {
-      jobOptions.setVisible(false);
+      optionsPanel.setVisible(false);
     }
 
-    // Now layout the parameters assuming they occupy one column - to calculate
-    // total height of options+parameters
-    fl = new FlowLayout(FlowLayout.LEFT);
-    // helpful hint from
-    // http://stackoverflow.com/questions/2743177/top-alignment-for-flowlayout
-    fl.setAlignOnBaseline(true);
     if (opanp.getParamSet().size() > 0)
     {
-      paramList.removeAll();
-      paramList.setLayout(new MigLayout("", "", ""));
-      fh = true;
+      paramsPanel.removeAll();
+      paramsPanel.setLayout(new MigLayout("", "", ""));
+      int hgap = 5;
+      int currentWidth = hgap;
+
+      JPanel lastAdded = null;
       for (ParamBox pbox : opanp.getParamSet().values())
       {
         pbox.validate();
-        cw += pbox.getSize().width + hgap;
-        if (cw + 160 > panewidth)
+        int boxWidth = pbox.getSize().width;
+        currentWidth += boxWidth + hgap;
+        boolean wrapAfterLast = currentWidth > availableWidth
+                && lastAdded != null;
+        if (wrapAfterLast)
         {
-          paramList.add(pbox, "wrap");
-          cw = pbox.getSize().width + hgap;
-          fh = true;
+          paramsPanel.remove(lastAdded);
+          paramsPanel.add(lastAdded, "wrap");
+          currentWidth = pbox.getSize().width + hgap;
         }
-        else
-        {
-          paramList.add(pbox);
-        }
-        if (fh)
-        {
-          finalh += pbox.getSize().height + fl.getVgap();
-          fh = false;
-        }
-
+        paramsPanel.add(pbox);
+        lastAdded = pbox;
       }
+
       /*
        * s = 2 * sep; for (ParamBox pbox : opanp.getParamSet().values()) {
        * pbox.validate(); s += sep +
@@ -938,11 +893,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
        * .getBorder().getBorderInsets(paramList).bottom+paramList
        * .getBorder().getBorderInsets(paramList).top;
        */
-      paramList.revalidate();
+      paramsPanel.revalidate();
     }
     else
     {
-      paramList.setVisible(false);
+      paramsPanel.setVisible(false);
     }
     // TODO: waste some time trying to eliminate any unnecessary .validate calls
     // here
@@ -953,244 +908,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
     paramPane.revalidate();
     revalidate();
   }
-
-  /**
-   * testing method - grab a service and parameter set and show the window
-   * 
-   * @param args
-   * @j2sIgnore
-   */
-  public static void main(String[] args)
-  {
-    jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
-            .getInstance();
-    int p = 0;
-    if (args.length > 0)
-    {
-      Vector<String> services = new Vector<>();
-      services.addElement(args[p++]);
-      Jws2Discoverer.getInstance().setServiceUrls(services);
-    }
-    try
-    {
-      disc.run();
-    } catch (Exception e)
-    {
-      System.err.println("Aborting. Problem discovering services.");
-      e.printStackTrace();
-      return;
-    }
-    Jws2Instance lastserv = null;
-    for (Jws2Instance service : disc.getServices())
-    {
-      lastserv = service;
-      if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
-      {
-        if (lastserv != null)
-        {
-          List<Preset> prl = null;
-          Preset pr = null;
-          if (++p < args.length)
-          {
-            PresetManager prman = lastserv.getPresets();
-            if (prman != null)
-            {
-              pr = prman.getPresetByName(args[p]);
-              if (pr == null)
-              {
-                // just grab the last preset.
-                prl = prman.getPresets();
-              }
-            }
-          }
-          else
-          {
-            PresetManager prman = lastserv.getPresets();
-            if (prman != null)
-            {
-              prl = prman.getPresets();
-            }
-          }
-          Iterator<Preset> en = (prl == null) ? null : prl.iterator();
-          while (en != null && en.hasNext())
-          {
-            if (en != null)
-            {
-              if (!en.hasNext())
-              {
-                en = prl.iterator();
-              }
-              pr = en.next();
-            }
-            {
-              System.out.println("Testing opts dupes for "
-                      + lastserv.getUri() + " : " + lastserv.getActionText()
-                      + ":" + pr.getName());
-              List<Option> rg = lastserv.getRunnerConfig().getOptions();
-              for (Option o : rg)
-              {
-                try
-                {
-                  Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
-                } catch (Exception e)
-                {
-                  System.err.println("Failed to copy " + o.getName());
-                  e.printStackTrace();
-                } catch (Error e)
-                {
-                  System.err.println("Failed to copy " + o.getName());
-                  e.printStackTrace();
-                }
-              }
-            }
-            {
-              System.out.println("Testing param dupes:");
-              List<Parameter> rg = lastserv.getRunnerConfig()
-                      .getParameters();
-              for (Parameter o : rg)
-              {
-                try
-                {
-                  Parameter cpy = jalview.ws.jws2.ParameterUtils
-                          .copyParameter(o);
-                } catch (Exception e)
-                {
-                  System.err.println("Failed to copy " + o.getName());
-                  e.printStackTrace();
-                } catch (Error e)
-                {
-                  System.err.println("Failed to copy " + o.getName());
-                  e.printStackTrace();
-                }
-              }
-            }
-            {
-              System.out.println("Testing param write:");
-              List<String> writeparam = null, readparam = null;
-              try
-              {
-                writeparam = jalview.ws.jws2.ParameterUtils
-                        .writeParameterSet(
-                                pr.getArguments(lastserv.getRunnerConfig()),
-                                " ");
-                System.out.println("Testing param read :");
-                List<Option> pset = jalview.ws.jws2.ParameterUtils
-                        .processParameters(writeparam,
-                                lastserv.getRunnerConfig(), " ");
-                readparam = jalview.ws.jws2.ParameterUtils
-                        .writeParameterSet(pset, " ");
-                Iterator<String> o = pr.getOptions().iterator(),
-                        s = writeparam.iterator(), t = readparam.iterator();
-                boolean failed = false;
-                while (s.hasNext() && t.hasNext())
-                {
-                  String on = o.next(), sn = s.next(), st = t.next();
-                  if (!sn.equals(st))
-                  {
-                    System.out.println(
-                            "Original was " + on + " Phase 1 wrote " + sn
-                                    + "\tPhase 2 wrote " + st);
-                    failed = true;
-                  }
-                }
-                if (failed)
-                {
-                  System.out.println(
-                          "Original parameters:\n" + pr.getOptions());
-                  System.out.println(
-                          "Wrote parameters in first set:\n" + writeparam);
-                  System.out.println(
-                          "Wrote parameters in second set:\n" + readparam);
-
-                }
-              } catch (Exception e)
-              {
-                e.printStackTrace();
-              }
-            }
-            WsJobParameters pgui = new WsJobParameters(lastserv,
-                    new JabaPreset(lastserv, pr));
-            JFrame jf = new JFrame(MessageManager
-                    .formatMessage("label.ws_parameters_for", new String[]
-                    { lastserv.getActionText() }));
-            JPanel cont = new JPanel(new BorderLayout());
-            pgui.validate();
-            cont.setPreferredSize(pgui.getPreferredSize());
-            cont.add(pgui, BorderLayout.CENTER);
-            jf.setLayout(new BorderLayout());
-            jf.add(cont, BorderLayout.CENTER);
-            jf.validate();
-            final Thread thr = Thread.currentThread();
-            jf.addWindowListener(new WindowListener()
-            {
-
-              @Override
-              public void windowActivated(WindowEvent e)
-              {
-                // TODO Auto-generated method stub
-
-              }
-
-              @Override
-              public void windowClosed(WindowEvent e)
-              {
-              }
-
-              @Override
-              public void windowClosing(WindowEvent e)
-              {
-                thr.interrupt();
-
-              }
-
-              @Override
-              public void windowDeactivated(WindowEvent e)
-              {
-                // TODO Auto-generated method stub
-
-              }
-
-              @Override
-              public void windowDeiconified(WindowEvent e)
-              {
-                // TODO Auto-generated method stub
-
-              }
-
-              @Override
-              public void windowIconified(WindowEvent e)
-              {
-                // TODO Auto-generated method stub
-
-              }
-
-              @Override
-              public void windowOpened(WindowEvent e)
-              {
-                // TODO Auto-generated method stub
-
-              }
-
-            });
-            jf.setVisible(true);
-            boolean inter = false;
-            while (!inter)
-            {
-              try
-              {
-                Thread.sleep(10000);
-              } catch (Exception e)
-              {
-                inter = true;
-              }
-            }
-            jf.dispose();
-          }
-        }
-      }
-    }
-  }
-
   public boolean isServiceDefaults()
   {
     return (!isModified()
@@ -1202,8 +919,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
     return opanp.getCurrentSettings();
   }
 
-  String lastParmSet = null;
-
   /*
    * Hashtable<String, Object[]> editedParams = new Hashtable<String,
    * Object[]>();
@@ -1243,10 +958,10 @@ public class WsJobParameters extends JPanel implements ItemListener,
     int n = 0;
     // remove any set names in the drop down menu that aren't either a reserved
     // setting, or a user defined or service preset.
-    Vector items = new Vector();
+    Vector<String> items = new Vector<>();
     while (n < setName.getItemCount())
     {
-      String item = (String) setName.getItemAt(n);
+      String item = setName.getItemAt(n);
       if (!item.equals(SVC_DEF) && !paramStore.presetExists(item))
       {
         setName.removeItemAt(n);
@@ -1314,7 +1029,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
     initArgSetModified();
     syncSetNamesWithStore();
     setName.setSelectedItem(lastParmSet);
-    SetNamePanel.validate();
+    setNamePanel.validate();
     validate();
     settingDialog = false;
   }
@@ -1325,9 +1040,13 @@ public class WsJobParameters extends JPanel implements ItemListener,
    */
   protected void updateWebServiceMenus()
   {
+    if (Desktop.getInstance() == null)
+    {
+      return;
+    }
     for (AlignFrame alignFrame : Desktop.getAlignFrames())
     {
-      alignFrame.BuildWebServiceMenu();
+      alignFrame.buildWebServicesMenu();
     }
   }
 
@@ -1336,11 +1055,12 @@ public class WsJobParameters extends JPanel implements ItemListener,
   @Override
   public void itemStateChanged(ItemEvent e)
   {
-    if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
+    if (e.getSource() == setName
+            && e.getStateChange() == ItemEvent.SELECTED)
     {
       final String setname = (String) setName.getSelectedItem();
-      System.out.println("Item state changed for " + setname
-              + " (handling ? " + !settingDialog + ")");
+      // System.out.println("Item state changed for " + setname
+      // + " (handling ? " + !settingDialog + ")");
       if (settingDialog)
       {
         // ignore event
@@ -1396,12 +1116,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
 
   }
 
-  private void _renameExistingPreset(String oldName, String curSetName2)
-  {
-    paramStore.updatePreset(oldName, curSetName2, setDescr.getText(),
-            getJobParams());
-  }
-
   /**
    * store current settings as given name. You should then reset gui.
    * 
index 0f315eb..272e05b 100644 (file)
@@ -56,13 +56,14 @@ import javax.xml.stream.XMLStreamReader;
  */
 public class WsParamSetManager implements ParamManager
 {
+  private static final String WS_PARAM_FILES = "WS_PARAM_FILES";
   Hashtable<String, ParamDatastoreI> paramparsers = new Hashtable<>();
 
   @Override
   public WsParamSetI[] getParameterSet(String name, String serviceUrl,
           boolean modifiable, boolean unmodifiable)
   {
-    String files = Cache.getProperty("WS_PARAM_FILES");
+    String files = Cache.getProperty(WS_PARAM_FILES);
     if (files == null)
     {
       return null;
@@ -107,7 +108,8 @@ public class WsParamSetManager implements ParamManager
       } catch (IOException e)
       {
         Cache.log.info("Failed to parse parameter file " + pfile
-                + " (Check that all JALVIEW_WSPARAMFILES entries are valid!)",
+                + " (Check that all " + WS_PARAM_FILES
+                + " entries are valid!)",
                 e);
       }
     }
@@ -218,7 +220,7 @@ public class WsParamSetManager implements ParamManager
     }
     if (outfile != null)
     {
-      String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES",
+      String paramFiles = jalview.bin.Cache.getDefault(WS_PARAM_FILES,
               filename);
       if (paramFiles.indexOf(filename) == -1)
       {
@@ -228,7 +230,8 @@ public class WsParamSetManager implements ParamManager
         }
         paramFiles = paramFiles.concat(filename);
       }
-      Cache.setProperty("WS_PARAM_FILES", paramFiles);
+
+      Cache.setProperty(WS_PARAM_FILES, paramFiles);
 
       WebServiceParameterSet paramxml = new WebServiceParameterSet();
 
@@ -290,7 +293,7 @@ public class WsParamSetManager implements ParamManager
     {
       return;
     }
-    String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES", "");
+    String paramFiles = jalview.bin.Cache.getDefault(WS_PARAM_FILES, "");
     if (paramFiles.indexOf(filename) > -1)
     {
       String nparamFiles = new String();
@@ -303,7 +306,7 @@ public class WsParamSetManager implements ParamManager
           nparamFiles = nparamFiles.concat("|").concat(fl);
         }
       }
-      jalview.bin.Cache.setProperty("WS_PARAM_FILES", nparamFiles);
+      jalview.bin.Cache.setProperty(WS_PARAM_FILES, nparamFiles);
     }
 
     try
index 8b5e664..cf88718 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
@@ -27,6 +28,7 @@ import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Vector;
 
@@ -40,6 +42,7 @@ import javax.swing.table.TableCellRenderer;
 import jalview.bin.Cache;
 import jalview.jbgui.GWsPreferences;
 import jalview.util.MessageManager;
+import jalview.ws.WSDiscovererI;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.rest.RestServiceDescription;
 
@@ -155,21 +158,22 @@ public class WsPreferences extends GWsPreferences
       String t = new String("");
       switch (((Integer) status).intValue())
       {
-      case 1:
+      case WSDiscovererI.STATUS_OK:
         // cb.setSelected(true);
         // cb.setBackground(
         c = Color.green;
         break;
-      case 0:
+      case WSDiscovererI.STATUS_NO_SERVICES:
         // cb.setSelected(true);
         // cb.setBackground(
         c = Color.lightGray;
         break;
-      case -1:
+      case WSDiscovererI.STATUS_INVALID:
         // cb.setSelected(false);
         // cb.setBackground(
         c = Color.red;
         break;
+      case WSDiscovererI.STATUS_UNKNOWN:
       default:
         // cb.setSelected(false);
         // cb.setBackground(
@@ -484,7 +488,7 @@ public class WsPreferences extends GWsPreferences
 
       if (validate == JvOptionPane.OK_OPTION)
       {
-        if (Jws2Discoverer.testServiceUrl(foo))
+        if (Jws2Discoverer.getInstance().testServiceUrl(foo))
         {
           return foo.toString();
         }
diff --git a/src/jalview/hmmer/HMMAlign.java b/src/jalview/hmmer/HMMAlign.java
new file mode 100644 (file)
index 0000000..d66ec33
--- /dev/null
@@ -0,0 +1,338 @@
+package jalview.hmmer;
+
+import jalview.analysis.AlignmentSorter;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.gui.SplitFrame;
+import jalview.io.DataSourceType;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
+import jalview.ws.params.ArgumentI;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.swing.JInternalFrame;
+
+public class HMMAlign extends HmmerCommand
+{
+  static final String HMMALIGN = "hmmalign";
+
+  private final AlignmentI dataset;
+
+  /**
+   * Constructor for the HMMAlignThread
+   * 
+   * @param af
+   * @param args
+   */
+  public HMMAlign(AlignFrame af, List<ArgumentI> args)
+  {
+    super(af, args);
+    if (alignment.getDataset() != null)
+    {
+      dataset = alignment.getDataset();
+    }
+    else
+    {
+      dataset = null;
+    }
+  }
+
+  /**
+   * Runs the HMMAlignThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame (if true). The command is executed
+   * for each segment of the alignment. Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    HiddenMarkovModel hmm = getHmmProfile();
+
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
+            msgId);
+
+    // ensure alignments are the same length
+    alignment.padGaps();
+
+    AlignmentView msa = af.gatherSequencesForAlignment();
+    SequenceI[][] subAlignments = msa.getVisibleContigs(alignment.getGapCharacter());
+
+    List<AlignmentOrder> allOrders = new ArrayList<>();
+
+    SequenceI[][] allResults = new SequenceI[subAlignments.length][];
+    int job = 0;
+    for (SequenceI[] seqs : subAlignments)
+    {
+      Hashtable sequencesHash = stashSequences(seqs);
+      try
+      {
+        File modelFile = FileUtils.createTempFile("hmm", ".hmm");
+        File alignmentFile = FileUtils.createTempFile("output", ".sto");
+        File resultFile = FileUtils.createTempFile("input", ".sto");
+
+        exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null);
+        exportHmm(hmm, modelFile.getAbsoluteFile());
+
+        boolean ran = runCommand(modelFile, alignmentFile, resultFile);
+        if (!ran)
+        {
+          JvOptionPane.showInternalMessageDialog(af, MessageManager
+                  .formatMessage("warn.command_failed", "hmmalign"));
+          return;
+        }
+
+        SequenceI[] result = importData(resultFile, allOrders);
+        recoverSequences(sequencesHash, result);
+        allResults[job] = result;
+        modelFile.delete();
+        alignmentFile.delete();
+        resultFile.delete();
+      } catch (IOException e)
+      {
+        e.printStackTrace();
+      }
+      job++;
+    }
+
+    String title = "hmmalign to " + hmm.getConsensusSequence().getName();
+    displayResults(allResults, allOrders, msa, title);
+
+    af.setProgressBar("", msgId);
+  }
+
+  /**
+   * Executes the hmmalign command and returns true if successful, false if an
+   * error is detected
+   * 
+   * @param modelFile
+   *          the HMM to align to
+   * @param alignmentFile
+   *          the sequences to align
+   * @param resultFile
+   *          the file to hold the results of alignment
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File modelFile, File alignmentFile,
+          File resultFile) throws IOException
+  {
+    String command = getCommandPath(HMMALIGN);
+    if (command == null)
+    {
+      return false;
+    }
+    List<String> args = new ArrayList<>();
+    args.add(command);
+
+    if (params != null)
+    {
+      for (ArgumentI arg : params)
+      {
+        String name = arg.getName();
+        if (MessageManager.getString("label.trim_termini").equals(name))
+        {
+          args.add(ARG_TRIM);
+        }
+      }
+    }
+    args.add("-o");
+    args.add(getFilePath(resultFile, true));
+    args.add(getFilePath(modelFile, true));
+    args.add(getFilePath(alignmentFile, true));
+    
+    return runCommand(args);
+  }
+
+  /**
+   * Imports the data from the file holding the output of hmmalign
+   * 
+   * @param resultFile
+   * @param allOrders
+   *          a list of alignment orders to add to
+   * 
+   * @return
+   * @throws IOException
+   */
+  private SequenceI[] importData(File resultFile,
+          List<AlignmentOrder> allOrders) throws IOException
+  {
+    StockholmFile file = new StockholmFile(getFilePath(resultFile, false),
+            DataSourceType.FILE);
+    SequenceI[] result = file.getSeqsAsArray();
+    AlignmentOrder msaorder = new AlignmentOrder(result);
+    AlignmentSorter.recoverOrder(result);
+    allOrders.add(msaorder);
+
+    return result;
+  }
+
+  /**
+   * Displays the results of all 'jobs' in a new frame
+   * 
+   * @param allResults
+   * 
+   * @param allOrders
+   * @param msa
+   * @param title
+   */
+  private void displayResults(SequenceI[][] allResults,
+          List<AlignmentOrder> allOrders, AlignmentView msa, String title)
+  {
+    AlignmentOrder[] arrOrders = allOrders
+            .toArray(new AlignmentOrder[allOrders.size()]);
+    Object[] newview = msa.getUpdatedView(allResults, arrOrders,
+            alignment.getGapCharacter());
+    SequenceI[] seqs = (SequenceI[]) newview[0];
+    HiddenColumns hidden = (HiddenColumns) newview[1];
+    Alignment al = new Alignment(seqs);
+    al.setProperty("Alignment Program", "hmmalign");
+    if (dataset != null)
+    {
+      al.setDataset(dataset);
+    }
+
+    displayInNewFrame(al, allOrders, hidden, title);
+  }
+
+  /**
+   * Displays the results in a new frame
+   * 
+   * @param al
+   *          The alignment containing the results
+   * @param alorders
+   *          The order of the sequences in the alignment on which the jobs were
+   *          run
+   * @param hidden
+   *          Hidden columns in the previous alignment
+   * @param title
+   */
+  private void displayInNewFrame(AlignmentI al,
+          List<AlignmentOrder> alorders, HiddenColumns hidden, String title)
+  {
+    AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+    alignFrame.setTitle(title);
+
+    FeatureRendererSettings featureSettings = af.getFeatureRenderer()
+            .getSettings();
+    // initialise with same renderer settings as in parent alignframe.
+    alignFrame.getFeatureRenderer().transferSettings(featureSettings);
+
+    addSortByMenuItems(alignFrame, alorders);
+
+    // TODO: refactor retrieve and show as new splitFrame as Desktop method
+
+    /*
+     * If alignment was requested from one half of a SplitFrame, show in a
+     * SplitFrame with the other pane similarly aligned.
+     */
+    AlignFrame requestedBy = this.af;
+    if (requestedBy != null && requestedBy.getSplitViewContainer() != null
+            && requestedBy.getSplitViewContainer()
+                    .getComplement(requestedBy) != null)
+    {
+      AlignmentI complement = requestedBy.getSplitViewContainer()
+              .getComplement(requestedBy);
+      String complementTitle = requestedBy.getSplitViewContainer()
+              .getComplementTitle(requestedBy);
+      // 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)
+      {
+        alignFrame.setTitle(this.af.getTitle());
+        AlignFrame af2 = new AlignFrame(copyComplement,
+                AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+        af2.setTitle(complementTitle);
+        String linkedTitle = MessageManager
+                .getString("label.linked_view_title");
+        JInternalFrame splitFrame = new SplitFrame(
+                al.isNucleotide() ? alignFrame : af2, al.isNucleotide() ? af2 : alignFrame);
+        Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
+        return;
+      }
+    }
+
+    /*
+     * Not from SplitFrame, or failed to created a complementary alignment
+     */
+    Desktop.addInternalFrame(alignFrame, alignFrame.getTitle(), AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+  }
+
+  /**
+   * Adds sort order options to the AlignFrame menus
+   * 
+   * @param alignFrame
+   * @param alorders
+   */
+  protected void addSortByMenuItems(AlignFrame alignFrame,
+          List<AlignmentOrder> alorders)
+  {
+    // update orders
+    if (alorders.size() == 1)
+    {
+      alignFrame.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
+    }
+    else
+    {
+      // construct a non-redundant ordering set
+      List<String> names = new ArrayList<>();
+      for (int i = 0, l = alorders.size(); i < l; i++)
+      {
+        String orderName = " Region " + i;
+        int j = i + 1;
+
+        while (j < l)
+        {
+          if (alorders.get(i).equals(alorders.get(j)))
+          {
+            alorders.remove(j);
+            l--;
+            orderName += "," + j;
+          }
+          else
+          {
+            j++;
+          }
+        }
+
+        if (i == 0 && j == 1)
+        {
+          names.add("");
+        }
+        else
+        {
+          names.add(orderName);
+        }
+      }
+      for (int i = 0, l = alorders.size(); i < l; i++)
+      {
+        alignFrame.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
+                alorders.get(i));
+      }
+    }
+  }
+}
diff --git a/src/jalview/hmmer/HMMBuild.java b/src/jalview/hmmer/HMMBuild.java
new file mode 100644 (file)
index 0000000..0c47c1d
--- /dev/null
@@ -0,0 +1,370 @@
+package jalview.hmmer;
+
+import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * A class that runs the hmmbuild command as a separate process.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class HMMBuild extends HmmerCommand
+{
+  static final String ARG_AMINO = "--amino";
+
+  static final String ARG_DNA = "--dna";
+
+  static final String ARG_RNA = "--rna";
+
+  /**
+   * Constructor
+   * 
+   * @param alignFrame
+   * @param args
+   */
+  public HMMBuild(AlignFrame alignFrame, List<ArgumentI> args)
+  {
+    super(alignFrame, args);
+  }
+
+  /**
+   * Builds a HMM from an alignment (and/or groups), then imports and adds it to
+   * the alignment (and/or groups). Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    if (params == null || params.isEmpty())
+    {
+      Cache.log.error("No parameters to HMMBuild!|");
+      return;
+    }
+
+    long msgID = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
+            msgID);
+
+    AlignViewportI viewport = af.getViewport();
+    try
+    {
+      /*
+       * run hmmbuild for alignment and/or groups as selected
+       */
+      List<AnnotatedCollectionI> runBuildFor = parseParameters(viewport);
+
+      for (AnnotatedCollectionI grp : runBuildFor)
+      {
+        runHMMBuild(grp);
+      }
+    } finally
+    {
+      af.setProgressBar("", msgID);
+      viewport.alignmentChanged(af.alignPanel);
+      af.buildColourMenu(); // to enable HMMER colour schemes
+    }
+  }
+
+  /**
+   * Scans the parameters to determine whether to run hmmmbuild for the whole
+   * alignment or specified subgroup(s) or both
+   * 
+   * @param viewport
+   * @return
+   */
+  protected List<AnnotatedCollectionI> parseParameters(
+          AlignViewportI viewport)
+  {
+    List<AnnotatedCollectionI> runBuildFor = new ArrayList<>();
+    boolean foundArg = false;
+
+    for (ArgumentI arg : params)
+    {
+      String name = arg.getName();
+      if (MessageManager.getString("label.hmmbuild_for").equals(name))
+      {
+        foundArg = true;
+        String value = arg.getValue();
+
+        if (MessageManager.getString("label.alignment").equals(value))
+        {
+          runBuildFor.add(viewport.getAlignmentView(false)
+                  .getVisibleAlignment('-'));
+        }
+        else if (MessageManager.getString("label.groups_and_alignment")
+                .equals(value))
+        {
+          runBuildFor.add(viewport.getAlignmentView(false)
+                  .getVisibleAlignment('-'));
+          runBuildFor.addAll(viewport.getAlignment().getGroups());
+        }
+        else if (MessageManager.getString("label.groups").equals(value))
+        {
+          runBuildFor.addAll(viewport.getAlignment().getGroups());
+        }
+        else if (MessageManager.getString("label.selected_group")
+                .equals(value))
+        {
+          runBuildFor.add(viewport.getSelectionGroup());
+        }
+      }
+      else if (MessageManager.getString("label.use_reference")
+              .equals(name))
+      {
+        // todo disable this option if no RF annotation on alignment
+        if (!af.getViewport().hasReferenceAnnotation())
+        {
+          JvOptionPane.showInternalMessageDialog(af, MessageManager
+                  .getString("warn.no_reference_annotation"));
+          // return;
+        }
+      }
+    }
+
+    /*
+     * default is to build for the whole alignment
+     */
+    if (!foundArg)
+    {
+      runBuildFor.add(alignment);
+    }
+
+    return runBuildFor;
+  }
+
+  /**
+   * Runs hmmbuild on the given sequences (alignment or group)
+   * 
+   * @param grp
+   */
+  private void runHMMBuild(AnnotatedCollectionI ac)
+  {
+    File hmmFile = null;
+    File alignmentFile = null;
+    try
+    {
+      hmmFile = FileUtils.createTempFile("hmm", ".hmm");
+      alignmentFile = FileUtils.createTempFile("output", ".sto");
+
+      if (ac instanceof Alignment)
+      {
+        AlignmentI al = (Alignment) ac;
+        // todo pad gaps in an unaligned SequenceGroup as well?
+        if (!al.isAligned())
+        {
+          al.padGaps();
+        }
+      }
+
+      deleteHmmSequences(ac);
+
+      List<SequenceI> copy = new ArrayList<>();
+      if (ac instanceof Alignment)
+      {
+        copy.addAll(ac.getSequences());
+      }
+      else
+      {
+        SequenceI[] sel = ((SequenceGroup) ac)
+                                               .getSelectionAsNewSequences((AlignmentI) ac.getContext());
+        for (SequenceI seq : sel)
+        {
+          if (seq != null)
+          {
+            copy.add(seq);
+          }
+        }
+      }
+      // TODO rather than copy alignment data we should anonymize in situ -
+      // export/File import could use anonymization hash to reinstate references
+      // at import level ?
+
+      SequenceI[] copyArray = copy.toArray(new SequenceI[copy.size()]);
+      Hashtable sequencesHash = stashSequences(copyArray);
+
+      exportStockholm(copyArray, alignmentFile, ac);
+
+      recoverSequences(sequencesHash, copy.toArray(new SequenceI[] {}));
+
+      boolean ran = runCommand(alignmentFile, hmmFile, ac);
+      if (!ran)
+      {
+        JvOptionPane.showInternalMessageDialog(af, MessageManager
+                .formatMessage("warn.command_failed", "hmmbuild"));
+        return;
+      }
+      importData(hmmFile, ac);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    } finally
+    {
+      if (hmmFile != null)
+      {
+        hmmFile.delete();
+      }
+      if (alignmentFile != null)
+      {
+        alignmentFile.delete();
+      }
+    }
+  }
+
+  /**
+   * Constructs and executes the hmmbuild command as a separate process
+   * 
+   * @param sequencesFile
+   *          the alignment from which the HMM is built
+   * @param hmmFile
+   *          the output file to which the HMM is written
+   * @param group
+   *          alignment or group for which the hmm is generated
+   * 
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File sequencesFile, File hmmFile,
+          AnnotatedCollectionI group) throws IOException
+  {
+    String cmd = getCommandPath(HMMBUILD);
+    if (cmd == null)
+    {
+      return false; // executable not found
+    }
+    List<String> args = new ArrayList<>();
+    args.add(cmd);
+
+    /*
+     * HMM name (will be given to consensus sequence) is
+     * - as specified by an input parameter if set
+     * - else group name with _HMM appended (if for a group)
+     * - else align frame title with _HMM appended (if title is not too long)
+     * - else "Alignment_HMM" 
+     */
+    String name = "";
+
+    if (params != null)
+    {
+      for (ArgumentI arg : params)
+      {
+        String argName = arg.getName();
+        switch (argName)
+        {
+        case "HMM Name":
+          name = arg.getValue().trim();
+          break;
+        case "Use Reference Annotation":
+          args.add("--hand");
+          break;
+        }
+      }
+    }
+
+    if (group instanceof SequenceGroup)
+    {
+      name = ((SequenceGroup) group).getName() + "_HMM";
+    }
+
+    if ("".equals(name))
+    {
+      if (af != null && af.getTitle().length() < 15)
+      {
+        name = af.getTitle();
+      }
+      else
+      {
+        name = "Alignment_HMM";
+      }
+    }
+
+    args.add("-n");
+    args.add(name.replace(' ', '_'));
+    if (!alignment.isNucleotide())
+    {
+      args.add(ARG_AMINO); // TODO check for rna
+    }
+    else
+    {
+      args.add(ARG_DNA);
+    }
+
+    args.add(getFilePath(hmmFile, true));
+    args.add(getFilePath(sequencesFile, true));
+
+    return runCommand(args);
+  }
+
+  /**
+   * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus
+   * sequence (with attached HMM profile) as the first sequence in the alignment
+   * or group for which it was generated
+   * 
+   * @param hmmFile
+   * @param ac
+   *          (optional) the group for which the hmm was generated
+   * @throws IOException
+   */
+  private void importData(File hmmFile, AnnotatedCollectionI ac)
+          throws IOException
+  {
+    if (hmmFile.length() == 0L)
+    {
+      Cache.log.error("Error: hmmbuild produced empty hmm file");
+      return;
+    }
+
+    HMMFile file = new HMMFile(
+            new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
+    SequenceI hmmSeq = file.getHMM().getConsensusSequence();
+
+
+
+    ResidueCount counts = new ResidueCount(alignment.getSequences());
+    hmmSeq.getHMM().setBackgroundFrequencies(counts);
+
+    if (hmmSeq == null)
+    {
+      // hmmbuild failure not detected earlier
+      return;
+    }
+
+    if (ac instanceof SequenceGroup)
+    {
+      SequenceGroup grp = (SequenceGroup) ac;
+      char gapChar = alignment.getGapCharacter();
+      hmmSeq.insertCharAt(0, ac.getStartRes(), gapChar);
+      hmmSeq.insertCharAt(ac.getEndRes() + 1,
+              alignment.getWidth() - ac.getEndRes() - 1, gapChar);
+      SequenceI topSeq = grp.getSequencesInOrder(alignment)[0];
+      int topIndex = alignment.findIndex(topSeq);
+      alignment.insertSequenceAt(topIndex, hmmSeq);
+      ac.setSeqrep(hmmSeq);
+      grp.addSequence(hmmSeq, false);
+    }
+    else
+    {
+      alignment.insertSequenceAt(0, hmmSeq);
+    }
+  }
+}
diff --git a/src/jalview/hmmer/HMMERParamStore.java b/src/jalview/hmmer/HMMERParamStore.java
new file mode 100644 (file)
index 0000000..df9ab55
--- /dev/null
@@ -0,0 +1,481 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.SequenceI;
+import jalview.gui.Preferences;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.DoubleParameter;
+import jalview.ws.params.simple.FileParameter;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.LogarithmicParameter;
+import jalview.ws.params.simple.Option;
+import jalview.ws.params.simple.RadioChoiceParameter;
+import jalview.ws.params.simple.StringParameter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+public final class HMMERParamStore implements ParamDatastoreI
+{
+  private static final String HMMBUILD = "hmmbuild";
+
+  private static final String HMMALIGN = "hmmalign";
+
+  private static final String HMMSEARCH = "hmmsearch";
+
+  private static final String JACKHMMER = "jackhmmer";
+
+  private String name;
+
+  private List<WsParamSetI> presets = new ArrayList<>();
+
+  private AlignmentViewport viewport;
+
+  private HMMERParamStore(String nam, AlignmentViewport av)
+  {
+    this.viewport = av;
+    this.name = nam;
+  }
+
+  public static HMMERParamStore forBuild(AlignmentViewport viewport)
+  {
+    return new HMMERParamStore(HMMBUILD, viewport);
+  }
+
+  public static HMMERParamStore forAlign(AlignmentViewport viewport)
+  {
+    return new HMMERParamStore(HMMALIGN, viewport);
+  }
+
+  public static HMMERParamStore forSearch(AlignmentViewport viewport)
+  {
+    return new HMMERParamStore(HMMSEARCH, viewport);
+  }
+
+  public static HMMERParamStore forJackhmmer(AlignmentViewport viewport)
+  {
+    return new HMMERParamStore(JACKHMMER, viewport);
+  }
+
+  @Override
+  public List<WsParamSetI> getPresets()
+  {
+    return presets;
+  }
+
+  @Override
+  public WsParamSetI getPreset(String nam)
+  {
+    return null;
+  }
+
+  @Override
+  public List<ArgumentI> getServiceParameters()
+  {
+    List<ArgumentI> args = new ArrayList<>();
+    switch (name)
+    {
+    case HMMSEARCH:
+      getHMMSearchParams(args);
+      break;
+    case HMMALIGN:
+      getHMMAlignParams(args);
+      break;
+    case HMMBUILD:
+      getHMMBuildParams(args);
+      break;
+    case JACKHMMER:
+      getJackhmmerParams(args);
+    default:
+    }
+
+    return args;
+  }
+
+  /**
+   * Answers default parameters for hmmsearch, taking into account any
+   * configured as user preferences
+   * 
+   * @param args
+   */
+  private void getHMMSearchParams(List<ArgumentI> args)
+  {
+    /*
+     * 'Options'
+     */
+    args.add(new BooleanOption(
+            MessageManager.getString(HMMSearch.AUTO_ALIGN_SEQS_KEY),
+            MessageManager.getString("label.auto_align_seqs_desc"), false,
+            false, false, null));
+    args.add(new BooleanOption(
+            MessageManager.getString(HMMSearch.USE_ACCESSIONS_KEY),
+            MessageManager.getString("label.use_accessions_desc"), false,
+            false, true, null));
+    args.add(new BooleanOption(
+            MessageManager.getString(HMMSearch.TRIM_TERMINI_KEY),
+            MessageManager.getString("label.trim_termini_desc"), false,
+            false, true, null));
+    args.add(new BooleanOption(
+            MessageManager.getString(HMMSearch.RETURN_N_NEW_SEQ),
+            MessageManager.getString("label.check_for_new_sequences_desc"),
+            false, false, false, null));
+
+    /*
+     * 'Parameters'
+     */
+    addChoiceOfHmm(args);
+
+    // addChoiceOfDatabase(args);
+
+    String thisAlignment = MessageManager
+            .getString(HMMSearch.THIS_ALIGNMENT_KEY);
+    String database = MessageManager.getString("label.database");
+    args.add(new FileParameter(database, "", false, "", ""));
+    args.add(new IntegerParameter(
+            MessageManager.getString(HMMSearch.NUMBER_OF_RESULTS_KEY),
+            MessageManager.getString("label.number_of_results_desc"), true,
+            100, 0, 100000));
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString(HMMSearch.REPORTING_CUTOFF_KEY), null,
+            Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+                    MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+            MessageManager.getString(HMMSearch.CUTOFF_EVALUE)));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.REPORTING_SEQ_EVALUE_KEY),
+            MessageManager.getString("label.reporting_seq_e_value_desc"),
+            false, 1D,
+            1E-100, 10D));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.REPORTING_DOM_EVALUE_KEY),
+            MessageManager.getString("label.reporting_dom_e_value_desc"),
+            false, 1D,
+            1E-100, 10D));
+    args.add(
+            new DoubleParameter(
+                    MessageManager
+                            .getString(HMMSearch.REPORTING_SEQ_SCORE_KEY),
+                    MessageManager.getString(
+                            "label.reporting_seq_score_desc"),
+                    false,
+                    0d, 0d, 1000d));
+    args.add(
+            new DoubleParameter(
+                    MessageManager
+                            .getString(HMMSearch.REPORTING_DOM_SCORE_KEY),
+                    MessageManager.getString(
+                            "label.reporting_dom_score_desc"),
+                    false,
+                    0d, 0d, 1000d));
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_THRESHOLD_KEY),
+            null,
+            Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+                    MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+            MessageManager.getString(HMMSearch.CUTOFF_EVALUE)));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_SEQ_EVALUE_KEY),
+            MessageManager.getString("label.inclusion_seq_e_value_desc"),
+            false, 1D,
+            1E-100, 10D));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_DOM_EVALUE_KEY),
+            MessageManager.getString("label.inclusion_dom_e_value_desc"),
+            false, 1D,
+            1E-100, 10D));
+    args.add(new DoubleParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_SEQ_SCORE_KEY),
+            MessageManager.getString("label.inclusion_seq_score_desc"),
+            false, 0d, 0d,
+            1000d));
+    args.add(new DoubleParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_DOM_SCORE_KEY),
+            MessageManager.getString("label.inclusion_dom_score_desc"),
+            false, 0d, 0d,
+            1000d));
+  }
+
+  /**
+   * Answers default parameters for jackhmmer, taking into account any configured
+   * as user preferences
+   * 
+   * @param args
+   */
+  private void getJackhmmerParams(List<ArgumentI> args)
+  {
+
+    /*
+     * 'Parameters'
+     */
+    addChoiceOfSequence(args);
+
+    // addChoiceOfDatabase(args);
+
+    String database = MessageManager.getString("label.database");
+    args.add(new FileParameter(database, "", false, "", ""));
+    args.add(new IntegerParameter(
+            MessageManager.getString(HMMSearch.NUMBER_OF_ITERATIONS),
+            MessageManager.getString("label.number_of_iterations_desc"),
+            true, 5, 1, 20));
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString(JackHMMER.REPORTING_CUTOFF_KEY), null,
+            Arrays.asList(MessageManager.getString(JackHMMER.CUTOFF_NONE),
+                    MessageManager.getString(JackHMMER.CUTOFF_EVALUE),
+                    MessageManager.getString(JackHMMER.CUTOFF_SCORE)),
+            MessageManager.getString(JackHMMER.CUTOFF_EVALUE)));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(JackHMMER.REPORTING_SEQ_EVALUE_KEY),
+            MessageManager.getString("label.reporting_seq_e_value_desc"),
+            false, 1D,
+            1E-38, 10D));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(JackHMMER.REPORTING_DOM_EVALUE_KEY),
+            MessageManager.getString(
+                    "label.reporting_dom_e_value_desc"),
+            false, 1D,
+            1E-38, 10D));
+    args.add(new DoubleParameter(
+            MessageManager.getString(JackHMMER.REPORTING_SEQ_SCORE_KEY),
+            MessageManager.getString("label.reporting_seq_score_desc"),
+            false, 0d, 0d,
+            1000d));
+    args.add(new DoubleParameter(
+            MessageManager.getString(JackHMMER.REPORTING_DOM_SCORE_KEY),
+            MessageManager.getString("label.reporting_dom_score_desc"),
+            false, 0d, 0d,
+            1000d));
+    args.add(new RadioChoiceParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_THRESHOLD_KEY),
+            null,
+            Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+                    MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+            MessageManager.getString(HmmerCommand.CUTOFF_EVALUE)));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_SEQ_EVALUE_KEY),
+            MessageManager.getString("label.inclusion_seq_e_value_desc"),
+            false, 1D, 1E-100, 10D));
+    args.add(new LogarithmicParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_DOM_EVALUE_KEY),
+            MessageManager.getString("label.inclusion_dom_e_value_desc"),
+            false, 1D, 1E-100, 10D));
+    args.add(new DoubleParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_SEQ_SCORE_KEY),
+            MessageManager.getString("label.inclusion_seq_score_desc"),
+            false, 0d, 0d, 1000d));
+    args.add(new DoubleParameter(
+            MessageManager.getString(HMMSearch.INCLUSION_DOM_SCORE_KEY),
+            MessageManager.getString("label.inclusion_dom_score_desc"),
+            false, 0d, 0d, 1000d));
+  }
+
+  /**
+   * Constructs a choice parameter for database to search; always includes 'this
+   * alignment', and also includes any databases held under user preferences key
+   * "HMMSEARCH_DBS" as a comma-delimited list
+   * 
+   * @param args
+   */
+  protected void addChoiceOfDatabase(List<ArgumentI> args)
+  {
+    String names = Cache.getProperty(Preferences.HMMSEARCH_DBS);
+    if (names == null || names.isEmpty())
+    {
+      return;
+    }
+
+    List<String> filePaths = new ArrayList<>();
+    List<String> fileNames = new ArrayList<>();
+
+    String thisAlignment = MessageManager.getString(HMMSearch.THIS_ALIGNMENT_KEY);
+    filePaths.add(thisAlignment);
+    fileNames.add(thisAlignment);
+
+    Scanner nameScanner = new Scanner(names);
+    nameScanner.useDelimiter(Preferences.COMMA);
+
+    while (nameScanner.hasNext())
+    {
+      String next = nameScanner.next();
+      if ("null".equals(next))
+      {
+        Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
+      }
+      else
+      {
+        filePaths.add(next);
+        int pos = next.lastIndexOf(File.separator);
+        String fileName = next.substring(pos + 1);
+        fileNames.add(fileName);
+      }
+    }
+    nameScanner.close();
+    ArgumentI databasesOption = new StringParameter(
+            MessageManager.getString(HMMSearch.DATABASE_KEY),
+            MessageManager.getString("label.database_for_hmmsearch"), true,
+            thisAlignment,
+            thisAlignment,
+            filePaths, fileNames);
+    args.add(databasesOption);
+  }
+
+  /**
+   * Answers default parameters for hmmalign, taking into account any configured
+   * as user preferences
+   * 
+   * @param args
+   */
+  private void getHMMAlignParams(List<ArgumentI> args)
+  {
+    addChoiceOfHmm(args);
+
+    boolean def = Cache.getDefault(Preferences.HMMALIGN_TRIM_TERMINI,
+            false);
+    args.add(new BooleanOption(
+            MessageManager.getString("label.trim_termini"),
+            MessageManager.getString("label.trim_termini_desc"),
+            false, false, def, null));
+  }
+
+  /**
+   * Adds an argument representing the choice of HMM sequences (profiles)
+   * against which to perform align or search, provided at least one is found
+   * 
+   * @param args
+   */
+  protected void addChoiceOfHmm(List<ArgumentI> args)
+  {
+    List<SequenceI> hmms = viewport.getAlignment().getHmmSequences();
+    if (!hmms.isEmpty())
+    {
+      List<String> options = new ArrayList<>();
+      for (SequenceI hmmSeq : hmms)
+      {
+        options.add(hmmSeq.getName());
+      }
+      String defseq = options.get(0);
+      ArgumentI arg = new StringParameter(
+              MessageManager.getString("label.use_hmm"), null, true, defseq,
+              defseq, options, null);
+      args.add(arg);
+    }
+  }
+
+  /**
+   * Adds an argument representing the choice of sequence against which to perform
+   * jackhmmer
+   * 
+   * @param args
+   */
+  protected void addChoiceOfSequence(List<ArgumentI> args)
+  {
+    List<SequenceI> sequences = viewport.getAlignment().getSequences();
+
+    List<String> options = new ArrayList<>();
+
+    for (SequenceI seq : sequences)
+    {
+      options.add(seq.getName());
+    }
+
+    String defseq = options.get(0);
+    ArgumentI arg = new StringParameter(
+            MessageManager.getString("label.use_sequence"), null, true,
+            defseq,
+            defseq, options, null);
+    args.add(arg);
+  }
+
+  /**
+   * Answers default parameters for hmmbuild, taking into account any configured
+   * as user preferences
+   * 
+   * @param args
+   */
+  private void getHMMBuildParams(List<ArgumentI> args)
+  {
+    /*
+     * name to give the computed alignment HMM consensus sequence
+     * (Jalview constructs group HMM consensus sequence names)
+     */
+    String defValue = "Alignment_HMM";
+    StringParameter nameParam = new StringParameter(MessageManager.getString("label.hmm_name"),
+            MessageManager.getString("label.hmm_name_desc"), true, defValue,
+            defValue);
+    args.add(nameParam);
+
+    /*
+     * only enable Use Reference Annotation if RF is present
+     */
+    if (viewport.hasReferenceAnnotation())
+    {
+      args.add(new BooleanOption(
+              MessageManager.getString("label.use_reference"),
+              MessageManager.getString("label.use_reference_desc"), true,
+              true, true, null));
+    }
+
+    /*
+     * choice of whether to compute HMM for alignment and/or group(s)
+     * - only if there are any groups
+     */
+    if (!viewport.getAlignment().getGroups().isEmpty())
+    {
+      List<String> options = new ArrayList<>();
+      options.add(MessageManager.getString("label.alignment"));
+      options.add(MessageManager.getString("label.groups_and_alignment"));
+      options.add(MessageManager.getString("label.groups"));
+      options.add(MessageManager.getString("label.selected_group"));
+      args.add(new Option(MessageManager.getString("label.hmmbuild_for"),
+              MessageManager.getString("label.hmmbuild_for_desc"), true,
+              MessageManager.getString("label.alignment"),
+              MessageManager.getString("label.alignment"), options, null));
+    }
+  }
+
+  @Override
+  public boolean presetExists(String forName)
+  {
+    return false;
+  }
+
+  @Override
+  public void deletePreset(String forName)
+  {
+  }
+
+  @Override
+  public void storePreset(String presetName, String text,
+          List<ArgumentI> jobParams)
+  {
+  }
+
+  @Override
+  public void updatePreset(String oldName, String presetName, String text,
+          List<ArgumentI> jobParams)
+  {
+  }
+
+  @Override
+  public WsParamSetI parseServiceParameterFile(String forName,
+          String description, String[] serviceURL, String parameters)
+          throws IOException
+  {
+    return null;
+  }
+
+  @Override
+  public String generateServiceParameterFile(WsParamSetI pset)
+          throws IOException
+  {
+    return null;
+  }
+
+}
diff --git a/src/jalview/hmmer/HMMERPreset.java b/src/jalview/hmmer/HMMERPreset.java
new file mode 100644 (file)
index 0000000..2712259
--- /dev/null
@@ -0,0 +1,57 @@
+package jalview.hmmer;
+
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
+
+public class HMMERPreset implements WsParamSetI
+{
+
+  @Override
+  public String getName()
+  {
+    return null;
+  }
+
+  @Override
+  public String getDescription()
+  {
+    return null;
+  }
+
+  @Override
+  public String[] getApplicableUrls()
+  {
+    return null;
+  }
+
+  @Override
+  public String getSourceFile()
+  {
+    return null;
+  }
+
+  @Override
+  public void setSourceFile(String newfile)
+  {
+  }
+
+  @Override
+  public boolean isModifiable()
+  {
+    return false;
+  }
+
+  @Override
+  public List<ArgumentI> getArguments()
+  {
+    return null;
+  }
+
+  @Override
+  public void setArguments(List<ArgumentI> args)
+  {
+  }
+
+}
diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java
new file mode 100644 (file)
index 0000000..f05823e
--- /dev/null
@@ -0,0 +1,318 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.Option;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+public class HMMSearch extends Search
+{
+
+  boolean realign = false;
+
+  boolean trim = false;
+
+  boolean returnNoOfNewSeqs = false;
+
+  int seqsToReturn = Integer.MAX_VALUE;
+
+
+  /**
+   * Constructor for the HMMSearchThread
+   * 
+   * @param af
+   */
+  public HMMSearch(AlignFrame af, List<ArgumentI> args)
+  {
+    super(af, args);
+  }
+
+  /**
+   * Runs the HMMSearchThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame. Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    HiddenMarkovModel hmm = getHmmProfile();
+    if (hmm == null)
+    {
+      // shouldn't happen if we got this far
+      Cache.log.error("Error: no hmm for hmmsearch");
+      return;
+    }
+
+    SequenceI hmmSeq = hmm.getConsensusSequence();
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_search"),
+            msgId);
+
+    try
+    {
+      File hmmFile = FileUtils.createTempFile("hmm", ".hmm");
+      File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment",
+              ".sto");
+      File searchOutputFile = FileUtils.createTempFile("searchOutput",
+              ".sto");
+
+      exportHmm(hmm, hmmFile.getAbsoluteFile());
+
+      boolean ran = runCommand(searchOutputFile, hitsAlignmentFile, hmmFile);
+      if (!ran)
+      {
+        JvOptionPane.showInternalMessageDialog(af, MessageManager
+                .formatMessage("warn.command_failed", "hmmsearch"));
+        return;
+      }
+
+      importData(hmmSeq, hitsAlignmentFile, hmmFile, searchOutputFile);
+      // TODO make realignment of search results a step at this level
+      // and make it conditional on this.realign
+    } catch (IOException | InterruptedException e)
+    {
+      e.printStackTrace();
+    }
+    finally
+    {
+      af.setProgressBar("", msgId);
+    }
+  }
+
+  /**
+   * Executes an hmmsearch with the given hmm as input. The database to be
+   * searched is a local file as specified by the 'Database' parameter, or the
+   * current alignment (written to file) if none is specified.
+   * 
+   * @param searchOutputFile
+   * @param hitsAlignmentFile
+   * @param hmmFile
+   * 
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+          File hmmFile) throws IOException
+  {
+    String command = getCommandPath(HMMSEARCH);
+    if (command == null)
+    {
+      return false;
+    }
+
+    List<String> args = new ArrayList<>();
+    args.add(command);
+    buildArguments(args, searchOutputFile, hitsAlignmentFile, hmmFile);
+
+    return runCommand(args);
+  }
+
+
+  /**
+   * Imports the data from the temporary file to which the output of hmmsearch
+   * was directed. The results are optionally realigned using hmmalign.
+   * 
+   * @param hmmSeq
+   */
+  private void importData(SequenceI hmmSeq, File inputAlignmentTemp,
+          File hmmTemp, File searchOutputFile)
+          throws IOException, InterruptedException
+  {
+    BufferedReader br = new BufferedReader(
+            new FileReader(inputAlignmentTemp));
+    try
+    {
+      if (br.readLine() == null)
+      {
+        JOptionPane.showMessageDialog(af,
+                MessageManager.getString("label.no_sequences_found"));
+        return;
+      }
+      StockholmFile file = new StockholmFile(new FileParse(
+              inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+      seqs = file.getSeqsAsArray();
+
+      readDomainTable(searchOutputFile, false);
+
+      if (searchAlignment)
+      {
+        recoverSequences(sequencesHash, seqs);
+      }
+
+      // look for PP cons and ref seq in alignment only annotation
+      AlignmentAnnotation modelpos = null, ppcons = null;
+      for (AlignmentAnnotation aa : file.getAnnotations())
+      {
+        if (aa.sequenceRef == null)
+        {
+          if (aa.label.equals("Reference Positions")) // RF feature type in
+                                                      // stockholm parser
+          {
+            modelpos = aa;
+          }
+          if (aa.label.equals("Posterior Probability"))
+          {
+            ppcons = aa;
+          }
+        }
+      }
+
+
+      int seqCount = Math.min(seqs.length, seqsToReturn);
+      SequenceI[] hmmAndSeqs = new SequenceI[seqCount + 1];
+      hmmSeq = hmmSeq.deriveSequence(); // otherwise all bad things happen
+      hmmAndSeqs[0] = hmmSeq;
+      System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqCount);
+      if (modelpos != null)
+      {
+        // TODO need - get ungapped sequence method
+        hmmSeq.setSequence(
+                hmmSeq.getDatasetSequence().getSequenceAsString());
+        Annotation[] refpos = modelpos.annotations;
+        // insert gaps to match with refseq positions
+        int gc = 0, lcol = 0;
+        for (int c = 0; c < refpos.length; c++)
+        {
+          if (refpos[c] != null && ("x".equals(refpos[c].displayCharacter)))
+          {
+            if (gc > 0)
+            {
+              hmmSeq.insertCharAt(lcol + 1, gc, '-');
+            }
+            gc = 0;
+            lcol = c;
+          }
+          else
+          {
+            gc++;
+          }
+        }
+      }
+
+      if (realign)
+      {
+        realignResults(hmmAndSeqs);
+      }
+      else
+      {
+        AlignmentI al = new Alignment(hmmAndSeqs);
+        if (ppcons != null)
+        {
+          al.addAnnotation(ppcons);
+        }
+        if (modelpos != null)
+        {
+          al.addAnnotation(modelpos);
+        }
+        AlignFrame alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
+                AlignFrame.DEFAULT_HEIGHT);
+        String ttl = "hmmSearch of " + databaseName + " using "
+                + hmmSeq.getName();
+        Desktop.addInternalFrame(alignFrame, ttl, AlignFrame.DEFAULT_WIDTH,
+                AlignFrame.DEFAULT_HEIGHT);
+
+        if (returnNoOfNewSeqs)
+        {
+          int nNew = checkForNewSequences();
+          JvOptionPane.showMessageDialog(af.alignPanel, nNew + " "
+                  + MessageManager.getString("label.new_returned"));
+        }
+
+      }
+
+
+      hmmTemp.delete();
+      inputAlignmentTemp.delete();
+      searchOutputFile.delete();
+    } finally
+    {
+      if (br != null)
+      {
+        br.close();
+      }
+    }
+  }
+
+  private int checkForNewSequences()
+  {
+    int nNew = seqs.length;
+
+    for (SequenceI resultSeq : seqs)
+    {
+      for (SequenceI aliSeq : alignment.getSequencesArray())
+      {
+        if (resultSeq.getName().equals(aliSeq.getName()))
+        {
+          nNew--;
+          break;
+        }
+      }
+    }
+
+    return nNew;
+
+  }
+
+  /**
+   * Realigns the given sequences using hmmalign, to the HMM profile sequence
+   * which is the first in the array, and opens the results in a new frame
+   * 
+   * @param hmmAndSeqs
+   */
+  protected void realignResults(SequenceI[] hmmAndSeqs)
+  {
+    /*
+     * and align the search results to the HMM profile
+     */
+    AlignmentI al = new Alignment(hmmAndSeqs);
+    AlignFrame frame = new AlignFrame(al, 1, 1);
+    List<ArgumentI> alignArgs = new ArrayList<>();
+    String alignTo = hmmAndSeqs[0].getName();
+    List<String> options = Collections.singletonList(alignTo);
+    Option option = new Option(MessageManager.getString("label.use_hmm"),
+            "", true, alignTo, alignTo, options, null);
+    alignArgs.add(option);
+    if (trim)
+    {
+      alignArgs.add(new BooleanOption(
+              MessageManager.getString(TRIM_TERMINI_KEY),
+              MessageManager.getString("label.trim_termini_desc"), true,
+              true, true, null));
+    }
+    HmmerCommand hmmalign = new HMMAlign(frame, alignArgs);
+    hmmalign.run();
+
+    if (returnNoOfNewSeqs)
+    {
+      int nNew = checkForNewSequences();
+      JvOptionPane.showMessageDialog(frame.alignPanel,
+              nNew + " " + MessageManager.getString("label.new_returned"));
+    }
+  }
+
+}
diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java
new file mode 100644 (file)
index 0000000..0240352
--- /dev/null
@@ -0,0 +1,536 @@
+package jalview.hmmer;
+
+import jalview.analysis.SeqsetUtils;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.gui.Preferences;
+import jalview.io.FastaFile;
+import jalview.io.HMMFile;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * Base class for hmmbuild, hmmalign and hmmsearch
+ * 
+ * @author TZVanaalten
+ *
+ */
+public abstract class HmmerCommand implements Runnable
+{
+  public static final String HMMBUILD = "hmmbuild";
+
+  protected final AlignFrame af;
+
+  protected final AlignmentI alignment;
+
+  protected final List<ArgumentI> params;
+
+  /*
+   * constants for i18n lookup of passed parameter names
+   */
+  static final String DATABASE_KEY = "label.database";
+
+  static final String THIS_ALIGNMENT_KEY = "label.this_alignment";
+
+  static final String USE_ACCESSIONS_KEY = "label.use_accessions";
+
+  static final String AUTO_ALIGN_SEQS_KEY = "label.auto_align_seqs";
+
+  static final String NUMBER_OF_RESULTS_KEY = "label.number_of_results";
+
+  static final String NUMBER_OF_ITERATIONS = "label.number_of_iterations";
+
+  static final String TRIM_TERMINI_KEY = "label.trim_termini";
+
+  static final String RETURN_N_NEW_SEQ = "label.check_for_new_sequences";
+
+  static final String REPORTING_CUTOFF_KEY = "label.reporting_cutoff";
+
+  static final String CUTOFF_NONE = "label.default";
+
+  static final String CUTOFF_SCORE = "label.score";
+
+  static final String CUTOFF_EVALUE = "label.evalue";
+
+  static final String REPORTING_SEQ_EVALUE_KEY = "label.reporting_seq_evalue";
+
+  static final String REPORTING_DOM_EVALUE_KEY = "label.reporting_dom_evalue";
+
+  static final String REPORTING_SEQ_SCORE_KEY = "label.reporting_seq_score";
+
+  static final String REPORTING_DOM_SCORE_KEY = "label.reporting_dom_score";
+
+  static final String INCLUSION_SEQ_EVALUE_KEY = "label.inclusion_seq_evalue";
+
+  static final String INCLUSION_DOM_EVALUE_KEY = "label.inclusion_dom_evalue";
+
+  static final String INCLUSION_SEQ_SCORE_KEY = "label.inclusion_seq_score";
+
+  static final String INCLUSION_DOM_SCORE_KEY = "label.inclusion_dom_score";
+
+  static final String ARG_TRIM = "--trim";
+
+  static final String INCLUSION_THRESHOLD_KEY = "label.inclusion_threshold";
+
+  /**
+   * Constructor
+   * 
+   * @param alignFrame
+   * @param args
+   */
+  public HmmerCommand(AlignFrame alignFrame, List<ArgumentI> args)
+  {
+    af = alignFrame;
+    alignment = af.getViewport().getAlignment();
+    params = args;
+  }
+
+  /**
+   * Answers true if preference HMMER_PATH is set, and its value is the path to
+   * a directory that contains an executable <code>hmmbuild</code> or
+   * <code>hmmbuild.exe</code>, else false
+   * 
+   * @return
+   */
+  public static boolean isHmmerAvailable()
+  {
+    File exec = FileUtils.getExecutable(HMMBUILD,
+            Cache.getProperty(Preferences.HMMER_PATH));
+    return exec != null;
+  }
+
+  /**
+   * Uniquifies the sequences when exporting and stores their details in a
+   * hashtable
+   * 
+   * @param seqs
+   */
+  protected Hashtable stashSequences(SequenceI[] seqs)
+  {
+    return SeqsetUtils.uniquify(seqs, true);
+  }
+
+  /**
+   * Restores the sequence data lost by uniquifying
+   * 
+   * @param hashtable
+   * @param seqs
+   */
+  protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs)
+  {
+    SeqsetUtils.deuniquify(hashtable, seqs);
+  }
+
+  /**
+   * Runs a command as a separate process and waits for it to complete. Answers
+   * true if the process return status is zero, else false.
+   * 
+   * @param commands
+   *          the executable command and any arguments to it
+   * @throws IOException
+   */
+  public boolean runCommand(List<String> commands)
+          throws IOException
+  {
+    List<String> args = Platform.isWindowsAndNotJS() ? wrapWithCygwin(commands)
+            : commands;
+
+    try
+    {
+      ProcessBuilder pb = new ProcessBuilder(args);
+      pb.redirectErrorStream(true); // merge syserr to sysout
+      if (Platform.isWindowsAndNotJS())
+      {
+        String path = pb.environment().get("Path");
+        path = jalview.bin.Cache.getProperty("CYGWIN_PATH") + ";" + path;
+        pb.environment().put("Path", path);
+      }
+      final Process p = pb.start();
+      new Thread(new Runnable()
+      {
+        @Override
+        public void run()
+        {
+          BufferedReader input = new BufferedReader(
+                  new InputStreamReader(p.getInputStream()));
+          try
+          {
+            String line = input.readLine();
+            while (line != null)
+            {
+              System.out.println(line);
+              line = input.readLine();
+            }
+          } catch (IOException e)
+          {
+            e.printStackTrace();
+          }
+        }
+      }).start();
+
+      p.waitFor();
+      int exitValue = p.exitValue();
+      if (exitValue != 0)
+      {
+        Cache.log.error("Command failed, return code = " + exitValue);
+        Cache.log.error("Command/args were: " + args.toString());
+      }
+      return exitValue == 0; // 0 is success, by convention
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  /**
+   * Converts the given command to a Cygwin "bash" command wrapper. The hmmer
+   * command and any arguments to it are converted into a single parameter to the
+   * bash command.
+   * 
+   * @param commands
+   */
+  protected List<String> wrapWithCygwin(List<String> commands)
+  {
+    File bash = FileUtils.getExecutable("bash",
+            Cache.getProperty(Preferences.CYGWIN_PATH));
+    if (bash == null)
+    {
+      Cache.log.error("Cygwin shell not found");
+      return commands;
+    }
+
+    List<String> wrapped = new ArrayList<>();
+    // wrapped.add("C:\Users\tva\run");
+    wrapped.add(bash.getAbsolutePath());
+    wrapped.add("-c");
+
+    /*
+     * combine hmmbuild/search/align and arguments to a single string
+     */
+    StringBuilder sb = new StringBuilder();
+    for (String cmd : commands)
+    {
+      sb.append(" ").append(cmd);
+    }
+    wrapped.add(sb.toString());
+
+    return wrapped;
+  }
+
+  /**
+   * Exports an alignment, and reference (RF) annotation if present, to the
+   * specified file, in Stockholm format, removing all HMM sequences
+   * 
+   * @param seqs
+   * @param toFile
+   * @param annotated
+   * @throws IOException
+   */
+  public void exportStockholm(SequenceI[] seqs, File toFile,
+          AnnotatedCollectionI annotated)
+          throws IOException
+  {
+    if (seqs == null)
+    {
+      return;
+    }
+    AlignmentI newAl = new Alignment(seqs);
+
+    if (!newAl.isAligned())
+    {
+      newAl.padGaps();
+    }
+
+    if (toFile != null && annotated != null)
+    {
+      AlignmentAnnotation[] annots = annotated.getAlignmentAnnotation();
+      if (annots != null)
+      {
+        for (AlignmentAnnotation annot : annots)
+        {
+          if (annot.label.contains("Reference") || "RF".equals(annot.label))
+          {
+            AlignmentAnnotation newRF;
+            if (annot.annotations.length > newAl.getWidth())
+            {
+              Annotation[] rfAnnots = new Annotation[newAl.getWidth()];
+              System.arraycopy(annot.annotations, 0, rfAnnots, 0,
+                      rfAnnots.length);
+              newRF = new AlignmentAnnotation("RF", "Reference Positions",
+                      rfAnnots);
+            }
+            else
+            {
+              newRF = new AlignmentAnnotation(annot);
+            }
+            newAl.addAnnotation(newRF);
+          }
+        }
+      }
+    }
+
+    for (SequenceI seq : newAl.getSequencesArray())
+    {
+      if (seq.getAnnotation() != null)
+      {
+        for (AlignmentAnnotation ann : seq.getAnnotation())
+        {
+          seq.removeAlignmentAnnotation(ann);
+        }
+      }
+    }
+
+    StockholmFile file = new StockholmFile(newAl);
+    String output = file.print(seqs, false);
+    PrintWriter writer = new PrintWriter(toFile);
+    writer.println(output);
+    writer.close();
+  }
+
+  /**
+   * Answers the full path to the given hmmer executable, or null if file cannot
+   * be found or is not executable
+   * 
+   * @param cmd
+   *          command short name e.g. hmmalign
+   * @return
+   * @throws IOException
+   */
+  protected String getCommandPath(String cmd)
+          throws IOException
+  {
+    String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH);
+    // ensure any symlink to the directory is resolved:
+    binariesFolder = Paths.get(binariesFolder).toRealPath().toString();
+    File file = FileUtils.getExecutable(cmd, binariesFolder);
+    if (file == null && af != null)
+    {
+      JvOptionPane.showInternalMessageDialog(af, MessageManager
+              .formatMessage("label.executable_not_found", cmd));
+    }
+
+    return file == null ? null : getFilePath(file, true);
+  }
+
+  /**
+   * Exports an HMM to the specified file
+   * 
+   * @param hmm
+   * @param hmmFile
+   * @throws IOException
+   */
+  public void exportHmm(HiddenMarkovModel hmm, File hmmFile)
+          throws IOException
+  {
+    if (hmm != null)
+    {
+      HMMFile file = new HMMFile(hmm);
+      PrintWriter writer = new PrintWriter(hmmFile);
+      writer.print(file.print());
+      writer.close();
+    }
+  }
+
+  // TODO is needed?
+  /**
+   * Exports a sequence to the specified file
+   * 
+   * @param hmm
+   * @param hmmFile
+   * @throws IOException
+   */
+  public void exportSequence(SequenceI seq, File seqFile) throws IOException
+  {
+    if (seq != null)
+    {
+      FastaFile file = new FastaFile();
+      PrintWriter writer = new PrintWriter(seqFile);
+      writer.print(file.print(new SequenceI[] { seq }, false));
+      writer.close();
+    }
+  }
+
+  /**
+   * Answers the HMM profile for the profile sequence the user selected (default
+   * is just the first HMM sequence in the alignment)
+   * 
+   * @return
+   */
+  protected HiddenMarkovModel getHmmProfile()
+  {
+    String alignToParamName = MessageManager.getString("label.use_hmm");
+    for (ArgumentI arg : params)
+    {
+      String name = arg.getName();
+      if (name.equals(alignToParamName))
+      {
+        String seqName = arg.getValue();
+        SequenceI hmmSeq = alignment.findName(seqName);
+        if (hmmSeq.hasHMMProfile())
+        {
+          return hmmSeq.getHMM();
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Answers the query sequence the user selected (default is just the first
+   * sequence in the alignment)
+   * 
+   * @return
+   */
+  protected SequenceI getSequence()
+  {
+    String alignToParamName = MessageManager
+            .getString("label.use_sequence");
+    for (ArgumentI arg : params)
+    {
+      String name = arg.getName();
+      if (name.equals(alignToParamName))
+      {
+        String seqName = arg.getValue();
+        SequenceI seq = alignment.findName(seqName);
+        return seq;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Answers an absolute path to the given file, in a format suitable for
+   * processing by a hmmer command. On a Windows platform, the native Windows file
+   * path is converted to Cygwin format, by replacing '\'with '/' and drive letter
+   * X with /cygdrive/x.
+   * 
+   * @param resultFile
+   * @param isInCygwin
+   *                     True if file is to be read/written from within the Cygwin
+   *                     shell. Should be false for any imports.
+   * @return
+   */
+  protected String getFilePath(File resultFile, boolean isInCygwin)
+  {
+    String path = resultFile.getAbsolutePath();
+    if (Platform.isWindowsAndNotJS() && isInCygwin)
+    {
+      // the first backslash escapes '\' for the regular expression argument
+      path = path.replaceAll("\\" + File.separator, "/");
+      int colon = path.indexOf(':');
+      if (colon > 0)
+      {
+        String drive = path.substring(0, colon);
+        path = path.replaceAll(drive + ":", "/cygdrive/" + drive);
+      }
+    }
+
+    return path;
+  }
+
+  /**
+   * A helper method that deletes any HMM consensus sequence from the given
+   * collection, and from the parent alignment if <code>ac</code> is a subgroup
+   * 
+   * @param ac
+   */
+  void deleteHmmSequences(AnnotatedCollectionI ac)
+  {
+    List<SequenceI> hmmSeqs = ac.getHmmSequences();
+    for (SequenceI hmmSeq : hmmSeqs)
+    {
+      if (ac instanceof SequenceGroup)
+      {
+        ((SequenceGroup) ac).deleteSequence(hmmSeq, false);
+        AnnotatedCollectionI context = ac.getContext();
+        if (context != null && context instanceof AlignmentI)
+        {
+          ((AlignmentI) context).deleteSequence(hmmSeq);
+        }
+      }
+      else
+      {
+        ((AlignmentI) ac).deleteSequence(hmmSeq);
+      }
+    }
+  }
+
+  /**
+   * Sets the names of any duplicates within the given sequences to include their
+   * respective lengths. Deletes any duplicates that have the same name after this
+   * step
+   * 
+   * @param seqs
+   */
+  void renameDuplicates(AlignmentI al)
+  {
+
+    SequenceI[] seqs = al.getSequencesArray();
+    List<Boolean> wasRenamed = new ArrayList<>();
+
+    for (SequenceI seq : seqs)
+    {
+      wasRenamed.add(false);
+    }
+
+    for (int i = 0; i < seqs.length; i++)
+    {
+      for (int j = 0; j < seqs.length; j++)
+      {
+        if (seqs[i].getName().equals(seqs[j].getName()) && i != j
+                && !wasRenamed.get(j))
+        {
+
+          wasRenamed.set(i, true);
+          String range = "/" + seqs[j].getStart() + "-" + seqs[j].getEnd();
+          // setting sequence name to include range - to differentiate between
+          // sequences of the same name. Currently have to include the range twice
+          // because the range is removed (once) when setting the name
+          // TODO come up with a better way of doing this
+          seqs[j].setName(seqs[j].getName() + range + range);
+        }
+
+      }
+      if (wasRenamed.get(i))
+      {
+        String range = "/" + seqs[i].getStart() + "-" + seqs[i].getEnd();
+        seqs[i].setName(seqs[i].getName() + range + range);
+      }
+    }
+
+    for (int i = 0; i < seqs.length; i++)
+    {
+      for (int j = 0; j < seqs.length; j++)
+      {
+        if (seqs[i].getName().equals(seqs[j].getName()) && i != j)
+        {
+          al.deleteSequence(j);
+        }
+      }
+    }
+  }
+
+}
diff --git a/src/jalview/hmmer/JackHMMER.java b/src/jalview/hmmer/JackHMMER.java
new file mode 100644 (file)
index 0000000..12c0492
--- /dev/null
@@ -0,0 +1,179 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+public class JackHMMER extends Search
+{
+
+  SequenceI seq = null;
+
+  /**
+   * Constructor for the JackhmmerThread
+   * 
+   * @param af
+   */
+  public JackHMMER(AlignFrame af, List<ArgumentI> args)
+  {
+    super(af, args);
+  }
+
+  /**
+   * Runs the JackhmmerThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame. Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    seq = getSequence();
+    if (seq == null)
+    {
+      // shouldn't happen if we got this far
+      Cache.log.error("Error: no sequence for jackhmmer");
+      return;
+    }
+
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_search"),
+            msgId);
+
+    try
+    {
+      File seqFile = FileUtils.createTempFile("seq", ".sto");
+      File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment",
+              ".sto");
+      File searchOutputFile = FileUtils.createTempFile("searchOutput",
+              ".txt");
+
+      exportStockholm(new SequenceI[] { seq }, seqFile.getAbsoluteFile(),
+              null);
+
+      boolean ran = runCommand(searchOutputFile, hitsAlignmentFile,
+              seqFile);
+      if (!ran)
+      {
+        JvOptionPane.showInternalMessageDialog(af, MessageManager
+                .formatMessage("warn.command_failed", "jackhmmer"));
+        return;
+      }
+
+      importData(hitsAlignmentFile, seqFile, searchOutputFile);
+      // TODO make realignment of search results a step at this level
+      // and make it conditional on this.realign
+    } catch (IOException | InterruptedException e)
+    {
+      e.printStackTrace();
+    } finally
+    {
+      af.setProgressBar("", msgId);
+    }
+  }
+
+  /**
+   * Executes an jackhmmer search with the given sequence as input. The database
+   * to be searched is a local file as specified by the 'Database' parameter, or
+   * the current alignment (written to file) if none is specified.
+   * 
+   * @param searchOutputFile
+   * @param hitsAlignmentFile
+   * @param seqFile
+   * 
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+          File seqFile) throws IOException
+  {
+    String command = getCommandPath(JACKHMMER);
+    if (command == null)
+    {
+      return false;
+    }
+
+    List<String> args = new ArrayList<>();
+    args.add(command);
+    buildArguments(args, searchOutputFile, hitsAlignmentFile, seqFile);
+
+    return runCommand(args);
+  }
+
+  /**
+   * Imports the data from the temporary file to which the output of jackhmmer was
+   * directed.
+   */
+  private void importData(File inputAlignmentTemp, File seqTemp,
+          File searchOutputFile) throws IOException, InterruptedException
+  {
+    BufferedReader br = new BufferedReader(
+            new FileReader(inputAlignmentTemp));
+    try
+    {
+      if (br.readLine() == null)
+      {
+        JOptionPane.showMessageDialog(af,
+                MessageManager.getString("label.no_sequences_found"));
+        return;
+      }
+      StockholmFile file = new StockholmFile(new FileParse(
+              inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+      seqs = file.getSeqsAsArray();
+
+      readDomainTable(searchOutputFile, true);
+
+      if (searchAlignment)
+      {
+        recoverSequences(sequencesHash, seqs);
+      }
+
+
+
+      int seqCount = seqs.length;
+
+
+      AlignmentI al = new Alignment(seqs);
+
+      AlignFrame alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+      String ttl = "jackhmmer search of " + databaseName + " using "
+              + seqs[0].getName();
+      Desktop.addInternalFrame(alignFrame, ttl, AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
+
+      seqTemp.delete();
+      inputAlignmentTemp.delete();
+      searchOutputFile.delete();
+    } finally
+    {
+      if (br != null)
+      {
+        br.close();
+      }
+    }
+  }
+
+
+
+
+}
diff --git a/src/jalview/hmmer/Search.java b/src/jalview/hmmer/Search.java
new file mode 100644 (file)
index 0000000..ceb79e5
--- /dev/null
@@ -0,0 +1,394 @@
+package jalview.hmmer;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Scanner;
+
+public abstract class Search extends HmmerCommand
+{
+
+  static final String JACKHMMER = "jackhmmer";
+
+  static final String HMMSEARCH = "hmmsearch";
+
+  boolean realign = false;
+
+  boolean trim = false;
+
+  SequenceI[] seqs;
+
+  String databaseName;
+
+  boolean searchAlignment = true;
+
+  Hashtable sequencesHash;
+
+  public Search(AlignFrame alignFrame, List<ArgumentI> args)
+  {
+    super(alignFrame, args);
+  }
+
+  @Override
+  public void run()
+  {
+  }
+
+  /*
+  void readOutputFile(File inputTableTemp) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+  
+  
+    String line = "";
+    while (!line.startsWith("//"))
+    {
+  
+      while (!line.startsWith(">> ") && !line.startsWith("//"))
+      {
+        line = br.readLine();
+      }
+  
+      if (line.startsWith("//"))
+      {
+        break;
+      }
+  
+      Scanner scanner = new Scanner(line);
+      String name = scanner.next();
+      name = scanner.next();
+  
+      br.readLine();
+      br.readLine();
+  
+      List<SequenceI> domains = new ArrayList<>();
+  
+      for (SequenceI seq : seqs)
+      {
+        if (seq.getName().contains(name))
+        {
+          domains.add(seq);
+        }
+      }
+  
+      if (domains.contains(getSequence()))
+      {
+        domains.remove(getSequence());
+      }
+  
+      if (domains.size() > 0)
+      {
+        readOutputTable(br, domains);
+      }
+  
+      line = br.readLine();
+    }
+  
+  }
+  
+  
+  /**
+   * Reads in the scores table output by jackhmmer and adds annotation to
+   * sequences for E-value and bit score
+   * 
+   * @param inputTableTemp
+   * @throws IOException
+   */
+  /*
+  void readOutputTable(BufferedReader br, List<SequenceI> seqs) throws IOException
+  {
+    String line = br.readLine();
+  
+    while (!"".equals(line) && line != null)
+    {
+      if ("  ------ inclusion threshold ------".equals(line))
+      {
+        line = br.readLine();
+        continue;
+      }
+  
+      Scanner scanner = new Scanner(line);
+      scanner.next();
+      scanner.next();
+      String score = scanner.next();
+  
+      scanner.next();
+  
+      String evalue = scanner.next();
+  
+      scanner.next();
+      scanner.next();
+      scanner.next();
+      scanner.next();
+  
+      int start = scanner.nextInt();
+      int end = scanner.nextInt();
+  
+      SequenceI seq = null;
+      for (SequenceI sequence : seqs)
+      {
+        if (sequence.getStart() >= start && sequence.getEnd() <= end)
+        {
+          seq = sequence;
+          break;
+        }
+      }
+  
+      if (seq != null)
+      {
+        addScoreAnnotations(evalue, score, seq);
+      }
+  
+      scanner.close();
+      line = br.readLine();
+    }
+  }
+  */
+
+  void readDomainTable(File inputTableTemp, boolean includesQuery)
+          throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+
+    String line = br.readLine();
+    br.readLine();
+    br.readLine();
+    line = br.readLine();
+
+    int index;
+
+    if (includesQuery)
+    {
+      index = 1;
+    }
+    else
+    {
+      index = 0;
+    }
+    while (!line.startsWith("#"))
+    {
+      if (line.contains("inclusion threshold"))
+      {
+        line = br.readLine();
+        continue;
+      }
+
+      Scanner scanner = new Scanner(line);
+      String name = scanner.next();
+
+      for (int i = 0; i < 10; i++)
+      {
+        scanner.next();
+      }
+
+      String evalue = scanner.next();
+      scanner.next();
+      String score = scanner.next();
+
+      addScoreAnnotations(evalue, score, seqs[index]);
+      index++;
+
+      scanner.close();
+      line = br.readLine();
+    }
+    br.close();
+  }
+
+
+
+
+  void addScoreAnnotations(String eValue, String bitScore, SequenceI seq)
+  {
+    String label = "Search Scores";
+    String description = "Full sequence bit score and E-Value";
+
+    try
+    {
+      AlignmentAnnotation annot = new AlignmentAnnotation(label,
+              description, null);
+
+      annot.label = label;
+      annot.description = description;
+
+      annot.setCalcId(JACKHMMER);
+
+      double dEValue = Double.parseDouble(eValue);
+      annot.setEValue(dEValue);
+
+      double dBitScore = Double.parseDouble(bitScore);
+      annot.setBitScore(dBitScore);
+
+      annot.setSequenceRef(seq);
+      seq.addAlignmentAnnotation(annot);
+
+    } catch (NumberFormatException e)
+    {
+      System.err.println("Error parsing " + label + " from " + eValue
+              + " & " + bitScore);
+    }
+  }
+
+  void buildArguments(List<String> args, File searchOutputFile,
+          File hitsAlignmentFile, File queryFile) throws IOException
+  {
+    args.add("--domtblout");
+    args.add(getFilePath(searchOutputFile, true));
+    args.add("-A");
+    args.add(getFilePath(hitsAlignmentFile, true));
+
+    File databaseFile = null;
+
+    boolean useEvalueCutoff = false;
+    boolean useScoreCutoff = false;
+    String seqReportingEvalueCutoff = null;
+    String domReportingEvalueCutoff = null;
+    String seqReportingScoreCutoff = null;
+    String domReportingScoreCutoff = null;
+    String seqInclusionEvalueCutoff = null;
+    String domInclusionEvalueCutoff = null;
+    String seqInclusionScoreCutoff = null;
+    String domInclusionScoreCutoff = null;
+    databaseName = "Alignment";
+
+    if (params != null)
+    {
+      for (ArgumentI arg : params)
+      {
+        String name = arg.getName();
+
+        if (MessageManager.getString(REPORTING_CUTOFF_KEY).equals(name))
+        {
+          if (MessageManager.getString(CUTOFF_EVALUE)
+                  .equals(arg.getValue()))
+          {
+            useEvalueCutoff = true;
+          }
+          else if (MessageManager.getString(CUTOFF_SCORE)
+                  .equals(arg.getValue()))
+          {
+            useScoreCutoff = true;
+          }
+        }
+        else if (MessageManager.getString(REPORTING_SEQ_EVALUE_KEY)
+                .equals(name))
+        {
+          seqReportingEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(REPORTING_SEQ_SCORE_KEY)
+                .equals(name))
+        {
+          seqReportingScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(REPORTING_DOM_EVALUE_KEY)
+                .equals(name))
+        {
+          domReportingEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(REPORTING_DOM_SCORE_KEY)
+                .equals(name))
+        {
+          domReportingScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(INCLUSION_SEQ_EVALUE_KEY)
+                .equals(name))
+        {
+          seqInclusionEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(INCLUSION_SEQ_SCORE_KEY)
+                .equals(name))
+        {
+          seqInclusionScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(INCLUSION_DOM_EVALUE_KEY)
+                .equals(name))
+        {
+          domInclusionEvalueCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(INCLUSION_DOM_SCORE_KEY)
+                .equals(name))
+        {
+          domInclusionScoreCutoff = arg.getValue();
+        }
+        else if (MessageManager.getString(DATABASE_KEY).equals(name))
+        {
+          databaseFile = new File(arg.getValue());
+          if (!arg.getValue().isEmpty())
+          {
+            searchAlignment = false;
+          }
+        }
+        else if (MessageManager.getString(NUMBER_OF_ITERATIONS)
+                .equals(name))
+        {
+          if (!arg.getValue().isEmpty())
+          {
+            args.add("-N");
+            args.add(arg.getValue());
+          }
+        }
+      }
+    }
+
+    if (useEvalueCutoff)
+    {
+      args.add("-E");
+      args.add(seqReportingEvalueCutoff);
+      args.add("--domE");
+      args.add(domReportingEvalueCutoff);
+
+      args.add("--incE");
+      args.add(seqInclusionEvalueCutoff);
+      args.add("--incdomE");
+      args.add(domInclusionEvalueCutoff);
+    }
+    else if (useScoreCutoff)
+    {
+      args.add("-T");
+      args.add(seqReportingScoreCutoff);
+      args.add("--domT");
+      args.add(domReportingScoreCutoff);
+
+      args.add("--incT");
+      args.add(seqInclusionEvalueCutoff);
+      args.add("--incdomT");
+      args.add(domInclusionEvalueCutoff);
+    }
+
+    // if (!dbFound || MessageManager.getString(THIS_ALIGNMENT_KEY)
+    // .equals(dbPath))
+    if (searchAlignment)
+    {
+      /*
+       * no external database specified for search, so
+       * export current alignment as 'database' to search
+       */
+      databaseFile = FileUtils.createTempFile("database", ".sto");
+      AlignmentI al = af.getViewport().getAlignment();
+      AlignmentI copy = new Alignment(al);
+
+      deleteHmmSequences(copy);
+
+      if (searchAlignment)
+      {
+        sequencesHash = stashSequences(copy.getSequencesArray());
+      }
+
+      exportStockholm(copy.getSequencesArray(), databaseFile, null);
+    }
+
+    args.add(getFilePath(queryFile, true));
+    args.add(getFilePath(databaseFile, true));
+  }
+}
index cea2870..41f2586 100755 (executable)
@@ -323,9 +323,9 @@ public abstract class AlignFile extends FileParse
    */
   protected void initData()
   {
-    seqs = new Vector<SequenceI>();
-    annotations = new Vector<AlignmentAnnotation>();
-    seqGroups = new ArrayList<SequenceGroup>();
+    seqs = new Vector<>();
+    annotations = new Vector<>();
+    seqGroups = new ArrayList<>();
     parseCalled = false;
   }
 
@@ -338,7 +338,7 @@ public abstract class AlignFile extends FileParse
   @Override
   public void setSeqs(SequenceI[] s)
   {
-    seqs = new Vector<SequenceI>();
+    seqs = new Vector<>();
 
     for (int i = 0; i < s.length; i++)
     {
@@ -409,7 +409,7 @@ public abstract class AlignFile extends FileParse
   {
     if (newickStrings == null)
     {
-      newickStrings = new Vector<String[]>();
+      newickStrings = new Vector<>();
     }
     newickStrings.addElement(new String[] { treeName, newickString });
   }
@@ -433,4 +433,16 @@ public abstract class AlignFile extends FileParse
   {
     seqs.add(seq);
   }
+
+  /**
+   * Used only for hmmer statistics, so should probably be removed at some
+   * point. TODO remove this
+   * 
+   * @return
+   */
+  public Vector<AlignmentAnnotation> getAnnotations()
+  {
+    return annotations;
+  }
+
 }
diff --git a/src/jalview/io/CountReader.java b/src/jalview/io/CountReader.java
new file mode 100644 (file)
index 0000000..a691c53
--- /dev/null
@@ -0,0 +1,63 @@
+package jalview.io;
+
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.util.MessageManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import javax.swing.JFileChooser;
+
+public class CountReader
+{
+  public static ResidueCount getBackgroundFrequencies(AlignmentPanel ap, SequenceI seq) throws MalformedURLException, IOException
+  {
+    JFileChooser bkgdFreqChooser = new JFileChooser();
+    
+    bkgdFreqChooser.showOpenDialog(ap);
+    
+    File file = bkgdFreqChooser.getSelectedFile();
+    if (file == null)
+    {
+      return null;
+    }
+    
+    IdentifyFile identifier = new IdentifyFile();
+    FileFormatI format = null;
+    try
+    {
+      format = identifier.identify(file.getPath(), DataSourceType.FILE);
+    } catch (Exception e)
+    {
+
+    }
+    
+    if (format == null)
+    {
+      if (!Jalview.isHeadlessMode())
+      {
+        JvOptionPane.showInternalMessageDialog(Desktop.getInstance(),
+                MessageManager.getString("label.couldnt_read_data") + " in "
+                        + file + "\n"
+                        + AppletFormatAdapter.getSupportedFormats(),
+                MessageManager.getString("label.couldnt_read_data"),
+                JvOptionPane.WARNING_MESSAGE);
+      }
+    }
+
+    FileParse parser = new FileParse(file.getPath(), DataSourceType.FILE);
+    AlignmentI al = new FormatAdapter().readFromFile(parser, format);
+    parser.close();
+    
+    ResidueCount counts = new ResidueCount(al.getSequences());
+    
+    return counts;
+  }
+}
index 0ad2901..b7df731 100644 (file)
@@ -373,6 +373,21 @@ public enum FileFormat implements FileFormatI
     {
       return true;
     }
+  },
+  HMMER3("HMMER3", "hmm", true, true)
+  {
+    @Override
+    public AlignmentFileReaderI getReader(FileParse source)
+            throws IOException
+    {
+      return new HMMFile(source);
+    }
+
+    @Override
+    public AlignmentFileWriterI getWriter(AlignmentI al)
+    {
+      return new HMMFile();
+    }
   },   BSML("BSML", "bbb", true, false)
   {
     @Override
@@ -389,6 +404,7 @@ public enum FileFormat implements FileFormatI
     }
   };
 
+
   private boolean writable;
 
   private boolean readable;
index 0317c7d..df64702 100755 (executable)
@@ -50,8 +50,13 @@ import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.utils.UrlDownloadClient;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class FileLoader implements Runnable
 {
+  private static final String TAB = "\t";
+
   String file;
 
   DataSourceType protocol;
@@ -214,56 +219,79 @@ public class FileLoader implements Runnable
     return alignFrame;
   }
 
-  public void updateRecentlyOpened()
+  public void LoadFileOntoAlignmentWaitTillLoaded(AlignViewport viewport,
+          String file, DataSourceType sourceType, FileFormatI format)
   {
     Vector<String> recent = new Vector<>();
     if (protocol == DataSourceType.PASTE)
+    this.viewport = viewport;
+    this.file = file;
+    this.protocol = sourceType;
+    this.format = format;
+    _LoadFileWaitTillLoaded();
+  }
+
+
+  /**
+   * Updates (or creates) the tab-separated list of recently opened files held
+   * under the given property name by inserting the filePath at the front of the
+   * list. Duplicates are removed, and the list is limited to 11 entries. The
+   * method returns the updated value of the property.
+   * 
+   * @param filePath
+   * @param sourceType
+   */
+  public static String updateRecentlyOpened(String filePath,
+          DataSourceType sourceType)
+  {
+    if (sourceType != DataSourceType.FILE
+            && sourceType != DataSourceType.URL)
     {
-      // do nothing if the file was pasted in as text... there is no filename to
-      // refer to it as.
-      return;
+      return null;
     }
-    if (file != null
-            && file.indexOf(System.getProperty("java.io.tmpdir")) > -1)
+
+    String propertyName = sourceType == DataSourceType.FILE ? "RECENT_FILE"
+            : "RECENT_URL";
+    String historyItems = Cache.getProperty(propertyName);
+    if (filePath != null
+            && filePath.indexOf(System.getProperty("java.io.tmpdir")) > -1)
     {
       // ignore files loaded from the system's temporary directory
-      return;
+      return null;
     }
-    String type = protocol == DataSourceType.FILE ? "RECENT_FILE"
-            : "RECENT_URL";
 
-    String historyItems = Cache.getProperty(type);
-
-    StringTokenizer st;
+    List<String> recent = new ArrayList<>();
 
     if (historyItems != null)
     {
-      st = new StringTokenizer(historyItems, "\t");
+      StringTokenizer st = new StringTokenizer(historyItems, TAB);
 
       while (st.hasMoreTokens())
       {
-        recent.addElement(st.nextToken().trim());
+        String trimmed = st.nextToken().trim();
+       recent.add(trimmed);
       }
     }
 
-    if (recent.contains(file))
+    /*
+     * if file was already in the list, it moves to the top
+     */
+    if (recent.contains(filePath))
     {
-      recent.remove(file);
+      recent.remove(filePath);
     }
 
-    StringBuffer newHistory = new StringBuffer(file);
+    StringBuilder newHistory = new StringBuilder(filePath);
     for (int i = 0; i < recent.size() && i < 10; i++)
     {
-      newHistory.append("\t");
-      newHistory.append(recent.elementAt(i));
+      newHistory.append(TAB);
+      newHistory.append(recent.get(i));
     }
 
-    Cache.setProperty(type, newHistory.toString());
+    String newProperty = newHistory.toString();
+    Cache.setProperty(propertyName, newProperty);
 
-    if (protocol == DataSourceType.FILE)
-    {
-      Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName());
-    }
+    return newProperty;
   }
 
   @Override
@@ -424,6 +452,22 @@ public class FileLoader implements Runnable
             }
             // append to existing alignment
             viewport.addAlignment(al, title);
+            if (source instanceof HMMFile)
+            {
+              AlignmentI alignment = viewport.getAlignment();
+              SequenceI seq = alignment
+                      .getSequenceAt(alignment.getHeight() - 1);
+              if (seq.hasHMMProfile())
+              {
+                /* 
+                 * fudge: move HMM consensus sequence from last to first
+                 */
+                alignment.deleteSequence(alignment.getAbsoluteHeight() - 1);
+                alignment.insertSequenceAt(0, seq);
+              }
+              viewport.getAlignPanel().adjustAnnotationHeight();
+              viewport.updateSequenceIdColours();
+            }
           }
           else
           {
@@ -531,7 +575,12 @@ public class FileLoader implements Runnable
         }
       }
 
-      updateRecentlyOpened();
+      updateRecentlyOpened(file, protocol);
+
+      if (protocol == DataSourceType.FILE && format != null)
+      {
+        Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName());
+      }
 
     } catch (Exception er)
     {
diff --git a/src/jalview/io/HMMFile.java b/src/jalview/io/HMMFile.java
new file mode 100644 (file)
index 0000000..2fce4cc
--- /dev/null
@@ -0,0 +1,716 @@
+package jalview.io;
+
+import jalview.api.AlignExportSettingsI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.HMMNode;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+
+/**
+ * Adds capability to read in and write out HMMER3 files. .
+ * 
+ * 
+ * @author TZVanaalten
+ *
+ */
+public class HMMFile extends AlignFile
+        implements AlignmentFileReaderI, AlignmentFileWriterI
+{
+  private static final String TERMINATOR = "//";
+
+  /*
+   * keys to data in HMM file, used to store as properties of the HiddenMarkovModel
+   */
+  public static final String HMM = "HMM";
+
+  public static final String NAME = "NAME";
+
+  public static final String ACCESSION_NUMBER = "ACC";
+
+  public static final String DESCRIPTION = "DESC";
+
+  public static final String LENGTH = "LENG";
+
+  public static final String MAX_LENGTH = "MAXL";
+
+  public static final String ALPHABET = "ALPH";
+
+  public static final String DATE = "DATE";
+
+  public static final String COMMAND_LOG = "COM";
+
+  public static final String NUMBER_OF_SEQUENCES = "NSEQ";
+
+  public static final String EFF_NUMBER_OF_SEQUENCES = "EFFN";
+
+  public static final String CHECK_SUM = "CKSUM";
+
+  public static final String STATISTICS = "STATS";
+
+  public static final String COMPO = "COMPO";
+
+  public static final String GATHERING_THRESHOLD = "GA";
+
+  public static final String TRUSTED_CUTOFF = "TC";
+
+  public static final String NOISE_CUTOFF = "NC";
+
+  public static final String VITERBI = "VITERBI";
+
+  public static final String MSV = "MSV";
+
+  public static final String FORWARD = "FORWARD";
+
+  public static final String MAP = "MAP";
+
+  public static final String REFERENCE_ANNOTATION = "RF";
+
+  public static final String CONSENSUS_RESIDUE = "CONS";
+
+  public static final String CONSENSUS_STRUCTURE = "CS";
+
+  public static final String MASKED_VALUE = "MM";
+
+  private static final String ALPH_AMINO = "amino";
+
+  private static final String ALPH_DNA = "DNA";
+
+  private static final String ALPH_RNA = "RNA";
+
+  private static final String ALPHABET_AMINO = "ACDEFGHIKLMNPQRSTVWY";
+
+  private static final String ALPHABET_DNA = "ACGT";
+
+  private static final String ALPHABET_RNA = "ACGU";
+
+  private static final int NUMBER_OF_TRANSITIONS = 7;
+
+  private static final String SPACE = " ";
+
+  /*
+   * optional guide line added to an output HMMER file, purely for readability
+   */
+  private static final String TRANSITIONTYPELINE = "            m->m     m->i     m->d     i->m     i->i     d->m     d->d";
+
+  private static String NL = System.lineSeparator();
+
+  private HiddenMarkovModel hmm;
+
+  // number of symbols in the alphabet used in the hidden Markov model
+  private int numberOfSymbols;
+
+  /**
+   * Constructor that parses immediately
+   * 
+   * @param inFile
+   * @param type
+   * @throws IOException
+   */
+  public HMMFile(String inFile, DataSourceType type) throws IOException
+  {
+    super(inFile, type);
+  }
+
+  /**
+   * Constructor that parses immediately
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public HMMFile(FileParse source) throws IOException
+  {
+    super(source);
+  }
+
+  /**
+   * Default constructor
+   */
+  public HMMFile()
+  {
+  }
+
+  /**
+   * Constructor for HMMFile used for exporting
+   * 
+   * @param hmm
+   */
+  public HMMFile(HiddenMarkovModel markov)
+  {
+    hmm = markov;
+  }
+
+  /**
+   * Returns the HMM produced by parsing a HMMER3 file
+   * 
+   * @return
+   */
+  public HiddenMarkovModel getHMM()
+  {
+    return hmm;
+  }
+
+  /**
+   * Gets the name of the hidden Markov model
+   * 
+   * @return
+   */
+  public String getName()
+  {
+    return hmm.getName();
+  }
+
+  /**
+   * Reads the data from HMM file into the HMM model
+   */
+  @Override
+  public void parse()
+  {
+    try
+    {
+      hmm = new HiddenMarkovModel();
+      parseHeaderLines(dataIn);
+      parseModel(dataIn);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Reads the header properties from a HMMER3 file and saves them in the
+   * HiddeMarkovModel. This method exits after reading the next line after the
+   * HMM line.
+   * 
+   * @param input
+   * @throws IOException
+   */
+  void parseHeaderLines(BufferedReader input) throws IOException
+  {
+    boolean readingHeaders = true;
+    hmm.setFileHeader(input.readLine());
+    String line = input.readLine();
+    while (readingHeaders && line != null)
+    {
+      Scanner parser = new Scanner(line);
+      String next = parser.next();
+      if (ALPHABET.equals(next))
+      {
+        String alphabetType = parser.next();
+        hmm.setProperty(ALPHABET, alphabetType);
+        String alphabet = ALPH_DNA.equalsIgnoreCase(alphabetType)
+                ? ALPHABET_DNA
+                : (ALPH_RNA.equalsIgnoreCase(alphabetType) ? ALPHABET_RNA
+                        : ALPHABET_AMINO);
+        numberOfSymbols = hmm.setAlphabet(alphabet);
+      }
+      else if (HMM.equals(next))
+      {
+        readingHeaders = false;
+        String symbols = line.substring(line.indexOf(HMM) + HMM.length());
+        numberOfSymbols = hmm.setAlphabet(symbols);
+      }
+      else if (STATISTICS.equals(next))
+      {
+        parser.next();
+        String key;
+        String value;
+        key = parser.next();
+        value = parser.next() + SPACE + SPACE + parser.next();
+        hmm.setProperty(key, value);
+      }
+      else
+      {
+        String key = next;
+        String value = parser.next();
+        while (parser.hasNext())
+        {
+          value = value + SPACE + parser.next();
+        }
+        hmm.setProperty(key, value);
+      }
+      parser.close();
+      line = input.readLine();
+    }
+  }
+
+  /**
+   * Parses the model data from the HMMER3 file. The input buffer should be
+   * positioned at the (optional) COMPO line if there is one, else at the insert
+   * emissions line for the BEGIN node of the model.
+   * 
+   * @param input
+   * @throws IOException
+   */
+  void parseModel(BufferedReader input) throws IOException
+  {
+    /*
+     * specification says there must always be an HMM header (already read)
+     * and one more header (guide headings) which is skipped here
+     */
+    int nodeNo = 0;
+    String line = input.readLine();
+    List<HMMNode> nodes = new ArrayList<>();
+
+    while (line != null && !TERMINATOR.equals(line))
+    {
+      HMMNode node = new HMMNode();
+      nodes.add(node);
+      Scanner scanner = new Scanner(line);
+      String next = scanner.next();
+
+      /*
+       * expect COMPO (optional) for average match emissions
+       * or a node number followed by node's match emissions
+       */
+      if (COMPO.equals(next) || nodeNo > 0)
+      {
+        /*
+         * parse match emissions
+         */
+        double[] matches = parseDoubles(scanner, numberOfSymbols);
+        node.setMatchEmissions(matches);
+        if (!COMPO.equals(next))
+        {
+          int resNo = parseAnnotations(scanner, node);
+          if (resNo == 0)
+          {
+            /*
+             * no MAP annotation provided, just number off from 0 (begin node)
+             */
+            resNo = nodeNo;
+          }
+          node.setResidueNumber(resNo);
+        }
+        line = input.readLine();
+      }
+      scanner.close();
+
+      /*
+       * parse insert emissions
+       */
+      scanner = new Scanner(line);
+      double[] inserts = parseDoubles(scanner, numberOfSymbols);
+      node.setInsertEmissions(inserts);
+      scanner.close();
+
+      /*
+       * parse state transitions
+       */
+      line = input.readLine();
+      scanner = new Scanner(line);
+      double[] transitions = parseDoubles(scanner,
+              NUMBER_OF_TRANSITIONS);
+      node.setStateTransitions(transitions);
+      scanner.close();
+      line = input.readLine();
+
+      nodeNo++;
+    }
+
+    hmm.setNodes(nodes);
+  }
+
+  /**
+   * Parses the annotations on the match emission line and add them to the node.
+   * (See p109 of the HMMER User Guide (V3.1b2) for the specification.) Returns
+   * the residue position that the node maps to, if provided, else zero.
+   * 
+   * @param scanner
+   * @param node
+   */
+  int parseAnnotations(Scanner scanner, HMMNode node)
+  {
+    int mapTo = 0;
+
+    /*
+     * map from hmm node to sequence position, if provided
+     */
+    if (scanner.hasNext())
+    {
+      String value = scanner.next();
+      if (!"-".equals(value))
+      {
+        try
+        {
+          mapTo = Integer.parseInt(value);
+          node.setResidueNumber(mapTo);
+        } catch (NumberFormatException e)
+        {
+          // ignore
+        }
+      }
+    }
+
+    /*
+     * hmm consensus residue if provided, else '-'
+     */
+    if (scanner.hasNext())
+    {
+      node.setConsensusResidue(scanner.next().charAt(0));
+    }
+
+    /*
+     * RF reference annotation, if provided, else '-'
+     */
+    if (scanner.hasNext())
+    {
+      node.setReferenceAnnotation(scanner.next().charAt(0));
+    }
+
+    /*
+     * 'm' for masked position, if provided, else '-'
+     */
+    if (scanner.hasNext())
+    {
+      node.setMaskValue(scanner.next().charAt(0));
+    }
+
+    /*
+     * structure consensus symbol, if provided, else '-'
+     */
+    if (scanner.hasNext())
+    {
+      node.setConsensusStructure(scanner.next().charAt(0));
+    }
+
+    return mapTo;
+  }
+
+  /**
+   * Fills an array of doubles parsed from an input line
+   * 
+   * @param input
+   * @param numberOfElements
+   * @return
+   * @throws IOException
+   */
+  static double[] parseDoubles(Scanner input,
+          int numberOfElements) throws IOException
+  {
+    double[] values = new double[numberOfElements];
+    for (int i = 0; i < numberOfElements; i++)
+    {
+      if (!input.hasNext())
+      {
+        throw new IOException("Incomplete data");
+      }
+      String next = input.next();
+      if (next.contains("*"))
+      {
+        values[i] = Double.NEGATIVE_INFINITY;
+      }
+      else
+      {
+        double prob = Double.valueOf(next);
+        prob = Math.pow(Math.E, -prob);
+        values[i] = prob;
+      }
+    }
+    return values;
+  }
+
+  /**
+   * Returns a string to be added to the StringBuilder containing the entire
+   * output String.
+   * 
+   * @param initialColumnSeparation
+   *          The initial whitespace separation between the left side of the
+   *          file and first character.
+   * @param columnSeparation
+   *          The separation between subsequent data entries.
+   * @param data
+   *          The list of data to be added to the String.
+   * @return
+   */
+  String addData(int initialColumnSeparation,
+          int columnSeparation, List<String> data)
+  {
+    String line = "";
+    boolean first = true;
+    for (String value : data)
+    {
+      int sep = first ? initialColumnSeparation : columnSeparation;
+      line += String.format("%" + sep + "s", value);
+      first = false;
+    }
+    return line;
+  }
+
+  /**
+   * Converts list of characters into a list of Strings.
+   * 
+   * @param list
+   * @return Returns the list of Strings.
+   */
+  List<String> charListToStringList(List<Character> list)
+  {
+    List<String> strList = new ArrayList<>();
+    for (char value : list)
+    {
+      String strValue = Character.toString(value);
+      strList.add(strValue);
+    }
+    return strList;
+  }
+
+  /**
+   * Converts an array of doubles into a list of Strings, rounded to the nearest
+   * 5th decimal place
+   * 
+   * @param doubles
+   * @param noOfDecimals
+   * @return
+   */
+  List<String> doublesToStringList(double[] doubles)
+  {
+    List<String> strList = new ArrayList<>();
+    for (double value : doubles)
+    {
+      String strValue;
+      if (value > 0)
+      {
+        strValue = String.format("%.5f", value);
+      }
+      else if (value == -0.00000d)
+      {
+        strValue = "0.00000";
+      }
+      else
+      {
+        strValue = "*";
+      }
+      strList.add(strValue);
+    }
+    return strList;
+  }
+
+  /**
+   * Appends model data in string format to the string builder
+   * 
+   * @param output
+   */
+  void appendModelAsString(StringBuilder output)
+  {
+    output.append(HMM).append("  ");
+    String charSymbols = hmm.getSymbols();
+    for (char c : charSymbols.toCharArray())
+    {
+      output.append(String.format("%9s", c));
+    }
+    output.append(NL).append(TRANSITIONTYPELINE);
+
+    int length = hmm.getLength();
+
+    for (int nodeNo = 0; nodeNo <= length; nodeNo++)
+    {
+      String matchLine = String.format("%7s",
+              nodeNo == 0 ? COMPO : Integer.toString(nodeNo));
+
+      double[] doubleMatches = convertToLogSpace(
+              hmm.getNode(nodeNo).getMatchEmissions());
+      List<String> strMatches = doublesToStringList(doubleMatches);
+      matchLine += addData(10, 9, strMatches);
+
+      if (nodeNo != 0)
+      {
+        matchLine += SPACE + (hmm.getNodeMapPosition(nodeNo));
+        matchLine += SPACE + hmm.getConsensusResidue(nodeNo);
+        matchLine += SPACE + hmm.getReferenceAnnotation(nodeNo);
+        if (hmm.getFileHeader().contains("HMMER3/f"))
+        {
+          matchLine += SPACE + hmm.getMaskedValue(nodeNo);
+          matchLine += SPACE + hmm.getConsensusStructure(nodeNo);
+        }
+      }
+
+      output.append(NL).append(matchLine);
+      
+      String insertLine = "";
+
+      double[] doubleInserts = convertToLogSpace(
+              hmm.getNode(nodeNo).getInsertEmissions());
+      List<String> strInserts = doublesToStringList(doubleInserts);
+      insertLine += addData(17, 9, strInserts);
+
+      output.append(NL).append(insertLine);
+
+      String transitionLine = "";
+      double[] doubleTransitions = convertToLogSpace(
+              hmm.getNode(nodeNo).getStateTransitions());
+      List<String> strTransitions = doublesToStringList(
+              doubleTransitions);
+      transitionLine += addData(17, 9, strTransitions);
+
+      output.append(NL).append(transitionLine);
+    }
+  }
+
+  /**
+   * Appends formatted HMM file properties to the string builder
+   * 
+   * @param output
+   */
+  void appendProperties(StringBuilder output)
+  {
+    output.append(hmm.getFileHeader());
+
+    String format = "%n%-5s %1s";
+    appendProperty(output, format, NAME);
+    appendProperty(output, format, ACCESSION_NUMBER);
+    appendProperty(output, format, DESCRIPTION);
+    appendProperty(output, format, LENGTH);
+    appendProperty(output, format, MAX_LENGTH);
+    appendProperty(output, format, ALPHABET);
+    appendBooleanProperty(output, format, REFERENCE_ANNOTATION);
+    appendBooleanProperty(output, format, MASKED_VALUE);
+    appendBooleanProperty(output, format, CONSENSUS_RESIDUE);
+    appendBooleanProperty(output, format, CONSENSUS_STRUCTURE);
+    appendBooleanProperty(output, format, MAP);
+    appendProperty(output, format, DATE);
+    appendProperty(output, format, NUMBER_OF_SEQUENCES);
+    appendProperty(output, format, EFF_NUMBER_OF_SEQUENCES);
+    appendProperty(output, format, CHECK_SUM);
+    appendProperty(output, format, GATHERING_THRESHOLD);
+    appendProperty(output, format, TRUSTED_CUTOFF);
+    appendProperty(output, format, NOISE_CUTOFF);
+
+    if (hmm.getMSV() != null)
+    {
+      format = "%n%-19s %18s";
+      output.append(String.format(format, "STATS LOCAL MSV", hmm.getMSV()));
+
+      output.append(String.format(format, "STATS LOCAL VITERBI",
+              hmm.getViterbi()));
+
+      output.append(String.format(format, "STATS LOCAL FORWARD",
+              hmm.getForward()));
+    }
+  }
+
+  /**
+   * Appends 'yes' or 'no' for the given property, according to whether or not
+   * it is set in the HMM
+   * 
+   * @param output
+   * @param format
+   * @param propertyName
+   */
+  private void appendBooleanProperty(StringBuilder output, String format,
+          String propertyName)
+  {
+    boolean set = hmm.getBooleanProperty(propertyName);
+    output.append(String.format(format, propertyName,
+            set ? HiddenMarkovModel.YES : HiddenMarkovModel.NO));
+  }
+
+  /**
+   * Appends the value of the given property to the output, if not null
+   * 
+   * @param output
+   * @param format
+   * @param propertyName
+   */
+  private void appendProperty(StringBuilder output, String format,
+          String propertyName)
+  {
+    String value = hmm.getProperty(propertyName);
+    if (value != null)
+    {
+      output.append(String.format(format, propertyName, value));
+    }
+  }
+
+  @Override
+  public String print(SequenceI[] sequences, boolean jvsuffix)
+  {
+    if (sequences[0].getHMM() != null)
+    {
+      hmm = sequences[0].getHMM();
+    }
+    return print();
+  }
+
+  /**
+   * Prints the .hmm file to a String.
+   * 
+   * @return
+   */
+  public String print()
+  {
+    StringBuilder output = new StringBuilder();
+    appendProperties(output);
+    output.append(NL);
+    appendModelAsString(output);
+    output.append(NL).append(TERMINATOR).append(NL);
+    return output.toString();
+  }
+
+  /**
+   * Converts the probabilities contained in an array into log space
+   * 
+   * @param ds
+   */
+  double[] convertToLogSpace(double[] ds)
+  {
+    double[] converted = new double[ds.length];
+    for (int i = 0; i < ds.length; i++)
+    {
+      double prob = ds[i];
+      double logProb = -1 * Math.log(prob);
+
+      converted[i] = logProb;
+    }
+    return converted;
+  }
+
+  /**
+   * Returns the HMM sequence produced by reading a .hmm file.
+   */
+  @Override
+  public SequenceI[] getSeqsAsArray()
+  {
+    SequenceI hmmSeq = hmm.getConsensusSequence();
+    SequenceI[] seq = new SequenceI[1];
+    seq[0] = hmmSeq;
+    return seq;
+  }
+
+  @Override
+  public void setNewlineString(String newLine)
+  {
+    NL = newLine;
+  }
+
+  @Override
+  public void setExportSettings(AlignExportSettingsI exportSettings)
+  {
+
+  }
+
+  @Override
+  public void configureForView(AlignmentViewPanel viewpanel)
+  {
+
+  }
+
+  @Override
+  public boolean hasWarningMessage()
+  {
+    return false;
+  }
+
+  @Override
+  public String getWarningMessage()
+  {
+    return "warning message";
+  }
+
+}
+
index df40ec1..b8a4d6a 100755 (executable)
@@ -185,6 +185,11 @@ public class IdentifyFile
           reply = FileFormat.ScoreMatrix;
           break;
         }
+        if (data.startsWith("HMMER3"))
+        {
+          reply = FileFormat.HMMER3;
+          break;
+        }
         if (data.startsWith("H ") && !aaIndexHeaderRead)
         {
           aaIndexHeaderRead = true;
index 4d0bec7..d5c3ed3 100644 (file)
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 
 import jalview.api.FeatureColourI;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.GeneLociI;
@@ -480,12 +481,27 @@ public class SequenceAnnotationReport
       sb.append(tmp);
       maxWidth = Math.max(maxWidth, tmp.length());
     }
+
     SequenceI ds = sequence;
     while (ds.getDatasetSequence() != null)
     {
       ds = ds.getDatasetSequence();
     }
 
+    /*
+     * add any annotation scores
+     */
+    AlignmentAnnotation[] anns = ds.getAnnotation();
+    for (int i = 0; anns != null && i < anns.length; i++)
+    {
+      AlignmentAnnotation aa = anns[i];
+      if (aa != null && aa.hasScore() && aa.sequenceRef != null)
+      {
+        sb.append("<br>").append(aa.label).append(": ")
+                .append(aa.getScore());
+      }
+    }
+
     if (showDbRefs)
     {
       maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary));
@@ -505,7 +521,24 @@ public class SequenceAnnotationReport
         maxWidth = Math.max(maxWidth, sz);
       }
     }
+
+
+    if (sequence.getAnnotation("Search Scores") != null)
+    {
+      sb.append("<br>");
+      String eValue = " E-Value: "
+              + sequence.getAnnotation("Search Scores")[0].getEValue();
+      String bitScore = " Bit Score: "
+              + sequence.getAnnotation("Search Scores")[0].getBitScore();
+      sb.append(eValue);
+      sb.append("<br>");
+      sb.append(bitScore);
+      maxWidth = Math.max(maxWidth, eValue.length());
+      maxWidth = Math.max(maxWidth, bitScore.length());
+    }
+    sb.append("<br>");
     sb.append("</i>");
+
     return maxWidth;
   }
 
index 3d07e5a..50112c8 100644 (file)
@@ -79,8 +79,9 @@ public class StockholmFile extends AlignFile
 {
   private static final String ANNOTATION = "annotation";
 
-  // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using
-  // NOT_RNASS first.
+  private static final char UNDERSCORE = '_';
+  
+  // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using NOT_RNASS first.
 
   public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
 
@@ -118,7 +119,7 @@ public class StockholmFile extends AlignFile
 
   /**
    * Centralize all actual Regex instantialization in Platform.
-   * 
+   * // JBPNote: Why is this 'centralisation' better ?
    * @param id
    * @return
    */
@@ -181,14 +182,14 @@ public class StockholmFile extends AlignFile
 
   StringBuffer out; // output buffer
 
-  AlignmentI al;
+  private AlignmentI al;
 
   public StockholmFile()
   {
   }
 
   /**
-   * Creates a new StockholmFile object for output.
+   * Creates a new StockholmFile object for output
    */
   public StockholmFile(AlignmentI al)
   {
@@ -726,14 +727,15 @@ public class StockholmFile extends AlignFile
             if (features.containsKey(this.id2type(type)))
             {
               // logger.debug("Found content for " + this.id2type(type));
-              content = (Hashtable) features.get(this.id2type(type));
+              content = (Hashtable) features
+                      .get(this.id2type(type));
             }
             else
             {
               // logger.debug("Creating new content holder for " +
               // this.id2type(type));
               content = new Hashtable();
-              features.put(this.id2type(type), content);
+              features.put(id2type(type), content);
             }
             String ns = (String) content.get(ANNOTATION);
 
@@ -914,10 +916,9 @@ public class StockholmFile extends AlignFile
           Vector<AlignmentAnnotation> annotation, String label,
           String annots)
   {
-    String convert1, convert2 = null;
-
-    // convert1 = OPEN_PAREN.replaceAll(annots);
-    // convert2 = CLOSE_PAREN.replaceAll(convert1);
+         String convert1, convert2 = null;
+    // String convert1 = OPEN_PAREN.replaceAll(annots);
+    // String convert2 = CLOSE_PAREN.replaceAll(convert1);
     // annots = convert2;
 
     String type = label;
@@ -931,6 +932,7 @@ public class StockholmFile extends AlignFile
     type = id2type(type);
 
     boolean isrnass = false;
+
     if (type.equalsIgnoreCase("secondary structure"))
     {
       ss = true;
@@ -948,6 +950,10 @@ public class StockholmFile extends AlignFile
     for (int i = 0; i < annots.length(); i++)
     {
       String pos = annots.substring(i, i + 1);
+      if (UNDERSCORE == pos.charAt(0))
+      {
+        pos = " ";
+      }
       Annotation ann;
       ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not
       // be written out
@@ -1137,36 +1143,38 @@ public class StockholmFile extends AlignFile
       if (alAnot != null)
       {
         Annotation[] ann;
-        for (int j = 0, nj = alAnot.length; j < nj; j++)
+        for (int j = 0; j < alAnot.length; j++)
         {
-
-          String key = type2id(alAnot[j].label);
-          boolean isrna = alAnot[j].isValidStruc();
-
-          if (isrna)
-          {
-            // hardwire to secondary structure if there is RNA secondary
-            // structure on the annotation
-            key = "SS";
-          }
-          if (key == null)
+          if (alAnot[j].annotations != null)
           {
+            String key = type2id(alAnot[j].label);
+            boolean isrna = alAnot[j].isValidStruc();
 
-            continue;
-          }
+            if (isrna)
+            {
+              // hardwire to secondary structure if there is RNA secondary
+              // structure on the annotation
+              key = "SS";
+            }
+            if (key == null)
+            {
+              continue;
+            }
 
-          // out.append("#=GR ");
-          out.append(new Format("%-" + maxid + "s").form(
-                  "#=GR " + printId(seq, jvSuffix) + " " + key + " "));
-          ann = alAnot[j].annotations;
-          String sseq = "";
-          for (int k = 0, nk = ann.length; k < nk; k++)
-          {
-            sseq += outputCharacter(key, k, isrna, ann, seq);
-          }
-          out.append(sseq);
-          out.append(newline);
+            // out.append("#=GR ");
+            out.append(new Format("%-" + maxid + "s").form(
+                    "#=GR " + printId(s[i], jvSuffix) + " " + key + " "));
+            ann = alAnot[j].annotations;
+            String sseq = "";
+            for (int k = 0; k < ann.length; k++)
+            {
+              sseq += outputCharacter(key, k, isrna, ann, s[i]);
+            }
+            out.append(sseq);
+            out.append(newline);
+         }
         }
+
       }
 
       out.append(new Format("%-" + maxid + "s")
@@ -1231,6 +1239,7 @@ public class StockholmFile extends AlignFile
     return out.toString();
   }
 
+
   /**
    * add an annotation character to the output row
    * 
@@ -1298,6 +1307,26 @@ public class StockholmFile extends AlignFile
             : seq;
   }
 
+  /**
+   * make a friendly ID string.
+   * 
+   * @param dataName
+   * @return truncated dataName to after last '/'
+   */
+  private String safeName(String dataName)
+  {
+    int b = 0;
+    while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())
+    {
+      dataName = dataName.substring(b + 1).trim();
+
+    }
+    int e = (dataName.length() - dataName.indexOf(".")) + 1;
+    dataName = dataName.substring(1, e).trim();
+    return dataName;
+  }
+  
+  
   public String print()
   {
     out = new StringBuffer();
@@ -1335,7 +1364,7 @@ public class StockholmFile extends AlignFile
 
     }
   }
-
+  
   protected static String id2type(String id)
   {
     if (typeIds.containsKey(id))
@@ -1368,23 +1397,4 @@ public class StockholmFile extends AlignFile
             "Warning : Unknown Stockholm annotation type: " + type);
     return key;
   }
-
-  /**
-   * make a friendly ID string.
-   * 
-   * @param dataName
-   * @return truncated dataName to after last '/'
-   */
-  private String safeName(String dataName)
-  {
-    int b = 0;
-    while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())
-    {
-      dataName = dataName.substring(b + 1).trim();
-
-    }
-    int e = (dataName.length() - dataName.indexOf(".")) + 1;
-    dataName = dataName.substring(1, e).trim();
-    return dataName;
-  }
 }
index 6c6d123..25db31a 100755 (executable)
@@ -31,6 +31,7 @@ import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -57,11 +58,14 @@ import jalview.api.SplitContainerI;
 import jalview.bin.Cache;
 import jalview.gui.JvSwingUtils;
 import jalview.gui.Preferences;
+import jalview.hmmer.HmmerCommand;
+import jalview.io.FileFormatException;
 import jalview.io.FileFormats;
 import jalview.schemes.ResidueColourScheme;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
+
 @SuppressWarnings("serial")
 public class GAlignFrame extends JInternalFrame
 {
@@ -71,9 +75,11 @@ public class GAlignFrame extends JInternalFrame
 
   public JMenu webService = new JMenu();// BH 2019 was protected, but not
                                         // sufficient for AlignFrame thread run
+    // JBP - followed suite for these other service related GUI elements.
+    // TODO: check we really need these to be public
+  public JMenu hmmerMenu = new JMenu();
 
-  public JMenuItem webServiceNoServices;// BH 2019 was protected, but not
-                                        // sufficient for AlignFrame thread run
+  public JMenuItem webServiceNoServices;
 
   protected JCheckBoxMenuItem viewBoxesMenuItem = new JCheckBoxMenuItem();
 
@@ -203,6 +209,12 @@ public class GAlignFrame extends JInternalFrame
 
   protected JCheckBoxMenuItem normaliseSequenceLogo = new JCheckBoxMenuItem();
 
+  protected JCheckBoxMenuItem showInformationHistogram = new JCheckBoxMenuItem();
+
+  protected JCheckBoxMenuItem showHMMSequenceLogo = new JCheckBoxMenuItem();
+
+  protected JCheckBoxMenuItem normaliseHMMSequenceLogo = new JCheckBoxMenuItem();
+
   protected JCheckBoxMenuItem applyAutoAnnotationSettings = new JCheckBoxMenuItem();
 
   protected JMenuItem openFeatureSettings;
@@ -264,7 +276,7 @@ public class GAlignFrame extends JInternalFrame
   private void jbInit() throws Exception
   {
     initColourMenu();
-
+  
     JMenuItem saveAs = new JMenuItem(
             MessageManager.getString("action.save_as"));
     ActionListener al = new ActionListener()
@@ -275,12 +287,12 @@ public class GAlignFrame extends JInternalFrame
         saveAs_actionPerformed();
       }
     };
-
+  
     // FIXME getDefaultToolkit throws an exception in Headless mode
     KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, Platform.SHORTCUT_KEY_MASK | InputEvent.SHIFT_DOWN_MASK,
             false);
     addMenuActionAndAccelerator(keyStroke, saveAs, al);
-
+  
     closeMenuItem.setText(MessageManager.getString("action.close"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, Platform.SHORTCUT_KEY_MASK, false);
     al = new ActionListener()
@@ -292,7 +304,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, closeMenuItem, al);
-
+  
     JMenu editMenu = new JMenu(MessageManager.getString("action.edit"));
     JMenu viewMenu = new JMenu(MessageManager.getString("action.view"));
     JMenu annotationsMenu = new JMenu(
@@ -302,6 +314,9 @@ public class GAlignFrame extends JInternalFrame
     JMenu calculateMenu = new JMenu(
             MessageManager.getString("action.calculate"));
     webService.setText(MessageManager.getString("action.web_service"));
+
+    initHMMERMenu();
+
     JMenuItem selectAllSequenceMenuItem = new JMenuItem(
             MessageManager.getString("action.select_all"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
@@ -315,7 +330,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, selectAllSequenceMenuItem, al);
-
+  
     JMenuItem deselectAllSequenceMenuItem = new JMenuItem(
             MessageManager.getString("action.deselect_all"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
@@ -328,7 +343,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, deselectAllSequenceMenuItem, al);
-
+  
     JMenuItem invertSequenceMenuItem = new JMenuItem(
             MessageManager.getString("action.invert_sequence_selection"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
@@ -342,7 +357,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, invertSequenceMenuItem, al);
-
+  
     JMenuItem grpsFromSelection = new JMenuItem(
             MessageManager.getString("action.make_groups_selection"));
     grpsFromSelection.addActionListener(new ActionListener()
@@ -378,7 +393,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, remove2LeftMenuItem, al);
-
+  
     JMenuItem remove2RightMenuItem = new JMenuItem(
             MessageManager.getString("action.remove_right"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R,
@@ -392,7 +407,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, remove2RightMenuItem, al);
-
+  
     JMenuItem removeGappedColumnMenuItem = new JMenuItem(
             MessageManager.getString("action.remove_empty_columns"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
@@ -406,7 +421,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, removeGappedColumnMenuItem, al);
-
+  
     JMenuItem removeAllGapsMenuItem = new JMenuItem(
             MessageManager.getString("action.remove_all_gaps"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
@@ -422,7 +437,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, removeAllGapsMenuItem, al);
-
+  
     JMenuItem justifyLeftMenuItem = new JMenuItem(
             MessageManager.getString("action.left_justify_alignment"));
     justifyLeftMenuItem.addActionListener(new ActionListener()
@@ -514,7 +529,27 @@ public class GAlignFrame extends JInternalFrame
         sortGroupMenuItem_actionPerformed(e);
       }
     });
-
+    JMenuItem sortEValueMenuItem = new JMenuItem(
+            MessageManager.getString("action.by_evalue"));
+    sortEValueMenuItem.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        sortEValueMenuItem_actionPerformed(e);
+      }
+    });
+    JMenuItem sortBitScoreMenuItem = new JMenuItem(
+            MessageManager.getString("action.by_bit_score"));
+    sortBitScoreMenuItem.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        sortBitScoreMenuItem_actionPerformed(e);
+      }
+    });
+  
     JMenuItem removeRedundancyMenuItem = new JMenuItem(
             MessageManager.getString("action.remove_redundancy"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D,
@@ -529,6 +564,30 @@ public class GAlignFrame extends JInternalFrame
     };
     addMenuActionAndAccelerator(keyStroke, removeRedundancyMenuItem, al);
 
+    JMenuItem filterByEValue = new JMenuItem(
+            MessageManager.getString("action.filter_by_evalue"));
+    filterByEValue.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        filterByEValue_actionPerformed();
+      }
+
+    });
+
+    JMenuItem filterByScore = new JMenuItem(
+            MessageManager.getString("action.filter_by_score"));
+    filterByScore.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        filterByScore_actionPerformed();
+      }
+
+    });
+  
     JMenuItem pairwiseAlignmentMenuItem = new JMenuItem(
             MessageManager.getString("action.pairwise_alignment"));
     pairwiseAlignmentMenuItem.addActionListener(new ActionListener()
@@ -539,16 +598,18 @@ public class GAlignFrame extends JInternalFrame
         pairwiseAlignmentMenuItem_actionPerformed(e);
       }
     });
-
+  
     this.getContentPane().setLayout(new BorderLayout());
     alignFrameMenuBar.setFont(new java.awt.Font("Verdana", 0, 11));
     statusBar.setBackground(Color.white);
     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
     statusBar.setBorder(BorderFactory.createLineBorder(Color.black));
     statusBar.setText(MessageManager.getString("label.status_bar"));
+
     outputTextboxMenu
             .setText(MessageManager.getString("label.out_to_textbox"));
 
+
     annotationPanelMenuItem.setActionCommand("");
     annotationPanelMenuItem
             .setText(MessageManager.getString("label.show_annotations"));
@@ -616,6 +677,7 @@ public class GAlignFrame extends JInternalFrame
     final JCheckBoxMenuItem sortAnnByLabel = new JCheckBoxMenuItem(
             MessageManager.getString("label.sort_annotations_by_label"));
 
+
     sortAnnBySequence.setSelected(
             sortAnnotationsBy == SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
     sortAnnBySequence.addActionListener(new ActionListener()
@@ -656,7 +718,7 @@ public class GAlignFrame extends JInternalFrame
         colourTextMenuItem_actionPerformed(e);
       }
     });
-
+  
     JMenuItem htmlMenuItem = new JMenuItem(
             MessageManager.getString("label.html"));
     htmlMenuItem.addActionListener(new ActionListener()
@@ -667,7 +729,7 @@ public class GAlignFrame extends JInternalFrame
         htmlMenuItem_actionPerformed(e);
       }
     });
-
+  
     JMenuItem createBioJS = new JMenuItem(
             MessageManager.getString("label.biojs_html_export"));
     createBioJS.addActionListener(new java.awt.event.ActionListener()
@@ -678,7 +740,7 @@ public class GAlignFrame extends JInternalFrame
         bioJSMenuItem_actionPerformed(e);
       }
     });
-
+  
     JMenuItem overviewMenuItem = new JMenuItem(
             MessageManager.getString("label.overview_window"));
     overviewMenuItem.addActionListener(new ActionListener()
@@ -689,7 +751,7 @@ public class GAlignFrame extends JInternalFrame
         overviewMenuItem_actionPerformed(e);
       }
     });
-
+  
     undoMenuItem.setEnabled(false);
     undoMenuItem.setText(MessageManager.getString("action.undo"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
@@ -703,7 +765,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, undoMenuItem, al);
-
+  
     redoMenuItem.setEnabled(false);
     redoMenuItem.setText(MessageManager.getString("action.redo"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
@@ -717,7 +779,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, redoMenuItem, al);
-
+  
     wrapMenuItem.setText(MessageManager.getString("label.wrap"));
     wrapMenuItem.addActionListener(new ActionListener()
     {
@@ -727,7 +789,7 @@ public class GAlignFrame extends JInternalFrame
         wrapMenuItem_actionPerformed(e);
       }
     });
-
+  
     JMenuItem printMenuItem = new JMenuItem(
             MessageManager.getString("action.print"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P,
@@ -741,7 +803,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, printMenuItem, al);
-
+  
     renderGapsMenuItem
             .setText(MessageManager.getString("action.show_gaps"));
     renderGapsMenuItem.setState(true);
@@ -753,7 +815,7 @@ public class GAlignFrame extends JInternalFrame
         renderGapsMenuItem_actionPerformed(e);
       }
     });
-
+  
     JMenuItem findMenuItem = new JMenuItem(
             MessageManager.getString("action.find"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F,
@@ -772,6 +834,7 @@ public class GAlignFrame extends JInternalFrame
 
     showSeqFeatures.setText(
             MessageManager.getString("label.show_sequence_features"));
+
     showSeqFeatures.addActionListener(new ActionListener()
     {
       @Override
@@ -790,86 +853,86 @@ public class GAlignFrame extends JInternalFrame
             .setText(MessageManager.getString("label.show_database_refs"));
     showDbRefsMenuitem.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showDbRefs_actionPerformed(e);
       }
-
+  
     });
     showNpFeatsMenuitem.setText(
             MessageManager.getString("label.show_non_positional_features"));
     showNpFeatsMenuitem.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showNpFeats_actionPerformed(e);
       }
-
+  
     });
     showGroupConservation
             .setText(MessageManager.getString("label.group_conservation"));
     showGroupConservation.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showGroupConservation_actionPerformed(e);
       }
-
+  
     });
 
     showGroupConsensus
             .setText(MessageManager.getString("label.group_consensus"));
     showGroupConsensus.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showGroupConsensus_actionPerformed(e);
       }
-
+  
     });
     showConsensusHistogram.setText(
             MessageManager.getString("label.show_consensus_histogram"));
     showConsensusHistogram.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showConsensusHistogram_actionPerformed(e);
       }
-
+  
     });
     showSequenceLogo
             .setText(MessageManager.getString("label.show_consensus_logo"));
     showSequenceLogo.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         showSequenceLogo_actionPerformed(e);
       }
-
+  
     });
     normaliseSequenceLogo
             .setText(MessageManager.getString("label.norm_consensus_logo"));
     normaliseSequenceLogo.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         normaliseSequenceLogo_actionPerformed(e);
       }
-
+  
     });
     applyAutoAnnotationSettings
             .setText(MessageManager.getString("label.apply_all_groups"));
@@ -883,7 +946,7 @@ public class GAlignFrame extends JInternalFrame
         applyAutoAnnotationSettings_actionPerformed(e);
       }
     });
-
+  
     ButtonGroup buttonGroup = new ButtonGroup();
     final JRadioButtonMenuItem showAutoFirst = new JRadioButtonMenuItem(
             MessageManager.getString("label.show_first"));
@@ -914,7 +977,7 @@ public class GAlignFrame extends JInternalFrame
         sortAnnotations_actionPerformed();
       }
     });
-
+  
     JMenuItem deleteGroups = new JMenuItem(
             MessageManager.getString("action.undefine_groups"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U,
@@ -928,7 +991,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, deleteGroups, al);
-
+  
     JMenuItem annotationColumn = new JMenuItem(
             MessageManager.getString("action.select_by_annotation"));
     annotationColumn.addActionListener(new ActionListener()
@@ -939,7 +1002,7 @@ public class GAlignFrame extends JInternalFrame
         annotationColumn_actionPerformed(e);
       }
     });
-
+  
     JMenuItem createGroup = new JMenuItem(
             MessageManager.getString("action.create_group"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
@@ -953,7 +1016,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, createGroup, al);
-
+  
     JMenuItem unGroup = new JMenuItem(
             MessageManager.getString("action.remove_group"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
@@ -969,7 +1032,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, unGroup, al);
-
+  
     copy.setText(MessageManager.getString("action.copy"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C,
             Platform.SHORTCUT_KEY_MASK, false);
@@ -983,7 +1046,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, copy, al);
-
+  
     cut.setText(MessageManager.getString("action.cut"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X,
             Platform.SHORTCUT_KEY_MASK, false);
@@ -996,7 +1059,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, cut, al);
-
+  
     JMenuItem delete = new JMenuItem(
             MessageManager.getString("action.delete"));
     delete.addActionListener(new ActionListener()
@@ -1007,7 +1070,7 @@ public class GAlignFrame extends JInternalFrame
         delete_actionPerformed();
       }
     });
-
+  
     pasteMenu.setText(MessageManager.getString("action.paste"));
     JMenuItem pasteNew = new JMenuItem(
             MessageManager.getString("label.to_new_alignment"));
@@ -1020,11 +1083,18 @@ public class GAlignFrame extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        pasteNew_actionPerformed(e);
+        try
+        {
+          pasteNew_actionPerformed(e);
+        } catch (IOException | InterruptedException e1)
+        {
+          // TODO Auto-generated catch block
+          e1.printStackTrace();
+        }
       }
     };
     addMenuActionAndAccelerator(keyStroke, pasteNew, al);
-
+  
     JMenuItem pasteThis = new JMenuItem(
             MessageManager.getString("label.to_this_alignment"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
@@ -1034,11 +1104,18 @@ public class GAlignFrame extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        pasteThis_actionPerformed(e);
+        try
+        {
+          pasteThis_actionPerformed(e);
+        } catch (IOException | InterruptedException e1)
+        {
+          // TODO Auto-generated catch block
+          e1.printStackTrace();
+        }
       }
     };
     addMenuActionAndAccelerator(keyStroke, pasteThis, al);
-
+  
     JMenuItem createPNG = new JMenuItem("PNG");
     createPNG.addActionListener(new ActionListener()
     {
@@ -1050,7 +1127,6 @@ public class GAlignFrame extends JInternalFrame
     });
     createPNG.setActionCommand(
             MessageManager.getString("label.save_png_image"));
-
     JMenuItem font = new JMenuItem(MessageManager.getString("action.font"));
     font.addActionListener(new ActionListener()
     {
@@ -1080,7 +1156,7 @@ public class GAlignFrame extends JInternalFrame
         createEPS(null);
       }
     });
-
+  
     JMenuItem createSVG = new JMenuItem("SVG");
     createSVG.addActionListener(new ActionListener()
     {
@@ -1090,7 +1166,7 @@ public class GAlignFrame extends JInternalFrame
         createSVG(null);
       }
     });
-
+  
     JMenuItem loadTreeMenuItem = new JMenuItem(
             MessageManager.getString("label.load_associated_tree"));
     loadTreeMenuItem.setActionCommand(
@@ -1103,7 +1179,7 @@ public class GAlignFrame extends JInternalFrame
         loadTreeMenuItem_actionPerformed(e);
       }
     });
-
+  
     scaleAbove.setVisible(false);
     scaleAbove.setText(MessageManager.getString("action.scale_above"));
     scaleAbove.addActionListener(new ActionListener()
@@ -1154,15 +1230,15 @@ public class GAlignFrame extends JInternalFrame
             .setText(MessageManager.getString("label.automatic_scrolling"));
     followHighlightMenuItem.addActionListener(new ActionListener()
     {
-
+  
       @Override
       public void actionPerformed(ActionEvent e)
       {
         followHighlight_actionPerformed();
       }
-
+  
     });
-
+  
     sortByTreeMenu
             .setText(MessageManager.getString("action.by_tree_order"));
     sort.setText(MessageManager.getString("action.sort"));
@@ -1191,12 +1267,12 @@ public class GAlignFrame extends JInternalFrame
       {
         buildTreeSortMenu();
       }
-
+  
       @Override
       public void menuDeselected(MenuEvent e)
       {
       }
-
+  
       @Override
       public void menuCanceled(MenuEvent e)
       {
@@ -1207,17 +1283,17 @@ public class GAlignFrame extends JInternalFrame
     sort.add(sortByAnnotScore);
     sort.addMenuListener(new javax.swing.event.MenuListener()
     {
-
+  
       @Override
       public void menuCanceled(MenuEvent e)
       {
       }
-
+  
       @Override
       public void menuDeselected(MenuEvent e)
       {
       }
-
+  
       @Override
       public void menuSelected(MenuEvent e)
       {
@@ -1297,7 +1373,7 @@ public class GAlignFrame extends JInternalFrame
         showReverse_actionPerformed(true);
       }
     });
-
+  
     JMenuItem extractScores = new JMenuItem(
             MessageManager.getString("label.extract_scores"));
     extractScores.addActionListener(new ActionListener()
@@ -1310,10 +1386,10 @@ public class GAlignFrame extends JInternalFrame
     });
     extractScores.setVisible(true);
     // JBPNote: TODO: make gui for regex based score extraction
-
+  
     // 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"));
@@ -1350,7 +1426,7 @@ public class GAlignFrame extends JInternalFrame
         fetchSequence_actionPerformed();
       }
     });
-
+  
     JMenuItem associatedData = new JMenuItem(
             MessageManager.getString("label.load_features_annotations"));
     associatedData.addActionListener(new ActionListener()
@@ -1358,7 +1434,14 @@ public class GAlignFrame extends JInternalFrame
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        associatedData_actionPerformed(e);
+        try
+        {
+          associatedData_actionPerformed(e);
+        } catch (IOException | InterruptedException e1)
+        {
+          // TODO Auto-generated catch block
+          e1.printStackTrace();
+        }
       }
     });
     loadVcf = new JMenuItem(
@@ -1413,7 +1496,7 @@ public class GAlignFrame extends JInternalFrame
         listenToViewSelections_actionPerformed(e);
       }
     });
-
+  
     JMenu addSequenceMenu = new JMenu(
             MessageManager.getString("label.add_sequences"));
     JMenuItem addFromFile = new JMenuItem(
@@ -1559,7 +1642,7 @@ public class GAlignFrame extends JInternalFrame
         hiddenMarkers_actionPerformed(e);
       }
     });
-
+  
     JMenuItem invertColSel = new JMenuItem(
             MessageManager.getString("action.invert_column_selection"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
@@ -1575,7 +1658,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, invertColSel, al);
-
+  
     showComplementMenuItem.setVisible(false);
     showComplementMenuItem.addActionListener(new ActionListener()
     {
@@ -1585,7 +1668,7 @@ public class GAlignFrame extends JInternalFrame
         showComplement_actionPerformed(showComplementMenuItem.getState());
       }
     });
-
+  
     tabbedPane.addChangeListener(new javax.swing.event.ChangeListener()
     {
       @Override
@@ -1606,7 +1689,7 @@ public class GAlignFrame extends JInternalFrame
           tabbedPane_mousePressed(e);
         }
       }
-
+  
       @Override
       public void mouseReleased(MouseEvent e)
       {
@@ -1624,7 +1707,7 @@ public class GAlignFrame extends JInternalFrame
         tabbedPane_focusGained(e);
       }
     });
-
+  
     JMenuItem save = new JMenuItem(MessageManager.getString("action.save"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
             Platform.SHORTCUT_KEY_MASK, false);
@@ -1637,7 +1720,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, save, al);
-
+  
     reload.setEnabled(false);
     reload.setText(MessageManager.getString("action.reload"));
     reload.addActionListener(new ActionListener()
@@ -1648,7 +1731,7 @@ public class GAlignFrame extends JInternalFrame
         reload_actionPerformed(e);
       }
     });
-
+  
     JMenuItem newView = new JMenuItem(
             MessageManager.getString("action.new_view"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T,
@@ -1662,11 +1745,11 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, newView, al);
-
+  
     tabbedPane.setToolTipText("<html><i>"
             + MessageManager.getString("label.rename_tab_eXpand_reGroup")
             + "</i></html>");
-
+  
     formatMenu.setText(MessageManager.getString("action.format"));
     JMenu selectMenu = new JMenu(MessageManager.getString("action.select"));
 
@@ -1680,7 +1763,7 @@ public class GAlignFrame extends JInternalFrame
         idRightAlign_actionPerformed(e);
       }
     });
-
+  
     gatherViews.setEnabled(false);
     gatherViews.setText(MessageManager.getString("action.gather_views"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false);
@@ -1693,7 +1776,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, gatherViews, al);
-
+  
     expandViews.setEnabled(false);
     expandViews.setText(MessageManager.getString("action.expand_views"));
     keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false);
@@ -1706,7 +1789,7 @@ public class GAlignFrame extends JInternalFrame
       }
     };
     addMenuActionAndAccelerator(keyStroke, expandViews, al);
-
+  
     JMenuItem pageSetup = new JMenuItem(
             MessageManager.getString("action.page_setup"));
     pageSetup.addActionListener(new ActionListener()
@@ -1739,12 +1822,24 @@ public class GAlignFrame extends JInternalFrame
         selectHighlightedColumns_actionPerformed(actionEvent);
       }
     };
+    JMenuItem Filter = new JMenuItem(
+            MessageManager.getString("action.select_highlighted_columns"));
+    selectHighlighted.setToolTipText(
+            MessageManager.getString("tooltip.select_highlighted_columns"));
+    al = new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        selectHighlightedColumns_actionPerformed(actionEvent);
+      }
+    };
     selectHighlighted.addActionListener(al);
     JMenu tooltipSettingsMenu = new JMenu(
             MessageManager.getString("label.sequence_id_tooltip"));
     JMenu autoAnnMenu = new JMenu(
             MessageManager.getString("label.autocalculated_annotation"));
-
+  
     JMenu exportImageMenu = new JMenu(
             MessageManager.getString("label.export_image"));
     JMenu fileMenu = new JMenu(MessageManager.getString("action.file"));
@@ -1756,11 +1851,12 @@ public class GAlignFrame extends JInternalFrame
     alignFrameMenuBar.add(formatMenu);
     alignFrameMenuBar.add(colourMenu);
     alignFrameMenuBar.add(calculateMenu);
+    alignFrameMenuBar.add(webService);
     if (!Platform.isJS())
     {
-      alignFrameMenuBar.add(webService);
+      alignFrameMenuBar.add(hmmerMenu);
     }
-
+  
     fileMenu.add(fetchSequence);
     fileMenu.add(addSequenceMenu);
     fileMenu.add(reload);
@@ -1783,7 +1879,7 @@ public class GAlignFrame extends JInternalFrame
     }
     fileMenu.addSeparator();
     fileMenu.add(closeMenuItem);
-
+  
     pasteMenu.add(pasteNew);
     pasteMenu.add(pasteThis);
     editMenu.add(undoMenuItem);
@@ -1805,7 +1901,10 @@ public class GAlignFrame extends JInternalFrame
     // editMenu.add(justifyRightMenuItem);
     // editMenu.addSeparator();
     editMenu.add(padGapsMenuitem);
-
+    editMenu.addSeparator();
+    editMenu.add(filterByEValue);
+    editMenu.add(filterByScore);
+  
     showMenu.add(showAllColumns);
     showMenu.add(showAllSeqs);
     showMenu.add(showAllhidden);
@@ -1833,7 +1932,7 @@ public class GAlignFrame extends JInternalFrame
     viewMenu.add(alignmentProperties);
     viewMenu.addSeparator();
     viewMenu.add(overviewMenuItem);
-
+  
     annotationsMenu.add(annotationPanelMenuItem);
     annotationsMenu.addSeparator();
     annotationsMenu.add(showAllAlAnnotations);
@@ -1860,6 +1959,8 @@ public class GAlignFrame extends JInternalFrame
     sort.add(sortLengthMenuItem);
     sort.add(sortGroupMenuItem);
     sort.add(sortPairwiseMenuItem);
+    sort.add(sortEValueMenuItem);
+    sort.add(sortBitScoreMenuItem);
     sort.add(sortByTreeMenu);
     calculateMenu.add(sort);
     calculateMenu.add(calculateTree);
@@ -1880,7 +1981,6 @@ public class GAlignFrame extends JInternalFrame
       calculateMenu.addSeparator();
       calculateMenu.add(runGroovy);
     }
-
     webServiceNoServices = new JMenuItem(
             MessageManager.getString("label.no_services"));
     webService.add(webServiceNoServices);
@@ -1901,7 +2001,7 @@ 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);
-
+  
     formatMenu.add(font);
     formatMenu.addSeparator();
     formatMenu.add(wrapMenuItem);
@@ -1935,6 +2035,170 @@ public class GAlignFrame extends JInternalFrame
     // selectMenu.add(listenToViewSelections);
   }
 
+  /**
+   * Constructs the entries on the HMMER menu
+   */
+  protected void initHMMERMenu()
+  {
+    /*
+     * hmmbuild
+     */
+    JMenu hmmBuild = new JMenu(MessageManager.getString("label.hmmbuild"));
+    JMenuItem hmmBuildSettings = new JMenuItem(
+            MessageManager.getString("label.edit_settings_and_run"));
+    hmmBuildSettings.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmBuild_actionPerformed(false);
+      }
+    });
+    JMenuItem hmmBuildRun = new JMenuItem(MessageManager.formatMessage(
+            "label.action_with_default_settings", "hmmbuild"));
+    hmmBuildRun.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmBuild_actionPerformed(true);
+      }
+    });
+    hmmBuild.add(hmmBuildRun);
+    hmmBuild.add(hmmBuildSettings);
+
+    /*
+     * hmmalign
+     */
+    JMenu hmmAlign = new JMenu(MessageManager.getString("label.hmmalign"));
+    JMenuItem hmmAlignRun = new JMenuItem(MessageManager.formatMessage(
+            "label.action_with_default_settings", "hmmalign"));
+    hmmAlignRun.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmAlign_actionPerformed(true);
+      }
+    });
+    JMenuItem hmmAlignSettings = new JMenuItem(
+            MessageManager.getString("label.edit_settings_and_run"));
+    hmmAlignSettings.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmAlign_actionPerformed(false);
+      }
+    });
+    hmmAlign.add(hmmAlignRun);
+    hmmAlign.add(hmmAlignSettings);
+
+    /*
+     * hmmsearch
+     */
+    JMenu hmmSearch = new JMenu(
+            MessageManager.getString("label.hmmsearch"));
+    JMenuItem hmmSearchSettings = new JMenuItem(
+            MessageManager.getString("label.edit_settings_and_run"));
+    hmmSearchSettings.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmSearch_actionPerformed(false);
+      }
+    });
+    JMenuItem hmmSearchRun = new JMenuItem(MessageManager.formatMessage(
+            "label.action_with_default_settings", "hmmsearch"));
+    hmmSearchRun.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        hmmSearch_actionPerformed(true);
+      }
+    });
+    JMenuItem addDatabase = new JMenuItem(
+            MessageManager.getString("label.add_database"));
+    addDatabase.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        try
+        {
+          addDatabase_actionPerformed();
+        } catch (IOException e1)
+        {
+          e1.printStackTrace();
+        }
+      }
+    });
+    hmmSearch.add(hmmSearchRun);
+    hmmSearch.add(hmmSearchSettings);
+    // hmmSearch.add(addDatabase);
+
+    /*
+     * jackhmmer
+     */
+    JMenu jackhmmer = new JMenu(
+            MessageManager.getString("label.jackhmmer"));
+    JMenuItem jackhmmerSettings = new JMenuItem(
+            MessageManager.getString("label.edit_settings_and_run"));
+    jackhmmerSettings.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        jackhmmer_actionPerformed(false);
+      }
+    });
+    JMenuItem jackhmmerRun = new JMenuItem(MessageManager.formatMessage(
+            "label.action_with_default_settings", "jackhmmer"));
+    jackhmmerRun.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        jackhmmer_actionPerformed(true);
+      }
+
+    });
+    /*
+    JMenuItem addDatabase = new JMenuItem(
+            MessageManager.getString("label.add_database"));
+    addDatabase.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        try
+        {
+          addDatabase_actionPerformed();
+        } catch (IOException e1)
+        {
+          e1.printStackTrace();
+        }
+      }
+    });
+    */
+    jackhmmer.add(jackhmmerRun);
+    jackhmmer.add(jackhmmerSettings);
+    // hmmSearch.add(addDatabase);
+
+    /*
+     * top level menu
+     */
+    hmmerMenu.setText(MessageManager.getString("action.hmmer"));
+    hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
+    hmmerMenu.add(hmmBuild);
+    hmmerMenu.add(hmmAlign);
+    hmmerMenu.add(hmmSearch);
+    hmmerMenu.add(jackhmmer);
+
+  }
+
   protected void enableSortMenuOptions()
   {
   }
@@ -2354,6 +2618,14 @@ public class GAlignFrame extends JInternalFrame
   {
   }
 
+  protected void sortEValueMenuItem_actionPerformed(ActionEvent e)
+  {
+  }
+
+  protected void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
+  {
+  }
+
   protected void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
   {
   }
@@ -2415,10 +2687,12 @@ public class GAlignFrame extends JInternalFrame
   }
 
   protected void pasteNew_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
   }
 
   protected void pasteThis_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
   }
 
@@ -2426,6 +2700,27 @@ public class GAlignFrame extends JInternalFrame
   {
   }
 
+  protected void hmmBuild_actionPerformed(boolean withDefaults)
+  {
+  }
+
+  protected void hmmSearch_actionPerformed(boolean withDefaults)
+  {
+  }
+
+  protected void jackhmmer_actionPerformed(boolean b)
+  {
+  }
+
+  protected void addDatabase_actionPerformed()
+          throws FileFormatException, IOException
+  {
+  }
+
+  protected void hmmAlign_actionPerformed(boolean withDefaults)
+  {
+  }
+
   public void createPNG(java.io.File f)
   {
   }
@@ -2482,6 +2777,14 @@ public class GAlignFrame extends JInternalFrame
   {
   }
 
+  protected void filterByEValue_actionPerformed()
+  {
+  }
+
+  protected void filterByScore_actionPerformed()
+  {
+  }
+
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
   }
@@ -2541,6 +2844,7 @@ public class GAlignFrame extends JInternalFrame
   }
 
   public void associatedData_actionPerformed(ActionEvent e)
+          throws IOException, InterruptedException
   {
 
   }
index 08fbea3..26c37d0 100755 (executable)
@@ -49,7 +49,6 @@ import java.awt.Insets;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseAdapter;
@@ -57,13 +56,16 @@ import java.awt.event.MouseEvent;
 import java.util.Arrays;
 import java.util.List;
 
+import javax.swing.AbstractButton;
 import javax.swing.AbstractCellEditor;
 import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
+import javax.swing.JComponent;
 import javax.swing.JFileChooser;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -87,6 +89,8 @@ import javax.swing.event.ChangeListener;
 import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 
+import net.miginfocom.swing.MigLayout;
+
 /**
  * Base class for the Preferences panel.
  * 
@@ -161,10 +165,15 @@ public class GPreferences extends JPanel
 
   protected JCheckBox showConsensLogo = new JCheckBox();
 
+  protected JCheckBox showInformationHistogram = new JCheckBox();
+
+  protected JCheckBox showHMMLogo = new JCheckBox();
+
   protected JCheckBox showDbRefTooltip = new JCheckBox();
 
   protected JCheckBox showNpTooltip = new JCheckBox();
 
+
   /*
    * Structure tab and components
    */
@@ -288,10 +297,29 @@ public class GPreferences extends JPanel
   protected JCheckBox sortByTree = new JCheckBox();
 
   /*
+   * hmmer tab and components
+   */
+  protected JPanel hmmerTab;
+
+  protected JCheckBox hmmrTrimTermini;
+
+  protected AbstractButton hmmerBackgroundUniprot;
+
+  protected AbstractButton hmmerBackgroundAlignment;
+
+  protected JTextField hmmerSequenceCount;
+
+  protected JTextField hmmerPath;
+
+  protected JTextField cygwinPath;
+
+  /*
    * Web Services tab
    */
   protected JPanel wsTab = new JPanel();
 
+  protected JPanel slivkaTab = new JPanel();
+
   /*
    * Backups tab components
    * a lot of these are member variables instead of local variables only so that they
@@ -395,6 +423,8 @@ public class GPreferences extends JPanel
     tabbedPane.add(initEditingTab(),
             MessageManager.getString("label.editing"));
 
+    tabbedPane.add(initHMMERTab(), MessageManager.getString("label.hmmer"));
+
     /*
      * See WsPreferences for the real work of configuring this tab.
      */
@@ -402,11 +432,13 @@ public class GPreferences extends JPanel
     {
       wsTab.setLayout(new BorderLayout());
       tabbedPane.add(wsTab, MessageManager.getString("label.web_services"));
+      slivkaTab.setLayout(new BorderLayout());
+      tabbedPane.add(slivkaTab, "Slivka Services");
     }
 
     /*
      * Handler to validate a tab before leaving it - currently only for
-     * Structure.
+     * Structure
      */
     tabbedPane.addChangeListener(new ChangeListener()
     {
@@ -460,7 +492,135 @@ public class GPreferences extends JPanel
   }
 
   /**
-   * Initialises the Output tab
+   * Initialises the hmmer tabbed panel
+   * 
+   * @return
+   */
+  private JPanel initHMMERTab()
+  {
+    hmmerTab = new JPanel();
+    hmmerTab.setLayout(new BoxLayout(hmmerTab, BoxLayout.Y_AXIS));
+    hmmerTab.setLayout(new MigLayout("flowy"));
+
+    /*
+     * path to hmmer binaries folder
+     */
+    JPanel installationPanel = new JPanel(new MigLayout("flowy"));
+    // new FlowLayout(FlowLayout.LEFT));
+    JvSwingUtils.createTitledBorder(installationPanel,
+            MessageManager.getString("label.installation"), true);
+    hmmerTab.add(installationPanel);
+    JLabel hmmerLocation = new JLabel(
+            MessageManager.getString("label.hmmer_location"));
+    hmmerLocation.setFont(LABEL_FONT);
+    final int pathFieldLength = 40;
+    hmmerPath = new JTextField(pathFieldLength);
+    hmmerPath.addMouseListener(new MouseAdapter()
+    {
+      @Override
+      public void mouseClicked(MouseEvent e)
+      {
+        if (e.getClickCount() == 2)
+        {
+          String chosen = openFileChooser(true);
+          if (chosen != null)
+          {
+            hmmerPath.setText(chosen);
+            validateHmmerPath();
+          }
+        }
+      }
+    });
+    installationPanel.add(hmmerLocation);
+    installationPanel.add(hmmerPath);
+
+    /*
+     * path to Cygwin binaries folder (for Windows)
+     */
+    if (Platform.isWindowsAndNotJS())
+    {
+      JLabel cygwinLocation = new JLabel(
+              MessageManager.getString("label.cygwin_location"));
+      cygwinLocation.setFont(LABEL_FONT);
+      cygwinPath = new JTextField(pathFieldLength);
+      cygwinPath.addMouseListener(new MouseAdapter()
+      {
+        @Override
+        public void mouseClicked(MouseEvent e)
+        {
+          if (e.getClickCount() == 2)
+          {
+            String chosen = openFileChooser(true);
+            if (chosen != null)
+            {
+              cygwinPath.setText(chosen);
+              validateCygwinPath();
+            }
+          }
+        }
+      });
+      installationPanel.add(cygwinLocation);
+      installationPanel.add(cygwinPath);
+    }
+
+    /*
+     * preferences for hmmalign
+     */
+    JPanel alignOptionsPanel = new JPanel(new MigLayout());
+    // new FlowLayout(FlowLayout.LEFT));
+    JvSwingUtils.createTitledBorder(alignOptionsPanel,
+            MessageManager.getString("label.hmmalign_options"), true);
+    hmmerTab.add(alignOptionsPanel);
+    hmmrTrimTermini = new JCheckBox();
+    hmmrTrimTermini.setFont(LABEL_FONT);
+    hmmrTrimTermini.setText(MessageManager.getString("label.trim_termini"));
+    alignOptionsPanel.add(hmmrTrimTermini);
+
+    /*
+     * preferences for hmmsearch
+     */
+    JPanel searchOptions = new JPanel(new MigLayout());
+    // FlowLayout(FlowLayout.LEFT));
+    JvSwingUtils.createTitledBorder(searchOptions,
+            MessageManager.getString("label.hmmsearch_options"), true);
+    hmmerTab.add(searchOptions);
+    JLabel sequencesToKeep = new JLabel(
+            MessageManager.getString("label.no_of_sequences"));
+    sequencesToKeep.setFont(LABEL_FONT);
+    searchOptions.add(sequencesToKeep);
+    hmmerSequenceCount = new JTextField(5);
+    searchOptions.add(hmmerSequenceCount);
+
+    /*
+     * preferences for Information Content annotation
+     */
+    // JPanel dummy = new JPanel(new FlowLayout(FlowLayout.LEFT));
+    JPanel annotationOptions = new JPanel(new MigLayout("left"));
+    JvSwingUtils.createTitledBorder(annotationOptions,
+            MessageManager.getString("label.information_annotation"), true);
+    // dummy.add(annotationOptions);
+    hmmerTab.add(annotationOptions);
+    ButtonGroup backgroundOptions = new ButtonGroup();
+    hmmerBackgroundUniprot = new JRadioButton(
+            MessageManager.getString("label.freq_uniprot"));
+    hmmerBackgroundUniprot.setFont(LABEL_FONT);
+    hmmerBackgroundAlignment = new JRadioButton(
+            MessageManager.getString("label.freq_alignment"));
+    hmmerBackgroundAlignment.setFont(LABEL_FONT);
+    backgroundOptions.add(hmmerBackgroundUniprot);
+    backgroundOptions.add(hmmerBackgroundAlignment);
+    backgroundOptions.setSelected(hmmerBackgroundUniprot.getModel(), true);
+    // disable buttons for now as annotation only uses Uniprot background
+    hmmerBackgroundAlignment.setEnabled(false);
+    hmmerBackgroundUniprot.setEnabled(false);
+    annotationOptions.add(hmmerBackgroundUniprot, "wrap");
+    annotationOptions.add(hmmerBackgroundAlignment);
+
+    return hmmerTab;
+  }
+
+  /**
+   * Initialises the Output tabbed panel.
    * 
    * @return
    */
@@ -1044,7 +1204,7 @@ public class GPreferences extends JPanel
     protColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
     protColourLabel.setText(
             MessageManager.getString("label.prot_alignment_colour") + " ");
-    JvSwingUtils.addtoLayout(coloursTab,
+    GPreferences.addtoLayout(coloursTab,
             MessageManager
                     .getString("label.default_colour_scheme_for_alignment"),
             protColourLabel, protColour);
@@ -1056,7 +1216,7 @@ public class GPreferences extends JPanel
     nucColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
     nucColourLabel.setText(
             MessageManager.getString("label.nuc_alignment_colour") + " ");
-    JvSwingUtils.addtoLayout(coloursTab,
+    GPreferences.addtoLayout(coloursTab,
             MessageManager
                     .getString("label.default_colour_scheme_for_alignment"),
             nucColourLabel, nucColour);
@@ -1065,11 +1225,11 @@ public class GPreferences extends JPanel
     annotationShding.setBorder(new TitledBorder(
             MessageManager.getString("label.annotation_shading_default")));
     annotationShding.setLayout(new GridLayout(1, 2));
-    JvSwingUtils.addtoLayout(annotationShding,
+    GPreferences.addtoLayout(annotationShding,
             MessageManager.getString(
                     "label.default_minimum_colour_annotation_shading"),
             mincolourLabel, minColour);
-    JvSwingUtils.addtoLayout(annotationShding,
+    GPreferences.addtoLayout(annotationShding,
             MessageManager.getString(
                     "label.default_maximum_colour_annotation_shading"),
             maxcolourLabel, maxColour);
@@ -1323,7 +1483,7 @@ public class GPreferences extends JPanel
       {
         if (e.getClickCount() == 2)
         {
-          String chosen = openFileChooser();
+          String chosen = openFileChooser(false);
           if (chosen != null)
           {
             chimeraPath.setText(chosen);
@@ -1389,10 +1549,14 @@ public class GPreferences extends JPanel
    * 
    * @return
    */
-  protected String openFileChooser()
+  protected String openFileChooser(boolean forFolder)
   {
     String choice = null;
     JFileChooser chooser = new JFileChooser();
+    if (forFolder)
+    {
+      chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+    }
 
     // chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
@@ -1408,21 +1572,6 @@ public class GPreferences extends JPanel
     return choice;
   }
 
-  /**
-   * Validate the structure tab preferences; if invalid, set focus on this tab.
-   * 
-   * @param e
-   */
-  protected boolean validateStructure(FocusEvent e)
-  {
-    if (!validateStructure())
-    {
-      e.getComponent().requestFocusInWindow();
-      return false;
-    }
-    return true;
-  }
-
   protected boolean validateStructure()
   {
     return false;
@@ -2895,5 +3044,41 @@ public class GPreferences extends JPanel
     }
 
   }
+
+  protected void validateHmmerPath()
+  {
+  }
+
+  protected void validateCygwinPath()
+  {
+  }
+
+  /**
+   * A helper method to add a panel containing a label and a component to a
+   * panel
+   * 
+   * @param panel
+   * @param tooltip
+   * @param label
+   * @param valBox
+   */
+  protected static void addtoLayout(JPanel panel, String tooltip,
+          JComponent label, JComponent valBox)
+  {
+    JPanel laypanel = new JPanel(new GridLayout(1, 2));
+    JPanel labPanel = new JPanel(new BorderLayout());
+    JPanel valPanel = new JPanel();
+    labPanel.setBounds(new Rectangle(7, 7, 158, 23));
+    valPanel.setBounds(new Rectangle(172, 7, 270, 23));
+    labPanel.add(label, BorderLayout.WEST);
+    valPanel.add(valBox);
+    laypanel.add(labPanel);
+    laypanel.add(valPanel);
+    valPanel.setToolTipText(tooltip);
+    labPanel.setToolTipText(tooltip);
+    valBox.setToolTipText(tooltip);
+    panel.add(laypanel);
+    panel.validate();
+  }
 }
 
index 5170a6c..14ebbc0 100644 (file)
@@ -103,7 +103,7 @@ public class GRestInputParamEditDialog
     optionsPanel = new JPanel(new MigLayout("", "[fill]", "[fill]"));
     JScrollPane optionView = new JScrollPane();
     optionView.setViewportView(options);
-    JvSwingUtils.mgAddtoLayout(dpane,
+    JvSwingUtils.addtoLayout(dpane,
             MessageManager.getString("label.input_parameter_name"),
             new JLabel(MessageManager.getString("label.name")), tok,
             "grow,spanx 3,wrap");
index a4dca4b..db68757 100644 (file)
@@ -109,20 +109,20 @@ public class GRestServiceEditorPane extends JPanel
     cpanel = details;
     name = new JTextArea(1, 12);
 
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager
                     .getString("label.short_descriptive_name_for_service"),
             new JLabel(MessageManager.getString("label.name")), name,
             "wrap");
     action = new JComboBox();
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager.getString("label.function_service_performs"),
             new JLabel(MessageManager.getString("label.service_action")),
             action, "wrap");
     descr = new JTextArea(4, 60);
     descrVp = new JScrollPane();
     descrVp.setViewportView(descr);
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager.getString("label.brief_description_service"),
             new JLabel(MessageManager.getString("label.description")),
             descrVp, "wrap");
@@ -130,7 +130,7 @@ public class GRestServiceEditorPane extends JPanel
     url = new JTextArea(2, 60);
     urlVp = new JScrollPane();
     urlVp.setViewportView(url);
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager.getString("label.url_post_data_service"),
             new JLabel(MessageManager.getString("label.post_url")), urlVp,
             "wrap");
@@ -138,7 +138,7 @@ public class GRestServiceEditorPane extends JPanel
     urlsuff = new JTextArea();
     urlsuff.setColumns(60);
 
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager.getString("label.optional_suffix"),
             new JLabel(MessageManager.getString("label.url_suffix")),
             urlsuff, "wrap");
@@ -175,7 +175,7 @@ public class GRestServiceEditorPane extends JPanel
       }
     });
     gapChar = new JComboBox();
-    JvSwingUtils.mgAddtoLayout(cpanel,
+    JvSwingUtils.addtoLayout(cpanel,
             MessageManager.getString("label.preferred_gap_character"),
             new JLabel(
                     MessageManager.getString("label.gap_character") + ":"),
index b4b5003..e88a4a1 100644 (file)
@@ -42,6 +42,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLocus;
 import jalview.datamodel.GraphLine;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Point;
 import jalview.datamodel.RnaViewerModel;
@@ -74,6 +75,7 @@ import jalview.gui.TreePanel;
 import jalview.io.BackupFiles;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
+import jalview.io.HMMFile;
 import jalview.io.NewickFile;
 import jalview.math.Matrix;
 import jalview.math.MatrixI;
@@ -97,9 +99,9 @@ import jalview.viewmodel.ViewportRanges;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
-import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.PreferredServiceRegistry;
 import jalview.ws.jws2.dm.AAConSettings;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.AutoCalcSetting;
 import jalview.ws.params.WsParamSetI;
@@ -226,6 +228,8 @@ public class Jalview2XML
 
   private static final String RNA_PREFIX = "rna_";
 
+  private static final String HMMER_PREFIX = "hmmer_";
+
   private static final String UTF_8 = "UTF-8";
 
   /**
@@ -1105,6 +1109,9 @@ public class Jalview2XML
         jseq.getFeatures().add(features);
       }
 
+      /*
+       * save PDB entries for sequence
+       */
       if (jdatasq.getAllPDBEntries() != null)
       {
         Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
@@ -1197,6 +1204,11 @@ public class Jalview2XML
 
       saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
 
+      if (jds.hasHMMProfile())
+      {
+        saveHmmerProfile(jout, jseq, jds);
+      }
+
       // jms.addJSeq(jseq);
       object.getJSeq().add(jseq);
     }
@@ -1745,7 +1757,39 @@ public class Jalview2XML
     }
     return object;
   }
+  /**
+   * Saves the HMMER profile associated with the sequence as a file in the jar,
+   * in HMMER format, and saves the name of the file as a child element of the
+   * XML sequence element
+   * 
+   * @param jout
+   * @param xmlSeq
+   * @param seq
+   */
+  protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
+          SequenceI seq)
+  {
+    HiddenMarkovModel profile = seq.getHMM();
+    if (profile == null)
+    {
+      warn("Want to save HMM profile for " + seq.getName()
+              + " but none found");
+      return;
+    }
+    HMMFile hmmFile = new HMMFile(profile);
+    String hmmAsString = hmmFile.print();
+    String jarEntryName = HMMER_PREFIX + nextCounter();
+    try
+    {
+      writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
+      xmlSeq.setHmmerProfile(jarEntryName);
+    } catch (IOException e)
+    {
+      warn("Error saving HMM profile: " + e.getMessage());
+    }
+  }
 
+    
   /**
    * Writes PCA viewer attributes and computed values to an XML model object and
    * adds it to the JalviewModel. Any exceptions are reported by logging.
@@ -2140,9 +2184,9 @@ public class Jalview2XML
       }
       else if (!matchedFile.equals(pdbentry.getFile()))
       {
-        Cache.log.warn(
-                "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
-                        + pdbentry.getFile());
+         Cache.log.warn(
+                  "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+                          + pdbentry.getFile());
       }
       // record the
       // file so we
@@ -2424,7 +2468,7 @@ public class Jalview2XML
     if (calcIdParam.getVersion().equals("1.0"))
     {
       final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
-      Jws2Instance service = Jws2Discoverer.getInstance()
+      ServiceWithParameters service = PreferredServiceRegistry.getRegistry()
               .getPreferredServiceFor(calcIds);
       if (service != null)
       {
@@ -2457,7 +2501,7 @@ public class Jalview2XML
           argList = parmSet.getArguments();
           parmSet = null;
         }
-        AAConSettings settings = new AAConSettings(
+        AutoCalcSetting settings = new AAConSettings(
                 calcIdParam.isAutoUpdate(), service, parmSet, argList);
         av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
                 calcIdParam.isNeedsUpdate());
@@ -2465,7 +2509,7 @@ public class Jalview2XML
       }
       else
       {
-        warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
+        warn("Cannot resolve a service for the parameters used in this project. Try configuring a server in the Web Services preferences tab.");
         return false;
       }
     }
@@ -3687,6 +3731,16 @@ public class Jalview2XML
           }
         }
 
+        /*
+         * load any HMMER profile
+         */
+        // TODO fix this
+
+        String hmmJarFile = jseqs.get(i).getHmmerProfile();
+        if (hmmJarFile != null && jprovider != null)
+        {
+          loadHmmerProfile(jprovider, hmmJarFile, al.getSequenceAt(i));
+        }
       }
     } // end !multipleview
 
@@ -4211,6 +4265,31 @@ public class Jalview2XML
   }
 
   /**
+   * Loads a HMMER profile from a file stored in the project, and associates it
+   * with the specified sequence
+   * 
+   * @param jprovider
+   * @param hmmJarFile
+   * @param seq
+   */
+  protected void loadHmmerProfile(jarInputStreamProvider jprovider,
+          String hmmJarFile, SequenceI seq)
+  {
+    try
+    {
+      String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
+      HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
+      HiddenMarkovModel hmmModel = parser.getHMM();
+      hmmModel = new HiddenMarkovModel(hmmModel, seq);
+      seq.setHMM(hmmModel);
+    } catch (IOException e)
+    {
+      warn("Error loading HMM profile for " + seq.getName() + ": "
+              + e.getMessage());
+    }
+  }
+
+  /**
    * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
    * panel is restored from separate jar entries, two (gapped and trimmed) per
    * sequence and secondary structure.
@@ -5619,10 +5698,10 @@ public class Jalview2XML
     String id = object.getViewport().get(0).getSequenceSetId();
     if (skipList.containsKey(id))
     {
-      if (Cache.log != null && Cache.log.isDebugEnabled())
-      {
-        Cache.log.debug("Skipping seuqence set id " + id);
-      }
+       if (Cache.log != null && Cache.log.isDebugEnabled())
+        {
+          Cache.log.debug("Skipping seuqence set id " + id);
+        }
       return true;
     }
     return false;
@@ -6096,7 +6175,6 @@ public class Jalview2XML
         jmap.setTo(djs);
         incompleteSeqs.put(sqid, djs);
         seqRefIds.put(sqid, djs);
-
       }
       jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
       addDBRefs(djs, ms);
@@ -6282,7 +6360,7 @@ public class Jalview2XML
       }
       else
       {
-        Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
+          Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
       }
     }
   }
@@ -6758,7 +6836,7 @@ public class Jalview2XML
         maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
       } catch (Exception e)
       {
-        Cache.log.warn("Couldn't parse out graduated feature color.", e);
+          Cache.log.warn("Couldn't parse out graduated feature color.", e);
       }
   
       NoValueColour noCol = colourModel.getNoValueColour();
index c61606e..70991c6 100644 (file)
@@ -29,12 +29,14 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.ProfilesI;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.ZappoColourScheme;
 import jalview.util.Platform;
+import jalview.workers.InformationThread;
 
 import java.awt.BasicStroke;
 import java.awt.Color;
@@ -69,8 +71,14 @@ public class AnnotationRenderer
 
   private final boolean USE_FILL_ROUND_RECT = Platform.isAMacAndNotJS();
 
-  boolean av_renderHistogram = true, av_renderProfile = true,
-          av_normaliseProfile = false;
+  // todo remove these flags, read from group/viewport where needed
+  boolean av_renderHistogram = true;
+
+  boolean av_renderProfile = true;
+
+  boolean av_normaliseProfile = false;
+
+  boolean av_infoHeight = false;
 
   ResidueShaderI profcolour = null;
 
@@ -86,6 +94,8 @@ public class AnnotationRenderer
 
   private boolean av_ignoreGapsConsensus;
 
+  private boolean av_ignoreBelowBackground;
+
   /**
    * attributes set from AwtRenderPanelI
    */
@@ -344,8 +354,12 @@ public class AnnotationRenderer
     complementConsensus = av.getComplementConsensusHash();
     hStrucConsensus = av.getRnaStructureConsensusHash();
     av_ignoreGapsConsensus = av.isIgnoreGapsConsensus();
+    av_ignoreBelowBackground = av.isIgnoreBelowBackground();
+    av_infoHeight = av.isInfoLetterHeight();
   }
 
+
+
   /**
    * Returns profile data; the first element is the profile type, the second is
    * the number of distinct values, the third the total count, and the remainder
@@ -361,17 +375,25 @@ public class AnnotationRenderer
     // properties/rendering attributes as a global 'alignment group' which holds
     // all vis settings for the alignment as a whole rather than a subset
     //
-    if (aa.autoCalculated && (aa.label.startsWith("Consensus")
-            || aa.label.startsWith("cDNA Consensus")))
+    if (InformationThread.HMM_CALC_ID.equals(aa.getCalcId()))
+    {
+      HiddenMarkovModel hmm = aa.sequenceRef.getHMM();
+      return AAFrequency.extractHMMProfile(hmm, column,
+              av_ignoreBelowBackground, av_infoHeight); // TODO check if this follows standard
+                                         // pipeline
+    }
+    if (aa.autoCalculated
+            && (aa.label.startsWith("Consensus") || aa.label
+                    .startsWith("cDNA Consensus")))
     {
       boolean forComplement = aa.label.startsWith("cDNA Consensus");
-      if (aa.groupRef != null && aa.groupRef.consensusData != null
+      if (aa.groupRef != null && aa.groupRef.getConsensusData() != null
               && aa.groupRef.isShowSequenceLogo())
       {
         // TODO? group consensus for cDNA complement
         return AAFrequency.extractProfile(
-                aa.groupRef.consensusData.get(column),
-                aa.groupRef.getIgnoreGapsConsensus());
+                aa.groupRef.getConsensusData().get(column),
+                                               aa.groupRef.getIgnoreGapsConsensus());
       }
       // TODO extend annotation row to enable dynamic and static profile data to
       // be stored
@@ -500,6 +522,28 @@ public class AnnotationRenderer
         renderProfile = av_renderProfile;
         normaliseProfile = av_normaliseProfile;
       }
+      else if (InformationThread.HMM_CALC_ID.equals(row.getCalcId()))
+      {
+        if (row.groupRef != null)
+        {
+          renderHistogram = row.groupRef.isShowInformationHistogram();
+          renderProfile = row.groupRef.isShowHMMSequenceLogo();
+          normaliseProfile = row.groupRef.isNormaliseHMMSequenceLogo();
+        }
+        else
+        {
+          renderHistogram = av.isShowInformationHistogram();
+          renderProfile = av.isShowHMMSequenceLogo();
+          normaliseProfile = av.isNormaliseHMMSequenceLogo();
+        }
+      }
+      else if (row == consensusAnnot || row == structConsensusAnnot
+              || row == complementConsensusAnnot)
+      {
+        renderHistogram = av_renderHistogram;
+        renderProfile = av_renderProfile;
+        normaliseProfile = av_normaliseProfile;
+      }
 
       Annotation[] row_annotations = row.annotations;
       if (!row.visible)
index 4d97171..7e67598 100644 (file)
@@ -5,16 +5,16 @@
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
+ * modify it under the terms of the GNU General License 
  * as published by the Free Software Foundation, either version 3
  * of the License, or (at your option) any later version.
  *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
+ * PURPOSE.  See the GNU General License for more details.
  * 
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU General License
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
@@ -32,16 +32,15 @@ import java.util.Map;
 
 public interface ResidueShaderI
 {
+  void setConsensus(ProfilesI cons);
 
-  public abstract void setConsensus(ProfilesI cons);
+  boolean conservationApplied();
 
-  public abstract boolean conservationApplied();
+  void setConservationApplied(boolean conservationApplied);
 
-  public abstract void setConservationApplied(boolean conservationApplied);
+  void setConservation(Conservation cons);
 
-  public abstract void setConservation(Conservation cons);
-
-  public abstract void alignmentChanged(AnnotatedCollectionI alignment,
+  void alignmentChanged(AnnotatedCollectionI alignment,
           Map<SequenceI, SequenceCollectionI> hiddenReps);
 
   /**
@@ -51,19 +50,19 @@ public interface ResidueShaderI
    * @param consensusThreshold
    * @param ignoreGaps
    */
-  public abstract void setThreshold(int consensusThreshold,
+  void setThreshold(int consensusThreshold,
           boolean ignoreGaps);
 
-  public abstract void setConservationInc(int i);
+  void setConservationInc(int i);
 
-  public abstract int getConservationInc();
+  int getConservationInc();
 
   /**
    * Get the percentage threshold for this colour scheme
    * 
    * @return Returns the percentage threshold
    */
-  public abstract int getThreshold();
+  int getThreshold();
 
   /**
    * Returns the possibly context dependent colour for the given symbol at the
@@ -75,11 +74,11 @@ public interface ResidueShaderI
    * @param seq
    * @return
    */
-  public abstract Color findColour(char symbol, int position,
+  Color findColour(char symbol, int position,
           SequenceI seq);
 
-  public abstract ColourSchemeI getColourScheme();
+  ColourSchemeI getColourScheme();
 
-  public abstract void setColourScheme(ColourSchemeI cs);
+  void setColourScheme(ColourSchemeI cs);
 
 }
\ No newline at end of file
index 75a07b9..a84ea52 100755 (executable)
@@ -37,6 +37,16 @@ import java.util.Map;
 
 public class AnnotationColourGradient extends FollowerColourScheme
 {
+  /**
+   * map positional scores to transparency rather than colour
+   */
+  boolean positionToTransparency = true;
+
+  /**
+   * compute shade based on annotation row score
+   */
+  boolean perLineScore = true;
+
   public static final int NO_THRESHOLD = -1;
 
   public static final int BELOW_THRESHOLD = 0;
@@ -94,6 +104,8 @@ public class AnnotationColourGradient extends FollowerColourScheme
     acg.predefinedColours = predefinedColours;
     acg.seqAssociated = seqAssociated;
     acg.noGradient = noGradient;
+    acg.positionToTransparency = positionToTransparency;
+    acg.perLineScore = perLineScore;
     return acg;
   }
 
@@ -192,14 +204,16 @@ public class AnnotationColourGradient extends FollowerColourScheme
       AnnotatedCollectionI alcontext = alignment instanceof AlignmentI
               ? alignment
               : alignment.getContext();
-      boolean f = true, rna = false;
-      for (AlignmentAnnotation alan : alcontext
-              .findAnnotation(annotation.getCalcId()))
+      boolean f = true, sf = true, rna = false;
+      long plcount = 0, ancount = 0;
+      for (AlignmentAnnotation alan : alcontext.findAnnotation(annotation
+              .getCalcId()))
       {
         if (alan.sequenceRef != null
                 && (alan.label != null && annotation != null
                         && alan.label.equals(annotation.label)))
         {
+          ancount++;
           if (!rna && alan.isRNA())
           {
             rna = true;
@@ -214,8 +228,30 @@ public class AnnotationColourGradient extends FollowerColourScheme
             aamin = alan.graphMin;
           }
           f = false;
+          if (alan.score == alan.score)
+          {
+            if (sf || alan.score < plmin)
+            {
+              plmin = alan.score;
+            }
+            if (sf || alan.score > plmax)
+            {
+              plmax = alan.score;
+            }
+            sf = false;
+            plcount++;
+          }
         }
       }
+      if (plcount > 0 && plcount == ancount)
+      {
+        perLineScore = plcount == ancount;
+        aamax=plmax;
+      }
+      else
+      {
+        perLineScore = false;
+      }
       if (rna)
       {
         ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax);
@@ -223,7 +259,15 @@ public class AnnotationColourGradient extends FollowerColourScheme
     }
   }
 
-  float aamin = 0f, aamax = 0f;
+  /**
+   * positional annotation max/min
+   */
+  double aamin = 0.0, aamax = 0.0;
+
+  /**
+   * per line score max/min
+   */
+  double plmin = Double.NaN, plmax = Double.NaN;
 
   public AlignmentAnnotation getAnnotation()
   {
@@ -439,11 +483,25 @@ public class AnnotationColourGradient extends FollowerColourScheme
       }
     }
 
-    int dr = (int) (redRange * range + redMin);
-    int dg = (int) (greenRange * range + greenMin);
-    int db = (int) (blueRange * range + blueMin);
-
-    return new Color(dr, dg, db);
+    // midtr sets the ceiling for bleaching out the shading
+    int trans = 0, midtr = 239;
+    if (perLineScore)
+    {
+      trans = (int) ((1f - range) * midtr);
+      range = (float) ((ann.score - plmin) / (plmax - aamin));
+    }
+    int dr = (int) (redRange * range + redMin),
+            dg = (int) (greenRange * range + greenMin),
+            db = (int) (blueRange * range + blueMin);
+    if (ann.score == ann.score && positionToTransparency)
+    {
+      return new Color(Math.min(dr + trans, midtr), Math.min(dg
+              + trans, midtr), Math.min(db + trans, midtr));
+    }
+    else
+    {
+      return new Color(dr, dg, db);
+    }
   }
 
   public boolean isPredefinedColours()
index b15e4cf..3d82f9b 100644 (file)
@@ -22,6 +22,7 @@ package jalview.schemes;
 
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsModelI;
+import jalview.datamodel.features.FeatureMatcherSetI;
 
 /**
  * An adapter class that may be extended to instantiate feature colour schemes
@@ -65,4 +66,10 @@ public class FeatureSettingsAdapter implements FeatureSettingsModelI
     return false;
   }
 
+  @Override
+  public FeatureMatcherSetI getFeatureFilters(String type)
+  {
+    return null;
+  }
+
 }
diff --git a/src/jalview/schemes/HMMMatchScoreColourScheme.java b/src/jalview/schemes/HMMMatchScoreColourScheme.java
new file mode 100644 (file)
index 0000000..96eb26a
--- /dev/null
@@ -0,0 +1,369 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+
+
+public class HMMMatchScoreColourScheme extends ResidueColourScheme
+{
+  
+  private Map<Character, Map<Integer, Map<String, Double>>> probabilities;
+
+  private List<Integer> ranges;
+
+  private static double binSize;
+
+  public class MatchProbReader
+  {
+    private BufferedReader reader;
+    
+    MatchProbReader() throws FileNotFoundException
+    {
+      reader = new BufferedReader(
+              new FileReader("resources/ProbabilityOfMatch"));
+    }
+    
+    /*
+    public Map<Character, Map<String, Double>>  getProbabilities() throws IOException
+    {
+      Map<Character, Map<String, Double>> probabilities = new HashMap<>();
+      
+      String[] alphabet = reader.readLine().split("\\,");
+      for (int i = 1; i < alphabet.length - 1; i++)
+      {
+        probabilities.put(alphabet[i].replaceAll("\\ ", "").charAt(0),
+                new HashMap<>());
+      }
+      
+      String line = reader.readLine();
+      while(line != null)
+      {
+        String[] contents = line.split("\\,");
+        
+        for(int i = 1; i < contents.length; i++)
+        {
+          probabilities.get(alphabet[i].replaceAll("\\ ", "").charAt(0))
+                  .put(contents[0], Double
+                          .valueOf(contents[i].replaceAll("\\ ", "")));
+        }
+        line = reader.readLine();
+    
+      }
+      reader.close();
+      return probabilities;
+    }
+    */
+    
+    public Map<Character, Map<Integer, Map<String, Double>>> getProbabilities()
+            throws IOException
+    {
+
+      Map<Character, Map<Integer, Map<String, Double>>> probabilities = new HashMap<>();
+
+      ranges = new ArrayList<>();
+      ranges.add(0);
+
+      binSize = Double.valueOf((reader.readLine().replaceAll("\\ ", "")));
+      String line = reader.readLine();
+      char c = line.charAt(0);
+
+      while (line != null)
+      {
+        line = reader.readLine();
+        while (line != null && line.split("\\,").length != 1)
+        {
+          String[] llrs = line.split("\\,");
+          String[] counts = reader.readLine().split("\\,");
+          int range = Integer.valueOf(llrs[0]);
+
+          if (!ranges.contains(range))
+          {
+            ranges.add(range);
+          }
+          if (!probabilities.containsKey(c))
+          {
+            probabilities.put(c, new HashMap<>());
+          }
+          probabilities.get(c).put(range, new HashMap<>());
+
+          for (int i = 1; i < llrs.length; i++)
+          {
+            probabilities.get(c).get(range).put(
+                    llrs[i].replaceAll("\\ ", ""),
+                    Double.valueOf(counts[i].replaceAll("\\ ", "")));
+          }
+
+          line = reader.readLine();
+        }
+        if (line != null)
+        {
+          c = line.charAt(0);
+        }
+      }
+
+      return probabilities;
+    }
+    
+  }
+
+  private static final Color INSERTION_COLOUR = Color.white;
+
+  /*
+   * the aligned HMM consensus sequence to use as reference for colouring
+   */
+  private SequenceI hmmSeq;
+
+  private HiddenMarkovModel hmm;
+
+  private Map<Character, Float> frequencies;
+
+  /**
+   * Constructor given a list of Hidden Markov Model consensus sequences. The
+   * first sequence provides the HMM profile from which we can read the emission
+   * probabilities that determine the colour.
+   * 
+   * @param hmmSeqs
+   * @throws IOException
+   */
+  public HMMMatchScoreColourScheme(List<SequenceI> hmmSeqs)
+  {
+    hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0);
+    hmm = hmmSeq == null ? null : hmmSeq.getHMM();
+
+    try
+    {
+      MatchProbReader probabilityReader = new MatchProbReader();
+      probabilities = probabilityReader.getProbabilities();
+    } catch (IOException e)
+    {
+      System.out.println(e.getStackTrace());
+    }
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HMMMatchScoreColourScheme()
+  {
+  }
+
+  @Override
+  public Color findColour(char symbol, int column, SequenceI seq,
+          String consensusResidue, float pid)
+  {
+    if (seq == null)
+    {
+      return null;
+    }
+    return findColour(symbol, column, seq.gapMap().length);
+  }
+
+  // TODO change documentation
+  /**
+   * Returns the colour at a particular symbol at a column in the alignment:
+   * <ul>
+   * <li>white for a gap</li>
+   * <li>red for an insertion</li>
+   * <li>orange for negative information content</li>
+   * <li>white to blue for increasing information content</li>
+   * </ul>
+   * 
+   * @param symbol
+   * @param column
+   * @return
+   */
+  private Color findColour(char symbol, int column, int length)
+  {
+    if (getHmm() == null || Comparison.isGap(symbol))
+    {
+      return Color.white;
+    }
+    if (Comparison.isGap(hmmSeq.getCharAt(column)))
+    {
+      return INSERTION_COLOUR;
+    }
+    if (Character.isLowerCase(symbol))
+    {
+      symbol = Character.toUpperCase(symbol);
+    }
+
+    double prob = 0;
+    if (hmm.getBackgroundFrequencies().containsKey(symbol))
+    {
+      int lengthBin = getLengthBin(length);
+
+      double llr = Math
+              .log(getHmm().getMatchEmissionProbability(column, symbol)
+                      / hmm.getBackgroundFrequencies().get(symbol));
+
+      if (!probabilities.containsKey(symbol)
+              || !probabilities.get(symbol).get(lengthBin)
+              .containsKey(format(llr)))
+      {
+        return new Color(140, 140, 140);
+      }
+
+
+      prob = probabilities.get(symbol).get(lengthBin).get(format(llr));
+    }
+    else
+    {
+      return new Color(140, 140, 140);
+    }
+
+    Color colour = Color.ORANGE;
+    if (prob >= 0.5)
+    {
+
+      colour = ColorUtils.getGraduatedColour((float) prob, 0.5f,
+              Color.WHITE, 1f,
+              Color.blue);
+    }
+    else
+    {
+      colour = ColorUtils.getGraduatedColour((float) prob, 0f, Color.red,
+              0.5f, Color.WHITE);
+    }
+
+    return colour;
+  }
+
+  public static String format(Double d)
+  {
+    String formatArg = String.valueOf(binSize);
+
+    // if bin size, need format "%.n" where n is number of decimal places
+    if (binSize < 1)
+    {
+      formatArg = "." + formatArg.split("\\.")[1].length();
+    }
+
+    Double rounded = Math.round(d / binSize) * binSize;
+    String formatted = String.format("%" + formatArg + "f", rounded);
+
+    // format sometimes returns a number rounded to 0 as -0
+    // this ensures output will always be 0
+    if (Double.valueOf(formatted) == 0)
+    {
+      formatted = "0";
+    }
+    return formatted;
+
+  }
+
+  /**
+   * Answers the maximum possible value of information score (log ratio), for use
+   * in scaling a graduated colour range
+   * 
+   * @return
+   */
+  protected float getMaxInformationScore()
+  {
+    return 0f;
+  }
+
+  /**
+   * Answers a new colour scheme instance based on the HMM of the first sequence
+   * in ac that has an HMM
+   */
+  @Override
+  public ColourSchemeI getInstance(AlignViewportI viewport,
+          AnnotatedCollectionI ac)
+  {
+    return newInstance(ac);
+  }
+
+  /**
+   * Constructor given a sequence collection
+   * 
+   * @param ac
+   */
+  public HMMMatchScoreColourScheme(AnnotatedCollectionI ac)
+  {
+    this(ac.getHmmSequences());
+  }
+
+  /**
+   * Answers a new instance of the colour scheme for the given HMM
+   * 
+   * @param ac
+   * @return
+   */
+  protected HMMMatchScoreColourScheme newInstance(AnnotatedCollectionI ac)
+  {
+    return new HMMMatchScoreColourScheme(ac);
+  }
+
+  @Override
+  public boolean isSimple()
+  {
+    return false;
+  }
+
+  /**
+   * Answers true if the sequence collection has an HMM consensus sequence and
+   * that the first HMM sequence contains background frequencies, else false
+   */
+  @Override
+  public boolean isApplicableTo(AnnotatedCollectionI ac)
+  {
+    return !ac.getHmmSequences().isEmpty() && ac.getHmmSequences().get(0)
+            .getHMM().getBackgroundFrequencies() != null;
+  }
+
+  protected Map<Character, Float> getFrequencies()
+  {
+    return frequencies;
+  }
+
+  protected void setFrequencies(Map<Character, Float> frequencies)
+  {
+    this.frequencies = frequencies;
+  }
+
+  protected HiddenMarkovModel getHmm()
+  {
+    return hmm;
+  }
+
+  protected SequenceI getHmmSequence()
+  {
+    return hmmSeq;
+  }
+
+  @Override
+  public String getSchemeName()
+  {
+    return JalviewColourScheme.HMMMatchScore.toString();
+  }
+
+  private int getLengthBin(int l)
+  {
+    for (int i = 1; i < ranges.size(); i++)
+    {
+      if (l >= ranges.get(i - 1) && l < ranges.get(i))
+      {
+        return ranges.get(i);
+      }
+    }
+    return -1;
+  }
+}
+
+
diff --git a/src/jalview/schemes/HmmerColourScheme.java b/src/jalview/schemes/HmmerColourScheme.java
new file mode 100644 (file)
index 0000000..05c9b66
--- /dev/null
@@ -0,0 +1,197 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for colour schemes based on a selected Hidden Markov Model. The
+ * colour is with reference to an HMM consensus sequence and HMM profile
+ * <ul>
+ * <li>white for a gap</li>
+ * <li>red for an insertion (position is gapped in the HMM consensus)</li>
+ * <li>orange for negative information content</li>
+ * <li>white to blue for increasing information content</li>
+ * </ul>
+ * where information content is the log ratio
+ * 
+ * <pre>
+ *   log(profile match emission probability / residue background probability)
+ * </pre>
+ * 
+ * Sub-class implementations use either global ('Uniprot') or local
+ * ('alignment') background frequencies.
+ * 
+ * @author tzvanaalten
+ * @author gmcarstairs
+ */
+public abstract class HmmerColourScheme extends ResidueColourScheme
+{
+  private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish
+
+  /*
+   * the aligned HMM consensus sequence to use as reference for colouring
+   */
+  private SequenceI hmmSeq;
+
+  private HiddenMarkovModel hmm;
+
+  private Map<Character, Float> frequencies;
+
+  /**
+   * Constructor given a list of Hidden Markov Model consensus sequences. The
+   * first sequence provides the HMM profile from which we can read the emission
+   * probabilities that determine the colour.
+   * 
+   * @param hmmSeqs
+   */
+  public HmmerColourScheme(List<SequenceI> hmmSeqs)
+  {
+    hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0);
+    hmm = hmmSeq == null ? null : hmmSeq.getHMM();
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HmmerColourScheme()
+  {
+  }
+
+  @Override
+  public Color findColour(char symbol, int column, SequenceI seq,
+          String consensusResidue, float pid)
+  {
+    return findColour(symbol, column);
+  }
+
+  /**
+   * Returns the colour at a particular symbol at a column in the alignment:
+   * <ul>
+   * <li>white for a gap</li>
+   * <li>red for an insertion</li>
+   * <li>orange for negative information content</li>
+   * <li>white to blue for increasing information content</li>
+   * </ul>
+   * 
+   * @param symbol
+   * @param column
+   * @return
+   */
+  private Color findColour(char symbol, int column)
+  {
+    if (getHmm() == null || Comparison.isGap(symbol))
+    {
+      return Color.white;
+    }
+    if (Comparison.isGap(hmmSeq.getCharAt(column)))
+    {
+      return INSERTION_COLOUR;
+    }
+    if (Character.isLowerCase(symbol))
+    {
+      symbol = Character.toUpperCase(symbol);
+    }
+
+    final double prob = getHmm().getMatchEmissionProbability(column,
+            symbol);
+
+    Float freq = 0f;
+
+    if (!frequencies.containsKey(symbol))
+    {
+      return Color.WHITE;
+    }
+    else
+    {
+      freq = frequencies.get(symbol);
+    }
+
+    /*
+     * Orange if match emission probability is less than background probability
+     */
+    double infoRatio = prob / freq.floatValue();
+    Color colour = Color.ORANGE;
+    if (infoRatio >= 1)
+    {
+      /*
+       * log-scale graduated shade of blue if prob is greater than background  
+       */
+      float infoLog = (float) Math.log(infoRatio);
+      colour = ColorUtils.getGraduatedColour(infoLog, 0, Color.WHITE,
+              getMaxInformationScore(), Color.blue);
+    }
+
+    return colour;
+  }
+
+  /**
+   * Answers the maximum possible value of information score (log ratio), for
+   * use in scaling a graduated colour range
+   * 
+   * @return
+   */
+  abstract float getMaxInformationScore();
+
+  /**
+   * Answers a new colour scheme instance based on the HMM of the first sequence
+   * in ac that has an HMM
+   */
+  @Override
+  public ColourSchemeI getInstance(AlignViewportI viewport,
+          AnnotatedCollectionI ac)
+  {
+    return newInstance(ac);
+  }
+
+  /**
+   * Answers a new instance of the colour scheme for the given HMM
+   * 
+   * @param ac
+   * @return
+   */
+  protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac);
+
+  @Override
+  public boolean isSimple()
+  {
+    return false;
+  }
+
+  /**
+   * Answers true if the sequence collection has an HMM consensus sequence, else
+   * false
+   */
+  @Override
+  public boolean isApplicableTo(AnnotatedCollectionI ac)
+  {
+    return !ac.getHmmSequences().isEmpty();
+  }
+
+  protected Map<Character, Float> getFrequencies()
+  {
+    return frequencies;
+  }
+
+  protected void setFrequencies(Map<Character, Float> frequencies)
+  {
+    this.frequencies = frequencies;
+  }
+
+  protected HiddenMarkovModel getHmm()
+  {
+    return hmm;
+  }
+
+  protected SequenceI getHmmSequence()
+  {
+    return hmmSeq;
+  }
+}
diff --git a/src/jalview/schemes/HmmerGlobalBackground.java b/src/jalview/schemes/HmmerGlobalBackground.java
new file mode 100644 (file)
index 0000000..a24b7ab
--- /dev/null
@@ -0,0 +1,73 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.SequenceCollectionI;
+
+/**
+ * An HMM colour scheme that uses global ('Uniprot') background frequencies for
+ * residues
+ * 
+ * @author tzvanaalten
+ */
+public class HmmerGlobalBackground extends HmmerColourScheme
+{
+  /*
+   * The highest possible log ratio is when match emission probability in
+   * the HMM model is 1, and background (for W) is 0.0109 giving
+   * log(1/0.0109) = log(91.743) = 4.519
+   */
+  private static final float MAX_LOG_RATIO = 4.519f;
+
+  /**
+   * Constructor given a sequence collection
+   * 
+   * @param ac
+   */
+  public HmmerGlobalBackground(SequenceCollectionI ac)
+  {
+    super(ac.getHmmSequences());
+    String alphabetType = getHmm() == null
+            ? ResidueProperties.ALPHABET_AMINO
+            : getHmm().getAlphabetType();
+    setFrequencies(
+            ResidueProperties.backgroundFrequencies.get(alphabetType));
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HmmerGlobalBackground()
+  {
+  }
+
+  @Override
+  public String getSchemeName()
+  {
+    return JalviewColourScheme.HMMERU.toString();
+  }
+
+  @Override
+  protected HmmerColourScheme newInstance(AnnotatedCollectionI ac)
+  {
+    return new HmmerGlobalBackground(ac);
+  }
+
+  @Override
+  float getMaxInformationScore()
+  {
+    return MAX_LOG_RATIO;
+  }
+
+  /**
+   * Answers a new colour scheme instance based on the HMM of the first sequence
+   * in alignment that has an HMM
+   */
+  @Override
+  public ColourSchemeI getInstance(AlignViewportI viewport,
+          AnnotatedCollectionI ac)
+  {
+    return newInstance(ac);
+  }
+
+}
diff --git a/src/jalview/schemes/HmmerLocalBackground.java b/src/jalview/schemes/HmmerLocalBackground.java
new file mode 100644 (file)
index 0000000..2fe775c
--- /dev/null
@@ -0,0 +1,96 @@
+package jalview.schemes;
+
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceI;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An HMM colour scheme that uses local (alignment or sub-group) background
+ * frequencies for residues
+ * 
+ * @author tzvanaalten
+ */
+public class HmmerLocalBackground extends HmmerColourScheme
+{
+  float logTotalCount;
+
+  /**
+   * Constructor given a sequence collection
+   * 
+   * @param ac
+   */
+  public HmmerLocalBackground(AnnotatedCollectionI ac)
+  {
+    super(ac.getHmmSequences());
+    countFrequencies(ac);
+  }
+
+  /**
+   * Default constructor (required by ColourSchemes.loadColourSchemes)
+   */
+  public HmmerLocalBackground()
+  {
+  }
+
+  @Override
+  public String getSchemeName()
+  {
+    return JalviewColourScheme.HMMERA.toString();
+  }
+
+  /**
+   * Counts and stores the relative frequency of every residue in the alignment
+   * (apart from any HMM consensus sequences)
+   * 
+   * @param sc
+   */
+  public void countFrequencies(SequenceCollectionI sc)
+  {
+    // TODO or total counts in Consensus Profile (how do we get at it?)?
+    Map<Character, Float> freqs = new HashMap<>();
+
+    /*
+     * count symbols, excluding any HMM consensus sequences
+     */
+    ResidueCount counts = new ResidueCount();
+    List<SequenceI> seqs = sc.getSequences();
+    for (SequenceI seq : seqs)
+    {
+      if (!seq.hasHMMProfile())
+      {
+        for (char c : seq.getSequence())
+        {
+          counts.add(c);
+        }
+      }
+    }
+    int total = counts.getTotalResidueCount(); // excludes gaps
+
+    for (char symbol : counts.getSymbolCounts().symbols)
+    {
+      double freq = counts.getCount(symbol) / (double) total;
+      freqs.put(symbol, (float) freq);
+    }
+
+    setFrequencies(freqs);
+
+    logTotalCount = (float) Math.log(total);
+  }
+
+  @Override
+  float getMaxInformationScore()
+  {
+    return logTotalCount;
+  }
+
+  @Override
+  protected HmmerColourScheme newInstance(AnnotatedCollectionI ac)
+  {
+    return new HmmerLocalBackground(ac);
+  }
+}
index 456397e..eb1edf1 100644 (file)
@@ -43,7 +43,10 @@ public enum JalviewColourScheme
   PurinePyrimidine("Purine/Pyrimidine", PurinePyrimidineColourScheme.class),
   RNAHelices("RNA Helices", RNAHelicesColour.class),
   TCoffee("T-Coffee Scores", TCoffeeColourScheme.class),
-  IdColour("Sequence ID", IdColourScheme.class);
+  IdColour("Sequence ID", IdColourScheme.class),
+  HMMERU("HMMER-Uniprot", HmmerGlobalBackground.class),
+  HMMERA("HMMER-Alignment", HmmerLocalBackground.class),
+  HMMMatchScore("HMM Match Score", HMMMatchScoreColourScheme.class);
   // RNAInteraction("RNA Interaction type", RNAInteractionColourScheme.class)
 
   private String name;
index 5f84ca0..0b62bb6 100755 (executable)
@@ -34,6 +34,13 @@ import java.util.Vector;
 
 public class ResidueProperties
 {
+  // alphabet names used in Hidden Markov Model files
+  public static final String ALPHABET_RNA = "RNA";
+
+  public static final String ALPHABET_DNA = "DNA";
+
+  public static final String ALPHABET_AMINO = "amino";
+
   // Stores residue codes/names and colours and other things
   public static final int[] aaIndex; // aaHash version 2.1.1 and below
 
@@ -50,6 +57,9 @@ public class ResidueProperties
   // lookup from modified amino acid (e.g. MSE) to canonical form (e.g. MET)
   public static final Map<String, String> modifications = new HashMap<>();
 
+  // residue background frequencies across different alphabets
+  public static final Map<String, Map<Character, Float>> backgroundFrequencies = new HashMap<>();
+
   static
   {
     aaIndex = new int[255];
@@ -2270,6 +2280,58 @@ public class ResidueProperties
 
   }
 
+  static
+  {
+    Map<Character, Float> amino = new HashMap<>();
+    amino.put('A', 0.0826f);
+    amino.put('Q', 0.0393f);
+    amino.put('L', 0.0965f);
+    amino.put('S', 0.0661f);
+    amino.put('R', 0.0553f);
+    amino.put('E', 0.0674f);
+    amino.put('K', 0.0582f);
+    amino.put('T', 0.0535f);
+    amino.put('N', 0.0406f);
+    amino.put('G', 0.0708f);
+    amino.put('M', 0.0241f);
+    amino.put('W', 0.0109f);
+    amino.put('D', 0.0546f);
+    amino.put('H', 0.0227f);
+    amino.put('F', 0.0386f);
+    amino.put('Y', 0.0292f);
+    amino.put('C', 0.0137f);
+    amino.put('I', 0.0593f);
+    amino.put('P', 0.0472f);
+    amino.put('V', 0.0686f);
+    backgroundFrequencies.put(ALPHABET_AMINO, amino);
+    // todo: these don't match https://www.ebi.ac.uk/uniprot/TrEMBLstats - what
+    // are they?
+  }
+
+  // TODO get correct frequencies
+
+  static
+  {
+    Map<Character, Float> dna = new HashMap<>();
+    dna.put('A', 0.25f);
+    dna.put('C', 0.25f);
+    dna.put('T', 0.25f);
+    dna.put('G', 0.25f);
+    backgroundFrequencies.put(ALPHABET_DNA, dna);
+
+  }
+
+  static
+  {
+    Map<Character, Float> rna = new HashMap<>();
+    rna.put('A', 0.25f);
+    rna.put('C', 0.25f);
+    rna.put('T', 0.25f);
+    rna.put('G', 0.25f);
+    backgroundFrequencies.put(ALPHABET_RNA, rna);
+
+  }
+
   public static String getCanonicalAminoAcid(String aA)
   {
     String canonical = modifications.get(aA);
index d4fc233..4afa12d 100644 (file)
@@ -256,7 +256,7 @@ public class Comparison
    */
   public static final boolean isGap(char c)
   {
-    return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE) ? true : false;
+    return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE);
   }
 
   /**
diff --git a/src/jalview/util/FileUtils.java b/src/jalview/util/FileUtils.java
new file mode 100644 (file)
index 0000000..7e607ab
--- /dev/null
@@ -0,0 +1,208 @@
+package jalview.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Miscellaneous file-related functions
+ */
+public final class FileUtils
+{
+
+  /**
+   * Answers the executable file for the given command, or null if not found or
+   * not executable. The path to the executable is the command name prefixed by
+   * the given folder path, optionally with .exe appended.
+   * 
+   * @param cmd
+   *          command short name, for example hmmbuild
+   * @param binaryPath
+   *          parent folder for the executable
+   * @return
+   */
+  public static File getExecutable(String cmd, String binaryPath)
+  {
+    File file = new File(binaryPath, cmd);
+    if (!file.canExecute())
+    {
+      file = new File(binaryPath, cmd + ".exe");
+      {
+        if (!file.canExecute())
+        {
+          file = null;
+        }
+      }
+    }
+    return file;
+  }
+
+  /**
+   * Answers the path to the folder containing the given executable file, by
+   * searching the PATH environment variable. Answers null if no such executable
+   * can be found.
+   * 
+   * @param cmd
+   * @return
+   */
+  public static String getPathTo(String cmd)
+  {
+    String paths = System.getenv("PATH");
+    // backslash is to escape regular expression argument
+    for (String path : paths.split("\\" + File.pathSeparator))
+    {
+      if (getExecutable(cmd, path) != null)
+      {
+        return path;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * A convenience method to create a temporary file that is deleted on exit of
+   * the JVM
+   * 
+   * @param prefix
+   * @param suffix
+   * @return
+   * @throws IOException
+   */
+  public static File createTempFile(String prefix, String suffix)
+          throws IOException
+  {
+    File f = File.createTempFile(prefix, suffix);
+    f.deleteOnExit();
+    return f;
+  }
+
+  /**
+   * Answers a (possibly empty) list of file paths found by searching below
+   * <code>from</code> that match the supplied regular expression
+   * <code>pattern</code>. Results may include <code>from</code> itself if it
+   * matches. If an exception occurs it is written to syserr and any results up to
+   * that point are returned. Note that the regular expression match applies to
+   * the whole path of any matched file.
+   * <p>
+   * WARNING: because the whole directory tree below <code>from</code> is
+   * searched, this method may be slow if used for a high level directory, or may
+   * exit prematurely if security or other exceptions occur.
+   * 
+   * <pre>
+   * Example: 
+   *   findMatchingPaths(Paths.get("C:/Program Files"), ".*&#47chimera.exe$")
+   * </pre>
+   * 
+   * @param from
+   * @param pattern
+   * 
+   * @return
+   * @see https://stackoverflow.com/questions/794381/how-to-find-files-that-match-a-wildcard-string-in-java/31685610#comment62441832_31685610
+   */
+  public static List<String> findMatchingPaths(Path from, String pattern)
+  {
+    List<String> matches = new ArrayList<>();
+    PathMatcher pathMatcher = FileSystems.getDefault()
+            .getPathMatcher("regex:" + pattern);
+    try
+    {
+      Files.walk(from).filter(pathMatcher::matches)
+              .forEach(m -> matches.add(m.toString()));
+    } catch (IOException e)
+    {
+      System.err.println(
+              "Error searching for " + pattern + " : " + e.toString());
+    }
+
+    return matches;
+  }
+
+  /**
+   * Answers a (possibly empty) list of paths to files below the given root path,
+   * that match the given pattern. The pattern should be a '/' delimited set of
+   * glob patterns, each of which is used to match child file names (not full
+   * paths). Note that 'directory spanning' glob patterns (**) are <em>not</em>
+   * supported by this method.
+   * <p>
+   * For example
+   * 
+   * <pre>
+   *   findMatches("C:\\", "Program Files*&#47Chimera*&#47bin/{chimera,chimera.exe}"
+   * </pre>
+   * 
+   * would match "C:\Program Files\Chimera 1.11\bin\chimera.exe" and "C:\Program
+   * Files (x86)\Chimera 1.10.1\bin\chimera"
+   * 
+   * @param root
+   * @param pattern
+   * @return
+   * @see https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
+   */
+  public static List<String> findMatches(String root, String pattern)
+  {
+    List<String> results = new ArrayList<>();
+    try
+    {
+      Path from = Paths.get(root);
+      findMatches(results, from, Arrays.asList(pattern.split("/")));
+    } catch (Throwable e)
+    {
+      // Paths.get can throw IllegalArgumentException
+      System.err.println(String.format("Error searching %s for %s: %s",
+              root, pattern, e.toString()));
+    }
+
+    return results;
+  }
+
+  /**
+   * A helper method that performs recursive search of file patterns and adds any
+   * 'leaf node' matches to the results list
+   * 
+   * @param results
+   * @param from
+   * @param patterns
+   */
+  protected static void findMatches(List<String> results, Path from,
+          List<String> patterns)
+  {
+    if (patterns.isEmpty())
+    {
+      /*
+       * reached end of recursion with all components matched
+       */
+      results.add(from.toString());
+      return;
+    }
+
+    String pattern = patterns.get(0);
+    try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(from,
+            pattern))
+    {
+      dirStream.forEach(p -> {
+
+        /*
+         * matched a next level file - search below it
+         * (ignore non-directory non-leaf matches)
+         */
+        List<String> subList = patterns.subList(1, patterns.size());
+        if (subList.isEmpty() || p.toFile().isDirectory())
+        {
+          findMatches(results, p, subList);
+        }
+      });
+    } catch (IOException e)
+    {
+      System.err.println(String.format("Error searching %s: %s", pattern,
+              e.toString()));
+    }
+  }
+}
diff --git a/src/jalview/util/HMMProbabilityDistributionAnalyser.java b/src/jalview/util/HMMProbabilityDistributionAnalyser.java
new file mode 100644 (file)
index 0000000..66ae552
--- /dev/null
@@ -0,0 +1,978 @@
+package jalview.util;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+import jalview.io.StockholmFile;
+import jalview.schemes.ResidueProperties;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.Vector;
+
+/**
+ * Processes probability data. The file indexes used in this program represent
+ * the index of the location of a family or hmm in their respective files,
+ * starting from 0.
+ * 
+ * @author TZVanaalten
+ *
+ */
+public class HMMProbabilityDistributionAnalyser
+{
+  AlignmentAnnotation reference = null;
+
+  Vector<SequenceI> sequences;
+
+  HiddenMarkovModel hmm;
+
+  // contains the raw data produced
+  List<ArrayList<Double>> raw = new ArrayList<>();
+
+  // contains binned data
+  Map<String, Double> binned = new HashMap<>();
+
+  // location of the family file
+  String families = "/media/sf_Shared_Folder/PFAM/Family/SeedFamilies.seed";
+
+  // location of the file containing the family-clan links
+  final static String FAMILIESTOCLAN = "/media/sf_Shared_Folder/PFAM/Family/Clanlinks.dat";
+
+  // location of the HMM file
+  String hmms = "/media/sf_Shared_Folder/PFAM/HMMs/Pfam-A.hmm";
+
+  // suffix for raw file
+  final static String RAW = "/Raw.csv";
+
+  // suffix for binned file
+  final static String BINNED = "/Binned.csv";
+
+  // normalisation scale
+  final static double SCALE = 1;
+
+  // current position in file
+  int currentFilePosition = 0;
+
+  final static String NL = "\n";
+
+  Random generator = new Random();
+
+  // current directory
+  String currentFolder;
+
+  boolean keepRaw = false;
+
+  /**
+   * Sets the working directory.
+   * 
+   * @param path
+   */
+  public void setFolder(String path)
+  {
+    currentFolder = path;
+  }
+
+  /**
+   * Moves a buffered reader forward in the file by a certain amount of entries.
+   * Each entry in the file is delimited by '//'.
+   * 
+   * @param index
+   *          The index of the location in the file.
+   * @param br
+   * @throws IOException
+   */
+  public void moveLocationBy(int index, BufferedReader br)
+          throws IOException
+  {
+    for (int i = 0; i < index; i++)
+    {
+      String line = br.readLine();
+      while (!"//".equals(line))
+      {
+        line = br.readLine();
+
+      }
+    }
+
+  }
+  
+  /**
+   * Analyses a specified number of families and then saves the data. Before
+   * analysing the data, the previous saved data will be imported and after
+   * analysing this, the data is exported back into the file. The file must be
+   * in flat file format.
+   * 
+   * @param increments
+   *          The number of families to read before saving.
+   * @throws IOException
+   */
+  public void run(int increments, boolean keepRawData) throws IOException
+  {
+    keepRaw = keepRawData;
+    try
+    {
+      readPreviousData(currentFolder);
+      BufferedReader posReader = new BufferedReader(
+              new FileReader(currentFolder + "/CurrentPosition.txt"));
+
+      String line = posReader.readLine();
+      posReader.close();
+      currentFilePosition = Integer.parseInt(line);
+    } catch (Exception e)
+    {
+      System.out.println("No previous data found");
+    }
+
+
+
+    BufferedReader inputSTO = new BufferedReader(new FileReader(families));
+    BufferedReader inputHMM = new BufferedReader(new FileReader(hmms));
+
+
+
+    moveLocationBy(currentFilePosition, inputHMM);
+    moveLocationBy(currentFilePosition, inputSTO);
+
+    int filesRead = 0;
+    int i = 0;
+    while (filesRead < increments)
+    {
+
+      readStockholm(inputSTO);
+
+      readHMM(inputHMM);
+
+        int count = countValidResidues();
+        processData(count);
+        filesRead++;
+
+      currentFilePosition++;
+      System.out.println(i);
+      i++;
+    }
+
+    PrintWriter p = new PrintWriter(
+            new File(currentFolder + "/CurrentPosition.txt"));
+    p.print(currentFilePosition);
+    p.close();
+    exportData(currentFolder);
+    raw.clear();
+    binned.clear();
+
+  }
+
+  /**
+   * Analyses all families and then saves the data. Before analysing the data,
+   * the previous saved data will be imported and after analysing this, the data
+   * is exported back into the file. The file must be in flat file format.
+   * 
+   * @param increments
+   *          The number of families to read before saving.
+   * @throws IOException
+   */
+  public void runToEnd(int minCount, int maxCount, boolean keepRawData,
+          boolean forClans)
+          throws IOException
+  {
+    keepRaw = keepRawData;
+    BufferedReader inputSTO = null;
+    BufferedReader inputHMM = null;
+    int size = 0;
+    int files = 1;
+    try
+    {
+    if (forClans)
+    {
+        files = 603;
+    }
+    int filesRead = 0;
+    for (int clan = 0; clan < files; clan++)
+    {
+      System.out.println(clan);
+      String clanPath = "";
+      int numberOfFamilies = 0;
+      if (forClans)
+      {
+        clanPath = currentFolder + "/Clan" + clan;
+          if (!new File(clanPath).exists())
+          {
+            continue;
+          }
+        BufferedReader famCountReader = new BufferedReader(
+                new FileReader(clanPath + "/NumberOfFamilies.txt"));
+        numberOfFamilies = Integer.parseInt(famCountReader.readLine());
+      }
+      else
+      {
+        numberOfFamilies = 1;
+      }
+      
+      for (int fam = 0; fam < numberOfFamilies; fam++)
+      {
+        if (forClans)
+        {
+          families = clanPath + "/Families/Fam" + fam + ".sto";
+          hmms = clanPath + "/HMMs/HMM" + fam + ".hmm";
+        }
+
+        inputSTO = new BufferedReader(new FileReader(families));
+        inputHMM = new BufferedReader(new FileReader(hmms));
+
+
+        int i = 0;
+        boolean endReached = atEnd(inputSTO);
+        while (!endReached)
+        {
+          readStockholm(inputSTO);
+          readHMM(inputHMM);
+
+        int count = countValidResidues();
+            if (count >= minCount && count < maxCount)
+            {
+              processData(count);
+            }
+        filesRead++;
+          System.out.println(filesRead);
+      endReached = atEnd(inputSTO);
+      }
+      }
+    }
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    } finally
+    {
+      exportData(currentFolder);
+      raw.clear();
+      binned.clear();
+    }
+  }
+
+  /**
+   * Reads the previous data from both files
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public void readPreviousData(String source) throws IOException
+  {
+    readBinned(source);
+    if (keepRaw)
+    {
+      readRaw(source);
+    }
+  }
+
+  /**
+   * Reads the previous data from the binned file.
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public void readBinned(String source) throws IOException
+  {
+    BufferedReader input = new BufferedReader(
+            new FileReader(source + BINNED));
+    String line = input.readLine();
+    binned = new HashMap<>();
+    while (!("".equals(line) || line == null))
+    {
+      Scanner scanner = new Scanner(line);
+      scanner.useDelimiter(",");
+      String key = scanner.next();
+      String value = scanner.next();
+      binned.put(key, Double.valueOf(value));
+      scanner.close();
+      line = input.readLine();
+    }
+
+    input.close();
+  }
+
+  /**
+   * Reads the previous data from the raw file.
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public void readRaw(String source) throws IOException
+  {
+    BufferedReader input = new BufferedReader(new FileReader(source + RAW));
+    String line = input.readLine();
+    if (line == null)
+    {
+      input.close();
+      return;
+    }
+    Scanner numberScanner = new Scanner(line);
+    numberScanner.useDelimiter(",");
+    raw = new ArrayList<>();
+    while (numberScanner.hasNext())
+    {
+      numberScanner.next();
+      raw.add(new ArrayList<Double>());
+    }
+    numberScanner.close();
+
+    line = input.readLine();
+    while (!("".equals(line) || line == null))
+    {
+      Scanner scanner = new Scanner(line);
+      scanner.useDelimiter(",");
+
+      int i = 0;
+      while (scanner.hasNext())
+      {
+        String value;
+        value = scanner.next();
+        if (!value.equals("EMPTY"))
+        {
+          raw.get(i).add(Double.parseDouble(value));
+        }
+        else
+        {
+          raw.get(i).add(null);
+        }
+
+        i++;
+      }
+      scanner.close();
+      line = input.readLine();
+    }
+
+    input.close();
+  }
+
+  /**
+   * Counts the number of valid residues in the sequence.
+   * 
+   * @return
+   */
+  public int countValidResidues()
+  {
+    int count = 0;
+
+    for (int width = 0; width < sequences.size(); width++)
+    {
+      for (int length = 1; length < hmm.getLength() + 1; length++)
+      {
+        char symbol;
+        int alignPos;
+        alignPos = hmm.getNodeMapPosition(length);
+
+        symbol = sequences.get(width).getCharAt(alignPos);
+        if (ResidueProperties.backgroundFrequencies.get("amino")
+                .containsKey(symbol))
+        {
+          count++;
+        }
+      }
+    }
+
+    return count;
+  }
+
+  /**
+   * Processes data, and stores it in both a raw and binned format.
+   * 
+   * @param count
+   */
+  public void processData(int count)
+  {
+    int rawPos = 0;
+    if (keepRaw)
+    {
+      raw.add(new ArrayList<Double>());
+      rawPos = raw.size() - 1;
+    }
+    Double total = 0d;
+    for (int width = 0; width < sequences.size(); width++)
+    {
+      for (int length = 1; length < hmm.getLength() + 1; length++)
+      {
+        char symbol;
+        int alignPos;
+        alignPos = hmm.getNodeMapPosition(length);
+        
+        symbol = sequences.get(width).getCharAt(alignPos);
+        if (ResidueProperties.backgroundFrequencies.get("amino")
+                .containsKey(symbol))
+        {
+          Double prob;
+          Float bfreq;
+          Double llr;
+          prob = hmm.getMatchEmissionProbability(alignPos, symbol);
+          bfreq = ResidueProperties.backgroundFrequencies.get("amino")
+                  .get(symbol);
+          if (prob == 0 || bfreq == 0)
+          {
+            System.out.println("error");
+          }
+          llr = Math.log(prob / bfreq);
+          if (keepRaw)
+          {
+            raw.get(rawPos).add(llr);
+          }
+
+          String output;
+          output = String.format("%.1f", llr);
+          total += Double.parseDouble(output);
+          if ("-0.0".equals(output))
+          {
+            output = "0.0";
+          }
+          if (binned.containsKey(output))
+          {
+            double prev = binned.get(output);
+            prev += (SCALE / count);
+            binned.put(output, prev);
+
+          }
+          else
+          {
+            binned.put(output, SCALE / count);
+          }
+        }
+      }
+    }
+    System.out.println(total / count);
+  }
+
+
+  /**
+   * Reads in the sequence data from a Stockholm file.
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public void readStockholm(BufferedReader inputSTO) throws IOException
+  {
+    FileParse parserSTO = new FileParse(inputSTO, "", DataSourceType.FILE);
+    StockholmFile file = new StockholmFile(parserSTO);
+    Vector<AlignmentAnnotation> annots = file.getAnnotations();
+
+    for (AlignmentAnnotation annot : annots)
+    {
+      if (annot.label.contains("Reference"))
+      {
+        reference = annot;
+      }
+    }
+    sequences = file.getSeqs();
+  }
+
+  /**
+   * Reads in the HMM data from a HMMer file.
+   * 
+   * @param source
+   * @throws IOException
+   */
+  public void readHMM(BufferedReader inputHMM) throws IOException
+  {
+    FileParse parserHMM = new FileParse(inputHMM, "", DataSourceType.FILE);
+    HMMFile file = new HMMFile(parserHMM);
+    hmm = file.getHMM();
+
+
+  }
+
+  /**
+   * Exports both the binned and raw data into separate files.
+   * 
+   * @param location
+   * @throws FileNotFoundException
+   */
+  public void exportData(String location) throws FileNotFoundException
+  {
+    PrintWriter writerBin = new PrintWriter(new File(location + BINNED));
+    for (Map.Entry<String, Double> entry : binned.entrySet())
+    {
+      writerBin.println(entry.getKey() + "," + entry.getValue());
+    }
+    writerBin.close();
+    if (keepRaw)
+    {
+
+    PrintWriter writerRaw = new PrintWriter(new File(location + RAW));
+    
+    StringBuilder identifier = new StringBuilder();
+    
+    for (int i = 1; i < raw.size() + 1; i++)
+    {
+      identifier.append("Fam " + i + ",");
+    }
+    
+    writerRaw.println(identifier);
+    
+    boolean rowIsEmpty = false;
+    int row = 0;
+    while (!rowIsEmpty)
+    {
+      rowIsEmpty = true;
+      StringBuilder string = new StringBuilder();
+      for (int column = 0; column < raw.size(); column++)
+      {
+        if (raw.get(column).size() <= row)
+        {
+          string.append("EMPTY,");
+        }
+        else
+        {
+          string.append(raw.get(column).get(row) + ",");
+          rowIsEmpty = false;
+        }
+      }
+      row++;
+      writerRaw.println(string);
+    }
+    writerRaw.close();
+
+    }
+
+  }
+
+  /**
+   * Prints the specified family on the console.
+   * 
+   * @param index
+   * @throws IOException
+   */
+  public void printFam(int index) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(families));
+
+    moveLocationBy(index, br);
+
+    String line = br.readLine();
+
+    while (!"//".equals(line))
+    {
+      System.out.println(line);
+      line = br.readLine();
+    }
+    System.out.println(line);
+    br.close();
+
+  }
+
+  /**
+   * Prints the specified HMM on the console.
+   * 
+   * @param index
+   * @throws IOException
+   */
+  public void printHMM(int index) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(hmms));
+
+    moveLocationBy(index, br);
+
+    String line = br.readLine();
+
+    while (!"//".equals(line))
+    {
+      System.out.println(line);
+      line = br.readLine();
+    }
+    System.out.println(line);
+    br.close();
+
+  }
+
+  /**
+   * Prints the specified family to a .sto file.
+   * 
+   * @param index
+   * @throws IOException
+   */
+  public void exportFam(int index, String location) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(families));
+
+    moveLocationBy(index, br);
+
+    String line = br.readLine();
+    PrintWriter writer = new PrintWriter(
+            new FileOutputStream(new File(location), true));
+    while (!"//".equals(line))
+    {
+      writer.println(line);
+      line = br.readLine();
+    }
+    writer.println(line);
+    writer.close();
+    br.close();
+
+  }
+
+  public void exportFile(BufferedReader br, String location, boolean append)
+          throws IOException
+  {
+    String line = br.readLine();
+    PrintWriter writer = new PrintWriter(
+            new FileOutputStream(location, append));
+    while (!"//".equals(line))
+    {
+      writer.println(line);
+      line = br.readLine();
+    }
+    writer.println(line);
+    writer.close();
+
+
+  }
+
+  public String getHMMName(int index) throws IOException
+  {
+    String name;
+
+    BufferedReader nameFinder = new BufferedReader(new FileReader(hmms));
+
+    moveLocationBy(index, nameFinder);
+
+    nameFinder.readLine();
+
+    Scanner scanner = new Scanner(nameFinder.readLine());
+    name = scanner.next();
+    name = scanner.next();
+    scanner.close();
+    return name;
+  }
+
+  public String getFamilyName(int index) throws IOException
+  {
+    String name;
+
+    BufferedReader nameFinder = new BufferedReader(
+            new FileReader(families));
+
+    moveLocationBy(index, nameFinder);
+
+    nameFinder.readLine();
+
+    Scanner scanner = new Scanner(nameFinder.readLine());
+    name = scanner.next();
+    name = scanner.next();
+    name = scanner.next();
+    scanner.close();
+    return name;
+  }
+
+  /**
+   * Prints the specified family to a .hmm file.
+   * 
+   * @param index
+   * @throws IOException
+   */
+  public void exportHMM(int index, String location) throws IOException
+  {
+
+
+    BufferedReader br = new BufferedReader(new FileReader(hmms));
+
+    moveLocationBy(index, br);
+
+    String line = br.readLine();
+
+    PrintWriter writer = new PrintWriter(
+            new FileOutputStream(new File(location), true));
+    while (!"//".equals(line))
+    {
+      writer.println(line);
+      line = br.readLine();
+    }
+    writer.println(line);
+    writer.close();
+    br.close();
+
+  }
+  
+  /**
+   * Clears all raw, binned and current position data in the current directory.
+   * 
+   * @throws FileNotFoundException
+   */
+  public void clear() throws FileNotFoundException
+  {
+    PrintWriter pos = new PrintWriter(
+            currentFolder + "/CurrentPosition.txt");
+    pos.println("0");
+    
+    PrintWriter raw = new PrintWriter(currentFolder + RAW);
+    
+    PrintWriter bin = new PrintWriter(currentFolder + BINNED);
+    
+    pos.close();
+    bin.close();
+    raw.close();
+  }
+
+  public void sortIntoClans(String directory) throws IOException
+  {
+    BufferedReader clanFinder = new BufferedReader(new FileReader(FAMILIESTOCLAN));
+    BufferedReader familyReader = new BufferedReader(
+            new FileReader(families));
+    BufferedReader hmmReader = new BufferedReader(new FileReader(hmms));
+    int families = 0;
+    // moveLocationBy(7000, familyReader);
+    // moveLocationBy(7000, clanFinder);
+    // moveLocationBy(7000, hmmReader);
+    HashMap<String, Integer> clanIndexes = new HashMap<>();
+    ArrayList<Integer> familyCounts = new ArrayList<>();
+    int filePos = 0; 
+    int clanCount = 0;
+    String line;
+    line = clanFinder.readLine();
+    
+    while (!"".equals(line) && !" ".equals(line) && line != null)
+    {
+     String clanName;
+      boolean inClan = false;
+     while (!(line.indexOf("//") > -1))
+     {
+       
+      if (line.indexOf("#=GF CL") > -1)
+      {
+          families++;
+          System.out.println(families);
+          inClan = true;
+        Scanner scanner = new Scanner(line);
+        scanner.next();
+        scanner.next();
+        clanName = scanner.next();
+          scanner.close();
+        
+        if (!clanIndexes.containsKey(clanName))
+        {
+          clanIndexes.put(clanName, clanCount);
+            clanCount++;
+            familyCounts.add(0);
+        }
+
+
+          Integer clanI = clanIndexes.get(clanName);
+          String clanPath = directory + "/Clan" + clanI.toString();
+          createFolders(clanPath);
+
+          int index = clanIndexes.get(clanName);
+          exportFile(familyReader,
+                  clanPath + "/Families/Fam" + familyCounts.get(index)
+                          + ".sto",
+                  false);
+          exportFile(hmmReader,
+                  clanPath + "/HMMs/HMM" + familyCounts.get(index) + ".hmm",
+                  false);
+
+          int count = familyCounts.get(index);
+          count++;
+          familyCounts.set(index, count);
+      }
+        line = clanFinder.readLine();
+
+      }
+      if (!inClan)
+      {
+        moveLocationBy(1, familyReader);
+        moveLocationBy(1, hmmReader);
+      }
+      filePos++;
+      // System.out.println(filePos + " files read.");
+      line = clanFinder.readLine();
+
+     }
+    clanFinder.close();
+
+    for (int clan = 0; clan < clanCount; clan++)
+    {
+      PrintWriter writer = new PrintWriter(
+              directory + "/Clan" + clan + "/NumberOfFamilies.txt");
+      int count = familyCounts.get(clan);
+      writer.print(count);
+      writer.close();
+    }
+      
+    }
+
+  public String getFamilies()
+  {
+    return families;
+  }
+
+  public void setFamilies(String families)
+  {
+    this.families = currentFolder + families;
+  }
+
+  public String getHmms()
+  {
+    return hmms;
+  }
+
+  public void setHmms(String hmms)
+  {
+    this.hmms = currentFolder + hmms;
+  }
+    
+  public void alignWithinClan(String exportLocation, String clansLocation)
+          throws IOException, InterruptedException
+  {
+    int alignmentsExported = 0;
+    for (int clan = 0; clan < 604; clan++)
+    {
+      System.out.println(clan);
+      int famCount = 0;
+      String clanPath = clansLocation + "/Clan" + clan;
+      int numberOfFamilies;
+      BufferedReader br = new BufferedReader(
+              new FileReader(clanPath + "/NumberOfFamilies.txt"));
+      String line = br.readLine();
+      numberOfFamilies = Integer.parseInt(line);
+      br.close();
+      if (numberOfFamilies == 1)
+      {
+        continue;
+      }
+      final String commandExportLocation = exportLocation + "/Clan" + clan;
+      createFolders(commandExportLocation);
+      for (int family = 0; family < numberOfFamilies; family++)
+      {
+        famCount++;
+        ArrayList<Integer> indexes = new ArrayList<>();
+        for (int i = 0; i < numberOfFamilies; i++)
+        {
+          if (i != family)
+          {
+            indexes.add(i);
+          }
+        }
+
+        int hmmIndex = getRandom(indexes);
+        String famPath = clanPath + "/Families/Fam" + family + ".sto";
+        String hmmPath = clanPath + "/HMMs/HMM" + hmmIndex + ".hmm";
+        String command = "/media/sf_Shared_Folder/hmmer/binaries/hmmalign --mapali "
+                + clanPath + "/Families/Fam" + hmmIndex + ".sto"
+                + " --trim ";
+        command += hmmPath + " ";
+        command += famPath;
+        final int familyIndex = family;
+        final Process p = Runtime.getRuntime().exec(command);
+
+        new Thread(new Runnable()
+        {
+          @Override
+          public void run()
+          {
+            BufferedReader input = new BufferedReader(
+                    new InputStreamReader(p.getInputStream()));
+            String line = null;
+
+            try
+            {
+              PrintWriter writer = new PrintWriter(commandExportLocation
+                      + "/Families/Fam" + familyIndex + ".sto");
+              String lastLine = "";
+              boolean dataFound = false;
+              while ((line = input.readLine()) != null)
+              {
+                if (line.contains("#=GR") && !dataFound)
+                {
+                  writer.println(lastLine);
+                  dataFound = true;
+                }
+                if (line.contains("#") || dataFound || " ".equals(line)
+                        || "".equals(line) || "//".equals(line))
+                {
+                  writer.println(line);
+                }
+                lastLine = line;
+              }
+              writer.close();
+            } catch (IOException e)
+            {
+              e.printStackTrace();
+            }
+          }
+        }).start();
+
+        p.waitFor();
+
+        BufferedReader hmmExporter = new BufferedReader(
+                new FileReader(hmmPath));
+
+        exportFile(hmmExporter,
+                commandExportLocation + "/HMMs/HMM" + family + ".hmm",
+                false);
+
+        alignmentsExported++;
+
+
+      }
+      PrintWriter writer = new PrintWriter(
+              commandExportLocation + "/NumberOfFamilies.txt");
+      writer.print(famCount);
+      writer.close();
+    }
+
+  }
+
+  public boolean atEnd(BufferedReader br) throws IOException
+  {
+    boolean end = false;
+    br.mark(80);
+    String line = br.readLine();
+    if ("".equals(line) || line == null)
+    {
+      end = true;
+    }
+    br.reset();
+    return end;
+  }
+
+  public int getRandom(ArrayList<Integer> list)
+  {
+    if (!(list.size() > 0))
+    {
+      System.out.println("Error - size = " + list.size());
+    }
+    int index = generator.nextInt(list.size());
+    int value = list.get(index);
+    list.remove(index);
+    return value;
+  }
+
+  public void createFolders(String clanPath)
+  {
+    File clanFolder = new File(clanPath);
+    if (!clanFolder.exists())
+    {
+      clanFolder.mkdir();
+    }
+
+    File famFolder = new File(clanPath + "/Families");
+    File hmmFolder = new File(clanPath + "/HMMs");
+    if (!famFolder.exists())
+    {
+      famFolder.mkdir();
+      hmmFolder.mkdir();
+    }
+  }
+}
+
+
+
+
index a5a9460..97c84bc 100644 (file)
@@ -20,6 +20,9 @@
  */
 package jalview.util;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -64,4 +67,46 @@ public class HttpUtils
     return false;
   }
 
+  /**
+   * download from given URL and return a pointer to temporary file
+   */
+  public static File fetchURLToTemp(String url) throws OutOfMemoryError,
+          IOException
+  {
+    long time = System.currentTimeMillis();
+    URL rcall = new URL(url);
+
+    InputStream is = new BufferedInputStream(rcall.openStream());
+    File outFile = null;
+    try
+    {
+      outFile = File.createTempFile("jalview", ".xml");
+      outFile.deleteOnExit();
+      if (outFile.length() == 0)
+      {
+        outFile.delete();
+        return null;
+      }
+    } catch (Exception ex)
+    {
+    }
+
+    if (outFile != null)
+    {
+      FileOutputStream fio = new FileOutputStream(outFile);
+      byte[] bb = new byte[32 * 1024];
+      int l;
+      while ((l = is.read(bb)) > 0)
+      {
+        fio.write(bb, 0, l);
+      }
+      fio.close();
+      is.close();
+      return outFile;
+    }
+    else
+    {
+      return null;
+    }
+  }
 }
index 731e976..986b18c 100644 (file)
@@ -1044,70 +1044,15 @@ public class MapList
 
     for (int[] range : map.getFromRanges())
     {
-      addRange(range, fromShifts);
+      MappingUtils.addRange(range, fromShifts);
     }
     for (int[] range : map.getToRanges())
     {
-      addRange(range, toShifts);
+      MappingUtils.addRange(range, toShifts);
     }
   }
 
   /**
-   * Adds the given range to a list of ranges. If the new range just extends
-   * existing ranges, the current endpoint is updated instead.
-   * 
-   * @param range
-   * @param addTo
-   */
-  static void addRange(int[] range, List<int[]> addTo)
-  {
-    /*
-     * list is empty - add to it!
-     */
-    if (addTo.size() == 0)
-    {
-      addTo.add(range);
-      return;
-    }
-
-    int[] last = addTo.get(addTo.size() - 1);
-    boolean lastForward = last[1] >= last[0];
-    boolean newForward = range[1] >= range[0];
-
-    /*
-     * contiguous range in the same direction - just update endpoint
-     */
-    if (lastForward == newForward && last[1] == range[0])
-    {
-      last[1] = range[1];
-      return;
-    }
-
-    /*
-     * next range starts at +1 in forward sense - update endpoint
-     */
-    if (lastForward && newForward && range[0] == last[1] + 1)
-    {
-      last[1] = range[1];
-      return;
-    }
-
-    /*
-     * next range starts at -1 in reverse sense - update endpoint
-     */
-    if (!lastForward && !newForward && range[0] == last[1] - 1)
-    {
-      last[1] = range[1];
-      return;
-    }
-
-    /*
-     * just add the new range
-     */
-    addTo.add(range);
-  }
-
-  /**
    * Returns true if mapping is from forward strand, false if from reverse
    * strand. Result is just based on the first 'from' range that is not a single
    * position. Default is true unless proven to be false. Behaviour is not well
index b552c21..cd8821d 100644 (file)
@@ -1020,4 +1020,59 @@ public final class MappingUtils
       }
     }
   }
+
+  /**
+   * Adds the given range to a list of ranges. If the new range just extends
+   * existing ranges, the current endpoint is updated instead.
+   * 
+   * @param range
+   * @param addTo
+   */
+  public static void addRange(int[] range, List<int[]> addTo)
+  {
+    /*
+     * list is empty - add to it!
+     */
+    if (addTo.size() == 0)
+    {
+      addTo.add(range);
+      return;
+    }
+  
+    int[] last = addTo.get(addTo.size() - 1);
+    boolean lastForward = last[1] >= last[0];
+    boolean newForward = range[1] >= range[0];
+  
+    /*
+     * contiguous range in the same direction - just update endpoint
+     */
+    if (lastForward == newForward && last[1] == range[0])
+    {
+      last[1] = range[1];
+      return;
+    }
+  
+    /*
+     * next range starts at +1 in forward sense - update endpoint
+     */
+    if (lastForward && newForward && range[0] == last[1] + 1)
+    {
+      last[1] = range[1];
+      return;
+    }
+  
+    /*
+     * next range starts at -1 in reverse sense - update endpoint
+     */
+    if (!lastForward && !newForward && range[0] == last[1] - 1)
+    {
+      last[1] = range[1];
+      return;
+    }
+  
+    /*
+     * just add the new range
+     */
+    addTo.add(range);
+  }
 }
index c068acc..daaab3a 100644 (file)
@@ -192,7 +192,7 @@ public class Platform
   }
 
   /**
-   * Check if we are on a Microsoft plaform...
+   * Check if we are on a Microsoft platform...
    * 
    * @return true if we have to cope with another platform variation
    */
diff --git a/src/jalview/util/ProbabilityAnalyserKickstarter.java b/src/jalview/util/ProbabilityAnalyserKickstarter.java
new file mode 100644 (file)
index 0000000..59c0a9f
--- /dev/null
@@ -0,0 +1,221 @@
+package jalview.util;
+
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * This class contains the brain of the analyser program, and contains a number
+ * of commands for the processing of data.
+ * 
+ * @author TZVanaalten
+ *
+ */
+
+public class ProbabilityAnalyserKickstarter
+{
+
+  public static void main(String[] args)
+          throws IOException, InterruptedException
+  {
+
+    // this does all of the processing
+    HMMProbabilityDistributionAnalyser analyser = new HMMProbabilityDistributionAnalyser();
+
+    boolean running = true;
+    System.out.println("ACTIVATED");
+    while (running)
+    {
+      Scanner keyboard = new Scanner(System.in);
+      String command = keyboard.nextLine();
+
+      Scanner inputScanner = new Scanner(command);
+      // prints family to console. Syntax is printFam <index>
+      if (command.indexOf("printFam") > -1)
+      {
+        try
+        {
+          inputScanner.next();
+          int index = inputScanner.nextInt();
+          analyser.printFam(index);
+          continue;
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+
+      }
+      // prints HMM to console. Syntax is printHMM <index>
+      if (command.indexOf("printHMM") > -1)
+      {
+        try
+        {
+        inputScanner.next();
+        int index = inputScanner.nextInt();
+        analyser.printHMM(index);
+        continue;
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+      }
+      // prints family to file in current folder. Syntax is exportFam <index>.
+      if (command.indexOf("exportFam") > -1)
+      {
+        try
+        {
+        inputScanner.next();
+        int index = inputScanner.nextInt();
+          String location = inputScanner.next();
+          analyser.exportFam(index, location);
+        continue;
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+      }
+      // prints HMM to file in current folder. Syntax is exportHMM <index>.
+      if (command.indexOf("exportHMM") > -1)
+      {
+        try
+        {
+        inputScanner.next();
+        int index = inputScanner.nextInt();
+          String location = inputScanner.next();
+          analyser.exportHMM(index, location);
+        continue;
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+      }
+      // Processes data. Syntax is run <number of loops> <increments>. The
+      // number loops specifies the number of increments the program will run.
+      // After each increment, the data stored currently in the program is
+      // exported and re-read back into the program. This is to ensure that the
+      // program can be terminated without losing a large quantity of data. The
+      // increment is the number of families read per 'save'.
+      if (command.indexOf("run") > -1 && !(command.indexOf("ToEnd") > -1))
+      {
+        try
+        {
+
+        inputScanner.next();
+
+        int loops = inputScanner.nextInt();
+        int increments = inputScanner.nextInt();
+        boolean keepRaw = inputScanner.nextBoolean();
+
+        for (int i = 0; i < loops; i++)
+        {
+          analyser.run(increments, keepRaw);
+          System.out.println("Saved");
+        }
+        System.out.println("Task completed");
+        continue;
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+        continue;
+      }
+      if ((command.indexOf("runToEnd") > -1))
+      {
+        try
+        {
+
+          inputScanner.next();
+          int minCount = inputScanner.nextInt();
+          int maxCount = inputScanner.nextInt();
+          boolean keepRaw = inputScanner.nextBoolean();
+          boolean forClans = inputScanner.nextBoolean();
+          analyser.runToEnd(minCount, maxCount, keepRaw, forClans);
+          System.out.println("Task completed");
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+        continue;
+      }
+      // terminates program. Syntax is terminate.
+      if (command.indexOf("terminate") > -1)
+      {
+        running = false;
+        continue;
+      }
+      // clears files in current directory (Only a specific set of files).
+      // Syntax is clear.
+      if (command.indexOf("clear") > -1)
+      {
+        analyser.clear();
+        continue;
+      }
+      // changes current directory. Syntax is cd <directory>
+      if (command.indexOf("cd") > -1)
+      {
+        try
+        {
+        inputScanner.next();
+        analyser.setFolder(inputScanner.next());
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+
+        }
+        continue;
+      }
+
+      if (command.indexOf("getFamName") > -1)
+      {
+        try
+        {
+        inputScanner.next();
+        System.out.println(analyser.getFamilyName(inputScanner.nextInt()));
+
+        } catch (Exception e)
+        {
+          System.out.println("Command failed");
+        }
+        continue;
+      }
+      if (command.indexOf("sortIntoClans") > -1)
+      {
+        inputScanner.next();
+        analyser.sortIntoClans(inputScanner.next());
+          continue;
+
+      }
+      if (command.indexOf("setFamilies") > -1)
+      {
+        inputScanner.next();
+        analyser.setFamilies(inputScanner.next());
+        continue;
+
+      }
+
+      if (command.indexOf("setHMMs") > -1)
+      {
+        inputScanner.next();
+        analyser.setHmms(inputScanner.next());
+        continue;
+
+      }
+
+      if (command.indexOf("alignWithinClans") > -1)
+      {
+        inputScanner.next();
+        String export = inputScanner.next();
+        String clans = inputScanner.next();
+        analyser.alignWithinClan(export, clans);
+        continue;
+
+      }
+
+      System.out.println("Unrecognised command");
+    }
+
+
+
+
+  }
+
+}
index c6af7f0..f0bc177 100644 (file)
@@ -117,29 +117,6 @@ public class StringUtils
   }
 
   /**
-   * Returns the last part of 'input' after the last occurrence of 'token'. For
-   * example to extract only the filename from a full path or URL.
-   * 
-   * @param input
-   * @param token
-   *          a delimiter which must be in regular expression format
-   * @return
-   */
-  public static String getLastToken(String input, String token)
-  {
-    if (input == null)
-    {
-      return null;
-    }
-    if (token == null)
-    {
-      return input;
-    }
-    String[] st = input.split(token);
-    return st[st.length - 1];
-  }
-
-  /**
    * Parses the input string into components separated by the delimiter. Unlike
    * String.split(), this method will ignore occurrences of the delimiter which
    * are nested within single quotes in name-value pair values, e.g. a='b,c'.
index 4148c72..4aec9d2 100644 (file)
@@ -24,6 +24,8 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
 import jalview.analysis.TreeModel;
 import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcManagerI2;
+import jalview.api.AlignCalcWorkerI;
 import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -57,8 +59,10 @@ import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.styles.ViewStyle;
 import jalview.workers.AlignCalcManager;
+import jalview.workers.AlignCalcManager2;
 import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
+import jalview.workers.InformationThread;
 import jalview.workers.StrucConsensusThread;
 
 import java.awt.Color;
@@ -106,6 +110,27 @@ public abstract class AlignmentViewport
    * alignment displayed in the viewport. Please use get/setter
    */
   protected AlignmentI alignment;
+  
+  /*
+   * probably unused indicator that view is of a dataset rather than an
+   * alignment
+   */
+
+  protected boolean ignoreBelowBackGroundFrequencyCalculation = false;
+
+  protected boolean infoLetterHeight = false;
+
+  protected AlignmentAnnotation occupancy;
+  
+  /**
+   * results of alignment consensus analysis for visible portion of view
+   */
+  protected ProfilesI consensusProfiles;
+
+  /**
+   * HMM profile for the alignment
+   */
+  protected ProfilesI hmmProfiles;
 
   public AlignmentViewport(AlignmentI al)
   {
@@ -593,7 +618,7 @@ public abstract class AlignmentViewport
    * alignment
    */
   protected boolean isDataset = false;
-
+  
   public void setDataset(boolean b)
   {
     isDataset = b;
@@ -636,7 +661,7 @@ public abstract class AlignmentViewport
   protected boolean ignoreGapsInConsensusCalculation = false;
 
   protected ResidueShaderI residueShading = new ResidueShader();
-
+  
   @Override
   public void setGlobalColourScheme(ColourSchemeI cs)
   {
@@ -710,7 +735,7 @@ public abstract class AlignmentViewport
   {
     return residueShading;
   }
-
+  
   protected AlignmentAnnotation consensus;
 
   protected AlignmentAnnotation complementConsensus;
@@ -744,7 +769,7 @@ public abstract class AlignmentViewport
   protected Hashtable<String, Object>[] hStrucConsensus = null;
 
   protected Conservation hconservation = null;
-
+  
   @Override
   public void setConservation(Conservation cons)
   {
@@ -783,6 +808,18 @@ public abstract class AlignmentViewport
   }
 
   @Override
+  public void setHmmProfiles(ProfilesI info)
+  {
+    hmmProfiles = info;
+  }
+
+  @Override
+  public ProfilesI getHmmProfiles()
+  {
+    return hmmProfiles;
+  }
+
+  @Override
   public Hashtable<String, Object>[] getComplementConsensusHash()
   {
     return hcomplementConsensus;
@@ -838,7 +875,7 @@ public abstract class AlignmentViewport
     return strucConsensus;
   }
 
-  protected AlignCalcManagerI calculator = new AlignCalcManager();
+  protected AlignCalcManagerI2 calculator = new AlignCalcManager2();
 
   /**
    * trigger update of conservation annotation
@@ -852,8 +889,8 @@ public abstract class AlignmentViewport
     {
       return;
     }
-    if (calculator.getRegisteredWorkersOfClass(
-            jalview.workers.ConservationThread.class) == null)
+    if (calculator.getWorkersOfClass(
+            jalview.workers.ConservationThread.class).isEmpty())
     {
       calculator.registerWorker(
               new jalview.workers.ConservationThread(this, ap));
@@ -870,8 +907,7 @@ public abstract class AlignmentViewport
     {
       return;
     }
-    if (calculator
-            .getRegisteredWorkersOfClass(ConsensusThread.class) == null)
+    if (calculator.getWorkersOfClass(ConsensusThread.class).isEmpty())
     {
       calculator.registerWorker(new ConsensusThread(this, ap));
     }
@@ -902,16 +938,23 @@ public abstract class AlignmentViewport
       }
       if (doConsensus)
       {
-        if (calculator.getRegisteredWorkersOfClass(
-                ComplementConsensusThread.class) == null)
+        if (calculator.getWorkersOfClass(ComplementConsensusThread.class).isEmpty())
         {
-          calculator
-                  .registerWorker(new ComplementConsensusThread(this, ap));
+          calculator.registerWorker(new ComplementConsensusThread(this, ap));
         }
       }
     }
   }
 
+  @Override
+  public void initInformationWorker(final AlignmentViewPanel ap)
+  {
+    if (calculator.getWorkersOfClass(InformationThread.class).isEmpty())
+    {
+      calculator.registerWorker(new InformationThread(this, ap));
+    }
+  }
+
   // --------START Structure Conservation
   public void updateStrucConsensus(final AlignmentViewPanel ap)
   {
@@ -927,8 +970,7 @@ public abstract class AlignmentViewport
     {
       return;
     }
-    if (calculator.getRegisteredWorkersOfClass(
-            StrucConsensusThread.class) == null)
+    if (calculator.getWorkersOfClass(StrucConsensusThread.class).isEmpty())
     {
       calculator.registerWorker(new StrucConsensusThread(this, ap));
     }
@@ -947,7 +989,7 @@ public abstract class AlignmentViewport
     {
       return false;
     }
-    if (calculator.workingInvolvedWith(alignmentAnnotation))
+    if (calculator.isWorkingWithAnnotation(alignmentAnnotation))
     {
       // System.err.println("grey out ("+alignmentAnnotation.label+")");
       return true;
@@ -975,12 +1017,14 @@ public abstract class AlignmentViewport
     strucConsensus = null;
     conservation = null;
     quality = null;
+    consensusProfiles = null;
     groupConsensus = null;
     groupConservation = null;
     hconsensus = null;
     hconservation = null;
     hcomplementConsensus = null;
     gapcounts = null;
+    calculator.shutdown();
     calculator = null;
     residueShading = null; // may hold a reference to Consensus
     changeSupport = null;
@@ -999,7 +1043,7 @@ public abstract class AlignmentViewport
   }
 
   @Override
-  public AlignCalcManagerI getCalcManager()
+  public AlignCalcManagerI2 getCalcManager()
   {
     return calculator;
   }
@@ -1030,6 +1074,21 @@ public abstract class AlignmentViewport
   protected boolean showConsensusHistogram = true;
 
   /**
+   * should hmm profile be rendered by default
+   */
+  protected boolean hmmShowSequenceLogo = false;
+
+  /**
+   * should hmm profile be rendered normalised to row height
+   */
+  protected boolean hmmNormaliseSequenceLogo = false;
+
+  /**
+   * should information histograms be rendered by default
+   */
+  protected boolean hmmShowHistogram = true;
+
+  /**
    * @return the showConsensusProfile
    */
   @Override
@@ -1039,6 +1098,15 @@ public abstract class AlignmentViewport
   }
 
   /**
+   * @return the showInformationProfile
+   */
+  @Override
+  public boolean isShowHMMSequenceLogo()
+  {
+    return hmmShowSequenceLogo;
+  }
+
+  /**
    * @param showSequenceLogo
    *          the new value
    */
@@ -1049,13 +1117,31 @@ public abstract class AlignmentViewport
       // TODO: decouple settings setting from calculation when refactoring
       // annotation update method from alignframe to viewport
       this.showSequenceLogo = showSequenceLogo;
-      calculator.updateAnnotationFor(ConsensusThread.class);
-      calculator.updateAnnotationFor(ComplementConsensusThread.class);
-      calculator.updateAnnotationFor(StrucConsensusThread.class);
+      for (AlignCalcWorkerI worker : calculator.getWorkers())
+      {
+        if (worker.getClass().equals(ConsensusThread.class) ||
+                worker.getClass().equals(ComplementConsensusThread.class) ||
+                worker.getClass().equals(StrucConsensusThread.class))
+        {
+          worker.updateAnnotation();
+        }
+      }
     }
     this.showSequenceLogo = showSequenceLogo;
   }
 
+  public void setShowHMMSequenceLogo(boolean showHMMSequenceLogo)
+  {
+    if (showHMMSequenceLogo != this.hmmShowSequenceLogo)
+    {
+      this.hmmShowSequenceLogo = showHMMSequenceLogo;
+      // TODO: updateAnnotation if description (tooltip) will show
+      // profile in place of information content?
+      // calculator.updateAnnotationFor(InformationThread.class);
+    }
+    this.hmmShowSequenceLogo = showHMMSequenceLogo;
+  }
+
   /**
    * @param showConsensusHistogram
    *          the showConsensusHistogram to set
@@ -1066,6 +1152,14 @@ public abstract class AlignmentViewport
   }
 
   /**
+   * @param showInformationHistogram
+   */
+  public void setShowInformationHistogram(boolean showInformationHistogram)
+  {
+    this.hmmShowHistogram = showInformationHistogram;
+  }
+
+  /**
    * @return the showGroupConservation
    */
   public boolean isShowGroupConservation()
@@ -1111,6 +1205,17 @@ public abstract class AlignmentViewport
   }
 
   /**
+   * 
+   * @return flag to indicate if the information content histogram should be
+   *         rendered by default
+   */
+  @Override
+  public boolean isShowInformationHistogram()
+  {
+    return this.hmmShowHistogram;
+  }
+
+  /**
    * when set, updateAlignment will always ensure sequences are of equal length
    */
   private boolean padGaps = false;
@@ -1266,7 +1371,16 @@ public abstract class AlignmentViewport
                 ignoreGapsInConsensusCalculation);
       }
     }
+  }
+
+  public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap)
+  {
+    ignoreBelowBackGroundFrequencyCalculation = b;
+  }
 
+  public void setInfoLetterHeight(boolean b, AlignmentViewPanel ap)
+  {
+    infoLetterHeight = b;
   }
 
   private long sgrouphash = -1, colselhash = -1;
@@ -1324,6 +1438,18 @@ public abstract class AlignmentViewport
     return ignoreGapsInConsensusCalculation;
   }
 
+  @Override
+  public boolean isIgnoreBelowBackground()
+  {
+    return ignoreBelowBackGroundFrequencyCalculation;
+  }
+
+  @Override
+  public boolean isInfoLetterHeight()
+  {
+    return infoLetterHeight;
+  }
+
   // property change stuff
   // JBPNote Prolly only need this in the applet version.
   private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
@@ -1902,7 +2028,6 @@ public abstract class AlignmentViewport
 
     updateAllColourSchemes();
     calculator.restartWorkers();
-    // alignment.adjustSequenceAnnotations();
   }
 
   /**
@@ -1955,6 +2080,7 @@ public abstract class AlignmentViewport
               MessageManager.getString("label.consensus_descr"),
               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
       initConsensus(consensus);
+
       initGapCounts();
 
       initComplementConsensus();
@@ -2161,6 +2287,9 @@ public abstract class AlignmentViewport
     boolean showprf = isShowSequenceLogo();
     boolean showConsHist = isShowConsensusHistogram();
     boolean normLogo = isNormaliseSequenceLogo();
+    boolean showHMMPrf = isShowHMMSequenceLogo();
+    boolean showInfoHist = isShowInformationHistogram();
+    boolean normHMMLogo = isNormaliseHMMSequenceLogo();
 
     /**
      * TODO reorder the annotation rows according to group/sequence ordering on
@@ -2198,6 +2327,9 @@ public abstract class AlignmentViewport
           sg.setshowSequenceLogo(showprf);
           sg.setShowConsensusHistogram(showConsHist);
           sg.setNormaliseSequenceLogo(normLogo);
+          sg.setShowHMMSequenceLogo(showHMMPrf);
+          sg.setShowInformationHistogram(showInfoHist);
+          sg.setNormaliseHMMSequenceLogo(normHMMLogo);
         }
         if (conv)
         {
@@ -2982,6 +3114,19 @@ public abstract class AlignmentViewport
     return sq;
   }
 
+  public boolean hasReferenceAnnotation()
+  {
+    AlignmentAnnotation[] annots = this.alignment.getAlignmentAnnotation();
+    for (AlignmentAnnotation annot : annots)
+    {
+      if ("RF".equals(annot.label) || annot.label.contains("Reference"))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
   @Override
   public void setCurrentTree(TreeModel tree)
   {
@@ -3024,6 +3169,27 @@ public abstract class AlignmentViewport
     return ed;
   }
   
+  @Override
+  public boolean isNormaliseSequenceLogo()
+  {
+    return normaliseSequenceLogo;
+  }
+
+  public void setNormaliseSequenceLogo(boolean state)
+  {
+    normaliseSequenceLogo = state;
+  }
+
+  @Override
+  public boolean isNormaliseHMMSequenceLogo()
+  {
+    return hmmNormaliseSequenceLogo;
+  }
+
+  public void setNormaliseHMMSequenceLogo(boolean state)
+  {
+    hmmNormaliseSequenceLogo = state;
+  }
   /**
    * flag set to indicate if structure views might be out of sync with sequences
    * in the alignment
@@ -3087,7 +3253,47 @@ public abstract class AlignmentViewport
       codingComplement.setUpdateStructures(needToUpdateStructureViews);
     }
   }
-  
+  /**
+   * Filters out sequences with an eValue higher than the specified value. The
+   * filtered sequences are hidden or deleted. Sequences with no eValues are also
+   * filtered out.
+   * 
+   * @param eValue
+   * @param delete
+   */
+  public void filterByEvalue(double eValue)
+  {
+    for (SequenceI seq : alignment.getSequencesArray())
+    {
+      if ((seq.getAnnotation("Search Scores") == null
+              || seq.getAnnotation("Search Scores")[0].getEValue() > eValue)
+              && seq.getHMM() == null)
+      {
+        hideSequence(new SequenceI[] { seq });
+      }
+    }
+  }
+
+  /**
+   * Filters out sequences with an score lower than the specified value. The
+   * filtered sequences are hidden or deleted.
+   * 
+   * @param score
+   * @param delete
+   */
+  public void filterByScore(double score)
+  {
+    for (SequenceI seq : alignment.getSequencesArray())
+    {
+      if ((seq.getAnnotation("Search Scores") == null
+              || seq.getAnnotation("Search Scores")[0]
+                      .getBitScore() < score)
+              && seq.getHMM() == null)
+      {
+        hideSequence(new SequenceI[] { seq });
+      }
+    }
+  }  
 
   /**
    * Notify TreePanel and AlignmentPanel of some sort of alignment change.
@@ -3104,5 +3310,4 @@ public abstract class AlignmentViewport
   {
     changeSupport.firePropertyChange(PROPERTY_SEQUENCE, null, null);
   }
-
 }
index c596f05..ec80576 100644 (file)
@@ -22,10 +22,12 @@ package jalview.workers;
 
 import jalview.api.AlignCalcManagerI;
 import jalview.api.AlignCalcWorkerI;
+import jalview.bin.Cache;
 import jalview.datamodel.AlignmentAnnotation;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.List;
@@ -37,48 +39,49 @@ public class AlignCalcManager implements AlignCalcManagerI
   /*
    * list of registered workers
    */
-  private volatile List<AlignCalcWorkerI> restartable;
+  private final List<AlignCalcWorkerI> restartable = Collections
+          .synchronizedList(new ArrayList<AlignCalcWorkerI>());
 
   /*
    * types of worker _not_ to run (for example, because they have
    * previously thrown errors)
    */
-  private volatile List<Class<? extends AlignCalcWorkerI>> blackList;
+  private final List<Class<? extends AlignCalcWorkerI>> blackList = Collections
+          .synchronizedList(new ArrayList<Class<? extends AlignCalcWorkerI>>());
 
   /*
    * global record of calculations in progress
    */
-  private volatile List<AlignCalcWorkerI> inProgress;
+  private final List<AlignCalcWorkerI> inProgress = Collections
+          .synchronizedList(new ArrayList<AlignCalcWorkerI>());
 
   /*
    * record of calculations pending or in progress in the current context
    */
-  private volatile Map<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>> updating;
+  private final Map<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>> updating =
+          new Hashtable<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>>();
 
   /*
    * workers that have run to completion so are candidates for visual-only 
    * update of their results
    */
-  private HashSet<AlignCalcWorkerI> canUpdate;
+  private HashSet<AlignCalcWorkerI> canUpdate = new HashSet<>();;
 
-  /**
-   * Constructor
-   */
-  public AlignCalcManager()
+  private static boolean listContains(List<AlignCalcWorkerI> upd,
+          AlignCalcWorkerI worker)
   {
-    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>();
+    // avoid use of 'Contains' in case
+    for (AlignCalcWorkerI _otherworker : upd)
+    {
+      if (_otherworker == upd)
+      {
+        return true;
+      }
+    }
+    return false;
   }
-
   @Override
-  public void notifyStart(AlignCalcWorkerI worker)
+  public void notifyStarted(AlignCalcWorkerI worker)
   {
     synchronized (updating)
     {
@@ -90,7 +93,16 @@ public class AlignCalcManager implements AlignCalcManagerI
       }
       synchronized (upd)
       {
-        upd.add(worker);
+        if (listContains(upd, worker))
+        {
+          Cache.log.debug(
+                    "Ignoring second call to notifyStart for worker "
+                            + worker);
+        }
+        else
+        {
+          upd.add(worker);
+        }
       }
     }
   }
@@ -103,22 +115,10 @@ public class AlignCalcManager implements AlignCalcManagerI
   @Override
   public boolean isPending(AlignCalcWorkerI workingClass)
   {
-    List<AlignCalcWorkerI> upd;
     synchronized (updating)
     {
-      upd = updating.get(workingClass.getClass());
-      if (upd == null)
-      {
-        return false;
-      }
-      synchronized (upd)
-      {
-        if (upd.size() > 1)
-        {
-          return true;
-        }
-      }
-      return false;
+      List<AlignCalcWorkerI> upd = updating.get(workingClass.getClass());
+      return upd != null && upd.size() > 1;
     }
   }
 
@@ -127,7 +127,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   {
     synchronized (inProgress)
     {
-      if (inProgress.contains(worker))
+      if (listContains(inProgress, worker))
       {
         return false; // worker is already working, so ask caller to wait around
       }
@@ -144,7 +144,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   {
     synchronized (inProgress)
     {
-      // System.err.println("Worker " + worker + " marked as complete.");
+      Cache.log.debug("Worker " + worker + " marked as complete.");
       inProgress.remove(worker);
       List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
       if (upd != null)
@@ -181,7 +181,15 @@ public class AlignCalcManager implements AlignCalcManagerI
   {
     if (!isDisabled(worker))
     {
-      Thread tw = new Thread(worker);
+      Thread tw = new Thread(() -> {
+        try
+        {
+          worker.run();
+        } catch (Throwable e)
+        {
+          e.printStackTrace();
+        }
+      });
       tw.setName(worker.getClass().toString());
       tw.start();
     }
@@ -216,7 +224,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   {
     synchronized (restartable)
     {
-      if (!restartable.contains(worker))
+      if (!listContains(restartable, worker))
       {
         restartable.add(worker);
       }
@@ -289,7 +297,7 @@ public class AlignCalcManager implements AlignCalcManagerI
   public List<AlignCalcWorkerI> getRegisteredWorkersOfClass(
           Class<? extends AlignCalcWorkerI> workerClass)
   {
-    List<AlignCalcWorkerI> workingClass = new ArrayList<AlignCalcWorkerI>();
+    List<AlignCalcWorkerI> workingClass = new ArrayList<>();
     synchronized (canUpdate)
     {
       for (AlignCalcWorkerI worker : canUpdate)
@@ -313,11 +321,11 @@ public class AlignCalcManager implements AlignCalcManagerI
   }
 
   @Override
-  public void removeRegisteredWorkersOfClass(
+  public void removeWorkersOfClass(
           Class<? extends AlignCalcWorkerI> typeToRemove)
   {
-    List<AlignCalcWorkerI> removable = new ArrayList<AlignCalcWorkerI>();
-    Set<AlignCalcWorkerI> toremovannot = new HashSet<AlignCalcWorkerI>();
+    List<AlignCalcWorkerI> removable = new ArrayList<>();
+    Set<AlignCalcWorkerI> toremovannot = new HashSet<>();
     synchronized (restartable)
     {
       for (AlignCalcWorkerI worker : restartable)
@@ -367,7 +375,7 @@ public class AlignCalcManager implements AlignCalcManagerI
      * first just find those to remove (to avoid
      * ConcurrentModificationException)
      */
-    List<AlignCalcWorkerI> toRemove = new ArrayList<AlignCalcWorkerI>();
+    List<AlignCalcWorkerI> toRemove = new ArrayList<>();
     for (AlignCalcWorkerI worker : restartable)
     {
       if (worker.involves(ann))
diff --git a/src/jalview/workers/AlignCalcManager2.java b/src/jalview/workers/AlignCalcManager2.java
new file mode 100644 (file)
index 0000000..0f9b8e5
--- /dev/null
@@ -0,0 +1,502 @@
+package jalview.workers;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.String.format;
+import static java.util.Collections.synchronizedMap;
+import static java.util.Collections.unmodifiableList;
+
+import java.util.ArrayList;
+
+import jalview.api.AlignCalcListener;
+import jalview.api.AlignCalcManagerI2;
+import jalview.api.AlignCalcWorkerI;
+import jalview.api.PollableAlignCalcWorkerI;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+
+public class AlignCalcManager2 implements AlignCalcManagerI2
+{
+  private abstract class WorkerManager
+  {
+    protected volatile boolean enabled = true;
+            
+    protected final AlignCalcWorkerI worker;
+    
+    WorkerManager(AlignCalcWorkerI worker)
+    {
+      this.worker = worker;
+    }
+    
+    AlignCalcWorkerI getWorker()
+    {
+      return worker;
+    }
+    
+    boolean isEnabled()
+    {
+      return enabled;
+    }
+    
+    void setEnabled(boolean enabled)
+    {
+      this.enabled = enabled;
+    }
+    
+    synchronized void restart()
+    {
+      if (!isEnabled())
+      {
+        return;
+      }
+      if (isWorking())
+      {
+        cancel();
+      }
+      submit();
+    }
+    
+    abstract boolean isWorking();
+    
+    protected abstract void submit();
+    
+    abstract void cancel();  
+  }
+  
+  
+  private class SimpleWorkerManager extends WorkerManager
+  {
+    private Future<?> task = null;
+    
+    SimpleWorkerManager(AlignCalcWorkerI worker)
+    {
+      super(worker);
+    }
+    
+    @Override
+    boolean isWorking()
+    {
+      return task != null && !task.isDone();
+    }
+
+    @Override
+    protected void submit()
+    {
+      if (task != null && !(task.isDone() || task.isCancelled()))
+      {
+        throw new IllegalStateException(
+            "Cannot submit new task if the prevoius one is still running");
+      }
+      Cache.log.debug(format("Worker %s queued",
+              worker.getClass().getName()));
+      task = executor.submit(() -> {
+        try
+        {
+          Cache.log.debug(format("Worker %s started",
+                  worker.getClass().getName()));
+          worker.run();
+          Cache.log.debug(format("Worker %s finished",
+                  worker.getClass().getName()));
+        }
+        catch (InterruptedException e)
+        {
+          Cache.log.debug(format("Worker %s interrupted",
+                  worker.getClass().getName()));
+        }
+        catch (Throwable th)
+        {
+          Cache.log.debug(format("Worker %s failed",
+                  worker.getClass().getName()), th);
+        }
+        finally
+        {
+        }
+      });
+    }
+
+    @Override
+    synchronized void cancel()
+    {
+      if (!isWorking())
+      {
+        return;
+      }
+      Cache.log.debug(format("Cancelling worker %s",
+              worker.getClass().getName()));
+      task.cancel(true);
+    }
+  }
+  
+  
+  private class PollableWorkerManager extends WorkerManager
+  {
+    private final PollableAlignCalcWorkerI worker;
+    private Future<?> task = null;
+    
+    PollableWorkerManager(PollableAlignCalcWorkerI worker)
+    {
+      super(worker);
+      this.worker = worker;
+    }
+    
+    @Override
+    boolean isWorking()
+    {
+      return task != null && !task.isDone();
+    }
+    
+    protected void submit()
+    {
+      if (task != null && !(task.isDone() || task.isCancelled()))
+      {
+        throw new IllegalStateException(
+            "Cannot submit new task if the prevoius one is still running");
+      }
+      Cache.log.debug(format("Worker %s queued",
+              worker.getClass().getName()));
+      final var runnable = new Runnable()
+      {
+        private boolean started = false;
+        private boolean completed = false;
+        Future<?> future = null;
+        
+        @Override
+        public void run()
+        {
+          try
+          {
+            if (!started)
+            {
+              Cache.log.debug(format("Worker %s started",
+                      worker.getClass().getName()));
+              worker.startUp();
+              started = true;
+            }
+            else if (!completed)
+            {
+              Cache.log.debug(format("Polling worker %s",
+                      worker.getClass().getName()));
+              if (worker.poll())
+              {
+                Cache.log.debug(format("Worker %s finished",
+                        worker.getClass().getName()));
+                completed = true;
+              }
+            }
+          } catch (Throwable th)
+          {
+            Cache.log.debug(format("Worker %s failed",
+                    worker.getClass().getName()), th);
+            completed = true;
+          }
+          if (completed)
+          {
+            Cache.log.debug(format("Finalizing completed worker %s",
+                    worker.getClass().getName()));
+            worker.done();
+            // almost impossible, but the future may be null at this point
+            // let it throw NPE to cancel forcefully
+            future.cancel(false);
+          }
+        }
+      };
+      runnable.future = task = executor.scheduleWithFixedDelay(
+              runnable, 10, 1000, TimeUnit.MILLISECONDS);
+    }
+    
+    synchronized protected void cancel()
+    {
+      if (!isWorking())
+      {
+        return;
+      }
+      Cache.log.debug(format("Cancelling worker %s",
+              worker.getClass().getName()));
+      task.cancel(false);
+      executor.submit(() -> {
+        worker.cancel();
+        Cache.log.debug(format("Finalizing cancelled worker %s",
+                worker.getClass().getName()));
+        worker.done();
+      });
+    }
+  }
+  
+  
+  private final ScheduledExecutorService executor =
+          Executors.newSingleThreadScheduledExecutor();
+  private final Map<AlignCalcWorkerI, WorkerManager> registered =
+          synchronizedMap(new HashMap<>());
+  
+  private final List<AlignCalcListener> listeners =
+          new CopyOnWriteArrayList<>();
+  
+  
+  @Override
+  public void registerWorker(AlignCalcWorkerI worker)
+  {
+    Objects.requireNonNull(worker);
+    WorkerManager manager = (worker instanceof PollableAlignCalcWorkerI) ?
+            new PollableWorkerManager((PollableAlignCalcWorkerI) worker) : 
+              new SimpleWorkerManager(worker);
+    registered.putIfAbsent(worker, manager);
+    startWorker(worker);
+  }
+
+  @Override
+  public List<AlignCalcWorkerI> getWorkers()
+  {
+    List<AlignCalcWorkerI> result = new ArrayList<>(registered.size());
+    result.addAll(registered.keySet());
+    return result;
+  }
+
+  @Override
+  public List<AlignCalcWorkerI> getWorkersOfClass(
+          Class<? extends AlignCalcWorkerI> cls)
+  {
+    List<AlignCalcWorkerI> collected = new ArrayList<>();
+    for (var worker : getWorkers())
+    {
+      if (worker.getClass().equals(cls))
+      {
+        collected.add(worker);
+      }
+    }
+    return unmodifiableList(collected);
+  }
+
+  @Override
+  public void removeWorker(AlignCalcWorkerI worker)
+  {
+    registered.remove(worker);
+  }
+
+  @Override
+  public void removeWorkerForAnnotation(AlignmentAnnotation annot)
+  {
+    synchronized (registered)
+    {
+      for (var worker : getWorkers())
+      {
+        if (worker.involves(annot) && worker.isDeletable())
+        {
+          removeWorker(worker);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void removeWorkersOfClass(Class<? extends AlignCalcWorkerI> cls)
+  {
+    synchronized (registered)
+    {
+      for (var worker : getWorkers())
+      {
+        if (worker.getClass().equals(cls))
+        {
+          removeWorker(worker);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void disableWorker(AlignCalcWorkerI worker)
+  {
+    // Null pointer check might be needed
+    registered.get(worker).setEnabled(false);
+  }
+
+  @Override
+  public void enableWorker(AlignCalcWorkerI worker)
+  {
+    // Null pointer check might be needed
+    registered.get(worker).setEnabled(true);
+  }
+
+  @Override
+  public boolean isDisabled(AlignCalcWorkerI worker)
+  {
+    if (registered.containsKey(worker))
+    {
+      return !registered.get(worker).isEnabled();
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  @Override
+  public boolean isWorking(AlignCalcWorkerI worker)
+  {
+    if (!registered.containsKey(worker))
+    {
+      return false;
+    }
+    else
+    {
+      return registered.get(worker).isWorking();
+    }
+  }
+
+  @Override
+  public boolean isWorkingWithAnnotation(AlignmentAnnotation annot)
+  {
+    synchronized (registered)
+    {
+      for (var entry : registered.entrySet())
+      {
+        if (entry.getKey().involves(annot) &&
+                entry.getValue().isWorking())
+        {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public boolean isWorking()
+  {
+    synchronized (registered)
+    {
+      for (var manager : registered.values())
+      {
+        if (manager.isWorking())
+        {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public void startWorker(AlignCalcWorkerI worker)
+  {
+    Objects.requireNonNull(worker);
+    var manager = registered.get(worker);
+    if (manager == null) 
+    {
+      throw new NoSuchElementException();
+    }
+    manager.restart();
+  }
+
+  @Override
+  public void restartWorkers()
+  {
+    synchronized (registered)
+    {
+      for (var manager : registered.values())
+      {
+        manager.restart();
+      }
+    }
+  }
+
+  @Override
+  public void cancelWorker(AlignCalcWorkerI worker)
+  {    
+    Objects.requireNonNull(worker);
+    var manager = registered.get(worker);
+    if (manager == null) 
+    {
+      throw new NoSuchElementException();
+    }
+    manager.cancel();
+  }
+  
+  private void notifyQueued(AlignCalcWorkerI worker)
+  {
+    for (AlignCalcListener listener : listeners)
+    {
+      listener.workerQueued(worker);
+    }
+  }
+
+  private void notifyStarted(AlignCalcWorkerI worker)
+  {
+    for (AlignCalcListener listener : listeners)
+    {
+      listener.workerStarted(worker);
+    }
+  }
+
+  private void notifyCompleted(AlignCalcWorkerI worker)
+  {
+    for (AlignCalcListener listener : listeners)
+    {
+      try
+      {
+        listener.workerCompleted(worker);
+      } catch (RuntimeException e)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void notifyCancelled(AlignCalcWorkerI worker)
+  {
+    for (AlignCalcListener listener : listeners)
+    {
+      try
+      {
+        listener.workerCancelled(worker);
+      } catch (RuntimeException e)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void notifyExceptional(AlignCalcWorkerI worker,
+          Throwable throwable)
+  {
+    for (AlignCalcListener listener : listeners)
+    {
+      try
+      {
+        listener.workerExceptional(worker, throwable);
+      } catch (RuntimeException e)
+      {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  @Override
+  public void addAlignCalcListener(AlignCalcListener listener)
+  {
+    listeners.add(listener);
+  }
+
+  @Override
+  public void removeAlignCalcListener(AlignCalcListener listener)
+  {
+    listeners.remove(listener);
+  }
+
+  @Override
+  public void shutdown()
+  {
+    executor.shutdownNow();
+    listeners.clear();
+    registered.clear();
+  }
+
+}
index 0ad8726..c94032f 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.workers;
 
 import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcManagerI2;
 import jalview.api.AlignCalcWorkerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
@@ -43,7 +44,7 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
    */
   protected AlignViewportI alignViewport;
 
-  protected AlignCalcManagerI calcMan;
+  protected AlignCalcManagerI2 calcMan;
 
   protected AlignmentViewPanel ap;
 
@@ -61,7 +62,8 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
   {
     if (calcMan != null)
     {
-      calcMan.workerComplete(this);
+      calcMan.cancelWorker(this);
+      calcMan.removeWorker(this);
     }
     alignViewport = null;
     calcMan = null;
@@ -136,4 +138,8 @@ public abstract class AlignCalcWorker implements AlignCalcWorkerI
     }
   }
 
+  public AlignViewportI getAlignViewport()
+  {
+    return alignViewport;
+  }
 }
index 8f37f15..98e26b3 100644 (file)
@@ -59,63 +59,41 @@ class AnnotationWorker extends AlignCalcWorker
   @Override
   public void run()
   {
-    try
+    if (alignViewport.isClosed())
     {
-      calcMan.notifyStart(this);
-
-      while (!calcMan.notifyWorking(this))
-      {
-        try
-        {
-          Thread.sleep(200);
-        } catch (InterruptedException ex)
-        {
-          ex.printStackTrace();
-        }
-      }
-      if (alignViewport.isClosed())
-      {
-        abortAndDestroy();
-        return;
-      }
+      abortAndDestroy();
+      return;
+    }
 
-      // removeAnnotation();
+    // removeAnnotation();
       AlignmentI alignment = alignViewport.getAlignment();
-      if (alignment != null)
+    if (alignment != null)
+    {
+      try
       {
-        try
+        List<AlignmentAnnotation> anns = counter.calculateAnnotation(
+                alignment, new FeatureRenderer(alignViewport));
+        for (AlignmentAnnotation ann : anns)
         {
-          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))
           {
-            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);
+            ourAnnots.add(theAnn);
           }
-        } catch (IndexOutOfBoundsException x)
-        {
-          // probable race condition. just finish and return without any fuss.
-          return;
+          // 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)
index 74695fe..a711f2b 100644 (file)
@@ -70,44 +70,22 @@ class ColumnCounterSetWorker extends AlignCalcWorker
   public void run()
   {
     boolean annotationAdded = false;
-    try
+    if (alignViewport.isClosed())
     {
-      calcMan.notifyStart(this);
+      abortAndDestroy();
+      return;
+    }
 
-      while (!calcMan.notifyWorking(this))
+    if (alignViewport.getAlignment() != null)
+    {
+      try
       {
-        try
-        {
-          Thread.sleep(200);
-        } catch (InterruptedException ex)
-        {
-          ex.printStackTrace();
-        }
-      }
-      if (alignViewport.isClosed())
+        annotationAdded = computeAnnotations();
+      } catch (IndexOutOfBoundsException x)
       {
-        abortAndDestroy();
+        // probable race condition. just finish and return without any fuss.
         return;
       }
-
-      if (alignViewport.getAlignment() != null)
-      {
-        try
-        {
-          annotationAdded = 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)
index 1a5aaa4..b97c4c5 100644 (file)
@@ -41,71 +41,33 @@ public class ConsensusThread extends AlignCalcWorker
   @Override
   public void run()
   {
-    if (calcMan.isPending(this))
+    AlignmentAnnotation consensus = getConsensusAnnotation();
+    AlignmentAnnotation gap = getGapAnnotation();
+    if ((consensus == null && gap == null))
     {
       return;
     }
-    calcMan.notifyStart(this);
-    // long started = System.currentTimeMillis();
-    try
+    if (alignViewport.isClosed())
     {
-      AlignmentAnnotation consensus = getConsensusAnnotation();
-      AlignmentAnnotation gap = getGapAnnotation();
-      if ((consensus == null && gap == null) || calcMan.isPending(this))
-      {
-        calcMan.workerComplete(this);
-        return;
-      }
-      while (!calcMan.notifyWorking(this))
-      {
-        // System.err.println("Thread
-        // (Consensus"+Thread.currentThread().getName()+") Waiting around.");
-        try
-        {
-          if (ap != null)
-          {
-            ap.paintAlignment(false, false);
-          }
-          Thread.sleep(200);
-        } catch (Exception ex)
-        {
-          ex.printStackTrace();
-        }
-      }
-      if (alignViewport.isClosed())
-      {
-        abortAndDestroy();
-        return;
-      }
-      AlignmentI alignment = alignViewport.getAlignment();
+      abortAndDestroy();
+      return;
+    }
+    AlignmentI alignment = alignViewport.getAlignment();
 
-      int aWidth = -1;
+    int aWidth = -1;
 
-      if (alignment == null || (aWidth = alignment.getWidth()) < 0)
-      {
-        calcMan.workerComplete(this);
-        return;
-      }
+    if (alignment == null || (aWidth = alignment.getWidth()) < 0)
+    {
+      return;
+    }
 
-      eraseConsensus(aWidth);
-      computeConsensus(alignment);
-      updateResultAnnotation(true);
+    eraseConsensus(aWidth);
+    computeConsensus(alignment);
+    updateResultAnnotation(true);
 
-      if (ap != null)
-      {
-        ap.paintAlignment(true, true);
-      }
-    } catch (OutOfMemoryError error)
+    if (ap != null)
     {
-      calcMan.disableWorker(this);
-      ap.raiseOOMWarning("calculating consensus", error);
-    } finally
-    {
-      /*
-       * e.g. ArrayIndexOutOfBoundsException can happen due to a race condition
-       * - alignment was edited at same time as calculation was running
-       */
-      calcMan.workerComplete(this);
+      ap.paintAlignment(true, true);
     }
   }
 
@@ -222,7 +184,6 @@ public class ConsensusThread extends AlignCalcWorker
   protected void deriveConsensus(AlignmentAnnotation consensusAnnotation,
           ProfilesI hconsensus)
   {
-
     long nseq = getSequences().length;
     AAFrequency.completeConsensus(consensusAnnotation, hconsensus,
             hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1,
index 54b0191..3752841 100644 (file)
@@ -51,69 +51,39 @@ public class ConservationThread extends AlignCalcWorker
   @Override
   public void run()
   {
-    try
+    if ((alignViewport == null) || (calcMan == null)
+            || (alignViewport.isClosed()))
     {
-      calcMan.notifyStart(this); // updatingConservation = true;
-
-      while ((calcMan != null) && (!calcMan.notifyWorking(this)))
-      {
-        try
-        {
-          if (ap != null)
-          {
-            // ap.paintAlignment(false);
-          }
-          Thread.sleep(200);
-        } catch (Exception ex)
-        {
-          ex.printStackTrace();
-        }
-      }
-      if ((alignViewport == null) || (calcMan == null)
-              || (alignViewport.isClosed()))
-      {
-        abortAndDestroy();
-        return;
-      }
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
-      AlignmentI alignment = alignViewport.getAlignment();
-      conservation = alignViewport.getAlignmentConservationAnnotation();
-      quality = alignViewport.getAlignmentQualityAnnot();
-      ourAnnot.add(conservation);
-      ourAnnot.add(quality);
-      ourAnnots = ourAnnot;
-      ConsPercGaps = alignViewport.getConsPercGaps();
-      // AlignViewport.UPDATING_CONSERVATION = true;
-
-      if (alignment == null || (alWidth = alignment.getWidth()) < 0)
-      {
-        calcMan.workerComplete(this);
-        // .updatingConservation = false;
-        // AlignViewport.UPDATING_CONSERVATION = false;
+      abortAndDestroy();
+      return;
+    }
+    List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
+    AlignmentI alignment = alignViewport.getAlignment();
+    conservation = alignViewport.getAlignmentConservationAnnotation();
+    quality = alignViewport.getAlignmentQualityAnnot();
+    ourAnnot.add(conservation);
+    ourAnnot.add(quality);
+    ourAnnots = ourAnnot;
+    ConsPercGaps = alignViewport.getConsPercGaps();
+    // AlignViewport.UPDATING_CONSERVATION = true;
 
-        return;
-      }
-      try
-      {
-        cons = Conservation.calculateConservation("All",
-                alignment.getSequences(), 0, alWidth - 1, false,
-                ConsPercGaps, quality != null);
-      } catch (IndexOutOfBoundsException x)
-      {
-        // probable race condition. just finish and return without any fuss.
-        calcMan.workerComplete(this);
-        return;
-      }
-      updateResultAnnotation(true);
-    } catch (OutOfMemoryError error)
+    if (alignment == null || (alWidth = alignment.getWidth()) < 0)
     {
-      ap.raiseOOMWarning("calculating conservation", error);
-      calcMan.disableWorker(this);
-      // alignViewport.conservation = null;
-      // this.alignViewport.quality = null;
-
+      // .updatingConservation = false;
+      // AlignViewport.UPDATING_CONSERVATION = false;
+      return;
+    }
+    try
+    {
+      cons = Conservation.calculateConservation("All",
+              alignment.getSequences(), 0, alWidth - 1, false,
+              ConsPercGaps, quality != null);
+    } catch (IndexOutOfBoundsException x)
+    {
+      // probable race condition. just finish and return without any fuss.
+      return;
     }
-    calcMan.workerComplete(this);
+    updateResultAnnotation(true);
 
     if ((alignViewport == null) || (calcMan == null)
             || (alignViewport.isClosed()))
diff --git a/src/jalview/workers/InformationThread.java b/src/jalview/workers/InformationThread.java
new file mode 100644 (file)
index 0000000..c8084b9
--- /dev/null
@@ -0,0 +1,284 @@
+package jalview.workers;
+
+import jalview.analysis.AAFrequency;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.ProfilesI;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class calculates HMM Information Content annotations, based on any HMM
+ * consensus sequences and their HMM models. HMM consensus sequences may be
+ * present for the whole alignment, or subgroups of it.
+ *
+ */
+public class InformationThread extends AlignCalcWorker
+{
+  public static final String HMM_CALC_ID = "HMM";
+
+  /**
+   * Constructor
+   * 
+   * @param alignViewport
+   * @param alignPanel
+   */
+  public InformationThread(AlignViewportI alignViewport,
+          AlignmentViewPanel alignPanel)
+  {
+    super(alignViewport, alignPanel);
+  }
+
+  /**
+   * Recomputes Information annotations for any HMM consensus sequences (for
+   * alignment and/or groups)
+   */
+  @Override
+  public void run()
+  {
+    if (alignViewport.getAlignment().getHmmSequences().isEmpty())
+    {
+      return;
+    }
+    if (alignViewport.isClosed())
+    {
+      abortAndDestroy();
+      return;
+    }
+
+    AlignmentI alignment = alignViewport.getAlignment();
+    int aWidth = alignment == null ? -1 : alignment.getWidth();
+    if (aWidth < 0)
+    {
+      return;
+    }
+
+    /*
+     * compute information profiles for any HMM consensus sequences
+     * for the alignment or sub-groups
+     */
+    computeProfiles(alignment);
+
+    /*
+     * construct the corresponding annotations
+     */
+    updateAnnotation();
+
+    if (ap != null)
+    {
+      ap.adjustAnnotationHeight();
+      ap.paintAlignment(true, true);
+    }
+  }
+
+  /**
+   * Computes HMM profiles for any HMM consensus sequences (for alignment or
+   * subgroups). Any alignment profile computed is stored on the viewport, any
+   * group profile computed is stored on the respective sequence group.
+   * 
+   * @param alignment
+   * @see AlignViewportI#setHmmProfiles(ProfilesI)
+   */
+  protected void computeProfiles(AlignmentI alignment)
+  {
+    int width = alignment.getWidth();
+
+    /*
+     * alignment HMM profile
+     */
+    List<SequenceI> seqs = alignment.getHmmSequences();
+    if (!seqs.isEmpty())
+    {
+      HiddenMarkovModel hmm = seqs.get(0).getHMM();
+      ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
+              0, width, alignViewport.isIgnoreBelowBackground(),
+              alignViewport.isInfoLetterHeight());
+      alignViewport.setHmmProfiles(hmmProfiles);
+    }
+
+    /*
+     * group HMM profiles
+     */
+    List<SequenceGroup> groups = alignment.getGroups();
+    for (SequenceGroup group : groups)
+    {
+      seqs = group.getHmmSequences();
+      if (!seqs.isEmpty())
+      {
+        HiddenMarkovModel hmm = seqs.get(0).getHMM();
+        ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width,
+                0, width, group.isIgnoreBelowBackground(),
+                group.isUseInfoLetterHeight());
+        group.setHmmProfiles(hmmProfiles);
+      }
+    }
+  }
+
+  /**
+   * gets the sequences on the alignment on the viewport.
+   * 
+   * @return
+   */
+  protected SequenceI[] getSequences()
+  {
+    return alignViewport.getAlignment().getSequencesArray();
+  }
+
+  /**
+   * Get the Gap annotation for the alignment
+   * 
+   * @return
+   */
+  protected AlignmentAnnotation getGapAnnotation()
+  {
+               return alignViewport.getAlignmentGapAnnotation();
+  }
+
+  /**
+   * Computes Information Content annotation for any HMM consensus sequences
+   * (for alignment or groups), and updates (or adds) the annotation to the
+   * sequence and the alignment
+   */
+  @Override
+  public void updateAnnotation()
+  {
+    AlignmentI alignment = alignViewport.getAlignment();
+
+    float maxInformation = 0f;
+    List<AlignmentAnnotation> infos = new ArrayList<>();
+
+    /*
+     * annotation for alignment HMM consensus if present
+     */
+    List<SequenceI> hmmSeqs = alignment.getHmmSequences();
+    if (!hmmSeqs.isEmpty())
+    {
+      ProfilesI profile = alignViewport.getHmmProfiles();
+      float m = updateInformationAnnotation(hmmSeqs.get(0), profile, null,
+              infos);
+      maxInformation = Math.max(maxInformation, m);
+    }
+
+    /*
+     * annotation for group HMM consensus if present
+     */
+    for (SequenceGroup group : alignment.getGroups())
+    {
+      hmmSeqs = group.getHmmSequences();
+      if (!hmmSeqs.isEmpty())
+      {
+        ProfilesI profiles = group.getHmmProfiles();
+        float m = updateInformationAnnotation(hmmSeqs.get(0), profiles,
+                group, infos);
+        maxInformation = Math.max(maxInformation, m);
+      }
+    }
+
+    /*
+     * maxInformation holds the maximum value of information score;
+     * set this as graphMax in all annotations to scale them all the same
+     */
+    for (AlignmentAnnotation ann : infos)
+    {
+      ann.graphMax = maxInformation;
+    }
+  }
+
+  /**
+   * Updates (and first constructs if necessary) an HMM Profile information
+   * content annotation for a sequence. The <code>group</code> argument is null
+   * for the whole alignment annotation, not null for a subgroup annotation. The
+   * updated annotation is added to the <code>infos</code> list. Answers the
+   * maximum information content value of any annotation (for use as a scaling
+   * factor for display).
+   * 
+   * @param seq
+   * @param profile
+   * @param group
+   * @param infos
+   * @return
+   */
+  protected float updateInformationAnnotation(SequenceI seq,
+          ProfilesI profile, SequenceGroup group,
+          List<AlignmentAnnotation> infos)
+  {
+    if (seq == null || profile == null)
+    {
+      return 0f;
+    }
+
+    AlignmentAnnotation ann = findOrCreateAnnotation(seq, group);
+
+    seq.addAlignmentAnnotation(ann);
+    infos.add(ann);
+
+    float max = AAFrequency.completeInformation(ann, profile,
+            profile.getStartColumn(), profile.getEndColumn() + 1);
+
+    return max;
+  }
+
+  /**
+   * A helper method that first searches for the HMM annotation that matches the
+   * group reference (null for the whole alignment annotation). If found, its
+   * sequence reference is updated to the given sequence (the recomputed HMM
+   * consensus sequence). If not found, it is created. This supports both
+   * creating the annotation the first time hmmbuild is run, and updating it if
+   * hmmbuild is re-run.
+   * 
+   * @param seq
+   * @param group
+   * @return
+   */
+  AlignmentAnnotation findOrCreateAnnotation(SequenceI seq,
+          SequenceGroup group)
+  {
+    /*
+     * can't use Alignment.findOrCreateAnnotation here because we 
+     * want to update, rather than match on, the sequence ref
+     */
+    AlignmentAnnotation info = null;
+
+    AlignmentI alignment = alignViewport.getAlignment();
+    AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
+    if (anns != null)
+    {
+      for (AlignmentAnnotation ann : anns)
+      {
+        if (HMM_CALC_ID.equals(ann.getCalcId()) && group == ann.groupRef)
+        {
+          info = ann;
+          info.setSequenceRef(seq);
+          info.label = seq.getName(); // in case group name changed!
+          break;
+        }
+      }
+    }
+
+    if (info == null)
+    {
+      int aWidth = alignment.getWidth();
+      String desc = MessageManager
+              .getString("label.information_description");
+      float graphMax = 6.52f; // todo where does this value derive from?
+      info = new AlignmentAnnotation(seq.getName(), desc,
+              new Annotation[aWidth], 0f, graphMax,
+              AlignmentAnnotation.BAR_GRAPH);
+      info.setCalcId(HMM_CALC_ID);
+      info.setSequenceRef(seq);
+      info.groupRef = group;
+      info.hasText = true;
+      alignment.addAnnotation(info);
+    }
+
+    return info;
+  }
+}
index 61ec3d0..3cb6114 100644 (file)
@@ -47,28 +47,6 @@ public class StrucConsensusThread extends AlignCalcWorker
   @Override
   public void run()
   {
-    try
-    {
-      if (calcMan.isPending(this))
-      {
-        return;
-      }
-      calcMan.notifyStart(this);
-      while (!calcMan.notifyWorking(this))
-      {
-        try
-        {
-          if (ap != null)
-          {
-            // ap.paintAlignment(false);
-          }
-
-          Thread.sleep(200);
-        } catch (Exception ex)
-        {
-          ex.printStackTrace();
-        }
-      }
       if (alignViewport.isClosed())
       {
         abortAndDestroy();
@@ -80,7 +58,6 @@ public class StrucConsensusThread extends AlignCalcWorker
 
       if (alignment == null || (aWidth = alignment.getWidth()) < 0)
       {
-        calcMan.workerComplete(this);
         return;
       }
       strucConsensus = alignViewport.getAlignmentStrucConsensusAnnotation();
@@ -109,7 +86,6 @@ public class StrucConsensusThread extends AlignCalcWorker
 
       if (rnaStruc == null || !rnaStruc.isValidStruc())
       {
-        calcMan.workerComplete(this);
         return;
       }
 
@@ -121,27 +97,11 @@ public class StrucConsensusThread extends AlignCalcWorker
                 alignment.getWidth(), hStrucConsensus, true, rnaStruc);
       } catch (ArrayIndexOutOfBoundsException x)
       {
-        calcMan.workerComplete(this);
         return;
       }
       alignViewport.setRnaStructureConsensusHash(hStrucConsensus);
       // TODO AlignmentAnnotation rnaStruc!!!
       updateResultAnnotation(true);
-    } catch (OutOfMemoryError error)
-    {
-      calcMan.disableWorker(this);
-
-      // consensus = null;
-      // hconsensus = null;
-      ap.raiseOOMWarning("calculating RNA structure consensus", error);
-    } finally
-    {
-      calcMan.workerComplete(this);
-      if (ap != null)
-      {
-        ap.paintAlignment(true, true);
-      }
-    }
 
   }
 
index 80918f9..096f4ee 100644 (file)
@@ -33,9 +33,15 @@ import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
 
-public abstract class AWSThread extends Thread
+import static java.lang.String.format;
+
+public abstract class AWSThread
 {
+  
+  private final Timer timer = new Timer();
 
   /**
    * view that this job was associated with
@@ -64,13 +70,15 @@ public abstract class AWSThread extends Thread
 
   /**
    * are there jobs still running in this thread.
+   *
+   * fixme: initialize with an empty array?
    */
   protected boolean jobComplete = false;
 
   /**
    * one or more jobs being managed by this thread.
    */
-  protected AWsJob jobs[] = null;
+  protected AWsJob[] jobs = null;
 
   /**
    * full name of service
@@ -95,115 +103,91 @@ public abstract class AWSThread extends Thread
    */
   private AlignFrame alignFrame;
 
-  /**
-   * generic web service job/subjob poll loop
-   */
-  @Override
-  public void run()
+  public void start()
   {
-    JobStateSummary jstate = null;
     if (jobs == null)
     {
       jobComplete = true;
+      Cache.log.debug(
+          "WebServiceJob poll loop finished with no jobs created.");
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+      wsInfo.appendProgressText(
+          MessageManager.getString("info.no_jobs_ran"));
+      wsInfo.setFinishedNoResults();
+      return;
     }
-    while (!jobComplete)
-    {
-      jstate = new JobStateSummary();
-      for (int j = 0; j < jobs.length; j++)
+    TimerTask task = new TimerTask() {
+      @Override
+      public void run() 
       {
-
-        if (!jobs[j].submitted && jobs[j].hasValidInput())
+        JobStateSummary jstate = new JobStateSummary();
+        for (final AWsJob job : jobs)
         {
-          StartJob(jobs[j]);
-        }
-
-        if (jobs[j].submitted && !jobs[j].subjobComplete)
-        {
-          try
+          if (!job.submitted && job.hasValidInput())
           {
-            pollJob(jobs[j]);
-            if (!jobs[j].hasResponse())
-            {
-              throw (new Exception(
-                      "Timed out when communicating with server\nTry again later.\n"));
-            }
-            jalview.bin.Cache.log.debug("Job " + j + " Result state "
-                    + jobs[j].getState() + "(ServerError="
-                    + jobs[j].isServerError() + ")");
-          } catch (Exception ex)
+            StartJob(job);
+          }
+          Cache.log.debug(format(
+                  "Job %s is %ssubmitted", job, job.submitted ? "" : "not "));
+          if (job.submitted && !job.subjobComplete)
           {
-            // Deal with Transaction exceptions
-            wsInfo.appendProgressText(jobs[j].jobnum, MessageManager
-                    .formatMessage("info.server_exception", new Object[]
-                    { WebServiceName, ex.getMessage() }));
-            // always output the exception's stack trace to the log
-            Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
-                    + ") Server exception.");
-            // todo: could limit trace to cause if this is a SOAPFaultException.
-            ex.printStackTrace();
-
-            if (jobs[j].allowedServerExceptions > 0)
+            Cache.log.debug(format(
+                    "Polling Job %s Result state was:%s(ServerError=%b)",
+                    job, job.getState(), job.isServerError()));
+            try
             {
-              jobs[j].allowedServerExceptions--;
-              Cache.log.debug("Sleeping after a server exception.");
-              try
+              pollJob(job);
+              if (!job.hasResponse())
+                throw new Exception("Timed out when communicating with server. Try again later.");
+              else
+                Cache.log.debug(format("Job %s Result state:%s(ServerError=%b)",
+                        job, job.getState(), job.isServerError()));
+            } catch (Exception exc)
+            {
+              // Deal with Transaction exceptions
+              wsInfo.appendProgressText(job.jobnum, MessageManager
+                      .formatMessage("info.server_exception", WebServiceName,
+                          exc.getMessage()));
+              // always output the exception's stack trace to the log
+              Cache.log.warn(format("%s job(%s) Server exception.",
+                      WebServiceName, job.jobnum));
+              exc.printStackTrace();
+              
+              if (job.allowedServerExceptions > 0)
               {
-                Thread.sleep(5000);
-              } catch (InterruptedException ex1)
+                job.allowedServerExceptions--;
+              }
+              else
               {
+                Cache.log.warn(format("Dropping job %s %s", job, job.jobId));
+                job.subjobComplete = true;
+                wsInfo.setStatus(job.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
               }
-            }
-            else
+            } catch (OutOfMemoryError oomerror)
             {
-              Cache.log.warn("Dropping job " + j + " " + jobs[j].jobId);
-              jobs[j].subjobComplete = true;
-              wsInfo.setStatus(jobs[j].jobnum,
-                      WebserviceInfo.STATE_STOPPED_SERVERERROR);
+              jobComplete = true;
+              job.subjobComplete = true;
+              job.clearResponse();
+              wsInfo.setStatus(job.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+              Cache.log.error(format("Out of memory when retrieving Job %s id:%s/%s",
+                      job, WsUrl, job.jobId), oomerror);
+              new jalview.gui.OOMWarning("retrieving result for " + WebServiceName, oomerror);
+              System.gc();
             }
-          } catch (OutOfMemoryError er)
-          {
-            jobComplete = true;
-            jobs[j].subjobComplete = true;
-            jobs[j].clearResponse(); // may contain out of date result data
-            wsInfo.setStatus(jobs[j].jobnum,
-                    WebserviceInfo.STATE_STOPPED_ERROR);
-            Cache.log.error("Out of memory when retrieving Job " + j
-                    + " id:" + WsUrl + "/" + jobs[j].jobId, er);
-            new jalview.gui.OOMWarning(
-                    "retrieving result for " + WebServiceName, er);
-            System.gc();
           }
+          jstate.updateJobPanelState(wsInfo, OutputHeader, job);
         }
-        jstate.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
-      }
-      // Decide on overall state based on collected jobs[] states
-      updateGlobalStatus(jstate);
-      if (!jobComplete)
-      {
-        try
-        {
-          Thread.sleep(5000);
-        } catch (InterruptedException e)
+        // Decide on overall state based on collected jobs[] states
+        updateGlobalStatus(jstate);
+        if (jobComplete)
         {
-          Cache.log.debug("Interrupted sleep waiting for next job poll.",
-                  e);
+          // jobs should never be null at this point
+          parseResult(); // tidy up and make results available to user
+          timer.cancel();
         }
-        // System.out.println("I'm alive "+alTitle);
       }
-    }
-    if (jobComplete && jobs != null)
-    {
-      parseResult(); // tidy up and make results available to user
-    }
-    else
-    {
-      Cache.log.debug(
-              "WebServiceJob poll loop finished with no jobs created.");
-      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
-      wsInfo.appendProgressText(
-              MessageManager.getString("info.no_jobs_ran"));
-      wsInfo.setFinishedNoResults();
-    }
+    };
+    timer.schedule(task, 0, 5000);
   }
 
   protected void updateGlobalStatus(JobStateSummary jstate)
@@ -233,40 +217,10 @@ public abstract class AWSThread extends Thread
       }
     }
   }
-
-  public AWSThread()
-  {
-    super();
-  }
-
-  public AWSThread(Runnable target)
-  {
-    super(target);
-  }
-
-  public AWSThread(String name)
-  {
-    super(name);
-  }
-
-  public AWSThread(ThreadGroup group, Runnable target)
-  {
-    super(group, target);
-  }
-
-  public AWSThread(ThreadGroup group, String name)
-  {
-    super(group, name);
-  }
-
-  public AWSThread(Runnable target, String name)
-  {
-    super(target, name);
-  }
-
-  public AWSThread(ThreadGroup group, Runnable target, String name)
+  
+  public void interrupt()
   {
-    super(group, target, name);
+    timer.cancel();
   }
 
   /**
@@ -319,12 +273,6 @@ public abstract class AWSThread extends Thread
     }
   }
 
-  public AWSThread(ThreadGroup group, Runnable target, String name,
-          long stackSize)
-  {
-    super(group, target, name, stackSize);
-  }
-
   /**
    * 
    * @return gap character to use for any alignment generation
@@ -338,7 +286,7 @@ public abstract class AWSThread extends Thread
    * 
    * @param alignFrame
    *          reference for copying mappings across
-   * @param wsInfo
+   * @param wsinfo
    *          gui attachment point
    * @param input
    *          input data for the calculation
@@ -383,7 +331,7 @@ public abstract class AWSThread extends Thread
               .getCodonFrames();
       if (cf != null)
       {
-        codonframe = new ArrayList<AlignedCodonFrame>();
+        codonframe = new ArrayList<>();
         codonframe.addAll(cf);
       }
     }
index f5f9377..4a9cb74 100644 (file)
  */
 package jalview.ws;
 
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Generic properties for an individual job within a Web Service Client thread.
  * Derived from jalview web services version 1 statuses, and revised for Jws2.
@@ -145,6 +152,12 @@ public abstract class AWsJob
    */
   protected boolean subjobComplete = false;
 
+  protected WsParamSetI preset = null;
+
+  protected List<ArgumentI> arguments = null;
+
+  protected Hashtable<String, Map> SeqNames = new Hashtable();
+
   public AWsJob()
   {
   }
@@ -227,4 +240,47 @@ public abstract class AWsJob
     String state = "";
     return state;
   }
+
+  public void setPreset(WsParamSetI jobpreset)
+  {
+    preset = jobpreset;
+  }
+
+  public void setArguments(List<ArgumentI> paramset)
+  {
+    arguments = paramset;
+
+  }
+
+  public boolean isPresetJob()
+  {
+    return preset!=null && arguments==null; 
+  }
+
+  public List<ArgumentI> getArguments()
+  {
+    return arguments;
+  }
+
+  public WsParamSetI getPreset()
+  {
+    return preset;
+  }
+
+  long nextChunk = 0;
+
+  /**
+   * update the record of the last position in the log file read for this job
+   * 
+   * @param nextChunk
+   */
+  public void setnextChunk(long nextChunk)
+  {
+    this.nextChunk = nextChunk;
+  }
+
+  public long getNextChunk()
+  {
+    return nextChunk;
+  }
 }
index 6b86775..478472b 100644 (file)
@@ -26,6 +26,9 @@ import jalview.gui.WebserviceInfo;
  * bookkeeper class for the WebServiceInfo GUI, maintaining records of web
  * service jobs handled by the window and reflecting any status updates.
  * 
+ * TODO: separate from the GUI cleanly since it also holds logic for
+ * interpreting failure states
+ * 
  * @author JimP
  * 
  */
diff --git a/src/jalview/ws/ServiceChangeListener.java b/src/jalview/ws/ServiceChangeListener.java
new file mode 100644 (file)
index 0000000..98e15b9
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.ws;
+
+import java.util.Collection;
+import java.util.EventListener;
+
+import jalview.ws.api.ServiceWithParameters;
+
+@FunctionalInterface
+public interface ServiceChangeListener extends EventListener
+{
+  public void servicesChanged(WSDiscovererI discoverer,
+          Collection<? extends ServiceWithParameters> services);
+}
index 0f5cee8..33aea90 100755 (executable)
  */
 package jalview.ws;
 
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
 import jalview.gui.WebserviceInfo;
+import jalview.gui.WsJobParameters;
+import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.api.UIinfo;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
 
 public abstract class WSClient // implements WSMenuEntryProviderI
 {
@@ -56,6 +67,11 @@ public abstract class WSClient // implements WSMenuEntryProviderI
   protected WebserviceInfo wsInfo;
 
   /**
+   * the root object for the service client
+   */
+  protected UIinfo serviceHandle;
+
+  /**
    * total number of jobs managed by this web service client instance.
    */
   int jobsRunning = 0;
@@ -65,13 +81,119 @@ public abstract class WSClient // implements WSMenuEntryProviderI
    * mappings between abstract interface names and menu entries
    */
   protected java.util.Hashtable ServiceActions;
+
+  /**
+   * alignFrame associated with this client
+   */
+  protected AlignFrame alignFrame;
   {
     ServiceActions = new java.util.Hashtable();
     ServiceActions.put("MsaWS", "Multiple Sequence Alignment");
     ServiceActions.put("SecStrPred", "Secondary Structure Prediction");
   };
 
+  /**
+   * The preset for the job executed by this client (may be null)
+   */
+  protected WsParamSetI preset;
+
+  /**
+   * The parameters for the job executed by this client (may be null)
+   */
+  protected List<ArgumentI> paramset;
+
   public WSClient()
   {
   }
+
+  /**
+   * base constructor for a web service with parameters. Extending classes
+   * should implement this constructor with additional logic to verify that
+   * preset and arguments are compatible with the service being configured.
+   * 
+   * @param _alignFrame
+   * @param preset
+   * @param arguments
+   */
+  public WSClient(AlignFrame _alignFrame, WsParamSetI preset,
+          List<ArgumentI> arguments)
+  {
+    alignFrame = _alignFrame;
+    this.preset = preset;
+    this.paramset = arguments;
+  }
+
+  protected WebserviceInfo setWebService(UIinfo serv, boolean b)
+  {
+    WebServiceName = serv.getName();
+    WebServiceJobTitle = serv.getActionText();
+    WsURL = serv.getHostURL();
+    if (!b)
+    {
+      return new WebserviceInfo(WebServiceJobTitle,
+              WebServiceJobTitle + " using service hosted at "
+                      + WsURL + "\n"
+                      + (serv.getDescription() != null
+                              ? serv.getDescription()
+                              : ""),
+              false);
+    }
+    return null;
+  }
+
+  /**
+   * called to open a parameter editing dialog for parameterised services
+   * 
+   * @param sh
+   * @param editParams
+   * @return
+   */
+  protected boolean processParams(ServiceWithParameters sh,
+          boolean editParams)
+  {
+    return processParams(sh, editParams, false);
+  }
+
+  protected boolean processParams(ServiceWithParameters sh,
+          boolean editParams,
+          boolean adjustingExisting)
+  {
+
+    if (editParams)
+    {
+      // always do this
+      sh.initParamStore(Desktop.getUserParameterStore());
+
+      WsJobParameters jobParams = (preset == null && paramset != null
+              && paramset.size() > 0)
+                      ? new WsJobParameters((ParamDatastoreI) null, sh,
+                              (WsParamSetI) null, paramset)
+                      : new WsJobParameters((ParamDatastoreI) null, sh,
+                              preset, (List<ArgumentI>) null);
+      if (adjustingExisting)
+      {
+        jobParams.setName(MessageManager
+                .getString("label.adjusting_parameters_for_calculation"));
+      }
+      if (!jobParams.showRunDialog())
+      {
+        return false; // dialog cancelled
+      }
+
+      WsParamSetI prset = jobParams.getPreset();
+      if (prset == null)
+      {
+        paramset = jobParams.isServiceDefaults() ? null
+                : jobParams.getJobParams();
+        this.preset = null;
+      }
+      else
+      {
+        this.preset = prset; // ((JabaPreset) prset).p;
+        paramset = null; // no user supplied parameters.
+      }
+    }
+    return true;
+  }
+
 }
diff --git a/src/jalview/ws/WSDiscovererI.java b/src/jalview/ws/WSDiscovererI.java
new file mode 100644 (file)
index 0000000..e9eedd3
--- /dev/null
@@ -0,0 +1,37 @@
+package jalview.ws;
+
+import jalview.ws.api.ServiceWithParameters;
+
+import java.net.URL;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public interface WSDiscovererI
+{
+  public static final int STATUS_OK = 1;
+  public static final int STATUS_NO_SERVICES = 0;
+  public static final int STATUS_INVALID = -1;
+  public static final int STATUS_UNKNOWN = -2;
+
+  public void setServiceUrls(List<String> wsUrls);
+
+  public List<String> getServiceUrls();
+
+  public List<ServiceWithParameters> getServices();
+
+  public boolean testServiceUrl(URL url);
+
+  public int getServerStatusFor(String url);
+  
+  public void addServiceChangeListener(ServiceChangeListener listener);
+  
+  public void removeServiceChangeListener(ServiceChangeListener listener);
+
+  public CompletableFuture<WSDiscovererI> startDiscoverer();
+
+  public String getErrorMessages();
+
+  public boolean hasServices();
+
+  public boolean isRunning();
+}
diff --git a/src/jalview/ws/api/CancellableI.java b/src/jalview/ws/api/CancellableI.java
new file mode 100644 (file)
index 0000000..adef2b9
--- /dev/null
@@ -0,0 +1,8 @@
+package jalview.ws.api;
+
+import jalview.ws.gui.WsJob;
+
+public interface CancellableI
+{
+  public boolean cancel(WsJob job);
+}
diff --git a/src/jalview/ws/api/DistanceMatrixResultI.java b/src/jalview/ws/api/DistanceMatrixResultI.java
new file mode 100644 (file)
index 0000000..a40d256
--- /dev/null
@@ -0,0 +1,16 @@
+package jalview.ws.api;
+
+import jalview.math.MatrixI;
+import jalview.ws.params.InvalidArgumentException;
+
+import java.io.IOError;
+import java.rmi.ServerError;
+
+public interface DistanceMatrixResultI
+{
+
+  public MatrixI getDistanceMatrixFor(JobId jobId)
+          throws InvalidArgumentException, ServerError, IOError;
+
+
+}
\ No newline at end of file
diff --git a/src/jalview/ws/api/JalviewServiceEndpointProviderI.java b/src/jalview/ws/api/JalviewServiceEndpointProviderI.java
new file mode 100644 (file)
index 0000000..b9b5109
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.ws.api;
+
+public interface JalviewServiceEndpointProviderI
+{
+
+  /**
+   * 
+   * @return endpoint instance implementing one or more jalview.ws.api
+   *         interfaces
+   */
+  Object getEndpoint();
+
+}
diff --git a/src/jalview/ws/api/JalviewWebServiceI.java b/src/jalview/ws/api/JalviewWebServiceI.java
new file mode 100644 (file)
index 0000000..6dda359
--- /dev/null
@@ -0,0 +1,27 @@
+package jalview.ws.api;
+
+import jalview.gui.WebserviceInfo;
+import jalview.ws.gui.WsJob;
+
+public interface JalviewWebServiceI
+{
+
+  void updateStatus(WsJob job);
+
+  /**
+   * Retrieve any additional log information for the job and update WsJob's
+   * progress. Results won't be retrieved until progress updates have finished.
+   * 
+   * @param job
+   * @return true if Job's stdout/progress panel was added to
+   * @throws Exception
+   */
+  boolean updateJobProgress(WsJob job) throws Exception;
+
+  boolean handleSubmitError(Throwable _lex, WsJob j, WebserviceInfo wsInfo)
+          throws Exception, Error;
+
+  boolean handleCollectionException(Exception e, WsJob msjob,
+          WebserviceInfo wsInfo);
+
+}
diff --git a/src/jalview/ws/api/JobId.java b/src/jalview/ws/api/JobId.java
new file mode 100644 (file)
index 0000000..2a092bd
--- /dev/null
@@ -0,0 +1,59 @@
+package jalview.ws.api;
+
+import java.time.Instant;
+import java.util.Date;
+
+public class JobId
+{
+  // TODO: JobId could include sequenceI anonymisation stuff
+  // TODO: getProgress() -> input stream to log file for job.
+  private String serviceType;
+
+  private String serviceImpl;
+
+  private String jobId;
+
+  private Instant creationTime;
+
+  public JobId(String serviceType, String serviceImpl, String id)
+  {
+    this.serviceType = serviceType;
+    this.serviceImpl = serviceImpl;
+    jobId = id;
+    creationTime = Instant.now();
+  }
+
+  @Override
+  public String toString()
+  {
+    return "" + serviceType + ":" + serviceImpl + ":" + jobId + "\nCreated "
+            + Date.from(creationTime);
+  }
+  /**
+   * a stringified version of the Job Id that can be saved in project.
+   */
+  public String getURI()
+  {
+    return jobId;
+  }
+
+  public String getServiceType()
+  {
+    return serviceType;
+  }
+
+  public String getServiceImpl()
+  {
+    return serviceImpl;
+  }
+
+  public String getJobId()
+  {
+    return jobId;
+  }
+
+  public Instant getCreationTime()
+  {
+    return creationTime;
+  }
+}
diff --git a/src/jalview/ws/api/MsaI.java b/src/jalview/ws/api/MsaI.java
new file mode 100644 (file)
index 0000000..3c426c0
--- /dev/null
@@ -0,0 +1,36 @@
+package jalview.ws.api;
+
+import jalview.datamodel.SequenceI;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
+
+/**
+ * MSA analysis interface
+ * 
+ * @author jprocter
+ * 
+ *         Generic job submission/management model: - A service instance
+ *         implements one or more analysis interfaces, a status interface, a
+ *         progress interface, and one or more results interface, plus any
+ *         informational/descriptional interfaces - analysis interfaces return
+ *         JobId or throw exceptions/errors.
+ * 
+ *
+ */
+public interface MsaI
+{
+  /**
+   * Given a set of sequences
+   * 
+   * @param toalign
+   * @param parameters
+   * @param list
+   * @return JobId or exceptions are thrown.
+   * @throws Throwable
+   */
+  public JobId align(List<SequenceI> toalign, WsParamSetI parameters,
+          List<ArgumentI> list)
+          throws Throwable;
+}
diff --git a/src/jalview/ws/api/MsaResultI.java b/src/jalview/ws/api/MsaResultI.java
new file mode 100644 (file)
index 0000000..38c0a0a
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.ws.api;
+
+import jalview.datamodel.AlignmentI;
+import jalview.ws.params.InvalidArgumentException;
+
+import java.io.IOError;
+import java.rmi.ServerError;
+
+public interface MsaResultI
+{
+  public AlignmentI getAlignmentFor(JobId jobId)
+          throws InvalidArgumentException, ServerError, IOError;
+}
\ No newline at end of file
diff --git a/src/jalview/ws/api/MsaWithGuideTreeI.java b/src/jalview/ws/api/MsaWithGuideTreeI.java
new file mode 100644 (file)
index 0000000..6c2ff53
--- /dev/null
@@ -0,0 +1,24 @@
+package jalview.ws.api;
+
+import jalview.analysis.NJTree;
+import jalview.datamodel.SequenceI;
+import jalview.ws.params.InvalidArgumentException;
+import jalview.ws.params.WsParamSetI;
+
+import java.io.IOError;
+import java.rmi.ServerError;
+import java.util.List;
+
+public interface MsaWithGuideTreeI
+{
+  /**
+   * Given a set of sequences
+   * 
+   * @param toalign
+   * @param parameters
+   * @return JobId or exceptions are thrown.
+   */
+  public JobId align(List<SequenceI> toalign, NJTree guideTree,
+          WsParamSetI parameters)
+          throws InvalidArgumentException, ServerError, IOError;
+}
\ No newline at end of file
diff --git a/src/jalview/ws/api/MultipleSequenceAlignmentI.java b/src/jalview/ws/api/MultipleSequenceAlignmentI.java
new file mode 100644 (file)
index 0000000..10b8383
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.ws.api;
+
+/**
+ * A simple parameterisable multiple sequence alignment service
+ * 
+ * @author jprocter
+ *
+ */
+public interface MultipleSequenceAlignmentI
+        extends JalviewWebServiceI, MsaI, MsaResultI
+{
+
+}
diff --git a/src/jalview/ws/api/SequenceAnnotationServiceI.java b/src/jalview/ws/api/SequenceAnnotationServiceI.java
new file mode 100644 (file)
index 0000000..9ca2d31
--- /dev/null
@@ -0,0 +1,51 @@
+package jalview.ws.api;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SequenceAnnotationServiceI extends JalviewWebServiceI
+{
+
+
+  /**
+   * submit sequences to service with no parameters, or preset or parameter set.
+   * Nb- almost the same as the 'align' method in the Msa service :)
+   * 
+   * @param seqs
+   * @param preset
+   * @param paramset
+   * @return
+   * @throws Throwable
+   */
+  JobId submitToService(List<SequenceI> seqs, WsParamSetI preset,
+          List<ArgumentI> paramset) throws Throwable;
+
+  /**
+   * materialise annotation and features for sequences input to the service
+   * 
+   * @param job
+   * @param seqs
+   *          - features and alignment annotation added to these will be
+   *          imported to the dataset for the alignment
+   * @param featureColours
+   *          - container for feature colours - any defined will be merged with
+   *          viewport
+   * @param featureFilters
+   *          - container for filters - any defined will be merged with viewport
+   * @return sequence and alignment annotation rows that should be made
+   *         visible/updated on alignment
+   * @throws Throwable
+   */
+  List<AlignmentAnnotation> getAnnotationResult(JobId job,
+          List<SequenceI> seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters) throws Throwable;
+  
+
+}
diff --git a/src/jalview/ws/api/ServiceWithParameters.java b/src/jalview/ws/api/ServiceWithParameters.java
new file mode 100644 (file)
index 0000000..645ef34
--- /dev/null
@@ -0,0 +1,111 @@
+package jalview.ws.api;
+
+import jalview.bin.Cache;
+import jalview.gui.AlignFrame;
+import jalview.ws.jws2.MsaWSClient;
+import jalview.ws.jws2.SequenceAnnotationWSClient;
+import jalview.ws.params.ParamManager;
+
+import javax.swing.JMenu;
+
+public abstract class ServiceWithParameters extends UIinfo
+{
+
+  protected jalview.ws.uimodel.AlignAnalysisUIText aaui;
+
+  public ServiceWithParameters(String serviceType, String action,
+          String name, String description, String hosturl)
+  {
+    super(serviceType, action, name, description, hosturl);
+  }
+
+  public abstract void initParamStore(ParamManager userParameterStore);
+
+  public jalview.ws.uimodel.AlignAnalysisUIText getAlignAnalysisUI()
+  {
+    return aaui;
+  }
+
+  public void setAlignAnalysisUI(
+          jalview.ws.uimodel.AlignAnalysisUIText aaui)
+  {
+    this.aaui = aaui;
+  }
+
+  public boolean isInteractiveUpdate()
+  {
+    return aaui != null && aaui.isAA();
+  }
+  // config flags for SeqAnnotationServiceCalcWorker
+
+  public boolean isProteinService()
+  {
+    return aaui == null ? true : aaui.isPr();
+  }
+
+  public boolean isNucleotideService()
+  {
+    return aaui == null ? false : aaui.isNa();
+  }
+
+  public boolean isNeedsAlignedSequences()
+  {
+    return aaui == null ? false : aaui.isNeedsAlignedSeqs();
+  }
+
+  public boolean isAlignmentAnalysis()
+  {
+    return aaui == null ? false : aaui.isAA();
+  }
+
+  public boolean isFilterSymbols()
+  {
+    return aaui != null ? aaui.isFilterSymbols() : true;
+  }
+
+  public int getMinimumInputSequences()
+  {
+    return aaui != null ? aaui.getMinimumSequences() : 1;
+  }
+
+  public String getNameURI()
+  {
+    return "java:" + getName();
+  }
+
+  public String getUri()
+  {
+    // TODO verify that service parameter sets in projects are consistent with
+    // Jalview 2.10.4
+    // this is only valid for Jaba 1.0 - this formula might have to change!
+    return getHostURL()
+            + (getHostURL().lastIndexOf("/") == (getHostURL().length() - 1)
+                    ? ""
+                    : "/")
+            + getName();
+  }
+
+  protected enum ServiceClient
+  {
+    MSAWSCLIENT, SEQUENCEANNOTATIONWSCLIENT;
+  };
+
+  protected ServiceClient style = null;
+
+  public void attachWSMenuEntry(JMenu atpoint, AlignFrame alignFrame)
+  {
+    switch (style)
+    {
+    case MSAWSCLIENT:
+        new MsaWSClient().attachWSMenuEntry(atpoint, this, alignFrame);
+      break;
+    case SEQUENCEANNOTATIONWSCLIENT:
+        new SequenceAnnotationWSClient().attachWSMenuEntry(atpoint, this,
+                alignFrame);
+      break;
+    default:
+      Cache.log.warn("Implementation error ? Service " + getName()
+              + " has Unknown service style " + style);
+    }
+  }
+}
diff --git a/src/jalview/ws/api/TreeResultI.java b/src/jalview/ws/api/TreeResultI.java
new file mode 100644 (file)
index 0000000..1a0c3bd
--- /dev/null
@@ -0,0 +1,14 @@
+package jalview.ws.api;
+
+import jalview.analysis.NJTree;
+import jalview.ws.params.InvalidArgumentException;
+
+import java.io.IOError;
+import java.rmi.ServerError;
+
+public interface TreeResultI
+{
+
+  public NJTree getTreeFor(JobId jobId)
+          throws InvalidArgumentException, ServerError, IOError;
+}
\ No newline at end of file
diff --git a/src/jalview/ws/api/UIinfo.java b/src/jalview/ws/api/UIinfo.java
new file mode 100644 (file)
index 0000000..8ef4d5b
--- /dev/null
@@ -0,0 +1,164 @@
+package jalview.ws.api;
+
+import jalview.ws.params.ParamDatastoreI;
+
+/**
+ * Service UI Info { Action, Specific Name of Service, Brief Description }
+ */
+
+public class UIinfo
+{
+  private String ServiceType;
+
+  public UIinfo(String serviceType, String action, String name,
+          String description, String hosturl)
+  {
+    this.setServiceType(serviceType == null ? "" : serviceType);
+    this.Action = action == null ? "" : action;
+    this.description = description == null ? "" : description;
+    this.Name = name == null ? "" : name;
+    this.hostURL = hosturl;
+  }
+
+  /**
+   * The type of analysis the service performs
+   */
+  public String getServiceType()
+  {
+    return ServiceType;
+  }
+
+  public void setServiceType(String serviceType)
+  {
+    ServiceType = serviceType;
+  }
+
+  /**
+   * The action when the service performs the analysis
+   */
+  public String getAction()
+  {
+    return Action;
+  }
+
+  public void setAction(String action)
+  {
+    Action = action;
+  }
+
+  /**
+   * name shown to user
+   * 
+   * @return
+   */
+  public String getName()
+  {
+    return Name;
+  }
+
+  public void setName(String name)
+  {
+    Name = name;
+  }
+
+  /**
+   * Detailed description (may include references, URLs, html,etc)
+   * 
+   * @return
+   */
+  public String getDescription()
+  {
+    return description;
+  }
+
+  public void setDescription(String description)
+  {
+    this.description = description;
+  }
+
+  @Override
+  public boolean equals(Object object)
+  {
+    if (object == null || !(object instanceof UIinfo))
+    {
+      return false;
+    }
+    UIinfo other = (UIinfo) object;
+
+    return (ServiceType == null && other.getServiceType() == null
+            || ServiceType != null && other.getServiceType() != null
+                    && ServiceType.equals(other.getServiceType()))
+            && (hostURL == null && other.getHostURL() == null
+                    || hostURL != null && other.getHostURL() != null
+                            && hostURL.equals(other.getHostURL()))
+            && (Name == null && other.getName() == null
+                    || Name != null && other.getName() != null
+                            && Name.equals(other.getName()))
+            && (Action == null && other.getAction() == null
+                    || Action != null && other.getAction() != null
+                            && Action.equals(other.getAction()))
+            && (description == null && other.getDescription() == null
+                    || description != null && other.getDescription() != null
+                            && description.equals(other.getDescription()));
+  }
+
+  /**
+   * @return short description of what the service will do
+   */
+  public String getActionText()
+  {
+    return getAction() + " with " + getName();
+  }
+
+  String Action;
+
+  String Name;
+
+  String description;
+
+  String hostURL;
+
+  public String getHostURL()
+  {
+    return hostURL;
+  }
+
+  public ParamDatastoreI getParamStore()
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  /**
+   * 
+   * @return true if the service has parameters (ie is instance of
+   *         jalview.ws.api.ServiceWithParameters)
+   */
+  public boolean hasParameters()
+  {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  private String docUrl = null;
+
+  /**
+   * set the URL that will be offered to show documentation for the service
+   * 
+   * @param url
+   */
+  public void setDocumentationUrl(String url)
+  {
+    docUrl = url;
+  }
+
+  public boolean hasDocumentationUrl()
+  {
+    return docUrl != null && docUrl.length() > 7;
+  }
+
+  public String getDocumentationUrl()
+  {
+    return docUrl;
+  }
+}
\ No newline at end of file
diff --git a/src/jalview/ws/api/WSAnnotationCalcManagerI.java b/src/jalview/ws/api/WSAnnotationCalcManagerI.java
new file mode 100644 (file)
index 0000000..47e3195
--- /dev/null
@@ -0,0 +1,6 @@
+package jalview.ws.api;
+
+public interface WSAnnotationCalcManagerI
+{
+
+}
diff --git a/src/jalview/ws/ebi/HmmerJSONProcessor.java b/src/jalview/ws/ebi/HmmerJSONProcessor.java
new file mode 100644 (file)
index 0000000..428c498
--- /dev/null
@@ -0,0 +1,331 @@
+package jalview.ws.ebi;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.io.FileParse;
+import jalview.viewmodel.AlignmentViewport;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+public class HmmerJSONProcessor
+{
+  /**
+   * result to be annotated. may not be null
+   */
+  AlignmentI resultAl;
+
+  /**
+   * viewport on the alignment. may be null at construction time
+   */
+  AlignmentViewport viewAl = null;
+
+  public HmmerJSONProcessor(AlignmentI searchResult)
+  {
+    resultAl = searchResult;
+  }
+
+  public void parseFrom(FileParse jsonsource) throws IOException,
+          OutOfMemoryError
+  {
+    JSONParser hmmerResultParser = new JSONParser();
+    Object jsonResults = null;
+    try
+    {
+      jsonResults = hmmerResultParser.parse(jsonsource.getReader());
+    } catch (Exception p)
+    {
+      throw new IOException("While parsing from " + jsonsource.getInFile(),
+              p);
+    }
+    if (jsonResults == null)
+    {
+      throw new IOException("No data at" + jsonsource.getInFile());
+    }
+    if (!(jsonResults instanceof JSONObject))
+    {
+      throw new IOException("Unexpected JSON model at "
+              + jsonsource.getInFile());
+    }
+    try
+    {
+      JSONObject hmmsearchr = (JSONObject) ((JSONObject) jsonResults)
+              .get("results");
+      // now process the hits
+      addStatistics((JSONObject) hmmsearchr.get("stats"));
+      JSONArray jsonArray = (JSONArray) hmmsearchr.get("hits");
+      long p = 1;
+      for (Object hit : jsonArray)
+      {
+        JSONObject hmmhit = (JSONObject) hit;
+        addHit(hmmhit, p++);
+      }
+    } catch (ClassCastException q)
+    {
+      throw new IOException("Unexpected JSON model content at "
+              + jsonsource.getInFile(), q);
+    }
+  }
+
+  /**
+   * 
+   * @param object
+   *          - actually a JSONObject key value set of search statistics.
+   */
+  public void addStatistics(JSONObject stats)
+  {
+    for (Object stat : stats.keySet())
+    {
+      String key = (String) stat;
+      Object val = stats.get(key);
+      resultAl.setProperty(key, "" + val);
+    }
+  }
+
+  // encodings for JSON keys
+  /**
+   * score becomes sequence associated AlignmentAnnotation
+   */
+  private String[] score = { "aliId", "ali_IdCount", "bitscore", "ievalue",
+      "aliSim", "aliSimCount", "aliL", "aliSim", "ievalue", "cevalue" };
+
+  /**
+   * attrib becomes numeric or binary attribute for sequence with respect to
+   * this hmmsearch run
+   */
+  private String[] attrib = { "bias", "oasc", "is_included", "is_reported" };
+
+  /**
+   * name of the hmmsearch query
+   */
+  private String[] label = { "alihmmname" // (query label?)},
+  };
+
+  /**
+   * integer attributes for each
+   */
+  private String[] ipos = { "alihmmfrom", "alihmmto" }, pos_l = {
+      "alimline", "alimodel", "alirfline" };
+
+  /**
+   * positional quantitative annotation encoded as strings.
+   */
+  private String[] pos_nscore = { "alippline" };
+
+  //
+  // mapping of keys to types of property on sequence
+  //
+  public void addHit(JSONObject hmmrhit, long p)
+  {
+    String sname = (String) hmmrhit.get("name");
+    SequenceI[] hits = resultAl.findSequenceMatch(sname);
+    if (hits == null)
+    {
+      System.err.println("No seq for " + sname);
+    }
+    double pvalue = (Double) hmmrhit.get("pvalue");
+
+    double evalue = Double.valueOf("" + hmmrhit.get("evalue"));
+    for (Object domainhit : ((JSONArray) hmmrhit.get("domains")))
+    {
+      JSONObject dhit = (JSONObject) domainhit;
+      // dhit.get(key)
+
+      // alihmmfrom,alihmmto alimodel
+      long alihmmfrom = (long) dhit.get("alihmmfrom"), alihmmto = (long) dhit
+              .get("alihmmto"), alisqfrom = (long) dhit.get("alisqfrom"), alisqto = (long) dhit
+              .get("alisqto");
+
+      // alisqfrom,alisqto,aliaseq
+
+      // alippline
+      String aliaseq = (String) dhit.get("aliaseq"), alimodel = (String) dhit
+              .get("alimodel"), ppline = (String) dhit.get("alippline");
+      //
+      int found = 0;
+      SequenceI firsthit = null;
+      for (SequenceI hitseq : hits)
+      {
+        // match alisqfrom,alisqto,seq
+        if (hitseq.getStart() == alisqfrom && hitseq.getEnd() == alisqto)
+        {
+          if (found == 0)
+          {
+            firsthit = hitseq;
+          }
+          found++; // annotated a sequence
+          AlignmentAnnotation alipp = parsePosteriorProb(ppline);
+          AlignmentAnnotation pval = new AlignmentAnnotation("p-value",
+                  "hmmer3 pvalue", pvalue);
+          AlignmentAnnotation eval = new AlignmentAnnotation("e-value",
+                  "hmmer3 evalue", evalue);
+          pval.setCalcId("HMMER3");
+          eval.setCalcId("HMMER3");
+          alipp.setCalcId("HMMER3");
+          hitseq.addAlignmentAnnotation(pval);
+          hitseq.addAlignmentAnnotation(eval);
+          alipp.createSequenceMapping(hitseq, hitseq.getStart(), false);
+          hitseq.addAlignmentAnnotation(alipp);
+          String arch;
+          hitseq.addSequenceFeature(new SequenceFeature(
+                  "Pfam Domain Architecture", (hmmrhit.get("archindex"))
+                          + " " + (arch = (String) hmmrhit.get("arch")), 0,
+                  0,
+                  (hmmrhit.get("archScore") != null ? Integer
+                          .valueOf((String) hmmrhit.get("archScore")) : 0f),
+                  "HMMER3"));
+          addArchGroup(hitseq, arch);
+          alipp.setScore(Double.valueOf("" + dhit.get("bitscore")));
+          alipp.adjustForAlignment();
+          resultAl.addAnnotation(pval);
+          resultAl.addAnnotation(eval);
+          resultAl.addAnnotation(alipp);
+          alipp.validateRangeAndDisplay();
+        }
+      }
+      // look for other sequences represented by this hit and create rep groups
+      // could be in "pdbs", or ..
+      addRedundantSeqGroup(firsthit, alisqfrom, alisqto,
+              (JSONArray) hmmrhit.get("seqs"), true);
+    }
+  }
+
+  /**
+   * series of operations to perform for the viewpanel associated with the
+   * alignment
+   */
+  private List<Runnable> viewOps = new ArrayList<Runnable>();
+
+  public void updateView(AlignmentViewport view)
+  {
+    viewAl = view;
+    for (Runnable op : viewOps)
+    {
+      op.run();
+    }
+  }
+
+  private void addRedundantSeqGroup(final SequenceI firsthit,
+          long alisqfrom, long alisqto, JSONArray others, boolean justDelete)
+  {
+    if (others != null)
+    {
+      final SequenceGroup repgroup = new SequenceGroup();
+      repgroup.setSeqrep(firsthit);
+      repgroup.addOrRemove(firsthit, false);
+      repgroup.setStartRes(0);
+      repgroup.setEndRes(resultAl.getWidth() - 1);
+      for (Object otherseq : others.toArray(new JSONObject[0]))
+      {
+        String repseq = (String) ((JSONObject) otherseq).get("dn");
+        SequenceI[] other = resultAl.findSequenceMatch(repseq);
+        if (other != null && other.length > 0)
+        {
+          if (justDelete)
+          {
+            for (SequenceI oth : other)
+            {
+              resultAl.deleteSequence(oth);
+            }
+            ;
+          }
+          else
+          {
+            int ofound = 0;
+            for (SequenceI oth : other)
+            {
+              if (oth.getStart() == alisqfrom && oth.getEnd() == alisqto)
+              {
+                ofound++;
+                repgroup.addSequence(oth, false);
+              }
+            }
+            if (ofound == 0)
+            {
+              System.err.println("Warn - no match for redundant hit "
+                      + repseq + "/" + alisqfrom + "-" + alisqto);
+            }
+            if (ofound > 1)
+            {
+              System.err
+                      .println("Warn - multiple matches for redundant hit "
+                              + repseq + "/" + alisqfrom + "-" + alisqto);
+            }
+          }
+        }
+      }
+      if (repgroup.getSequences().size() > 1)
+      {
+        // queue a hide operation
+        final HmmerJSONProcessor me = this;
+        viewOps.add(new Runnable()
+        {
+          @Override
+          public void run()
+          {
+            me.viewAl.hideRepSequences(firsthit, repgroup);
+          }
+        });
+      }
+    }
+  }
+
+  Map<String, SequenceGroup> groups = new HashMap<String, SequenceGroup>();
+
+  private void addArchGroup(SequenceI seqToAdd, String groupNam)
+  {
+    SequenceGroup sg = groups.get(groupNam);
+    if (sg == null)
+    {
+      sg = new SequenceGroup();
+      sg.setName(groupNam);
+      sg.addSequence(seqToAdd, false);
+      sg.setStartRes(0);
+      sg.setEndRes(resultAl.getWidth() - 1);
+      groups.put(groupNam, sg);
+      resultAl.addGroup(sg);
+    }
+    else
+    {
+      sg.addSequence(seqToAdd, false);
+    }
+  }
+
+  private AlignmentAnnotation parsePosteriorProb(String ppline)
+  {
+    Annotation[] ae = new Annotation[ppline.length()];
+    int spos = 0;
+    for (int i = 0, iSize = ppline.length(); i < iSize; i++)
+    {
+      char pp = ppline.charAt(i);
+      if (pp == '*')
+      {
+        ae[spos++] = new Annotation(10f);
+      }
+      else
+      {
+        if (pp >= '0' && pp <= '9')
+        {
+          ae[spos++] = new Annotation(Integer.valueOf("" + pp));
+        }
+      }
+    }
+    AlignmentAnnotation pprob = new AlignmentAnnotation(
+            "Posterior Probability",
+            "Likelihood of HMM fit at each hit position.", ae);
+    pprob.graph = AlignmentAnnotation.BAR_GRAPH;
+    pprob.visible = false;
+    return pprob;
+  }
+}
diff --git a/src/jalview/ws/ebi/hmmerClient.java b/src/jalview/ws/ebi/hmmerClient.java
new file mode 100644 (file)
index 0000000..41cd0d8
--- /dev/null
@@ -0,0 +1,319 @@
+package jalview.ws.ebi;
+
+import jalview.datamodel.AlignmentI;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileParse;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Matcher;
+
+import org.apache.axis.transport.http.HTTPConstants;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import compbio.util.FileUtil;
+
+public class hmmerClient
+{
+  /**
+   * URLs for ebi api
+   */
+  static String baseUrl = "http://www.ebi.ac.uk/Tools/hmmer",
+          jackH = "/search/jackhmmer", phmmer = "/search/phmmer",
+          hmmscan = "/search/hmmscan", hmmsearch = "/search/hmmsearch";
+
+  static String edseq = ">2abl_A mol:protein length:163  ABL TYROSINE KINASE\nMGPSENDPNLFVALYDFVASGDNTLSITKGEKLRVLGYNHNGEWCEAQTKNGQGWVPSNYITPVNSLEKHS\nWYHGPVSRNAAEYLLSSGINGSFLVRESESSPGQRSISLRYEGRVYHYRINTASDGKLYVSSESRFNTLAE\nLVHHHSTVADGLITTLHYPAP";
+
+  public static void main(String[] args)
+  {
+    String instr = edseq;
+    if (args.length > 0)
+    {
+      try
+      {
+        instr = FileUtil.readFileToString(new File(args[0]));
+      } catch (Exception f)
+      {
+        f.printStackTrace();
+        return;
+      }
+    }
+    String res = new hmmerClient().submitJackhmmerSearch(instr,
+            "jackhmmer", "pdb", 5);
+    if (res == null)
+    {
+      throw new Error("Failed.");
+    }
+    System.out.println("Result\n" + res);
+    return;
+  }
+
+  /**
+   * 
+   * @param input
+   *          - fasta or other formatted sequence or alignment
+   * @param algo
+   *          - jackhmmer
+   * @param db
+   *          - pdb, uniprot, etc.
+   * @param niter
+   *          number of iterations
+   * @return job id
+   */
+  String submitJackhmmerSearch(String input, String algo, String db,
+          int niter)
+  {
+    JSONObject inparam = new JSONObject();
+    HttpPost jackhp = new HttpPost(baseUrl + jackH);
+    String lastiter = null;
+    try
+    {
+      inparam.put("algo", algo);
+      inparam.put("seq", input);
+      inparam.put("seqdb", db);
+      inparam.put("iterations", niter);
+      // #Now POST the request and generate the search job.
+      // dumb json post service
+      jackhp.setHeader("content-type", "application/json");
+      jackhp.setEntity(new StringEntity(inparam.toString()));
+    } catch (Exception f)
+    {
+      f.printStackTrace();
+      return null;
+    }
+    HttpResponse r = null;
+    try
+    {
+      DefaultHttpClient httpCl = new DefaultHttpClient();
+
+      r = httpCl.execute(jackhp);
+
+    } catch (Exception x)
+    {
+      System.err.println("Submit failed.");
+      x.printStackTrace();
+    }
+    if (r.getStatusLine().getStatusCode() != 201)
+    {
+      throw new Error(r.toString());
+    }
+    // get uid for job
+    String jobid = null, redir = null;
+    try
+    {
+      JSONObject res = new JSONObject(EntityUtils.toString(r.getEntity()));
+      jobid = res.getString("job_id");
+
+      Header[] loc;
+      if ((loc = r.getHeaders(HTTPConstants.HEADER_LOCATION)) != null
+              && loc.length > 0)
+      {
+        if (loc.length > 1)
+        {
+          System.err
+                  .println("Ignoring additional "
+                          + (loc.length - 1)
+                          + " location(s) provided in response header ( next one is '"
+                          + loc[1].getValue() + "' )");
+        }
+        redir = loc[0].getValue();
+      }
+    } catch (Exception x)
+    {
+      System.err.println("job id extraction failed.");
+      x.printStackTrace();
+    }
+    int tries = 0;
+    boolean finished = false;
+    JSONObject jobstate = null;
+    do
+    {
+      try
+      {
+        DefaultHttpClient httpCl = new DefaultHttpClient();
+
+        HttpGet jackcheck = new HttpGet(redir);
+        jackcheck.setHeader("content-type", "application/json");
+        r = httpCl.execute(jackcheck);
+        switch (r.getStatusLine().getStatusCode())
+        {
+        case 200:
+          jobstate = new JSONObject(EntityUtils.toString(r.getEntity()));
+          String st = jobstate.getString("status");
+          if ("DONE".equals(st))
+          {
+            finished = true;
+          }
+          if ("ERROR".equals(st))
+          {
+            System.err.println("Error");
+            finished = true;
+          }
+          if ("PEND".equals(st) || "RUN".equals("st"))
+          {
+            JSONArray iters = jobstate.getJSONArray("result");
+            lastiter = iters.getJSONObject(iters.length() - 1).getString(
+                    "uuid");
+            if (lastiter.length() > 0)
+            {
+              java.util.regex.Pattern p = java.util.regex.Pattern
+                      .compile(".+(\\d+)");
+              Matcher m = p.matcher(lastiter);
+              if (m.matches())
+              {
+                System.out.println("On iteration " + m.group(1));
+              }
+            }
+          }
+          break;
+
+        default:
+          tries++;
+          Thread.sleep(2000);
+        }
+      } catch (Exception q)
+      {
+        q.printStackTrace();
+        return null;
+      }
+    } while (!finished && tries < 50);
+
+    if (!finished)
+    {
+      System.err.println("Giving up with job " + jobid + " at " + redir);
+      return null;
+    }
+    // get results
+    // http://www.ebi.ac.uk/Tools/hmmer/download/60048B38-7CEC-11E5-A230-CED6D26C98AD.5/score?format=csv
+    // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 1 2 4.4e-46 2.1e-43
+    // 151.758316040039 0.04 11 151 3 139 1 150 0.94 GROWTH FACTOR BOUND PROTEIN
+    // 2 1cj1_J 1gri_B
+    // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 2 2 1.6e-17 7.9e-15
+    // 58.8796501159668 0.01 7 66 157 215 153 216 0.95 GROWTH FACTOR BOUND
+    // PROTEIN 2 1cj1_J 1gri_B
+    // 4h1o_A 4h1o_A 560 jackhmmer - 163 2.1e-57 197.3 0.0 1 2 7.5e-28 3.6e-25
+    // 92.4921493530273 0.00 65 161 20 122 17 124 0.95 Tyrosine-protein
+    // phosphatase non-receptor typ 4h1o_A
+    //
+    // 4h1o_A 4h1o_A 560 jackhmmer - 163 2.1e-57 197.3 0.0 2 2 7.6e-31 3.7e-28
+    // 102.219146728516 0.03 66 161 127 236 124 238 0.94 Tyrosine-protein
+    // phosphatase non-receptor typ 4h1o_A
+    //
+    // $ua->get( $rootUrl."/results/".$lastIteration->{uuid} . "/score"
+    return lastiter;
+    /*
+     * * #Job should have finished, but we may have converged, so get the last
+     * job. my $results = $json->decode( $response->content ); my $lastIteration
+     * = pop( @{ $results->{result} } ); #Now fetch the results of the last
+     * iteration my $searchResult = $ua->get( $rootUrl."/results/" .
+     * $lastIteration->{uuid} . "/score", 'Accept' => 'application/json' );
+     * unless( $searchResult->status_line eq "200 OK"){ die
+     * "Failed to get search results\n"; }
+     * 
+     * #Decode the content of the full set of results $results = $json->decode(
+     * $searchResult->content ); print
+     * "Matched ".$results->{'results'}->{'stats'}->{'nincluded'}." sequences
+     * ($lastIteration->{uuid})!\n"; #Now do something more interesting with the
+     * results......
+     */
+  }
+
+  /**
+   * retrieve an alignment annotated with scores from JackHmmer
+   * 
+   * @param jobid
+   * @param dataset
+   * @return
+   */
+  AlignmentI retrieveJackhmmerResult(String jobid, AlignmentI dataset)
+          throws OutOfMemoryError, IOException
+  {
+    AlignmentI searchResult = null;
+
+    // get results
+
+    searchResult = new AppletFormatAdapter().readFile(baseUrl
+            + "/download/" + jobid + "/score?format=afa&t=.gz",
+            DataSourceType.URL, FileFormat.Fasta);
+
+    // TODO extract gapped columns as '.' - inserts to query profile
+
+    // TODO match up jackhammer results to dataset.
+
+    // do scores
+    FileParse jsonsource = new FileParse(baseUrl + "/download/" + jobid
+            + "/score?format=json", DataSourceType.URL);
+    if (!jsonsource.isValid())
+    {
+      throw new IOException("Couldn't access scores for Jackhammer results");
+    }
+    readJackhmmerScores(searchResult, jsonsource);
+    return searchResult;
+  }
+
+  /**
+   * // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 1 2 4.4e-46 2.1e-43
+   * 
+   * // 151.758316040039 0.04 11 151 3 139 1 150 0.94 GROWTH FACTOR BOUND
+   * PROTEIN // 2 1cj1_J 1gri_B // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62
+   * 212.4 0.1 2 2 1.6e-17 7.9e-15 // 58.8796501159668 0.01 7 66 157 215 153 216
+   * 0.95 GROWTH FACTOR BOUND // PROTEIN 2 1cj1_J 1gri_B // 4h1o_A 4h1o_A 560
+   * jackhmmer - 163 2.1e-57 197.3 0.0 1 2 7.5e-28 3.6e-25 // 92.4921493530273
+   * 0.00 65 161 20 122 17 124 0.95 Tyrosine-protein // phosphatase non-receptor
+   * typ 4h1o_A
+   */
+  private static String[] _hmmsearchcols = new String[] { "acc", "name", "" };
+
+  private void readJackhmmerScores(AlignmentI searchResult,
+          FileParse jsonsource) throws IOException, OutOfMemoryError
+  {
+    HmmerJSONProcessor hjp = new HmmerJSONProcessor(searchResult);
+    hjp.parseFrom(jsonsource);
+
+    // http://www.ebi.ac.uk/Tools/hmmer/download/60048B38-7CEC-11E5-A230-CED6D26C98AD.5/score?format=csv
+    // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 1 2 4.4e-46 2.1e-43
+    // 151.758316040039 0.04 11 151 3 139 1 150 0.94 GROWTH FACTOR BOUND PROTEIN
+    // 2 1cj1_J 1gri_B
+    // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 2 2 1.6e-17 7.9e-15
+    // 58.8796501159668 0.01 7 66 157 215 153 216 0.95 GROWTH FACTOR BOUND
+    // PROTEIN 2 1cj1_J 1gri_B
+    // 4h1o_A 4h1o_A 560 jackhmmer - 163 2.1e-57 197.3 0.0 1 2 7.5e-28 3.6e-25
+    // 92.4921493530273 0.00 65 161 20 122 17 124 0.95 Tyrosine-protein
+    // phosphatase non-receptor typ 4h1o_A
+    // each line scores a fragment
+    // so for a combined score ?
+
+    /**
+     * for a sequence q sort any t against q according to overallScore(q,t)
+     * maxFragment(q,t) in sequence features parlance: for alignment
+     * s.getFeature("overallScore",q) -> range on q and range on s
+     * 
+     * 
+     */
+
+    // 151.758316040039 0.04 11 151 3 139 1 150 0.94 GROWTH FACTOR BOUND PROTEIN
+    // 2 1cj1_J 1gri_B
+    // 1gri_A 1gri_A 217 jackhmmer - 163 4.7e-62 212.4 0.1 2 2 1.6e-17 7.9e-15
+    // 58.8796501159668 0.01 7 66 157 215 153 216 0.95 GROWTH FACTOR BOUND
+    // PROTEIN 2 1cj1_J 1gri_B
+    // 4h1o_A 4h1o_A 560 jackhmmer - 163 2.1e-57 197.3 0.0 1 2 7.5e-28 3.6e-25
+    // 92.4921493530273 0.00 65 161 20 122 17 124 0.95 Tyrosine-protein
+    // phosphatase non-receptor typ 4h1o_A
+    //
+    // 4h1o_A 4h1o_A 560 jackhmmer - 163 2.1e-57 197.3 0.0 2 2 7.6e-31 3.7e-28
+    // 102.219146728516 0.03 66 161 127 236 124 238 0.94 Tyrosine-protein
+    // phosphatase non-receptor typ 4h1o_A
+
+  }
+
+}
diff --git a/src/jalview/ws/gui/AnnotationWsJob.java b/src/jalview/ws/gui/AnnotationWsJob.java
new file mode 100644 (file)
index 0000000..3381138
--- /dev/null
@@ -0,0 +1,106 @@
+package jalview.ws.gui;
+
+import jalview.api.FeatureRenderer;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.SequenceI;
+
+import java.util.List;
+import java.util.Map;
+
+public class AnnotationWsJob extends WsJob
+{
+  /**
+   * sequences (anonymised)
+   */
+  List<SequenceI> seqs;
+
+  /**
+   * mapping to original sequences
+   */
+  Map<String, SequenceI> seqNames;
+
+  /**
+   * first column in the segment of the alignment view that was submitted
+   */
+  int startPos;
+
+  public int getStartPos()
+  {
+    return startPos;
+  }
+
+  public void setStartPos(int startPos)
+  {
+    this.startPos = startPos;
+  }
+
+  /**
+   * outputs
+   */
+  List<AlignmentAnnotation> annotation = null;
+
+  boolean transferSequenceFeatures = false;
+
+  public boolean isTransferSequenceFeatures()
+  {
+    return transferSequenceFeatures;
+  }
+
+  public void setTransferSequenceFeatures(boolean transferSequenceFeatures)
+  {
+    this.transferSequenceFeatures = transferSequenceFeatures;
+  }
+
+  public List<AlignmentAnnotation> getAnnotation()
+  {
+    return annotation;
+  }
+
+  public void setAnnotation(List<AlignmentAnnotation> annotation)
+  {
+    this.annotation = annotation;
+  }
+
+  @Override
+  public boolean hasResults()
+  {
+    return (isSubmitted() && isFinished()
+            && (annotation != null || transferSequenceFeatures));
+  }
+
+  public List<SequenceI> getSeqs()
+  {
+    return seqs;
+  }
+
+  public void setSeqs(List<SequenceI> seqs)
+  {
+    this.seqs = seqs;
+  }
+
+  public Map<String, SequenceI> getSeqNames()
+  {
+    return seqNames;
+  }
+
+  public void setSeqNames(Map<String, SequenceI> seqNames)
+  {
+    this.seqNames = seqNames;
+  }
+
+  /**
+   * configured by the WS framework just before results are collected
+   */
+  FeatureRenderer featureRenderer;
+
+  public void setFeatureRenderer(FeatureRenderer fr)
+  {
+    this.featureRenderer = fr;
+  }
+  public FeatureRenderer getFeatureRenderer()
+  {
+    // TODO Auto-generated method stub
+    return featureRenderer;
+  }
+
+}
diff --git a/src/jalview/ws/gui/MsaWSJob.java b/src/jalview/ws/gui/MsaWSJob.java
new file mode 100644 (file)
index 0000000..d8cae20
--- /dev/null
@@ -0,0 +1,370 @@
+package jalview.ws.gui;
+
+import jalview.analysis.AlignSeq;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.MessageManager;
+import jalview.ws.jws2.dm.JabaWsParamSet;
+import jalview.ws.params.ArgumentI;
+
+import java.util.ArrayList;
+import java.util.Vector;
+
+class MsaWSJob extends WsJob
+{
+  /**
+   * holds basic MSA analysis configuration - todo - encapsulate
+   */
+  private final MsaWSThread msaWSThread;
+
+  long lastChunk = 0;
+
+  /**
+   * input
+   */
+  ArrayList<SequenceI> seqs = new ArrayList<>();
+
+  /**
+   * output
+   */
+  AlignmentI alignment;
+
+  // set if the job didn't get run - then the input is simply returned to the
+  // user
+  private boolean returnInput = false;
+
+  /**
+   * MsaWSJob
+   * 
+   * @param jobNum
+   *          int
+   * @param msaWSThread
+   *          TODO - abstract the properties provided by the thread
+   * @param jobId
+   *          String
+   */
+  public MsaWSJob(MsaWSThread msaWSThread, int jobNum, SequenceI[] inSeqs)
+  {
+    this.msaWSThread = msaWSThread;
+    this.jobnum = jobNum;
+    if (!prepareInput(inSeqs, 2))
+    {
+      submitted = true;
+      subjobComplete = true;
+      returnInput = true;
+    } else
+    {
+      validInput = true;
+    }
+
+  }
+
+  Vector<String[]> emptySeqs = new Vector();
+
+  /**
+   * prepare input sequences for MsaWS service
+   * 
+   * @param seqs
+   *          jalview sequences to be prepared
+   * @param minlen
+   *          minimum number of residues required for this MsaWS service
+   * @return true if seqs contains sequences to be submitted to service.
+   */
+  // TODO: return compbio.seqs list or nothing to indicate validity.
+  private boolean prepareInput(SequenceI[] seqs, int minlen)
+  {
+    // TODO: service specific input data is generated in this method - for
+    // JABAWS it is client-side
+    // prepared, but for Slivka it could be uploaded at this stage.
+
+    int nseqs = 0;
+    if (minlen < 0)
+    {
+      throw new Error(MessageManager.getString(
+              "error.implementation_error_minlen_must_be_greater_zero"));
+    }
+    for (int i = 0; i < seqs.length; i++)
+    {
+      if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
+      {
+        nseqs++;
+      }
+    }
+    boolean valid = nseqs > 1; // need at least two seqs
+    Sequence seq;
+    for (int i = 0, n = 0; i < seqs.length; i++)
+    {
+      String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
+      // for
+      // any
+      // subjob
+      SeqNames.put(newname,
+              jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
+      if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
+      {
+        // make new input sequence with or without gaps
+        seq = new Sequence(newname,
+                (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
+                        : AlignSeq.extractGaps(
+                                jalview.util.Comparison.GapChars,
+                                seqs[i].getSequenceAsString()));
+        this.seqs.add(seq);
+      }
+      else
+      {
+        String empty = null;
+        if (seqs[i].getEnd() >= seqs[i].getStart())
+        {
+          empty = (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString()
+                  : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
+                          seqs[i].getSequenceAsString());
+        }
+        emptySeqs.add(new String[] { newname, empty });
+      }
+    }
+    return valid;
+  }
+
+  /**
+   * 
+   * @return true if getAlignment will return a valid alignment result.
+   */
+  @Override
+  public boolean hasResults()
+  {
+    if (subjobComplete && isFinished() && (alignment != null
+            || (emptySeqs != null && emptySeqs.size() > 0)))
+    {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * 
+   * get the alignment including any empty sequences in the original order
+   * with original ids. Caller must access the alignment.getMetadata() object
+   * to annotate the final result passsed to the user.
+   * 
+   * @return { SequenceI[], AlignmentOrder }
+   */
+  public Object[] getAlignment()
+  {
+    // TODO: make this generic based on MsaResultI
+    // TODO: decide if the data loss for this return signature is avoidable
+    // (ie should we just return AlignmentI instead ?)
+    if (hasResults())
+    {
+      SequenceI[] alseqs = null;
+      char alseq_gapchar = '-';
+      int alseq_l = 0;
+      alseqs = new SequenceI[alignment.getSequences().size()];
+      if (alignment.getSequences().size() > 0)
+      {
+        for (SequenceI seq : alignment
+                .getSequences())
+        {
+          alseqs[alseq_l++] = new Sequence(seq);
+        }
+        alseq_gapchar = alignment.getGapCharacter();
+
+      }
+      // add in the empty seqs.
+      if (emptySeqs.size() > 0)
+      {
+        SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
+        // get width
+        int i, w = 0;
+        if (alseq_l > 0)
+        {
+          for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
+          {
+            if (w < alseqs[i].getLength())
+            {
+              w = alseqs[i].getLength();
+            }
+            t_alseqs[i] = alseqs[i];
+            alseqs[i] = null;
+          }
+        }
+        // check that aligned width is at least as wide as emptySeqs width.
+        int ow = w, nw = w;
+        for (i = 0, w = emptySeqs.size(); i < w; i++)
+        {
+          String[] es = emptySeqs.get(i);
+          if (es != null && es[1] != null)
+          {
+            int sw = es[1].length();
+            if (nw < sw)
+            {
+              nw = sw;
+            }
+          }
+        }
+        // make a gapped string.
+        StringBuffer insbuff = new StringBuffer(w);
+        for (i = 0; i < nw; i++)
+        {
+          insbuff.append(alseq_gapchar);
+        }
+        if (ow < nw)
+        {
+          for (i = 0; i < alseq_l; i++)
+          {
+            int sw = t_alseqs[i].getLength();
+            if (nw > sw)
+            {
+              // pad at end
+              alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
+                      + insbuff.substring(0, sw - nw));
+            }
+          }
+        }
+        for (i = 0, w = emptySeqs.size(); i < w; i++)
+        {
+          String[] es = emptySeqs.get(i);
+          if (es[1] == null)
+          {
+            t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
+                    insbuff.toString(), 1, 0);
+          }
+          else
+          {
+            if (es[1].length() < nw)
+            {
+              t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
+                      es[0],
+                      es[1] + insbuff.substring(0, nw - es[1].length()),
+                      1, 1 + es[1].length());
+            }
+            else
+            {
+              t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
+                      es[0], es[1]);
+            }
+          }
+        }
+        alseqs = t_alseqs;
+      }
+      AlignmentOrder msaorder = new AlignmentOrder(alseqs);
+      // always recover the order - makes parseResult()'s life easier.
+      jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
+      // account for any missing sequences
+      jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
+      return new Object[] { alseqs, msaorder };
+    }
+    return null;
+  }
+
+  /**
+   * mark subjob as cancelled and set result object appropriatly
+   */
+  void cancel()
+  {
+    cancelled = true;
+    subjobComplete = true;
+    alignment = null;
+  }
+
+  /**
+   * 
+   * @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
+    // sequence alignment.
+    // TODO: check type of sequences are valid for this service
+    if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
+    {
+      return true;
+    }
+    return false;
+  }
+
+  StringBuffer jobProgress = new StringBuffer();
+
+  @Override
+  public void setStatus(String string)
+  {
+    jobProgress.setLength(0);
+    jobProgress.append(string);
+  }
+
+  @Override
+  public String getStatus()
+  {
+    return jobProgress.toString();
+  }
+
+  @Override
+  public boolean hasStatus()
+  {
+    return jobProgress != null;
+  }
+
+  /**
+   * @return the lastChunk
+   */
+  public long getLastChunk()
+  {
+    return lastChunk;
+  }
+
+  /**
+   * @param lastChunk
+   *          the lastChunk to set
+   */
+  public void setLastChunk(long lastChunk)
+  {
+    this.lastChunk = lastChunk;
+  }
+
+  String alignmentProgram = null;
+
+  public String getAlignmentProgram()
+  {
+    return alignmentProgram;
+  }
+
+  public boolean hasArguments()
+  {
+    return (arguments != null && arguments.size() > 0)
+            || (preset != null && preset instanceof JabaWsParamSet);
+  }
+
+  /**
+   * add a progess header to status string containing presets/args used
+   */
+  public void addInitialStatus()
+  {
+    // TODO: decide if it is useful to report 'JABAWS format' argument lists
+    // rather than generic Jalview service arguments
+    if (preset != null)
+    {
+      jobProgress.append(
+              "Using " + (preset.isModifiable() ? "Server" : "User")
+                      + "Preset: " + preset.getName());
+      for (ArgumentI opt : preset.getArguments())
+      {
+        jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
+      }
+    }
+    else
+    {
+      if (arguments != null && arguments.size() > 0)
+      {
+        jobProgress.append("With custom parameters : \n");
+        // merge arguments with preset's own arguments.
+        for (ArgumentI opt : arguments)
+        {
+          jobProgress.append(opt.getName() + " " + opt.getValue() + "\n");
+        }
+      }
+      jobProgress.append("\nJob Output:\n");
+    }
+  }
+}
\ No newline at end of file
similarity index 52%
rename from src/jalview/ws/jws2/MsaWSThread.java
rename to src/jalview/ws/gui/MsaWSThread.java
index db6e03f..7141e73 100644 (file)
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.ws.jws2;
+package jalview.ws.gui;
 
-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.HiddenColumns;
-import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.SplitFrame;
 import jalview.gui.WebserviceInfo;
 import jalview.util.MessageManager;
+import jalview.ws.AWSThread;
 import jalview.ws.AWsJob;
 import jalview.ws.JobStateSummary;
 import jalview.ws.WSClientI;
-import jalview.ws.jws2.dm.JabaWsParamSet;
+import jalview.ws.api.CancellableI;
+import jalview.ws.api.JobId;
+import jalview.ws.api.MultipleSequenceAlignmentI;
+import jalview.ws.gui.WsJob.JobState;
+import jalview.ws.params.ArgumentI;
 import jalview.ws.params.WsParamSetI;
 
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
-import java.util.Map;
-import java.util.Vector;
 
 import javax.swing.JInternalFrame;
 
-import compbio.data.msa.MsaWS;
-import compbio.metadata.Argument;
-import compbio.metadata.ChunkHolder;
-import compbio.metadata.JobStatus;
-import compbio.metadata.Preset;
-
-class MsaWSThread extends AWS2Thread implements WSClientI
+public class MsaWSThread extends AWSThread implements WSClientI
 {
   boolean submitGaps = false; // pass sequences including gaps to alignment
 
@@ -64,384 +58,13 @@ class MsaWSThread extends AWS2Thread implements WSClientI
 
   // order
 
-  class MsaWSJob extends JWs2Job
-  {
-    long lastChunk = 0;
-
-    WsParamSetI preset = null;
-
-    List<Argument> arguments = null;
-
-    /**
-     * input
-     */
-    ArrayList<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
-
-    /**
-     * output
-     */
-    compbio.data.sequence.Alignment alignment;
-
-    // set if the job didn't get run - then the input is simply returned to the
-    // user
-    private boolean returnInput = false;
-
-    /**
-     * MsaWSJob
-     * 
-     * @param jobNum
-     *          int
-     * @param jobId
-     *          String
-     */
-    public MsaWSJob(int jobNum, SequenceI[] inSeqs)
-    {
-      this.jobnum = jobNum;
-      if (!prepareInput(inSeqs, 2))
-      {
-        submitted = true;
-        subjobComplete = true;
-        returnInput = true;
-      }
-
-    }
-
-    Hashtable<String, Map> SeqNames = new Hashtable();
-
-    Vector<String[]> emptySeqs = new Vector();
-
-    /**
-     * prepare input sequences for MsaWS service
-     * 
-     * @param seqs
-     *          jalview sequences to be prepared
-     * @param minlen
-     *          minimum number of residues required for this MsaWS service
-     * @return true if seqs contains sequences to be submitted to service.
-     */
-    // TODO: return compbio.seqs list or nothing to indicate validity.
-    private boolean prepareInput(SequenceI[] seqs, int minlen)
-    {
-      int nseqs = 0;
-      if (minlen < 0)
-      {
-        throw new Error(MessageManager.getString(
-                "error.implementation_error_minlen_must_be_greater_zero"));
-      }
-      for (int i = 0; i < seqs.length; i++)
-      {
-        if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
-        {
-          nseqs++;
-        }
-      }
-      boolean valid = nseqs > 1; // need at least two seqs
-      compbio.data.sequence.FastaSequence seq;
-      for (int i = 0, n = 0; i < seqs.length; i++)
-      {
-
-        String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
-        // for
-        // any
-        // subjob
-        SeqNames.put(newname,
-                jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
-        if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
-        {
-          // make new input sequence with or without gaps
-          seq = new compbio.data.sequence.FastaSequence(newname,
-                  (submitGaps) ? seqs[i].getSequenceAsString()
-                          : AlignSeq.extractGaps(
-                                  jalview.util.Comparison.GapChars,
-                                  seqs[i].getSequenceAsString()));
-          this.seqs.add(seq);
-        }
-        else
-        {
-          String empty = null;
-          if (seqs[i].getEnd() >= seqs[i].getStart())
-          {
-            empty = (submitGaps) ? seqs[i].getSequenceAsString()
-                    : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
-                            seqs[i].getSequenceAsString());
-          }
-          emptySeqs.add(new String[] { newname, empty });
-        }
-      }
-      return valid;
-    }
-
-    /**
-     * 
-     * @return true if getAlignment will return a valid alignment result.
-     */
-    @Override
-    public boolean hasResults()
-    {
-      if (subjobComplete && isFinished() && (alignment != null
-              || (emptySeqs != null && emptySeqs.size() > 0)))
-      {
-        return true;
-      }
-      return false;
-    }
-
-    /**
-     * 
-     * get the alignment including any empty sequences in the original order
-     * with original ids. Caller must access the alignment.getMetadata() object
-     * to annotate the final result passsed to the user.
-     * 
-     * @return { SequenceI[], AlignmentOrder }
-     */
-    public Object[] getAlignment()
-    {
-      // is this a generic subjob or a Jws2 specific Object[] return signature
-      if (hasResults())
-      {
-        SequenceI[] alseqs = null;
-        char alseq_gapchar = '-';
-        int alseq_l = 0;
-        if (alignment.getSequences().size() > 0)
-        {
-          alseqs = new SequenceI[alignment.getSequences().size()];
-          for (compbio.data.sequence.FastaSequence seq : alignment
-                  .getSequences())
-          {
-            alseqs[alseq_l++] = new Sequence(seq.getId(),
-                    seq.getSequence());
-          }
-          alseq_gapchar = alignment.getMetadata().getGapchar();
-
-        }
-        // add in the empty seqs.
-        if (emptySeqs.size() > 0)
-        {
-          SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
-          // get width
-          int i, w = 0;
-          if (alseq_l > 0)
-          {
-            for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
-            {
-              if (w < alseqs[i].getLength())
-              {
-                w = alseqs[i].getLength();
-              }
-              t_alseqs[i] = alseqs[i];
-              alseqs[i] = null;
-            }
-          }
-          // check that aligned width is at least as wide as emptySeqs width.
-          int ow = w, nw = w;
-          for (i = 0, w = emptySeqs.size(); i < w; i++)
-          {
-            String[] es = emptySeqs.get(i);
-            if (es != null && es[1] != null)
-            {
-              int sw = es[1].length();
-              if (nw < sw)
-              {
-                nw = sw;
-              }
-            }
-          }
-          // make a gapped string.
-          StringBuffer insbuff = new StringBuffer(w);
-          for (i = 0; i < nw; i++)
-          {
-            insbuff.append(alseq_gapchar);
-          }
-          if (ow < nw)
-          {
-            for (i = 0; i < alseq_l; i++)
-            {
-              int sw = t_alseqs[i].getLength();
-              if (nw > sw)
-              {
-                // pad at end
-                alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
-                        + insbuff.substring(0, sw - nw));
-              }
-            }
-          }
-          for (i = 0, w = emptySeqs.size(); i < w; i++)
-          {
-            String[] es = emptySeqs.get(i);
-            if (es[1] == null)
-            {
-              t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
-                      insbuff.toString(), 1, 0);
-            }
-            else
-            {
-              if (es[1].length() < nw)
-              {
-                t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
-                        es[0],
-                        es[1] + insbuff.substring(0, nw - es[1].length()),
-                        1, 1 + es[1].length());
-              }
-              else
-              {
-                t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
-                        es[0], es[1]);
-              }
-            }
-          }
-          alseqs = t_alseqs;
-        }
-        AlignmentOrder msaorder = new AlignmentOrder(alseqs);
-        // always recover the order - makes parseResult()'s life easier.
-        jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
-        // account for any missing sequences
-        jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
-        return new Object[] { alseqs, msaorder };
-      }
-      return null;
-    }
-
-    /**
-     * mark subjob as cancelled and set result object appropriatly
-     */
-    void cancel()
-    {
-      cancelled = true;
-      subjobComplete = true;
-      alignment = null;
-    }
-
-    /**
-     * 
-     * @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
-      // sequence alignment.
-      if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ?
-      {
-        return true;
-      }
-      return false;
-    }
-
-    StringBuffer jobProgress = new StringBuffer();
-
-    public void setStatus(String string)
-    {
-      jobProgress.setLength(0);
-      jobProgress.append(string);
-    }
-
-    @Override
-    public String getStatus()
-    {
-      return jobProgress.toString();
-    }
-
-    @Override
-    public boolean hasStatus()
-    {
-      return jobProgress != null;
-    }
-
-    /**
-     * @return the lastChunk
-     */
-    public long getLastChunk()
-    {
-      return lastChunk;
-    }
-
-    /**
-     * @param lastChunk
-     *          the lastChunk to set
-     */
-    public void setLastChunk(long lastChunk)
-    {
-      this.lastChunk = lastChunk;
-    }
-
-    String alignmentProgram = null;
-
-    public String getAlignmentProgram()
-    {
-      return alignmentProgram;
-    }
-
-    public boolean hasArguments()
-    {
-      return (arguments != null && arguments.size() > 0)
-              || (preset != null && preset instanceof JabaWsParamSet);
-    }
-
-    public List<Argument> getJabaArguments()
-    {
-      List<Argument> newargs = new ArrayList<Argument>();
-      if (preset != null && preset instanceof JabaWsParamSet)
-      {
-        newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
-      }
-      if (arguments != null && arguments.size() > 0)
-      {
-        newargs.addAll(arguments);
-      }
-      return newargs;
-    }
-
-    /**
-     * add a progess header to status string containing presets/args used
-     */
-    public void addInitialStatus()
-    {
-      if (preset != null)
-      {
-        jobProgress.append("Using "
-                + (preset instanceof JabaPreset ? "Server" : "User")
-                + "Preset: " + preset.getName());
-        if (preset instanceof JabaWsParamSet)
-        {
-          for (Argument opt : ((JabaWsParamSet) preset).getjabaArguments())
-          {
-            jobProgress.append(
-                    opt.getName() + " " + opt.getDefaultValue() + "\n");
-          }
-        }
-      }
-      if (arguments != null && arguments.size() > 0)
-      {
-        jobProgress.append("With custom parameters : \n");
-        // merge arguments with preset's own arguments.
-        for (Argument opt : arguments)
-        {
-          jobProgress.append(
-                  opt.getName() + " " + opt.getDefaultValue() + "\n");
-        }
-      }
-      jobProgress.append("\nJob Output:\n");
-    }
-
-    public boolean isPresetJob()
-    {
-      return preset != null && preset instanceof JabaPreset;
-    }
-
-    public Preset getServerPreset()
-    {
-      return (isPresetJob()) ? ((JabaPreset) preset).p : null;
-    }
-  }
-
   String alTitle; // name which will be used to form new alignment window.
 
   AlignmentI dataset; // dataset to which the new alignment will be
 
   // associated.
 
-  @SuppressWarnings("unchecked")
-  MsaWS server = null;
+  MultipleSequenceAlignmentI server = null;
 
   /**
    * set basic options for this (group) of Msa jobs
@@ -451,7 +74,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI
    * @param presorder
    *          boolean
    */
-  private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo,
+  private MsaWSThread(MultipleSequenceAlignmentI server, String wsUrl,
+          WebserviceInfo wsinfo,
           jalview.gui.AlignFrame alFrame, AlignmentView alview,
           String wsname, boolean subgaps, boolean presorder)
   {
@@ -462,7 +86,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
   }
 
   /**
-   * create one or more Msa jobs to align visible seuqences in _msa
+   * create one or more Msa jobs to align visible sequences in _msa
    * 
    * @param title
    *          String
@@ -475,7 +99,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI
    * @param seqset
    *          Alignment
    */
-  MsaWSThread(MsaWS server2, WsParamSetI preset, List<Argument> paramset,
+  public MsaWSThread(MultipleSequenceAlignmentI server2, WsParamSetI preset,
+          List<ArgumentI> paramset,
           String wsUrl, WebserviceInfo wsinfo,
           jalview.gui.AlignFrame alFrame, String wsname, String title,
           AlignmentView _msa, boolean subgaps, boolean presorder,
@@ -490,23 +115,23 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     if (conmsa != null)
     {
       int nvalid = 0, njobs = conmsa.length;
-      jobs = new MsaWSJob[njobs];
+      jobs = new AWsJob[njobs];
       for (int j = 0; j < njobs; j++)
       {
         if (j != 0)
         {
-          jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
+          jobs[j] = new MsaWSJob(this, wsinfo.addJobPane(), conmsa[j]);
         }
         else
         {
-          jobs[j] = new MsaWSJob(0, conmsa[j]);
+          jobs[j] = new MsaWSJob(this, 0, conmsa[j]);
         }
-        if (((MsaWSJob) jobs[j]).hasValidInput())
+        if (jobs[j].hasValidInput())
         {
           nvalid++;
         }
-        ((MsaWSJob) jobs[j]).preset = preset;
-        ((MsaWSJob) jobs[j]).arguments = paramset;
+        jobs[j].setPreset(preset);
+        jobs[j].setArguments(paramset);
         ((MsaWSJob) jobs[j]).alignmentProgram = wsname;
         if (njobs > 0)
         {
@@ -533,12 +158,14 @@ class MsaWSThread extends AWS2Thread implements WSClientI
   @Override
   public boolean isCancellable()
   {
-    return true;
+    return server instanceof CancellableI;
   }
 
   @Override
   public void cancelJob()
   {
+    // TODO decide if when some jobs are not cancellable to shut down the thread
+    // anyhow ?
     if (!jobComplete && jobs != null)
     {
       boolean cancelled = true;
@@ -549,13 +176,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI
           String cancelledMessage = "";
           try
           {
-            boolean cancelledJob = server.cancelJob(jobs[job].getJobId());
-            if (true) // cancelledJob || true)
+            CancellableI service = (CancellableI) server;
+            boolean cancelledJob = service.cancel((WsJob) jobs[job]);
+            if (cancelledJob)
             {
               // CANCELLED_JOB
-              // if the Jaba server indicates the job can't be cancelled, its
-              // because its running on the server's local execution engine
-              // so we just close the window anyway.
               cancelledMessage = "Job cancelled.";
               ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this
                                                // ugliness -
@@ -615,42 +240,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     // this is standard code, but since the interface doesn't comprise of a
     // basic one that implements (getJobStatus, pullExecStatistics) we have to
     // repeat the code for all jw2s services.
-    j.setjobStatus(server.getJobStatus(job.getJobId()));
-    updateJobProgress(j);
-  }
-
-  /**
-   * 
-   * @param j
-   * @return true if more job progress data was available
-   * @throws Exception
-   */
-  protected boolean updateJobProgress(MsaWSJob j) throws Exception
-  {
-    StringBuffer response = j.jobProgress;
-    long lastchunk = j.getLastChunk();
-    boolean changed = false;
-    do
-    {
-      j.setLastChunk(lastchunk);
-      ChunkHolder chunk = server.pullExecStatistics(j.getJobId(),
-              lastchunk);
-      if (chunk != null)
-      {
-        changed |= chunk.getChunk().length() > 0;
-        response.append(chunk.getChunk());
-        lastchunk = chunk.getNextPosition();
-        try
-        {
-          Thread.sleep(50);
-        } catch (InterruptedException x)
-        {
-        }
-        ;
-      }
-      ;
-    } while (lastchunk >= 0 && j.getLastChunk() != lastchunk);
-    return changed;
+    server.updateStatus(j);
+    server.updateJobProgress(j);
   }
 
   @Override
@@ -679,26 +270,37 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     if (j.seqs == null || j.seqs.size() == 0)
     {
       // special case - selection consisted entirely of empty sequences...
-      j.setjobStatus(JobStatus.FINISHED);
+      j.setState(JobState.FINISHED);
       j.setStatus(MessageManager.getString("label.empty_alignment_job"));
     }
     try
     {
       j.addInitialStatus(); // list the presets/parameters used for the job in
                             // status
-      if (j.isPresetJob())
+      try
       {
-        j.setJobId(server.presetAlign(j.seqs, j.getServerPreset()));
-      }
-      else if (j.hasArguments())
-      {
-        j.setJobId(server.customAlign(j.seqs, j.getJabaArguments()));
-      }
-      else
+        JobId jobHandle = server.align(j.seqs, j.getPreset(),
+                j.getArguments());
+        if (jobHandle != null)
+        {
+          j.setJobHandle(jobHandle);
+        }
+
+      } catch (Throwable throwable)
       {
-        j.setJobId(server.align(j.seqs));
+        if (!server.handleSubmitError(throwable, j, wsInfo))
+        {
+          if (throwable instanceof Exception)
+          {
+            throw ((Exception) throwable);
+          }
+          if (throwable instanceof Error)
+          {
+            throw ((Error) throwable);
+          }
+        }
       }
-
+      ///// generic
       if (j.getJobId() != null)
       {
         j.setSubmitted(true);
@@ -713,40 +315,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI
                 new String[]
                 { WsUrl }));
       }
-    } catch (compbio.metadata.UnsupportedRuntimeException _lex)
-    {
-      lex = _lex;
-      wsInfo.appendProgressText(MessageManager.formatMessage(
-              "info.job_couldnt_be_run_server_doesnt_support_program",
-              new String[]
-              { _lex.getMessage() }));
-      wsInfo.warnUser(_lex.getMessage(),
-              MessageManager.getString("warn.service_not_supported"));
-      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
-      wsInfo.setStatus(j.getJobnum(),
-              WebserviceInfo.STATE_STOPPED_SERVERERROR);
-    } catch (compbio.metadata.LimitExceededException _lex)
-    {
-      lex = _lex;
-      wsInfo.appendProgressText(MessageManager.formatMessage(
-              "info.job_couldnt_be_run_exceeded_hard_limit", new String[]
-              { _lex.getMessage() }));
-      wsInfo.warnUser(_lex.getMessage(),
-              MessageManager.getString("warn.input_is_too_big"));
-      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
-      wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
-    } catch (compbio.metadata.WrongParameterException _lex)
-    {
-      lex = _lex;
-      wsInfo.warnUser(_lex.getMessage(),
-              MessageManager.getString("warn.invalid_job_param_set"));
-      wsInfo.appendProgressText(MessageManager.formatMessage(
-              "info.job_couldnt_be_run_incorrect_param_setting",
-              new String[]
-              { _lex.getMessage() }));
-      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
-      wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
-    } catch (Error e)
+    }
+    //// jabaws specific
+
+    //// generic
+    catch (Error e)
     {
       // For unexpected errors
       System.err.println(WebServiceName
@@ -802,7 +375,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
           {
             try
             {
-              jpchanged = updateJobProgress(msjob);
+              jpchanged = server.updateJobProgress(msjob);
               jpex = false;
               if (jpchanged)
               {
@@ -843,25 +416,18 @@ class MsaWSThread extends AWS2Thread implements WSClientI
             System.out.println("*** End of status");
 
           }
+          ///// jabaws specific(ish) Get Result from Server when available
           try
           {
-            msjob.alignment = server.getResult(msjob.getJobId());
-          } catch (compbio.metadata.ResultNotAvailableException e)
-          {
-            // job has failed for some reason - probably due to invalid
-            // parameters
-            Cache.log.debug(
-                    "Results not available for finished job - marking as broken job.",
-                    e);
-            msjob.jobProgress.append(
-                    "\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
-                            + e.getLocalizedMessage());
-            msjob.setjobStatus(JobStatus.FAILED);
+            msjob.alignment = server.getAlignmentFor(msjob.getJobHandle());
           } catch (Exception e)
           {
-            Cache.log.error("Couldn't get Alignment for job.", e);
-            // TODO: Increment count and retry ?
-            msjob.setjobStatus(JobStatus.UNDEFINED);
+            if (!server.handleCollectionException(e, msjob, wsInfo))
+            {
+              Cache.log.error("Couldn't get Alignment for job.", e);
+              // TODO: Increment count and retry ?
+              msjob.setState(JobState.SERVERERROR);
+            }
           }
         }
         finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
@@ -869,19 +435,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI
                 && jobs[j].hasResults())
         {
           results++;
-          compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment;
-          if (alignment != null)
-          {
-            // server.close(jobs[j].getJobnum());
-            // wsInfo.appendProgressText(jobs[j].getJobnum(),
-            // "\nAlignment Object Method Notes\n");
-            // wsInfo.appendProgressText(jobs[j].getJobnum(),
-            // "Calculated with
-            // "+alignment.getMetadata().getProgram().toString());
-            // JBPNote The returned files from a webservice could be
-            // hidden behind icons in the monitor window that,
-            // when clicked, pop up their corresponding data
-          }
         }
       }
     } catch (Exception ex)
@@ -931,7 +484,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
   void displayResults(boolean newFrame)
   {
     // view input or result data for each block
-    List<AlignmentOrder> alorders = new ArrayList<AlignmentOrder>();
+    List<AlignmentOrder> alorders = new ArrayList<>();
     SequenceI[][] results = new SequenceI[jobs.length][];
     AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
     String lastProgram = null;
@@ -981,7 +534,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     if (newFrame)
     {
       displayInNewFrame(al, alorders, hidden);
-
     }
     else
     {
@@ -1077,7 +629,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI
     else
     {
       // construct a non-redundant ordering set
-      List<String> names = new ArrayList<String>();
+      List<String> names = new ArrayList<>();
       for (int i = 0, l = alorders.size(); i < l; i++)
       {
         String orderName = " Region " + i;
diff --git a/src/jalview/ws/gui/WsJob.java b/src/jalview/ws/gui/WsJob.java
new file mode 100644 (file)
index 0000000..e5af8c1
--- /dev/null
@@ -0,0 +1,200 @@
+/**
+ * 
+ */
+package jalview.ws.gui;
+
+import jalview.ws.AWsJob;
+import jalview.ws.api.JobId;
+
+/**
+ * Bean that holds state for a job
+ * 
+ * @author jprocter
+ *
+ */
+public class WsJob extends AWsJob
+{
+
+  public enum JobState
+  {
+    INVALID, READY, SUBMITTED, QUEUED, RUNNING, FINISHED, BROKEN, FAILED,
+    UNKNOWN, SERVERERROR, CANCELLED;
+  };
+
+  JobState state = JobState.UNKNOWN;
+
+  boolean hasResults = false, validInput = false;
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#hasResults()
+   */
+  @Override
+  public boolean hasResults()
+  {
+    return hasResults;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#hasValidInput()
+   */
+  @Override
+  public boolean hasValidInput()
+  {
+    return validInput;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isRunning()
+   */
+  @Override
+  public boolean isRunning()
+  {
+    return JobState.RUNNING.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isQueued()
+   */
+  @Override
+  public boolean isQueued()
+  {
+    return JobState.QUEUED.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isFinished()
+   */
+  @Override
+  public boolean isFinished()
+  {
+    // TODO isSubjobComplete and finished flags mean same thing ?
+    return JobState.FINISHED.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isFailed()
+   */
+  @Override
+  public boolean isFailed()
+  {
+    return JobState.FAILED.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isBroken()
+   */
+  @Override
+  public boolean isBroken()
+  {
+    return JobState.BROKEN.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#isServerError()
+   */
+  @Override
+  public boolean isServerError()
+  {
+    return JobState.SERVERERROR.equals(state);
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#hasStatus()
+   */
+  @Override
+  public boolean hasStatus()
+  {
+    return status != null && status.length() > 0;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#getStatus()
+   */
+  @Override
+  public String getStatus()
+  {
+    return status;
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#hasResponse()
+   */
+  @Override
+  public boolean hasResponse()
+  {
+    // TODO Auto-generated method stub
+    return hasStatus();
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#clearResponse()
+   */
+  @Override
+  public void clearResponse()
+  {
+    status = "";
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.ws.AWsJob#getState()
+   */
+  @Override
+  public String getState()
+  {
+    return state.toString();
+  }
+
+  /**
+   * @return the current JobState
+   */
+  public JobState getJobState()
+  {
+    return state;
+  }
+
+  /**
+   * set the job state
+   * 
+   * @param state
+   */
+  public void setState(JobState state)
+  {
+    this.state = state;
+  }
+
+  String status = "";
+
+  /**
+   * Set the log for this job
+   * 
+   * @parag log
+   */
+  public void setStatus(String log)
+  {
+    status = log;
+
+  }
+
+  /*
+   * bean holding submission info for a next-gen ws job 
+   */
+  JobId jobHandle = null;
+
+  /**
+   * stash the handle for the job and mark it as submitted
+   * 
+   * @param align
+   */
+  public void setJobHandle(JobId align)
+  {
+    jobHandle = align;
+    setJobId(jobHandle.getJobId());
+    submitted = true;
+
+  }
+
+  public JobId getJobHandle()
+  {
+    return jobHandle;
+  }
+
+}
index 66569af..7d1b0f5 100644 (file)
@@ -29,9 +29,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.descriptor.BodyDescriptor;
 import org.apache.james.mime4j.parser.ContentHandler;
-import org.apache.james.mime4j.parser.Field;
+import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.Field;
 
 /**
  * ContentHandler for parsing mime encoded messages into Jalview objects. TODO:
@@ -71,7 +71,7 @@ public class JalviewMimeContentHandler implements ContentHandler
   /**
    * sources for data to be parsed
    */
-  List<DataProvider> dataItems = new ArrayList<DataProvider>();
+  List<DataProvider> dataItems = new ArrayList<>();
 
   @Override
   public void body(BodyDescriptor arg0, InputStream arg1)
@@ -176,5 +176,4 @@ public class JalviewMimeContentHandler implements ContentHandler
     // TODO Auto-generated method stub
     return null;
   }
-
 }
index 59843f2..9a6c445 100644 (file)
@@ -30,6 +30,7 @@ import ext.vamsas.IRegistryServiceLocator;
 import ext.vamsas.RegistryServiceSoapBindingStub;
 import ext.vamsas.ServiceHandle;
 import ext.vamsas.ServiceHandles;
+import jalview.bin.Cache;
 import jalview.bin.ApplicationSingletonProvider;
 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
 import jalview.gui.JvOptionPane;
@@ -401,17 +402,9 @@ public class Discoverer implements Runnable, ApplicationSingletonI
   @Override
   public void run()
   {
-    final Discoverer discoverer = this;
-    Thread discoverThread = new Thread()
-    {
-      @Override
-      public void run()
-      {
-        Discoverer.doDiscovery();
-        discoverer.discoverServices();
-      }
-    };
-    discoverThread.start();
+    Cache.log.info("Discovering jws1 services");
+    Discoverer.doDiscovery();
+    discoverServices();
   }
 
   /**
index e97d309..4c78339 100644 (file)
@@ -51,8 +51,6 @@ public class MsaWSClient extends WS1Client
    */
   ext.vamsas.MuscleWS server;
 
-  AlignFrame alignFrame;
-
   /**
    * Creates a new MsaWSClient object that uses a service given by an externally
    * retrieved ServiceHandle
index 006f014..7b3df82 100644 (file)
@@ -36,7 +36,6 @@ import jalview.ws.AWsJob;
 import jalview.ws.JobStateSummary;
 import jalview.ws.WSClientI;
 
-import java.util.Hashtable;
 import java.util.Vector;
 
 import vamsas.objects.simple.MsaResult;
@@ -78,8 +77,6 @@ class MsaWSThread extends JWS1Thread implements WSClientI
 
     }
 
-    Hashtable SeqNames = new Hashtable();
-
     Vector emptySeqs = new Vector();
 
     /**
index cb965f0..ba3b168 100644 (file)
@@ -56,8 +56,6 @@ public class SeqSearchWSClient extends WS1Client
    */
   ext.vamsas.SeqSearchI server;
 
-  AlignFrame alignFrame;
-
   /**
    * Creates a new MsaWSClient object that uses a service given by an externally
    * retrieved ServiceHandle
index 761b758..2f2bf2c 100644 (file)
@@ -37,7 +37,6 @@ import jalview.ws.JobStateSummary;
 import jalview.ws.WSClientI;
 
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Map;
 import java.util.Vector;
 
@@ -77,8 +76,6 @@ class SeqSearchWSThread extends JWS1Thread implements WSClientI
 
     }
 
-    Hashtable SeqNames = new Hashtable();
-
     Vector emptySeqs = new Vector();
 
     /**
diff --git a/src/jalview/ws/jws2/AAConClient.java b/src/jalview/ws/jws2/AAConClient.java
deleted file mode 100644 (file)
index 327864a..0000000
+++ /dev/null
@@ -1,131 +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.jws2;
-
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.gui.AlignFrame;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
-import jalview.ws.uimodel.AlignAnalysisUIText;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import compbio.data.sequence.FastaSequence;
-import compbio.data.sequence.Score;
-import compbio.metadata.Argument;
-
-public class AAConClient extends JabawsCalcWorker
-{
-
-  public AAConClient(Jws2Instance service, AlignFrame alignFrame,
-          WsParamSetI preset, List<Argument> paramset)
-  {
-    super(service, alignFrame, preset, paramset);
-    submitGaps = true;
-    alignedSeqs = true;
-    nucleotidesAllowed = false;
-    proteinAllowed = true;
-    filterNonStandardResidues = true;
-    gapMap = new boolean[0];
-    initViewportParams();
-  }
-
-  @Override
-  public String getServiceActionText()
-  {
-    return "calculating Amino acid consensus using AACon service";
-  }
-
-  /**
-   * update the consensus annotation from the sequence profile data using
-   * current visualization settings.
-   */
-
-  @Override
-  public void updateResultAnnotation(boolean immediate)
-  {
-    if (immediate || !calcMan.isWorking(this) && scoremanager != null)
-    {
-      Map<String, TreeSet<Score>> scoremap = scoremanager.asMap();
-      int alWidth = alignViewport.getAlignment().getWidth();
-      ArrayList<AlignmentAnnotation> ourAnnot = new ArrayList<>();
-      for (String score : scoremap.keySet())
-      {
-        Set<Score> scores = scoremap.get(score);
-        for (Score scr : scores)
-        {
-          if (scr.getRanges() != null && scr.getRanges().size() > 0)
-          {
-            /**
-             * annotation in range annotation = findOrCreate(scr.getMethod(),
-             * true, null, null); Annotation[] elm = new Annotation[alWidth];
-             * Iterator<Float> vals = scr.getScores().iterator(); for (Range rng
-             * : scr.getRanges()) { float val = vals.next().floatValue(); for
-             * (int i = rng.from; i <= rng.to; i++) { elm[i] = new
-             * Annotation("", "", ' ', val); } } annotation.annotations = elm;
-             * annotation.validateRangeAndDisplay();
-             */
-          }
-          else
-          {
-            createAnnotationRowsForScores(ourAnnot, getCalcId(), alWidth,
-                    scr);
-          }
-        }
-      }
-
-      if (ourAnnot.size() > 0)
-      {
-        updateOurAnnots(ourAnnot);
-      }
-    }
-  }
-
-  @Override
-  boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
-  {
-    return (seqs.size() > 1);
-  }
-
-  @Override
-  public String getCalcId()
-  {
-    return CALC_ID;
-  }
-
-  private static String CALC_ID = "jabaws2.AACon";
-
-  public static AlignAnalysisUIText getAlignAnalysisUITest()
-  {
-    return new AlignAnalysisUIText(
-            compbio.ws.client.Services.AAConWS.toString(),
-            jalview.ws.jws2.AAConClient.class, CALC_ID, false, true, true,
-            MessageManager.getString("label.aacon_calculations"),
-            MessageManager.getString("tooltip.aacon_calculations"),
-            MessageManager.getString("label.aacon_settings"),
-            MessageManager.getString("tooltip.aacon_settings"));
-  }
-}
diff --git a/src/jalview/ws/jws2/AADisorderClient.java b/src/jalview/ws/jws2/AADisorderClient.java
deleted file mode 100644 (file)
index a1b8e7a..0000000
+++ /dev/null
@@ -1,382 +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.jws2;
-
-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.FeatureColour;
-import jalview.util.ColorUtils;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import compbio.data.sequence.FastaSequence;
-import compbio.data.sequence.Range;
-import compbio.data.sequence.Score;
-import compbio.data.sequence.ScoreManager.ScoreHolder;
-import compbio.metadata.Argument;
-
-public class AADisorderClient extends JabawsCalcWorker
-{
-
-  private static final String THRESHOLD = "THRESHOLD";
-
-  private static final String RANGE = "RANGE";
-
-  String typeName;
-
-  String methodName;
-
-  String groupName;
-
-  AlignFrame af;
-
-  public AADisorderClient(Jws2Instance sh, AlignFrame alignFrame,
-          WsParamSetI thePreset, List<Argument> paramset)
-  {
-    super(sh, alignFrame, thePreset, paramset);
-    af = alignFrame;
-    typeName = sh.action;
-    methodName = sh.serviceType;
-
-    submitGaps = false;
-    alignedSeqs = false;
-    nucleotidesAllowed = false;
-    proteinAllowed = true;
-    bySequence = true;
-  }
-
-  @Override
-  public String getServiceActionText()
-  {
-    return "Submitting amino acid sequences for disorder prediction.";
-  }
-
-  @Override
-  boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
-  {
-    return (seqs.size() > 0);
-  }
-
-  private static Map<String, Map<String, String[]>> featureMap;
-
-  private static Map<String, Map<String, Map<String, Object>>> annotMap;
-
-  private static String DONTCOMBINE = "DONTCOMBINE";
-
-  private static String INVISIBLE = "INVISIBLE";
-  static
-  {
-    // TODO: turn this into some kind of configuration file that's a bit easier
-    // to edit
-    featureMap = new HashMap<>();
-    Map<String, String[]> fmap;
-    featureMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            fmap = new HashMap<>());
-    fmap.put("Glob",
-            new String[]
-            { "Globular Domain", "Predicted globular domain" });
-    featureMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            fmap = new HashMap<>());
-    featureMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            fmap = new HashMap<>());
-    fmap.put("REM465", new String[] { "REM465", "Missing density" });
-    fmap.put("HOTLOOPS", new String[] { "HOTLOOPS", "Flexible loops" });
-    fmap.put("COILS", new String[] { "COILS", "Random coil" });
-    featureMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            fmap = new HashMap<>());
-    fmap.put("GlobDoms",
-            new String[]
-            { "Globular Domain", "Predicted globular domain" });
-    fmap.put("Disorder",
-            new String[]
-            { "Protein Disorder", "Probable unstructured peptide region" });
-    Map<String, Map<String, Object>> amap;
-    annotMap = new HashMap<>();
-    annotMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
-            amap = new HashMap<>());
-    amap.put("Dydx", new HashMap<String, Object>());
-    amap.get("Dydx").put(DONTCOMBINE, DONTCOMBINE);
-    amap.get("Dydx").put(THRESHOLD, new double[] { 1, 0 });
-    amap.get("Dydx").put(RANGE, new float[] { -1, +1 });
-
-    amap.put("SmoothedScore", new HashMap<String, Object>());
-    amap.get("SmoothedScore").put(INVISIBLE, INVISIBLE);
-    amap.put("RawScore", new HashMap<String, Object>());
-    amap.get("RawScore").put(INVISIBLE, INVISIBLE);
-    annotMap.put(compbio.ws.client.Services.DisemblWS.toString(),
-            amap = new HashMap<>());
-    amap.put("COILS", new HashMap<String, Object>());
-    amap.put("HOTLOOPS", new HashMap<String, Object>());
-    amap.put("REM465", new HashMap<String, Object>());
-    amap.get("COILS").put(THRESHOLD, new double[] { 1, 0.516 });
-    amap.get("COILS").put(RANGE, new float[] { 0, 1 });
-
-    amap.get("HOTLOOPS").put(THRESHOLD, new double[] { 1, 0.6 });
-    amap.get("HOTLOOPS").put(RANGE, new float[] { 0, 1 });
-    amap.get("REM465").put(THRESHOLD, new double[] { 1, 0.1204 });
-    amap.get("REM465").put(RANGE, new float[] { 0, 1 });
-
-    annotMap.put(compbio.ws.client.Services.IUPredWS.toString(),
-            amap = new HashMap<>());
-    amap.put("Long", new HashMap<String, Object>());
-    amap.put("Short", new HashMap<String, Object>());
-    amap.get("Long").put(THRESHOLD, new double[] { 1, 0.5 });
-    amap.get("Long").put(RANGE, new float[] { 0, 1 });
-    amap.get("Short").put(THRESHOLD, new double[] { 1, 0.5 });
-    amap.get("Short").put(RANGE, new float[] { 0, 1 });
-    annotMap.put(compbio.ws.client.Services.JronnWS.toString(),
-            amap = new HashMap<>());
-    amap.put("JRonn", new HashMap<String, Object>());
-    amap.get("JRonn").put(THRESHOLD, new double[] { 1, 0.5 });
-    amap.get("JRonn").put(RANGE, new float[] { 0, 1 });
-  }
-
-  @Override
-  public void updateResultAnnotation(boolean immediate)
-  {
-
-    if (immediate || !calcMan.isWorking(this) && scoremanager != null)
-    {
-      Map<String, String[]> featureTypeMap = featureMap
-              .get(service.serviceType);
-      Map<String, Map<String, Object>> annotTypeMap = annotMap
-              .get(service.serviceType);
-      boolean dispFeatures = false;
-      Map<String, Object> fc = new Hashtable<>();
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
-      /**
-       * grouping for any annotation rows created
-       */
-      int graphGroup = 1;
-      if (alignViewport.getAlignment().getAlignmentAnnotation() != null)
-      {
-        for (AlignmentAnnotation ala : alignViewport.getAlignment()
-                .getAlignmentAnnotation())
-        {
-          if (ala.graphGroup > graphGroup)
-          {
-            graphGroup = ala.graphGroup;
-          }
-        }
-      }
-
-      for (String seqId : seqNames.keySet())
-      {
-        boolean sameGroup = false;
-        SequenceI dseq, aseq, seq = seqNames.get(seqId);
-        int base = seq.findPosition(start) - 1;
-        aseq = seq;
-        while ((dseq = seq).getDatasetSequence() != null)
-        {
-          seq = seq.getDatasetSequence();
-        }
-        ScoreHolder scores = null;
-        try
-        {
-          scores = scoremanager.getAnnotationForSequence(seqId);
-        } catch (Exception q)
-        {
-          Cache.log
-                  .info("Couldn't recover disorder prediction for sequence "
-                          + seq.getName() + "(Prediction name was " + seqId
-                          + ")"
-                          + "\nSee http://issues.jalview.org/browse/JAL-1319 for one possible reason why disorder predictions might fail.");
-        }
-        float last = Float.NaN, val = Float.NaN;
-        int lastAnnot = ourAnnot.size();
-        if (scores != null && scores.scores != null)
-        {
-          for (Score scr : scores.scores)
-          {
-
-            if (scr.getRanges() != null && scr.getRanges().size() > 0)
-            {
-              Iterator<Float> vals = scr.getScores().iterator();
-              // make features on sequence
-              for (Range rn : scr.getRanges())
-              {
-
-                SequenceFeature sf;
-                String[] type = featureTypeMap.get(scr.getMethod());
-                if (type == null)
-                {
-                  // create a default type for this feature
-                  type = new String[] {
-                      typeName + " (" + scr.getMethod() + ")",
-                      service.getActionText() };
-                }
-                if (vals.hasNext())
-                {
-                  val = vals.next().floatValue();
-                  sf = new SequenceFeature(type[0], type[1],
-                          base + rn.from, base + rn.to, val, methodName);
-                }
-                else
-                {
-                  sf = new SequenceFeature(type[0], type[1],
-                          base + rn.from, base + rn.to, methodName);
-                }
-                dseq.addSequenceFeature(sf);
-                if (last != val && !Float.isNaN(last))
-                {
-                  fc.put(sf.getType(), sf);
-                }
-                last = val;
-                dispFeatures = true;
-              }
-            }
-            else
-            {
-              if (scr.getScores().size() == 0)
-              {
-                continue;
-              }
-              String typename, calcName;
-              AlignmentAnnotation annot = createAnnotationRowsForScores(
-                      ourAnnot,
-                      typename = service.serviceType + " ("
-                              + scr.getMethod() + ")",
-                      calcName = service.getServiceTypeURI() + "/"
-                              + scr.getMethod(),
-                      aseq, base + 1, scr);
-              annot.graph = AlignmentAnnotation.LINE_GRAPH;
-
-              Map<String, Object> styleMap = (annotTypeMap == null) ? null
-                      : annotTypeMap.get(scr.getMethod());
-
-              annot.visible = (styleMap == null
-                      || styleMap.get(INVISIBLE) == null);
-              double[] thrsh = (styleMap == null) ? null
-                      : (double[]) styleMap.get(THRESHOLD);
-              float[] range = (styleMap == null) ? null
-                      : (float[]) styleMap.get(RANGE);
-              if (range != null)
-              {
-                annot.graphMin = range[0];
-                annot.graphMax = range[1];
-              }
-              if (styleMap == null || styleMap.get(DONTCOMBINE) == null)
-              {
-                {
-                  if (!sameGroup)
-                  {
-                    graphGroup++;
-                    sameGroup = true;
-                  }
-
-                  annot.graphGroup = graphGroup;
-                }
-              }
-
-              annot.description = "<html>" + service.getActionText()
-                      + " - raw scores";
-              if (thrsh != null)
-              {
-                String threshNote = (thrsh[0] > 0 ? "Above " : "Below ")
-                        + thrsh[1] + " indicates disorder";
-                annot.threshold = new GraphLine((float) thrsh[1],
-                        threshNote, Color.red);
-                annot.description += "<br/>" + threshNote;
-              }
-              annot.description += "</html>";
-              Color col = ColorUtils
-                      .createColourFromName(typeName + scr.getMethod());
-              for (int p = 0, ps = annot.annotations.length; p < ps; p++)
-              {
-                if (annot.annotations[p] != null)
-                {
-                  annot.annotations[p].colour = col;
-                }
-              }
-              annot._linecolour = col;
-              // finally, update any dataset annotation
-              replaceAnnotationOnAlignmentWith(annot, typename, calcName,
-                      aseq);
-            }
-          }
-        }
-        if (lastAnnot + 1 == ourAnnot.size())
-        {
-          // remove singleton alignment annotation row
-          ourAnnot.get(lastAnnot).graphGroup = -1;
-        }
-      }
-      {
-        if (dispFeatures)
-        {
-          jalview.api.FeatureRenderer fr = ((jalview.gui.AlignmentPanel) ap)
-                  .cloneFeatureRenderer();
-          for (String ft : fc.keySet())
-          {
-            FeatureColourI gc = fr.getFeatureStyle(ft);
-            if (gc.isSimpleColour())
-            {
-              // set graduated color as fading to white for minimum, and
-              // autoscaling to values on alignment
-              FeatureColourI ggc = new FeatureColour(gc.getColour(),
-                      Color.white, gc.getColour(), Color.white,
-                      Float.MIN_VALUE, Float.MAX_VALUE);
-              ggc.setAutoScaled(true);
-              fr.setColour(ft, ggc);
-            }
-          }
-          // TODO: JAL-1150 - create sequence feature settings API for defining
-          // styles and enabling/disabling feature overlay on alignment panel
-          ((jalview.gui.AlignmentPanel) ap).updateFeatureRendererFrom(fr);
-          if (af.alignPanel == ap)
-          {
-            // only do this if the alignFrame is currently showing this view.
-            af.setShowSeqFeatures(true);
-          }
-        }
-        if (ourAnnot.size() > 0)
-        {
-          // Modify the visible annotation on the alignment viewport with the
-          // new alignment annotation rows created.
-          updateOurAnnots(ourAnnot);
-          ap.adjustAnnotationHeight();
-          ap.paintAlignment(true, true);
-        }
-      }
-    }
-  }
-
-  @Override
-  public String getCalcId()
-  {
-    // Disorder predictions are not dynamically updated so we return null
-    return null;
-  }
-
-}
diff --git a/src/jalview/ws/jws2/AbstractJabaCalcWorker.java b/src/jalview/ws/jws2/AbstractJabaCalcWorker.java
deleted file mode 100644 (file)
index dd64e77..0000000
+++ /dev/null
@@ -1,658 +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.jws2;
-
-import jalview.analysis.AlignSeq;
-import jalview.analysis.SeqsetUtils;
-import jalview.api.AlignViewportI;
-import jalview.api.AlignmentViewPanel;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.AlignmentI;
-import jalview.datamodel.AnnotatedCollectionI;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignFrame;
-import jalview.gui.IProgressIndicator;
-import jalview.gui.IProgressIndicatorHandler;
-import jalview.schemes.ResidueProperties;
-import jalview.workers.AlignCalcWorker;
-import jalview.ws.jws2.dm.AAConSettings;
-import jalview.ws.jws2.dm.JabaWsParamSet;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import compbio.data.sequence.FastaSequence;
-import compbio.metadata.Argument;
-import compbio.metadata.ChunkHolder;
-import compbio.metadata.JobStatus;
-import compbio.metadata.JobSubmissionException;
-import compbio.metadata.Option;
-import compbio.metadata.ResultNotAvailableException;
-
-public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
-{
-
-  protected Jws2Instance service;
-
-  protected WsParamSetI preset;
-
-  protected List<Argument> arguments;
-
-  protected IProgressIndicator guiProgress;
-
-  protected boolean submitGaps = true;
-
-  /**
-   * by default, we filter out non-standard residues before submission
-   */
-  protected boolean filterNonStandardResidues = true;
-
-  /**
-   * Recover any existing parameters for this service
-   */
-  protected void initViewportParams()
-  {
-    if (getCalcId() != null)
-    {
-      ((jalview.gui.AlignViewport) alignViewport).setCalcIdSettingsFor(
-              getCalcId(),
-              new AAConSettings(true, service, this.preset,
-                      (arguments != null)
-                              ? JabaParamStore.getJwsArgsfromJaba(arguments)
-                              : null),
-              true);
-    }
-  }
-
-  /**
-   * 
-   * @return null or a string used to recover all annotation generated by this
-   *         worker
-   */
-  public abstract String getCalcId();
-
-  public WsParamSetI getPreset()
-  {
-    return preset;
-  }
-
-  public List<Argument> getArguments()
-  {
-    return arguments;
-  }
-
-  /**
-   * reconfigure and restart the AAConClient. This method will spawn a new
-   * thread that will wait until any current jobs are finished, modify the
-   * parameters and restart the conservation calculation with the new values.
-   * 
-   * @param newpreset
-   * @param newarguments
-   */
-  public void updateParameters(final WsParamSetI newpreset,
-          final List<Argument> newarguments)
-  {
-    preset = newpreset;
-    arguments = newarguments;
-    calcMan.startWorker(this);
-    initViewportParams();
-  }
-
-  public List<Option> getJabaArguments()
-  {
-    List<Option> newargs = new ArrayList<>();
-    if (preset != null && preset instanceof JabaWsParamSet)
-    {
-      newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
-    }
-    if (arguments != null && arguments.size() > 0)
-    {
-      for (Argument rg : arguments)
-      {
-        if (Option.class.isAssignableFrom(rg.getClass()))
-        {
-          newargs.add((Option) rg);
-        }
-      }
-    }
-    return newargs;
-  }
-
-  protected boolean alignedSeqs = true;
-
-  protected boolean nucleotidesAllowed = false;
-
-  protected boolean proteinAllowed = false;
-
-  /**
-   * record sequences for mapping result back to afterwards
-   */
-  protected boolean bySequence = false;
-
-  protected Map<String, SequenceI> seqNames;
-
-  protected boolean[] gapMap;
-
-  int realw;
-
-  protected int start;
-
-  int end;
-
-  public AbstractJabaCalcWorker(AlignViewportI alignViewport,
-          AlignmentViewPanel alignPanel)
-  {
-    super(alignViewport, alignPanel);
-  }
-
-  public AbstractJabaCalcWorker(Jws2Instance service, AlignFrame alignFrame,
-          WsParamSetI preset, List<Argument> paramset)
-  {
-    this(alignFrame.getCurrentView(), alignFrame.alignPanel);
-    this.guiProgress = alignFrame;
-    this.preset = preset;
-    this.arguments = paramset;
-    this.service = service;
-  }
-
-  /**
-   * 
-   * @return true if the submission thread should attempt to submit data
-   */
-  abstract boolean hasService();
-
-  volatile String rslt = "JOB NOT DEFINED";
-
-  @Override
-  public void run()
-  {
-    if (!hasService())
-    {
-      return;
-    }
-    long progressId = -1;
-
-    int serverErrorsLeft = 3;
-
-    StringBuffer msg = new StringBuffer();
-    try
-    {
-      if (checkDone())
-      {
-        return;
-      }
-      List<compbio.data.sequence.FastaSequence> seqs = getInputSequences(
-              alignViewport.getAlignment(),
-              bySequence ? alignViewport.getSelectionGroup() : null);
-
-      if (seqs == null || !checkValidInputSeqs(true, seqs))
-      {
-        calcMan.workerComplete(this);
-        return;
-      }
-
-      AlignmentAnnotation[] aa = alignViewport.getAlignment()
-              .getAlignmentAnnotation();
-      if (guiProgress != null)
-      {
-        guiProgress.setProgressBar("JABA " + getServiceActionText(),
-                progressId = System.currentTimeMillis());
-      }
-      rslt = submitToService(seqs);
-      if (guiProgress != null)
-      {
-        guiProgress.registerHandler(progressId,
-                new IProgressIndicatorHandler()
-                {
-
-                  @Override
-                  public boolean cancelActivity(long id)
-                  {
-                    cancelCurrentJob();
-                    return true;
-                  }
-
-                  @Override
-                  public boolean canCancel()
-                  {
-                    return true;
-                  }
-                });
-      }
-      boolean finished = false;
-      long rpos = 0;
-      do
-      {
-        JobStatus status = getJobStatus(rslt);
-        if (status.equals(JobStatus.FINISHED))
-        {
-          finished = true;
-        }
-        if (calcMan.isPending(this) && isInteractiveUpdate())
-        {
-          finished = true;
-          // cancel this job and yield to the new job
-          try
-          {
-            if (cancelJob(rslt))
-            {
-              System.err.println("Cancelled AACon job: " + rslt);
-            }
-            else
-            {
-              System.err.println("FAILED TO CANCEL AACon job: " + rslt);
-            }
-
-          } catch (Exception x)
-          {
-
-          }
-          rslt = "CANCELLED JOB";
-          return;
-        }
-        long cpos;
-        ChunkHolder stats = null;
-        do
-        {
-          cpos = rpos;
-          boolean retry = false;
-          do
-          {
-            try
-            {
-              stats = pullExecStatistics(rslt, rpos);
-            } catch (Exception x)
-            {
-
-              if (x.getMessage().contains(
-                      "Position in a file could not be negative!"))
-              {
-                // squash index out of bounds exception- seems to happen for
-                // disorder predictors which don't (apparently) produce any
-                // progress information and JABA server throws an exception
-                // because progress length is -1.
-                stats = null;
-              }
-              else
-              {
-                if (--serverErrorsLeft > 0)
-                {
-                  retry = true;
-                  try
-                  {
-                    Thread.sleep(200);
-                  } catch (InterruptedException q)
-                  {
-                  }
-                  ;
-                }
-                else
-                {
-                  throw x;
-                }
-              }
-            }
-          } while (retry);
-          if (stats != null)
-          {
-            System.out.print(stats.getChunk());
-            msg.append(stats);
-            rpos = stats.getNextPosition();
-          }
-        } while (stats != null && rpos > cpos);
-
-        if (!finished && status.equals(JobStatus.FAILED))
-        {
-          try
-          {
-            Thread.sleep(200);
-          } catch (InterruptedException x)
-          {
-          }
-          ;
-        }
-      } while (!finished);
-      if (serverErrorsLeft > 0)
-      {
-        try
-        {
-          Thread.sleep(200);
-        } catch (InterruptedException x)
-        {
-        }
-        if (collectAnnotationResultsFor(rslt))
-        {
-          jalview.bin.Cache.log.debug("Updating result annotation from Job "
-                  + rslt + " at " + service.getUri());
-          updateResultAnnotation(true);
-          ap.adjustAnnotationHeight();
-        }
-      }
-    }
-
-    catch (JobSubmissionException x)
-    {
-
-      System.err.println(
-              "submission error with " + getServiceActionText() + " :");
-      x.printStackTrace();
-      calcMan.disableWorker(this);
-    } catch (ResultNotAvailableException x)
-    {
-      System.err.println("collection error:\nJob ID: " + rslt);
-      x.printStackTrace();
-      calcMan.disableWorker(this);
-
-    } catch (OutOfMemoryError error)
-    {
-      calcMan.disableWorker(this);
-
-      // consensus = null;
-      // hconsensus = null;
-      ap.raiseOOMWarning(getServiceActionText(), error);
-    } catch (Exception x)
-    {
-      calcMan.disableWorker(this);
-
-      // consensus = null;
-      // hconsensus = null;
-      System.err
-              .println("Blacklisting worker due to unexpected exception:");
-      x.printStackTrace();
-    } finally
-    {
-
-      calcMan.workerComplete(this);
-      if (ap != null)
-      {
-        calcMan.workerComplete(this);
-        if (guiProgress != null && progressId != -1)
-        {
-          guiProgress.setProgressBar("", progressId);
-        }
-        // TODO: may not need to paintAlignment again !
-        ap.paintAlignment(false, false);
-      }
-      if (msg.length() > 0)
-      {
-        // TODO: stash message somewhere in annotation or alignment view.
-        // code below shows result in a text box popup
-        /*
-         * jalview.gui.CutAndPasteTransfer cap = new
-         * jalview.gui.CutAndPasteTransfer(); cap.setText(msg.toString());
-         * jalview.gui.Desktop.addInternalFrame(cap,
-         * "Job Status for "+getServiceActionText(), 600, 400);
-         */
-      }
-    }
-
-  }
-
-  /**
-   * validate input for dynamic/non-dynamic update context
-   * 
-   * @param dynamic
-   * @param seqs
-   * @return true if input is valid
-   */
-  abstract boolean checkValidInputSeqs(boolean dynamic,
-          List<FastaSequence> seqs);
-
-  abstract String submitToService(
-          List<compbio.data.sequence.FastaSequence> seqs)
-          throws JobSubmissionException;
-
-  abstract boolean cancelJob(String rslt) throws Exception;
-
-  abstract JobStatus getJobStatus(String rslt) throws Exception;
-
-  abstract ChunkHolder pullExecStatistics(String rslt, long rpos);
-
-  abstract boolean collectAnnotationResultsFor(String rslt)
-          throws ResultNotAvailableException;
-
-  public void cancelCurrentJob()
-  {
-    try
-    {
-      String id = rslt;
-      if (cancelJob(rslt))
-      {
-        System.err.println("Cancelled job " + id);
-      }
-      else
-      {
-        System.err.println("Job " + id + " couldn't be cancelled.");
-      }
-    } catch (Exception q)
-    {
-      q.printStackTrace();
-    }
-  }
-
-  /**
-   * Interactive updating. Analysis calculations that work on the currently
-   * displayed alignment data should cancel existing jobs when the input data
-   * has changed.
-   * 
-   * @return true if a running job should be cancelled because new input data is
-   *         available for analysis
-   */
-  abstract boolean isInteractiveUpdate();
-
-  public List<FastaSequence> getInputSequences(AlignmentI alignment,
-          AnnotatedCollectionI inputSeqs)
-  {
-    if (alignment == null || alignment.getWidth() <= 0
-            || alignment.getSequences() == null || alignment.isNucleotide()
-                    ? !nucleotidesAllowed
-                    : !proteinAllowed)
-    {
-      return null;
-    }
-    if (inputSeqs == null || inputSeqs.getWidth() <= 0
-            || inputSeqs.getSequences() == null
-            || inputSeqs.getSequences().size() < 1)
-    {
-      inputSeqs = alignment;
-    }
-
-    List<compbio.data.sequence.FastaSequence> seqs = new ArrayList<>();
-
-    int minlen = 10;
-    int ln = -1;
-    if (bySequence)
-    {
-      seqNames = new HashMap<>();
-    }
-    gapMap = new boolean[0];
-    start = inputSeqs.getStartRes();
-    end = inputSeqs.getEndRes();
-
-    for (SequenceI sq : (inputSeqs.getSequences()))
-    {
-      if (bySequence
-              ? sq.findPosition(end + 1)
-                      - sq.findPosition(start + 1) > minlen - 1
-              : sq.getEnd() - sq.getStart() > minlen - 1)
-      {
-        String newname = SeqsetUtils.unique_name(seqs.size() + 1);
-        // make new input sequence with or without gaps
-        if (seqNames != null)
-        {
-          seqNames.put(newname, sq);
-        }
-        FastaSequence seq;
-        if (submitGaps)
-        {
-          seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
-                  sq.getSequenceAsString()));
-          if (gapMap == null || gapMap.length < seq.getSequence().length())
-          {
-            boolean[] tg = gapMap;
-            gapMap = new boolean[seq.getLength()];
-            System.arraycopy(tg, 0, gapMap, 0, tg.length);
-            for (int p = tg.length; p < gapMap.length; p++)
-            {
-              gapMap[p] = false; // init as a gap
-            }
-          }
-          for (int apos : sq.gapMap())
-          {
-            char sqc = sq.getCharAt(apos);
-            if (!filterNonStandardResidues
-                    || (sq.isProtein() ? ResidueProperties.aaIndex[sqc] < 20
-                            : ResidueProperties.nucleotideIndex[sqc] < 5))
-            {
-              gapMap[apos] = true; // aligned and real amino acid residue
-            }
-            ;
-          }
-        }
-        else
-        {
-          seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
-                  AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
-                          sq.getSequenceAsString(start, end + 1))));
-        }
-        if (seq.getSequence().length() > ln)
-        {
-          ln = seq.getSequence().length();
-        }
-      }
-    }
-    if (alignedSeqs && submitGaps)
-    {
-      realw = 0;
-      for (int i = 0; i < gapMap.length; i++)
-      {
-        if (gapMap[i])
-        {
-          realw++;
-        }
-      }
-      // try real hard to return something submittable
-      // TODO: some of AAcon measures need a minimum of two or three amino
-      // acids at each position, and AAcon doesn't gracefully degrade.
-      for (int p = 0; p < seqs.size(); p++)
-      {
-        FastaSequence sq = seqs.get(p);
-        int l = sq.getSequence().length();
-        // strip gapped columns
-        char[] padded = new char[realw],
-                orig = sq.getSequence().toCharArray();
-        for (int i = 0, pp = 0; i < realw; pp++)
-        {
-          if (gapMap[pp])
-          {
-            if (orig.length > pp)
-            {
-              padded[i++] = orig[pp];
-            }
-            else
-            {
-              padded[i++] = '-';
-            }
-          }
-        }
-        seqs.set(p, new compbio.data.sequence.FastaSequence(sq.getId(),
-                new String(padded)));
-      }
-    }
-    return seqs;
-  }
-
-  @Override
-  public void updateAnnotation()
-  {
-    updateResultAnnotation(false);
-  }
-
-  public abstract void updateResultAnnotation(boolean immediate);
-
-  public abstract String getServiceActionText();
-
-  /**
-   * notify manager that we have started, and wait for a free calculation slot
-   * 
-   * @return true if slot is obtained and work still valid, false if another
-   *         thread has done our work for us.
-   */
-  protected boolean checkDone()
-  {
-    calcMan.notifyStart(this);
-    ap.paintAlignment(false, false);
-    while (!calcMan.notifyWorking(this))
-    {
-      if (calcMan.isWorking(this))
-      {
-        return true;
-      }
-      try
-      {
-        if (ap != null)
-        {
-          ap.paintAlignment(false, false);
-        }
-
-        Thread.sleep(200);
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
-      }
-    }
-    if (alignViewport.isClosed())
-    {
-      abortAndDestroy();
-      return true;
-    }
-    return false;
-  }
-
-  protected void updateOurAnnots(List<AlignmentAnnotation> ourAnnot)
-  {
-    List<AlignmentAnnotation> our = ourAnnots;
-    ourAnnots = ourAnnot;
-    AlignmentI alignment = alignViewport.getAlignment();
-    if (our != null)
-    {
-      if (our.size() > 0)
-      {
-        for (AlignmentAnnotation an : our)
-        {
-          if (!ourAnnots.contains(an))
-          {
-            // remove the old annotation
-            alignment.deleteAnnotation(an);
-          }
-        }
-      }
-      our.clear();
-
-      ap.adjustAnnotationHeight();
-    }
-  }
-
-}
index 5e034cd..929c5e2 100644 (file)
@@ -47,7 +47,7 @@ import compbio.metadata.RunnerConfig;
 public class JabaParamStore implements ParamDatastoreI
 {
 
-  Hashtable<String, JabaWsParamSet> editedParams = new Hashtable<String, JabaWsParamSet>();
+  Hashtable<String, JabaWsParamSet> editedParams = new Hashtable<>();
 
   private Jws2Instance service;
 
@@ -101,7 +101,7 @@ public class JabaParamStore implements ParamDatastoreI
     List<WsParamSetI> prefs = new ArrayList<>();
     if (servicePresets == null)
     {
-      servicePresets = new Hashtable<String, JabaPreset>();
+      servicePresets = new Hashtable<>();
       PresetManager prman;
       if ((prman = service.getPresets()) != null)
       {
@@ -148,8 +148,8 @@ public class JabaParamStore implements ParamDatastoreI
   public static List<ArgumentI> getJwsArgsfromJaba(List jabargs,
           boolean sortByOpt)
   {
-    List<ArgumentI> rgs = new ArrayList<ArgumentI>();
-    List<String> rgnames = new ArrayList<String>();
+    List<ArgumentI> rgs = new ArrayList<>();
+    List<String> rgnames = new ArrayList<>();
     for (Object rg : jabargs)
     {
       ArgumentI narg = null;
@@ -309,7 +309,7 @@ public class JabaParamStore implements ParamDatastoreI
     boolean found = false;
     for (String url : urls)
     {
-      if (service.getServiceTypeURI().equals(url)
+      if (service.getNameURI().equals(url)
               || service.getUri().equalsIgnoreCase(url))
       {
         found = true;
@@ -334,7 +334,7 @@ public class JabaParamStore implements ParamDatastoreI
     wsp.setDescription(descr);
     wsp.setApplicableUrls(urls.clone());
 
-    List<String> lines = new ArrayList<String>();
+    List<String> lines = new ArrayList<>();
     StringTokenizer st = new StringTokenizer(parameterfile, "\n");
     while (st.hasMoreTokens())
     {
index 981b288..b6a18dd 100644 (file)
@@ -100,4 +100,9 @@ public class JabaPreset implements WsParamSetI
     throw new Error(MessageManager
             .getString("error.cannot_set_params_for_ws_preset"));
   }
+
+  public Preset getJabaPreset()
+  {
+    return p;
+  }
 }
diff --git a/src/jalview/ws/jws2/JabaWsParamTest.java b/src/jalview/ws/jws2/JabaWsParamTest.java
new file mode 100644 (file)
index 0000000..bef7e29
--- /dev/null
@@ -0,0 +1,264 @@
+package jalview.ws.jws2;
+
+import jalview.gui.WsJobParameters;
+import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+
+import java.awt.BorderLayout;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import compbio.metadata.Option;
+import compbio.metadata.Parameter;
+import compbio.metadata.Preset;
+import compbio.metadata.PresetManager;
+
+public class JabaWsParamTest
+{
+
+  /**
+   * testing method - grab a service and parameter set and show the window
+   * 
+   * @param args
+   */
+  public static void main(String[] args)
+  {
+    jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
+            .getInstance();
+    int p = 0;
+    if (args.length > 0)
+    {
+      Vector<String> services = new Vector<>();
+      services.addElement(args[p++]);
+      Jws2Discoverer.getInstance().setServiceUrls(services);
+    }
+    try
+    {
+      disc.run();
+    } catch (Exception e)
+    {
+      System.err.println("Aborting. Problem discovering services.");
+      e.printStackTrace();
+      return;
+    }
+    Jws2Instance lastserv = null;
+    for (ServiceWithParameters service : disc.getServices())
+    {
+      // this will fail for non-JABAWS services !
+      lastserv = (Jws2Instance) service;
+      if (p >= args.length || service.getName().equalsIgnoreCase(args[p]))
+      {
+        if (lastserv != null)
+        {
+          List<Preset> prl = null;
+          Preset pr = null;
+          if (++p < args.length)
+          {
+            PresetManager prman = lastserv.getPresets();
+            if (prman != null)
+            {
+              pr = prman.getPresetByName(args[p]);
+              if (pr == null)
+              {
+                // just grab the last preset.
+                prl = prman.getPresets();
+              }
+            }
+          }
+          else
+          {
+            PresetManager prman = lastserv.getPresets();
+            if (prman != null)
+            {
+              prl = prman.getPresets();
+            }
+          }
+          Iterator<Preset> en = (prl == null) ? null : prl.iterator();
+          while (en != null && en.hasNext())
+          {
+            if (en != null)
+            {
+              if (!en.hasNext())
+              {
+                en = prl.iterator();
+              }
+              pr = en.next();
+            }
+            {
+              System.out.println("Testing opts dupes for "
+                      + lastserv.getUri() + " : " + lastserv.getActionText()
+                      + ":" + pr.getName());
+              List<Option> rg = lastserv.getRunnerConfig().getOptions();
+              for (Option o : rg)
+              {
+                try
+                {
+                  Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
+                } catch (Exception e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                } catch (Error e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                }
+              }
+            }
+            {
+              System.out.println("Testing param dupes:");
+              List<Parameter> rg = lastserv.getRunnerConfig()
+                      .getParameters();
+              for (Parameter o : rg)
+              {
+                try
+                {
+                  Parameter cpy = jalview.ws.jws2.ParameterUtils
+                          .copyParameter(o);
+                } catch (Exception e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                } catch (Error e)
+                {
+                  System.err.println("Failed to copy " + o.getName());
+                  e.printStackTrace();
+                }
+              }
+            }
+            {
+              System.out.println("Testing param write:");
+              List<String> writeparam = null, readparam = null;
+              try
+              {
+                writeparam = jalview.ws.jws2.ParameterUtils
+                        .writeParameterSet(
+                                pr.getArguments(lastserv.getRunnerConfig()),
+                                " ");
+                System.out.println("Testing param read :");
+                List<Option> pset = jalview.ws.jws2.ParameterUtils
+                        .processParameters(writeparam,
+                                lastserv.getRunnerConfig(), " ");
+                readparam = jalview.ws.jws2.ParameterUtils
+                        .writeParameterSet(pset, " ");
+                Iterator<String> o = pr.getOptions().iterator(),
+                        s = writeparam.iterator(), t = readparam.iterator();
+                boolean failed = false;
+                while (s.hasNext() && t.hasNext())
+                {
+                  String on = o.next(), sn = s.next(), st = t.next();
+                  if (!sn.equals(st))
+                  {
+                    System.out.println(
+                            "Original was " + on + " Phase 1 wrote " + sn
+                                    + "\tPhase 2 wrote " + st);
+                    failed = true;
+                  }
+                }
+                if (failed)
+                {
+                  System.out.println(
+                          "Original parameters:\n" + pr.getOptions());
+                  System.out.println(
+                          "Wrote parameters in first set:\n" + writeparam);
+                  System.out.println(
+                          "Wrote parameters in second set:\n" + readparam);
+
+                }
+              } catch (Exception e)
+              {
+                e.printStackTrace();
+              }
+            }
+            WsJobParameters pgui = new WsJobParameters(null, lastserv,
+                    new JabaPreset(lastserv, pr), null);
+            JFrame jf = new JFrame(MessageManager
+                    .formatMessage("label.ws_parameters_for", new String[]
+                    { lastserv.getActionText() }));
+            JPanel cont = new JPanel(new BorderLayout());
+            pgui.validate();
+            cont.setPreferredSize(pgui.getPreferredSize());
+            cont.add(pgui, BorderLayout.CENTER);
+            jf.setLayout(new BorderLayout());
+            jf.add(cont, BorderLayout.CENTER);
+            jf.validate();
+            final Thread thr = Thread.currentThread();
+            jf.addWindowListener(new WindowListener()
+            {
+
+              @Override
+              public void windowActivated(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void windowClosed(WindowEvent e)
+              {
+              }
+
+              @Override
+              public void windowClosing(WindowEvent e)
+              {
+                thr.interrupt();
+
+              }
+
+              @Override
+              public void windowDeactivated(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void windowDeiconified(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void windowIconified(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+              @Override
+              public void windowOpened(WindowEvent e)
+              {
+                // TODO Auto-generated method stub
+
+              }
+
+            });
+            jf.setVisible(true);
+            boolean inter = false;
+            while (!inter)
+            {
+              try
+              {
+                Thread.sleep(10000);
+              } catch (Exception e)
+              {
+                inter = true;
+              }
+              ;
+            }
+            jf.dispose();
+          }
+        }
+      }
+    }
+  }
+
+}
diff --git a/src/jalview/ws/jws2/JabawsCalcWorker.java b/src/jalview/ws/jws2/JabawsCalcWorker.java
deleted file mode 100644 (file)
index fc36205..0000000
+++ /dev/null
@@ -1,235 +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.jws2;
-
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignFrame;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
-
-import java.util.Iterator;
-import java.util.List;
-
-import compbio.data.msa.SequenceAnnotation;
-import compbio.data.sequence.Score;
-import compbio.data.sequence.ScoreManager;
-import compbio.metadata.Argument;
-import compbio.metadata.ChunkHolder;
-import compbio.metadata.JobStatus;
-import compbio.metadata.JobSubmissionException;
-import compbio.metadata.ResultNotAvailableException;
-import compbio.metadata.WrongParameterException;
-
-public abstract class JabawsCalcWorker extends AbstractJabaCalcWorker
-{
-
-  @SuppressWarnings("unchecked")
-  protected SequenceAnnotation aaservice;
-
-  protected ScoreManager scoremanager;
-
-  public JabawsCalcWorker(Jws2Instance service, AlignFrame alignFrame,
-          WsParamSetI preset, List<Argument> paramset)
-  {
-    super(service, alignFrame, preset, paramset);
-    aaservice = (SequenceAnnotation) service.service;
-  }
-
-  @Override
-  ChunkHolder pullExecStatistics(String rslt, long rpos)
-  {
-    return aaservice.pullExecStatistics(rslt, rpos);
-  }
-
-  @Override
-  boolean collectAnnotationResultsFor(String rslt)
-          throws ResultNotAvailableException
-  {
-    scoremanager = aaservice.getAnnotation(rslt);
-    if (scoremanager != null)
-    {
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  boolean cancelJob(String rslt) throws Exception
-  {
-    return aaservice.cancelJob(rslt);
-  }
-
-  @Override
-  protected JobStatus getJobStatus(String rslt) throws Exception
-  {
-    return aaservice.getJobStatus(rslt);
-  }
-
-  @Override
-  boolean hasService()
-  {
-    return aaservice != null;
-  }
-
-  @Override
-  protected boolean isInteractiveUpdate()
-  {
-    return this instanceof AAConClient;
-  }
-
-  @Override
-  protected String submitToService(
-          List<compbio.data.sequence.FastaSequence> seqs)
-          throws JobSubmissionException
-  {
-    String rslt;
-    if (preset == null && arguments == null)
-    {
-      rslt = aaservice.analize(seqs);
-    }
-    else
-    {
-      try
-      {
-        rslt = aaservice.customAnalize(seqs, getJabaArguments());
-      } catch (WrongParameterException x)
-      {
-        throw new JobSubmissionException(MessageManager.getString(
-                "exception.jobsubmission_invalid_params_set"), x);
-
-      }
-    }
-    return rslt;
-  }
-
-  protected void createAnnotationRowsForScores(
-          List<AlignmentAnnotation> ourAnnot, String calcId, int alWidth,
-          Score scr)
-  {
-    // simple annotation row
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
-            .findOrCreateAnnotation(scr.getMethod(), calcId, true, null,
-                    null);
-    if (alWidth == gapMap.length) // scr.getScores().size())
-    {
-      constructAnnotationFromScore(annotation, 0, alWidth, scr);
-      ourAnnot.add(annotation);
-    }
-  }
-
-  protected AlignmentAnnotation createAnnotationRowsForScores(
-          List<AlignmentAnnotation> ourAnnot, String typeName,
-          String calcId, SequenceI dseq, int base, Score scr)
-  {
-    System.out.println("Creating annotation on dseq:" + dseq.getStart()
-            + " base is " + base + " and length=" + dseq.getLength()
-            + " == " + scr.getScores().size());
-    // AlignmentAnnotation annotation = new AlignmentAnnotation(
-    // scr.getMethod(), typeName, new Annotation[]
-    // {}, 0, -1, AlignmentAnnotation.LINE_GRAPH);
-    // annotation.setCalcId(calcId);
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
-            .findOrCreateAnnotation(typeName, calcId, false, dseq, null);
-    constructAnnotationFromScore(annotation, 0, dseq.getLength(), scr);
-    annotation.createSequenceMapping(dseq, base, false);
-    annotation.adjustForAlignment();
-    dseq.addAlignmentAnnotation(annotation);
-    ourAnnot.add(annotation);
-    return annotation;
-  }
-
-  protected void replaceAnnotationOnAlignmentWith(
-          AlignmentAnnotation newAnnot, String typeName, String calcId,
-          SequenceI aSeq)
-  {
-    SequenceI dsseq = aSeq.getDatasetSequence();
-    while (dsseq.getDatasetSequence() != null)
-    {
-      dsseq = dsseq.getDatasetSequence();
-    }
-    // look for same annotation on dataset and lift this one over
-    List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
-            typeName);
-    if (dsan != null && dsan.size() > 0)
-    {
-      for (AlignmentAnnotation dssan : dsan)
-      {
-        dsseq.removeAlignmentAnnotation(dssan);
-      }
-    }
-    AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
-    dsseq.addAlignmentAnnotation(dssan);
-    dssan.adjustForAlignment();
-  }
-
-  private void constructAnnotationFromScore(AlignmentAnnotation annotation,
-          int base, int alWidth, Score scr)
-  {
-    Annotation[] elm = new Annotation[alWidth];
-    Iterator<Float> vals = scr.getScores().iterator();
-    float m = 0f, x = 0f;
-    for (int i = 0; vals.hasNext(); i++)
-    {
-      float val = vals.next().floatValue();
-      if (i == 0)
-      {
-        m = val;
-        x = val;
-      }
-      else
-      {
-        if (m > val)
-        {
-          m = val;
-        }
-        ;
-        if (x < val)
-        {
-          x = val;
-        }
-      }
-      // if we're at a gapped column then skip to next ungapped position
-      if (gapMap != null && gapMap.length > 0)
-      {
-        while (!gapMap[i])
-        {
-          elm[i++] = new Annotation("", "", ' ', Float.NaN);
-        }
-      }
-      elm[i] = new Annotation("", "" + val, ' ', val);
-    }
-
-    annotation.annotations = elm;
-    annotation.belowAlignment = true;
-    if (x < 0)
-    {
-      x = 0;
-    }
-    x += (x - m) * 0.1;
-    annotation.graphMax = x;
-    annotation.graphMin = m;
-    annotation.validateRangeAndDisplay();
-  }
-
-}
diff --git a/src/jalview/ws/jws2/JabawsMsaInterfaceAlignCalcWorker.java b/src/jalview/ws/jws2/JabawsMsaInterfaceAlignCalcWorker.java
deleted file mode 100644 (file)
index ee36d4a..0000000
+++ /dev/null
@@ -1,225 +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.jws2;
-
-import jalview.api.AlignViewportI;
-import jalview.api.AlignmentViewPanel;
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Annotation;
-import jalview.datamodel.SequenceI;
-import jalview.gui.AlignFrame;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
-
-import java.util.Iterator;
-import java.util.List;
-
-import compbio.data.msa.MsaWS;
-import compbio.data.sequence.Alignment;
-import compbio.data.sequence.Score;
-import compbio.metadata.Argument;
-import compbio.metadata.ChunkHolder;
-import compbio.metadata.JobStatus;
-import compbio.metadata.JobSubmissionException;
-import compbio.metadata.ResultNotAvailableException;
-import compbio.metadata.WrongParameterException;
-
-public abstract class JabawsMsaInterfaceAlignCalcWorker
-        extends AbstractJabaCalcWorker
-{
-
-  @SuppressWarnings("unchecked")
-  protected MsaWS msaservice;
-
-  protected Alignment msascoreset;
-
-  public JabawsMsaInterfaceAlignCalcWorker(AlignViewportI alignViewport,
-          AlignmentViewPanel alignPanel)
-  {
-    super(alignViewport, alignPanel);
-  }
-
-  public JabawsMsaInterfaceAlignCalcWorker(Jws2Instance service,
-          AlignFrame alignFrame, WsParamSetI preset,
-          List<Argument> paramset)
-  {
-    this(alignFrame.getCurrentView(), alignFrame.alignPanel);
-    this.guiProgress = alignFrame;
-    this.preset = preset;
-    this.arguments = paramset;
-    this.service = service;
-    msaservice = (MsaWS) service.service;
-
-  }
-
-  @Override
-  ChunkHolder pullExecStatistics(String rslt, long rpos)
-  {
-    return msaservice.pullExecStatistics(rslt, rpos);
-  }
-
-  @Override
-  boolean collectAnnotationResultsFor(String rslt)
-          throws ResultNotAvailableException
-  {
-    msascoreset = msaservice.getResult(rslt);
-    if (msascoreset != null)
-    {
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  boolean cancelJob(String rslt) throws Exception
-  {
-    return msaservice.cancelJob(rslt);
-  }
-
-  @Override
-  protected JobStatus getJobStatus(String rslt) throws Exception
-  {
-    return msaservice.getJobStatus(rslt);
-  }
-
-  @Override
-  boolean hasService()
-  {
-    return msaservice != null;
-  }
-
-  @Override
-  protected boolean isInteractiveUpdate()
-  {
-    return false; // this instanceof AAConClient;
-  }
-
-  @Override
-  protected String submitToService(
-          List<compbio.data.sequence.FastaSequence> seqs)
-          throws JobSubmissionException
-  {
-    String rslt;
-    if (preset == null && arguments == null)
-    {
-      rslt = msaservice.align(seqs);
-    }
-    else
-    {
-      try
-      {
-        rslt = msaservice.customAlign(seqs, getJabaArguments());
-      } catch (WrongParameterException x)
-      {
-        throw new JobSubmissionException(MessageManager.getString(
-                "exception.jobsubmission_invalid_params_set"), x);
-      }
-    }
-    return rslt;
-  }
-
-  protected void createAnnotationRowsForScores(
-          List<AlignmentAnnotation> ourAnnot, String calcId, int alWidth,
-          Score scr)
-  {
-    // simple annotation row
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
-            .findOrCreateAnnotation(scr.getMethod(), calcId, true, null,
-                    null);
-    if (alWidth == gapMap.length) // scr.getScores().size())
-    {
-      constructAnnotationFromScore(annotation, 0, alWidth, scr);
-      ourAnnot.add(annotation);
-    }
-  }
-
-  protected AlignmentAnnotation createAnnotationRowsForScores(
-          List<AlignmentAnnotation> ourAnnot, String typeName,
-          String calcId, SequenceI dseq, int base, Score scr)
-  {
-    System.out.println("Creating annotation on dseq:" + dseq.getStart()
-            + " base is " + base + " and length=" + dseq.getLength()
-            + " == " + scr.getScores().size());
-    // AlignmentAnnotation annotation = new AlignmentAnnotation(
-    // scr.getMethod(), typeName, new Annotation[]
-    // {}, 0, -1, AlignmentAnnotation.LINE_GRAPH);
-    // annotation.setCalcId(calcId);
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
-            .findOrCreateAnnotation(typeName, calcId, false, dseq, null);
-    constructAnnotationFromScore(annotation, 0, dseq.getLength(), scr);
-    annotation.createSequenceMapping(dseq, base, false);
-    annotation.adjustForAlignment();
-    dseq.addAlignmentAnnotation(annotation);
-    ourAnnot.add(annotation);
-    return annotation;
-  }
-
-  private void constructAnnotationFromScore(AlignmentAnnotation annotation,
-          int base, int alWidth, Score scr)
-  {
-    Annotation[] elm = new Annotation[alWidth];
-    Iterator<Float> vals = scr.getScores().iterator();
-    float m = 0f, x = 0f;
-    for (int i = 0; vals.hasNext(); i++)
-    {
-      float val = vals.next().floatValue();
-      if (i == 0)
-      {
-        m = val;
-        x = val;
-      }
-      else
-      {
-        if (m > val)
-        {
-          m = val;
-        }
-        ;
-        if (x < val)
-        {
-          x = val;
-        }
-      }
-      // if we're at a gapped column then skip to next ungapped position
-      if (gapMap != null && gapMap.length > 0)
-      {
-        while (!gapMap[i])
-        {
-          elm[i++] = new Annotation("", "", ' ', Float.NaN);
-        }
-      }
-      elm[i] = new Annotation("", "" + val, ' ', val);
-    }
-
-    annotation.annotations = elm;
-    annotation.belowAlignment = true;
-    if (x < 0)
-    {
-      x = 0;
-    }
-    x += (x - m) * 0.1;
-    annotation.graphMax = x;
-    annotation.graphMin = m;
-    annotation.validateRangeAndDisplay();
-  }
-
-}
index 004a845..36f927d 100644 (file)
  */
 package jalview.ws.jws2;
 
-import jalview.api.AlignCalcWorkerI;
-import jalview.bin.Cache;
 import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.JvSwingUtils;
-import jalview.gui.WebserviceInfo;
-import jalview.gui.WsJobParameters;
-import jalview.util.MessageManager;
-import jalview.ws.jws2.dm.AAConSettings;
-import jalview.ws.jws2.dm.JabaWsParamSet;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.params.ArgumentI;
 import jalview.ws.params.WsParamSetI;
-import jalview.ws.uimodel.AlignAnalysisUIText;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.util.List;
 
-import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.event.MenuEvent;
-import javax.swing.event.MenuListener;
-
-import compbio.metadata.Argument;
 
 /**
  * provides metadata for a jabaws2 service instance - resolves names, etc.
@@ -54,87 +37,18 @@ import compbio.metadata.Argument;
  */
 public abstract class Jws2Client extends jalview.ws.WSClient
 {
-  protected AlignFrame alignFrame;
-
-  protected WsParamSetI preset;
-
-  protected List<Argument> paramset;
-
+  /**
+   * instantiate a new service client. preset and arguments are assumed to be
+   * valid for the service
+   * 
+   * @param _alignFrame
+   * @param preset
+   * @param arguments
+   */
   public Jws2Client(AlignFrame _alignFrame, WsParamSetI preset,
-          List<Argument> arguments)
+          List<ArgumentI> arguments)
   {
-    alignFrame = _alignFrame;
-    this.preset = preset;
-    if (preset != null)
-    {
-      if (!((preset instanceof JabaPreset)
-              || preset instanceof JabaWsParamSet))
-      {
-        /*
-         * { this.preset = ((JabaPreset) preset).p; } else if (preset instanceof
-         * JabaWsParamSet) { List<Argument> newargs = new ArrayList<Argument>();
-         * JabaWsParamSet pset = ((JabaWsParamSet) preset); for (Option opt :
-         * pset.getjabaArguments()) { newargs.add(opt); } if (arguments != null
-         * && arguments.size() > 0) { // merge arguments with preset's own
-         * arguments. for (Argument opt : arguments) { newargs.add(opt); } }
-         * paramset = newargs; } else {
-         */
-        throw new Error(MessageManager.getString(
-                "error.implementation_error_can_only_instantiate_jaba_param_sets"));
-      }
-    }
-    else
-    {
-      // just provided with a bunch of arguments
-      this.paramset = arguments;
-    }
-  }
-
-  boolean processParams(Jws2Instance sh, boolean editParams)
-  {
-    return processParams(sh, editParams, false);
-  }
-
-  protected boolean processParams(Jws2Instance sh, boolean editParams,
-          boolean adjustingExisting)
-  {
-
-    if (editParams)
-    {
-      if (sh.paramStore == null)
-      {
-        sh.paramStore = new JabaParamStore(sh,
-                Desktop.getUserParameterStore());
-      }
-      WsJobParameters jobParams = (preset == null && paramset != null
-              && paramset.size() > 0)
-                      ? new WsJobParameters(null, sh, null, paramset)
-                      : new WsJobParameters(sh, preset);
-      if (adjustingExisting)
-      {
-        jobParams.setName(MessageManager
-                .getString("label.adjusting_parameters_for_calculation"));
-      }
-      if (!jobParams.showRunDialog())
-      {
-        return false;
-      }
-      WsParamSetI prset = jobParams.getPreset();
-      if (prset == null)
-      {
-        paramset = jobParams.isServiceDefaults() ? null
-                : JabaParamStore
-                        .getJabafromJwsArgs(jobParams.getJobParams());
-        this.preset = null;
-      }
-      else
-      {
-        this.preset = prset; // ((JabaPreset) prset).p;
-        paramset = null; // no user supplied parameters.
-      }
-    }
-    return true;
-
+    super(_alignFrame, preset, arguments);
   }
 
   public Jws2Client()
@@ -142,24 +56,6 @@ public abstract class Jws2Client extends jalview.ws.WSClient
     // anonymous constructor - used for headless method calls only
   }
 
-  protected WebserviceInfo setWebService(Jws2Instance serv, boolean b)
-  {
-    // serviceHandle = serv;
-    String serviceInstance = serv.action; // serv.service.getClass().getName();
-    WebServiceName = serv.serviceType;
-    WebServiceJobTitle = serv.getActionText();
-    WsURL = serv.hosturl;
-    if (!b)
-    {
-      return new WebserviceInfo(WebServiceJobTitle,
-              WebServiceJobTitle + " using service hosted at "
-                      + serv.hosturl + "\n"
-                      + (serv.description != null ? serv.description : ""), 
-                      Desktop.FRAME_NOT_VISIBLE);
-    }
-    return null;
-  }
-
   /*
    * Jws2Instance serviceHandle; (non-Javadoc)
    * 
@@ -178,254 +74,7 @@ public abstract class Jws2Client extends jalview.ws.WSClient
    * @param service
    * @param alignFrame
    */
-  abstract void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
+  abstract void attachWSMenuEntry(JMenu wsmenu,
+          final ServiceWithParameters service,
           final AlignFrame alignFrame);
-
-  protected boolean registerAAConWSInstance(final JMenu wsmenu,
-          final Jws2Instance service, final AlignFrame alignFrame)
-  {
-    final AlignAnalysisUIText aaui = service.getAlignAnalysisUI(); // null ; //
-                                                                   // AlignAnalysisUIText.aaConGUI.get(service.serviceType.toString());
-    if (aaui == null)
-    {
-      // not an instantaneous calculation GUI type service
-      return false;
-    }
-    // create the instaneous calculation GUI bits and update state if existing
-    // GUI elements already present
-
-    JCheckBoxMenuItem _aaConEnabled = null;
-    for (int i = 0; i < wsmenu.getItemCount(); i++)
-    {
-      JMenuItem item = wsmenu.getItem(i);
-      if (item instanceof JCheckBoxMenuItem
-              && item.getText().equals(aaui.getAAconToggle()))
-      {
-        _aaConEnabled = (JCheckBoxMenuItem) item;
-      }
-    }
-    // is there an aaCon worker already present - if so, set it to use the
-    // given service handle
-    {
-      List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
-              .getCalcManager()
-              .getRegisteredWorkersOfClass(aaui.getClient());
-      if (aaconClient != null && aaconClient.size() > 0)
-      {
-        AbstractJabaCalcWorker worker = (AbstractJabaCalcWorker) aaconClient
-                .get(0);
-        if (!worker.service.hosturl.equals(service.hosturl))
-        {
-          // javax.swing.SwingUtilities.invokeLater(new Runnable()
-          {
-            // @Override
-            // public void run()
-            {
-              removeCurrentAAConWorkerFor(aaui, alignFrame);
-              buildCurrentAAConWorkerFor(aaui, alignFrame, service);
-            }
-          } // );
-        }
-      }
-    }
-
-    // is there a service already registered ? there shouldn't be if we are
-    // being called correctly
-    if (_aaConEnabled == null)
-    {
-      final JCheckBoxMenuItem aaConEnabled = new JCheckBoxMenuItem(
-              aaui.getAAconToggle());
-
-      aaConEnabled.setToolTipText(
-              JvSwingUtils.wrapTooltip(true, aaui.getAAconToggleTooltip()));
-      aaConEnabled.addActionListener(new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent arg0)
-        {
-          List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
-                  .getCalcManager()
-                  .getRegisteredWorkersOfClass(aaui.getClient());
-          if (aaconClient != null && aaconClient.size() > 0)
-          {
-            removeCurrentAAConWorkerFor(aaui, alignFrame);
-          }
-          else
-          {
-            buildCurrentAAConWorkerFor(aaui, alignFrame);
-
-          }
-        }
-
-      });
-      wsmenu.add(aaConEnabled);
-      final JMenuItem modifyParams = new JMenuItem(
-              aaui.getAAeditSettings());
-      modifyParams.setToolTipText(JvSwingUtils.wrapTooltip(true,
-              aaui.getAAeditSettingsTooltip()));
-      modifyParams.addActionListener(new ActionListener()
-      {
-
-        @Override
-        public void actionPerformed(ActionEvent arg0)
-        {
-          showAAConAnnotationSettingsFor(aaui, alignFrame);
-        }
-      });
-      wsmenu.add(modifyParams);
-      wsmenu.addMenuListener(new MenuListener()
-      {
-
-        @Override
-        public void menuSelected(MenuEvent arg0)
-        {
-          // TODO: refactor to the implementing class.
-          if (alignFrame.getViewport().getAlignment().isNucleotide()
-                  ? aaui.isNa()
-                  : aaui.isPr())
-          {
-            aaConEnabled.setEnabled(true);
-            modifyParams.setEnabled(true);
-          }
-          else
-          {
-            aaConEnabled.setEnabled(false);
-            modifyParams.setEnabled(false);
-          }
-          List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
-                  .getCalcManager()
-                  .getRegisteredWorkersOfClass(aaui.getClient());
-          if (aaconClient != null && aaconClient.size() > 0)
-          {
-            aaConEnabled.setSelected(true);
-          }
-          else
-          {
-            aaConEnabled.setSelected(false);
-          }
-        }
-
-        @Override
-        public void menuDeselected(MenuEvent arg0)
-        {
-          // TODO Auto-generated method stub
-
-        }
-
-        @Override
-        public void menuCanceled(MenuEvent arg0)
-        {
-          // TODO Auto-generated method stub
-
-        }
-      });
-
-    }
-    return true;
-  }
-
-  private static void showAAConAnnotationSettingsFor(
-          final AlignAnalysisUIText aaui, AlignFrame alignFrame)
-  {
-    /*
-     * preferred settings Whether AACon is automatically recalculated Which
-     * AACon server to use What parameters to use
-     */
-    // could actually do a class search for this too
-    AAConSettings fave = (AAConSettings) alignFrame.getViewport()
-            .getCalcIdSettingsFor(aaui.getCalcId());
-    if (fave == null)
-    {
-      fave = createDefaultAAConSettings(aaui);
-    }
-    new SequenceAnnotationWSClient(fave, alignFrame, true);
-
-  }
-
-  private static void buildCurrentAAConWorkerFor(
-          final AlignAnalysisUIText aaui, AlignFrame alignFrame)
-  {
-    buildCurrentAAConWorkerFor(aaui, alignFrame, null);
-  }
-
-  private static void buildCurrentAAConWorkerFor(
-          final AlignAnalysisUIText aaui, AlignFrame alignFrame,
-          Jws2Instance service)
-  {
-    /*
-     * preferred settings Whether AACon is automatically recalculated Which
-     * AACon server to use What parameters to use
-     */
-    AAConSettings fave = (AAConSettings) alignFrame.getViewport()
-            .getCalcIdSettingsFor(aaui.getCalcId());
-    if (fave == null)
-    {
-      fave = createDefaultAAConSettings(aaui, service);
-    }
-    else
-    {
-      if (service != null
-              && !fave.getService().hosturl.equals(service.hosturl))
-      {
-        Cache.log.debug("Changing AACon service to " + service.hosturl
-                + " from " + fave.getService().hosturl);
-        fave.setService(service);
-      }
-    }
-    new SequenceAnnotationWSClient(fave, alignFrame, false);
-  }
-
-  private static AAConSettings createDefaultAAConSettings(
-          AlignAnalysisUIText aaui)
-  {
-    return createDefaultAAConSettings(aaui, null);
-  }
-
-  private static AAConSettings createDefaultAAConSettings(
-          AlignAnalysisUIText aaui, Jws2Instance service)
-  {
-    if (service != null)
-    {
-      if (!service.serviceType.toString()
-              .equals(compbio.ws.client.Services.AAConWS.toString()))
-      {
-        Cache.log.warn(
-                "Ignoring invalid preferred service for AACon calculations (service type was "
-                        + service.serviceType + ")");
-        service = null;
-      }
-      else
-      {
-        // check service is actually in the list of currently avaialable
-        // services
-        if (!Jws2Discoverer.getInstance().getServices().contains(service))
-        {
-          // it isn't ..
-          service = null;
-        }
-      }
-    }
-    if (service == null)
-    {
-      // get the default service for AACon
-      service = Jws2Discoverer.getInstance().getPreferredServiceFor(null,
-              aaui.getServiceType());
-    }
-    if (service == null)
-    {
-      // TODO raise dialog box explaining error, and/or open the JABA
-      // preferences menu.
-      throw new Error(
-              MessageManager.getString("error.no_aacon_service_found"));
-    }
-    return new AAConSettings(true, service, null, null);
-  }
-
-  private static void removeCurrentAAConWorkerFor(AlignAnalysisUIText aaui,
-          AlignFrame alignFrame)
-  {
-    alignFrame.getViewport().getCalcManager()
-            .removeRegisteredWorkersOfClass(aaui.getClient());
-  }
-
 }
diff --git a/src/jalview/ws/jws2/Jws2ClientFactory.java b/src/jalview/ws/jws2/Jws2ClientFactory.java
new file mode 100644 (file)
index 0000000..2456528
--- /dev/null
@@ -0,0 +1,292 @@
+package jalview.ws.jws2;
+
+import jalview.api.AlignCalcWorkerI;
+import jalview.bin.Cache;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvSwingUtils;
+import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.dm.AAConSettings;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.params.AutoCalcSetting;
+import jalview.ws.uimodel.AlignAnalysisUIText;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+
+public class Jws2ClientFactory
+{
+  static boolean registerAAConWSInstance(final JMenu wsmenu,
+          final ServiceWithParameters service, final AlignFrame alignFrame)
+  {
+    final AlignAnalysisUIText aaui = service.getAlignAnalysisUI(); // null
+                                                                        // ; //
+    // AlignAnalysisUIText.aaConGUI.get(service.serviceType.toString());
+    if (aaui == null)
+    {
+      // not an instantaneous calculation GUI type service
+      return false;
+    }
+    // create the instaneous calculation GUI bits and update state if existing
+    // GUI elements already present
+
+    JCheckBoxMenuItem _aaConEnabled = null;
+    for (int i = 0; i < wsmenu.getItemCount(); i++)
+    {
+      JMenuItem item = wsmenu.getItem(i);
+      if (item instanceof JCheckBoxMenuItem
+              && item.getText().equals(aaui.getAAconToggle()))
+      {
+        _aaConEnabled = (JCheckBoxMenuItem) item;
+      }
+    }
+    // is there an aaCon worker already present - if so, set it to use the
+    // given service handle
+    {
+      List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
+              .getCalcManager()
+              .getWorkersOfClass(aaui.getClient());
+      if (aaconClient != null && aaconClient.size() > 0)
+      {
+        SeqAnnotationServiceCalcWorker worker = (SeqAnnotationServiceCalcWorker) aaconClient
+                .get(0);
+        if (!worker.service.getHostURL().equals(service.getHostURL()))
+        {
+          // javax.swing.SwingUtilities.invokeLater(new Runnable()
+          {
+            // @Override
+            // public void run()
+            {
+              removeCurrentAAConWorkerFor(aaui, alignFrame);
+              buildCurrentAAConWorkerFor(aaui, alignFrame, service);
+            }
+          } // );
+        }
+      }
+    }
+
+    // is there a service already registered ? there shouldn't be if we are
+    // being called correctly
+    if (_aaConEnabled == null)
+    {
+      final JCheckBoxMenuItem aaConEnabled = new JCheckBoxMenuItem(
+              aaui.getAAconToggle());
+
+      aaConEnabled.setToolTipText(
+              JvSwingUtils.wrapTooltip(true, aaui.getAAconToggleTooltip()));
+      aaConEnabled.addActionListener(new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent arg0)
+        {
+
+          List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
+                  .getCalcManager()
+                  .getWorkersOfClass(SeqAnnotationServiceCalcWorker.class);
+          if (aaconClient != null)
+          {
+            for (AlignCalcWorkerI worker : aaconClient)
+            {
+              if (((SeqAnnotationServiceCalcWorker) worker).getService()
+                      .getClass().equals(aaui.getClient()))
+              {
+                removeCurrentAAConWorkerFor(aaui, alignFrame);
+                return;
+              }
+            }
+          }
+          buildCurrentAAConWorkerFor(aaui, alignFrame);
+        }
+
+      });
+      wsmenu.add(aaConEnabled);
+      final JMenuItem modifyParams = new JMenuItem(
+              aaui.getAAeditSettings());
+      modifyParams.setToolTipText(JvSwingUtils.wrapTooltip(true,
+              aaui.getAAeditSettingsTooltip()));
+      modifyParams.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent arg0)
+        {
+          showAAConAnnotationSettingsFor(aaui, alignFrame);
+        }
+      });
+      wsmenu.add(modifyParams);
+      wsmenu.addMenuListener(new MenuListener()
+      {
+
+        @Override
+        public void menuSelected(MenuEvent arg0)
+        {
+          // TODO: refactor to the implementing class.
+          if (alignFrame.getViewport().getAlignment().isNucleotide()
+                  ? aaui.isNa()
+                  : aaui.isPr())
+          {
+            aaConEnabled.setEnabled(true);
+            modifyParams.setEnabled(true);
+          }
+          else
+          {
+            aaConEnabled.setEnabled(false);
+            modifyParams.setEnabled(false);
+            return;
+          }
+          List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
+                  .getCalcManager()
+                  .getWorkersOfClass(SeqAnnotationServiceCalcWorker.class);
+
+          boolean serviceEnabled = false;
+          if (aaconClient != null)
+          {
+            // NB code duplicatino again!
+            for (AlignCalcWorkerI _worker : aaconClient)
+            {
+              SeqAnnotationServiceCalcWorker worker = (SeqAnnotationServiceCalcWorker) _worker;
+              // this could be cleaner ?
+              if (worker.hasService()
+                      && aaui.getClient()
+                              .equals(worker.getService().getClass()))
+              {
+                serviceEnabled = true;
+              }
+            }
+          }
+          aaConEnabled.setSelected(serviceEnabled);
+        }
+
+        @Override
+        public void menuDeselected(MenuEvent arg0)
+        {
+          // TODO Auto-generated method stub
+
+        }
+
+        @Override
+        public void menuCanceled(MenuEvent arg0)
+        {
+          // TODO Auto-generated method stub
+
+        }
+      });
+
+    }
+    return true;
+  }
+
+  private static void showAAConAnnotationSettingsFor(
+          final AlignAnalysisUIText aaui, AlignFrame alignFrame)
+  {
+    /*
+     * preferred settings Whether AACon is automatically recalculated Which
+     * AACon server to use What parameters to use
+     */
+    // could actually do a class search for this too
+    AutoCalcSetting fave = alignFrame.getViewport()
+            .getCalcIdSettingsFor(aaui.getCalcId());
+    if (fave == null)
+    {
+      fave = createDefaultAAConSettings(aaui);
+    }
+    new SequenceAnnotationWSClient(fave, alignFrame, true);
+
+  }
+
+  private static void buildCurrentAAConWorkerFor(
+          final AlignAnalysisUIText aaui, AlignFrame alignFrame)
+  {
+    buildCurrentAAConWorkerFor(aaui, alignFrame, null);
+  }
+
+  private static void buildCurrentAAConWorkerFor(
+          final AlignAnalysisUIText aaui, AlignFrame alignFrame,
+          ServiceWithParameters service)
+  {
+    /*
+     * preferred settings Whether AACon is automatically recalculated Which
+     * AACon server to use What parameters to use
+     */
+    AutoCalcSetting fave = alignFrame.getViewport()
+            .getCalcIdSettingsFor(aaui.getCalcId());
+    if (fave == null)
+    {
+      fave = createDefaultAAConSettings(aaui, service);
+    }
+    else
+    {
+      if (service != null && !fave.getService().getHostURL()
+              .equals(service.getHostURL()))
+      {
+        Cache.log.debug("Changing AACon service to " + service.getHostURL()
+                + " from " + fave.getService().getHostURL());
+        fave.setService(service);
+      }
+    }
+    new SequenceAnnotationWSClient(fave, alignFrame, false);
+  }
+
+  private static AutoCalcSetting createDefaultAAConSettings(
+          AlignAnalysisUIText aaui)
+  {
+    return createDefaultAAConSettings(aaui, null);
+  }
+
+  private static AutoCalcSetting createDefaultAAConSettings(
+          AlignAnalysisUIText aaui, ServiceWithParameters service)
+  {
+    if (service != null)
+    {
+      // if (!service.getServiceType()
+      // .equals(compbio.ws.client.Services.AAConWS.toString()))
+      // {
+      // Cache.log.warn(
+      // "Ignoring invalid preferred service for AACon calculations (service
+      // type was "
+      // + service.getServiceType() + ")");
+      // service = null;
+      // }
+      // else
+      {
+        // check service is actually in the list of currently avaialable
+        // services
+        if (!PreferredServiceRegistry.getRegistry().contains(service))
+        {
+          // it isn't ..
+          service = null;
+        }
+      }
+    }
+    if (service == null)
+    {
+      // get the default service for AACon
+      service = PreferredServiceRegistry.getRegistry().getPreferredServiceFor(null,
+              aaui.getServiceType());
+    }
+    if (service == null)
+    {
+      // TODO raise dialog box explaining error, and/or open the JABA
+      // preferences menu.
+      throw new Error(
+              MessageManager.getString("error.no_aacon_service_found"));
+    }
+    return service instanceof Jws2Instance
+            ? new AAConSettings(true, service, null, null)
+            : new AutoCalcSetting(service, null, null, true);
+  }
+
+  private static void removeCurrentAAConWorkerFor(AlignAnalysisUIText aaui,
+          AlignFrame alignFrame)
+  {
+    alignFrame.getViewport().getCalcManager()
+            .removeWorkersOfClass(aaui.getClient());
+  }
+}
\ No newline at end of file
index 255ef8f..d391f8b 100644 (file)
@@ -24,34 +24,32 @@ import jalview.bin.Cache;
 import jalview.bin.ApplicationSingletonProvider;
 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
 import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.JvSwingUtils;
 import jalview.util.MessageManager;
-import jalview.ws.WSMenuEntryProviderI;
+import jalview.ws.ServiceChangeListener;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.ParamDatastoreI;
 
-import java.awt.Color;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.HashSet;
-import java.util.Hashtable;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 
 import javax.swing.JMenu;
-import javax.swing.JMenuItem;
 
 import compbio.ws.client.Services;
 
@@ -62,8 +60,7 @@ import compbio.ws.client.Services;
  * @author JimP
  * 
  */
-public class Jws2Discoverer
-        implements Runnable, WSMenuEntryProviderI, ApplicationSingletonI
+public class Jws2Discoverer implements WSDiscovererI, Runnable, ApplicationSingletonI
 {
 
   /**
@@ -77,14 +74,6 @@ public class Jws2Discoverer
             .getInstance(Jws2Discoverer.class);
   }
 
-  /**
-   * Private constructor enforces use of singleton via getDiscoverer()
-   */
-  private Jws2Discoverer()
-  {
-    // use getInstance();
-  }
-
   public static final String COMPBIO_JABAWS = "http://www.compbio.dundee.ac.uk/jabaws";
 
   /*
@@ -99,10 +88,8 @@ public class Jws2Discoverer
 
   // preferred url has precedence over others
   private String preferredUrl;
-
-  protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
-          this);
-
+  
+  private Set<ServiceChangeListener> serviceListeners = new CopyOnWriteArraySet<>();
   private Vector<String> invalidServiceUrls = null;
 
   private Vector<String> urlsWithoutServices = null;
@@ -112,8 +99,8 @@ public class Jws2Discoverer
   private volatile boolean running = false;
 
   private volatile boolean aborted = false;
-
-  private Thread oldthread = null;
+  
+  private volatile Thread oldthread = null;
 
   /**
    * holds list of services.
@@ -121,27 +108,31 @@ public class Jws2Discoverer
   protected Vector<Jws2Instance> services;
 
   /**
-   * change listeners are notified of "services" property changes
-   * 
-   * @param listener
-   *          to be added that consumes new services Hashtable object.
+   * Private constructor enforces use of singleton via getDiscoverer()
    */
-  public void addPropertyChangeListener(
-          java.beans.PropertyChangeListener listener)
+  private Jws2Discoverer()
   {
-    changeSupport.addPropertyChangeListener(listener);
   }
 
-  /**
-   * 
-   * 
-   * @param listener
-   *          to be removed
-   */
-  public void removePropertyChangeListener(
-          java.beans.PropertyChangeListener listener)
+
+  @Override
+  public void addServiceChangeListener(ServiceChangeListener listener)
+  {
+    serviceListeners.add(listener);
+  }
+
+  @Override
+  public void removeServiceChangeListener(ServiceChangeListener listener)
   {
-    changeSupport.removePropertyChangeListener(listener);
+    serviceListeners.remove(listener);
+  }
+
+  private void notifyServiceListeners(List<? extends ServiceWithParameters> services) 
+  {
+    if (services == null) services = this.services;
+    for (var listener : serviceListeners) {
+      listener.servicesChanged(this, services);
+    }
   }
 
   /**
@@ -196,13 +187,11 @@ public class Jws2Discoverer
       ignoredServices.add(ignored);
     }
 
-    changeSupport.firePropertyChange("services", services,
-            new Vector<Jws2Instance>());
+    notifyServiceListeners(Collections.emptyList());
     oldthread = Thread.currentThread();
     try
     {
-      getClass().getClassLoader()
-              .loadClass("compbio.ws.client.Jws2Client");
+      getClass().getClassLoader().loadClass("compbio.ws.client.Jws2Client");
     } catch (ClassNotFoundException e)
     {
       System.err.println(
@@ -291,14 +280,14 @@ public class Jws2Discoverer
         for (Jws2Instance svc : services)
         {
           svcs[ipos] = svc;
-          spos[ipos++] = 1000 * svcUrls.indexOf(svc.getHost()) + 1
-                  + svctypes.indexOf(svc.serviceType);
+          spos[ipos++] = 1000 * svcUrls.indexOf(svc.getHostURL()) + 1
+                  + svctypes.indexOf(svc.getName());
         }
         jalview.util.QuickSort.sort(spos, svcs);
         services = new Vector<>();
         for (Jws2Instance svc : svcs)
         {
-          if (!ignoredServices.contains(svc.serviceType))
+          if (!ignoredServices.contains(svc.getName()))
           {
             services.add(svc);
           }
@@ -307,8 +296,7 @@ public class Jws2Discoverer
     }
     oldthread = null;
     running = false;
-    changeSupport.firePropertyChange("services", new Vector<Jws2Instance>(),
-            services);
+    notifyServiceListeners(services);
   }
 
   /**
@@ -345,249 +333,6 @@ public class Jws2Discoverer
   }
 
   /**
-   * attach all available web services to the appropriate submenu in the given
-   * JMenu
-   */
-  @Override
-  public void attachWSMenuEntry(JMenu wsmenu, final AlignFrame alignFrame)
-  {
-    // dynamically regenerate service list.
-    populateWSMenuEntry(wsmenu, alignFrame, null);
-  }
-
-  private boolean isRecalculable(String action)
-  {
-    return (action != null && action.equalsIgnoreCase("conservation"));
-  }
-
-  private void populateWSMenuEntry(JMenu jws2al,
-          final AlignFrame alignFrame, String typeFilter)
-  {
-    if (running || services == null || services.size() == 0)
-    {
-      return;
-    }
-
-    /**
-     * eventually, JWS2 services will appear under the same align/etc submenus.
-     * for moment we keep them separate.
-     */
-    JMenu atpoint;
-    List<Jws2Instance> enumerableServices = new ArrayList<>();
-    // jws2al.removeAll();
-    Map<String, Jws2Instance> preferredHosts = new HashMap<>();
-    Map<String, List<Jws2Instance>> alternates = new HashMap<>();
-    for (Jws2Instance service : services.toArray(new Jws2Instance[0]))
-    {
-      if (!isRecalculable(service.action))
-      {
-        // add 'one shot' services to be displayed using the classic menu
-        // structure
-        enumerableServices.add(service);
-      }
-      else
-      {
-        if (!preferredHosts.containsKey(service.serviceType))
-        {
-          Jws2Instance preferredInstance = getPreferredServiceFor(
-                  alignFrame, service.serviceType);
-          if (preferredInstance != null)
-          {
-            preferredHosts.put(service.serviceType, preferredInstance);
-          }
-          else
-          {
-            preferredHosts.put(service.serviceType, service);
-          }
-        }
-        List<Jws2Instance> ph = alternates.get(service.serviceType);
-        if (preferredHosts.get(service.serviceType) != service)
-        {
-          if (ph == null)
-          {
-            ph = new ArrayList<>();
-          }
-          ph.add(service);
-          alternates.put(service.serviceType, ph);
-        }
-      }
-
-    }
-
-    // create GUI element for classic services
-    addEnumeratedServices(jws2al, alignFrame, enumerableServices);
-    // and the instantaneous services
-    for (final Jws2Instance service : preferredHosts.values())
-    {
-      atpoint = JvSwingUtils.findOrCreateMenu(jws2al, service.action);
-      JMenuItem hitm;
-      if (atpoint.getItemCount() > 1)
-      {
-        // previous service of this type already present
-        atpoint.addSeparator();
-      }
-      atpoint.add(hitm = new JMenuItem(service.getHost()));
-      hitm.setForeground(Color.blue);
-      hitm.addActionListener(new ActionListener()
-      {
-
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          Desktop.showUrl(service.getHost());
-        }
-      });
-      hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
-              MessageManager.getString("label.open_jabaws_web_page")));
-
-      service.attachWSMenuEntry(atpoint, alignFrame);
-      if (alternates.containsKey(service.serviceType))
-      {
-        atpoint.add(hitm = new JMenu(
-                MessageManager.getString("label.switch_server")));
-        hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
-                MessageManager.getString("label.choose_jabaws_server")));
-        for (final Jws2Instance sv : alternates.get(service.serviceType))
-        {
-          JMenuItem itm;
-          hitm.add(itm = new JMenuItem(sv.getHost()));
-          itm.setForeground(Color.blue);
-          itm.addActionListener(new ActionListener()
-          {
-
-            @Override
-            public void actionPerformed(ActionEvent arg0)
-            {
-              new Thread(new Runnable()
-              {
-                @Override
-                public void run()
-                {
-                  setPreferredServiceFor(alignFrame, sv.serviceType,
-                          sv.action, sv);
-                  changeSupport.firePropertyChange("services",
-                          new Vector<Jws2Instance>(), services);
-                }
-              }).start();
-
-            }
-          });
-        }
-      }
-    }
-  }
-
-  /**
-   * add services using the Java 2.5/2.6/2.7 system which optionally creates
-   * submenus to index by host and service program type
-   */
-  private void addEnumeratedServices(final JMenu jws2al,
-          final AlignFrame alignFrame,
-          List<Jws2Instance> enumerableServices)
-  {
-    boolean byhost = Cache.getDefault("WSMENU_BYHOST", false),
-            bytype = Cache.getDefault("WSMENU_BYTYPE", false);
-    /**
-     * eventually, JWS2 services will appear under the same align/etc submenus.
-     * for moment we keep them separate.
-     */
-    JMenu atpoint;
-
-    List<String> hostLabels = new ArrayList<>();
-    Hashtable<String, String> lasthostFor = new Hashtable<>();
-    Hashtable<String, ArrayList<Jws2Instance>> hosts = new Hashtable<>();
-    ArrayList<String> hostlist = new ArrayList<>();
-    for (Jws2Instance service : enumerableServices)
-    {
-      ArrayList<Jws2Instance> hostservices = hosts.get(service.getHost());
-      if (hostservices == null)
-      {
-        hosts.put(service.getHost(),
-                hostservices = new ArrayList<>());
-        hostlist.add(service.getHost());
-      }
-      hostservices.add(service);
-    }
-    // now add hosts in order of the given array
-    for (String host : hostlist)
-    {
-      Jws2Instance orderedsvcs[] = hosts.get(host)
-              .toArray(new Jws2Instance[1]);
-      String sortbytype[] = new String[orderedsvcs.length];
-      for (int i = 0; i < sortbytype.length; i++)
-      {
-        sortbytype[i] = orderedsvcs[i].serviceType;
-      }
-      jalview.util.QuickSort.sort(sortbytype, orderedsvcs);
-      for (final Jws2Instance service : orderedsvcs)
-      {
-        atpoint = JvSwingUtils.findOrCreateMenu(jws2al, service.action);
-        String type = service.serviceType;
-        if (byhost)
-        {
-          atpoint = JvSwingUtils.findOrCreateMenu(atpoint, host);
-          if (atpoint.getToolTipText() == null)
-          {
-            atpoint.setToolTipText(MessageManager
-                    .formatMessage("label.services_at", new String[]
-                    { host }));
-          }
-        }
-        if (bytype)
-        {
-          atpoint = JvSwingUtils.findOrCreateMenu(atpoint, type);
-          if (atpoint.getToolTipText() == null)
-          {
-            atpoint.setToolTipText(service.getActionText());
-          }
-        }
-        if (!byhost && !hostLabels.contains(
-                host + service.serviceType + service.getActionText()))
-        // !hostLabels.contains(host + (bytype ?
-        // service.serviceType+service.getActionText() : "")))
-        {
-          // add a marker indicating where this service is hosted
-          // relies on services from the same host being listed in a
-          // contiguous
-          // group
-          JMenuItem hitm;
-          if (hostLabels.contains(host))
-          {
-            atpoint.addSeparator();
-          }
-          else
-          {
-            hostLabels.add(host);
-          }
-          if (lasthostFor.get(service.action) == null
-                  || !lasthostFor.get(service.action).equals(host))
-          {
-            atpoint.add(hitm = new JMenuItem(host));
-            hitm.setForeground(Color.blue);
-            hitm.addActionListener(new ActionListener()
-            {
-
-              @Override
-              public void actionPerformed(ActionEvent e)
-              {
-                Desktop.showUrl(service.getHost());
-              }
-            });
-            hitm.setToolTipText(
-                    JvSwingUtils.wrapTooltip(true, MessageManager
-                            .getString("label.open_jabaws_web_page")));
-            lasthostFor.put(service.action, host);
-          }
-          hostLabels.add(
-                  host + service.serviceType + service.getActionText());
-        }
-
-        service.attachWSMenuEntry(atpoint, alignFrame);
-      }
-    }
-  }
-
-  /**
    * 
    * @param args
    * @j2sIgnore
@@ -603,35 +348,28 @@ public class Jws2Discoverer
         instance.testUrls.add(url);
       }
     }
-    Thread runner = instance.startDiscoverer(new PropertyChangeListener()
-    {
-
-      @Override
-      public void propertyChange(PropertyChangeEvent evt)
+    var discoverer = getInstance();
+    discoverer.addServiceChangeListener((_discoverer, _services) -> {
+      if (discoverer.services != null)
       {
-        if (getInstance().services != null)
+        System.out.println("Changesupport: There are now "
+                + discoverer.services.size() + " services");
+        int i = 1;
+        for (ServiceWithParameters s_instance : discoverer.services)
         {
-          System.out.println("Changesupport: There are now "
-                  + getInstance().services.size() + " services");
-          int i = 1;
-          for (Jws2Instance instance : getInstance().services)
-          {
-            System.out.println("Service " + i++ + " " + instance.getClass()
-                    + "@" + instance.getHost() + ": "
-                    + instance.getActionText());
-          }
-
+          System.out.println(
+                  "Service " + i++ + " " + s_instance.getClass()
+                          + "@" + s_instance.getHostURL() + ": "
+                          + s_instance.getActionText());
         }
+
       }
     });
-    while (runner.isAlive())
+    try
+    {
+      discoverer.startDiscoverer().get();
+    } catch (InterruptedException | ExecutionException e)
     {
-      try
-      {
-        Thread.sleep(50);
-      } catch (InterruptedException e)
-      {
-      }
     }
     try
     {
@@ -641,16 +379,20 @@ public class Jws2Discoverer
     }
   }
 
+
+  @Override
   public boolean hasServices()
   {
     return !running && services != null && services.size() > 0;
   }
 
+  @Override
   public boolean isRunning()
   {
     return running;
   }
 
+  @Override
   public void setServiceUrls(List<String> wsUrls)
   {
     if (wsUrls != null && !wsUrls.isEmpty())
@@ -677,6 +419,7 @@ public class Jws2Discoverer
    * 
    * @return
    */
+  @Override
   public List<String> getServiceUrls()
   {
     if (testUrls != null)
@@ -730,10 +473,10 @@ public class Jws2Discoverer
     return urls;
   }
 
-  public Vector<Jws2Instance> getServices()
+  @Override
+  public Vector<ServiceWithParameters> getServices()
   {
-    return (services == null) ? new Vector<>()
-            : new Vector<>(services);
+    return (services == null) ? new Vector<>() : new Vector<>(services);
   }
 
   /**
@@ -742,7 +485,8 @@ public class Jws2Discoverer
    * @param foo
    * @return
    */
-  public static boolean testServiceUrl(URL foo)
+  @Override
+  public boolean testServiceUrl(URL foo)
   {
     try
     {
@@ -790,7 +534,8 @@ public class Jws2Discoverer
    * @param changeSupport2
    * @return new thread
    */
-  public Thread startDiscoverer(PropertyChangeListener changeSupport2)
+  @Override
+  public CompletableFuture<WSDiscovererI> startDiscoverer()
   {
     /*    if (restart())
         {
@@ -806,10 +551,12 @@ public class Jws2Discoverer
     {
       setAborted(true);
     }
-    addPropertyChangeListener(changeSupport2);
-    Thread thr = new Thread(this);
-    thr.start();
-    return thr;
+    CompletableFuture<WSDiscovererI> task = CompletableFuture
+            .supplyAsync(() -> {
+              run();
+              return Jws2Discoverer.this;
+            });
+    return task;
   }
 
   /**
@@ -871,6 +618,7 @@ public class Jws2Discoverer
    * @return a human readable report of any problems with the service URLs used
    *         for discovery
    */
+  @Override
   public String getErrorMessages()
   {
     if (!isRunning() && !isAborted())
@@ -919,129 +667,22 @@ public class Jws2Discoverer
     return null;
   }
 
+  @Override
   public int getServerStatusFor(String url)
   {
     if (validServiceUrls != null && validServiceUrls.contains(url))
     {
-      return 1;
+      return STATUS_OK;
     }
     if (urlsWithoutServices != null && urlsWithoutServices.contains(url))
     {
-      return 0;
+      return STATUS_NO_SERVICES;
     }
     if (invalidServiceUrls != null && invalidServiceUrls.contains(url))
     {
-      return -1;
-    }
-    return -2;
-  }
-
-  /**
-   * pick the user's preferred service based on a set of URLs (jaba server
-   * locations) and service URIs (specifying version and service interface
-   * class)
-   * 
-   * @param serviceURL
-   * @return null or best match for given uri/ls.
-   */
-  public Jws2Instance getPreferredServiceFor(String[] serviceURLs)
-  {
-    HashSet<String> urls = new HashSet<>();
-    urls.addAll(Arrays.asList(serviceURLs));
-    Jws2Instance match = null;
-    if (services != null)
-    {
-      for (Jws2Instance svc : services)
-      {
-        if (urls.contains(svc.getServiceTypeURI()))
-        {
-          if (match == null)
-          {
-            // for moment we always pick service from server ordered first in
-            // user's preferences
-            match = svc;
-          }
-          if (urls.contains(svc.getUri()))
-          {
-            // stop and return - we've matched type URI and URI for service
-            // endpoint
-            return svc;
-          }
-        }
-      }
-    }
-    return match;
-  }
-
-  Map<String, Map<String, String>> preferredServiceMap = new HashMap<>();
-
-  /**
-   * get current preferred service of the given type, or global default
-   * 
-   * @param af
-   *          null or a specific alignFrame
-   * @param serviceType
-   *          Jws2Instance.serviceType for service
-   * @return null if no service of this type is available, the preferred service
-   *         for the serviceType and af if specified and if defined.
-   */
-  public Jws2Instance getPreferredServiceFor(AlignFrame af,
-          String serviceType)
-  {
-    String serviceurl = null;
-    synchronized (preferredServiceMap)
-    {
-      String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
-      Map<String, String> prefmap = preferredServiceMap.get(afid);
-      if (afid.length() > 0 && prefmap == null)
-      {
-        // recover global setting, if any
-        prefmap = preferredServiceMap.get("");
-      }
-      if (prefmap != null)
-      {
-        serviceurl = prefmap.get(serviceType);
-      }
-
+      return STATUS_INVALID;
     }
-    Jws2Instance response = null;
-    for (Jws2Instance svc : services)
-    {
-      if (svc.serviceType.equals(serviceType))
-      {
-        if (serviceurl == null || serviceurl.equals(svc.getHost()))
-        {
-          response = svc;
-          break;
-        }
-      }
-    }
-    return response;
-  }
-
-  public void setPreferredServiceFor(AlignFrame af, String serviceType,
-          String serviceAction, Jws2Instance selectedServer)
-  {
-    String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
-    if (preferredServiceMap == null)
-    {
-      preferredServiceMap = new HashMap<>();
-    }
-    Map<String, String> prefmap = preferredServiceMap.get(afid);
-    if (prefmap == null)
-    {
-      prefmap = new HashMap<>();
-      preferredServiceMap.put(afid, prefmap);
-    }
-    prefmap.put(serviceType, selectedServer.getHost());
-    prefmap.put(serviceAction, selectedServer.getHost());
-  }
-
-  public void setPreferredServiceFor(String serviceType,
-          String serviceAction, Jws2Instance selectedServer)
-  {
-    setPreferredServiceFor(null, serviceType, serviceAction,
-            selectedServer);
+    return STATUS_UNKNOWN;
   }
 
   /**
index 319252a..e44381c 100644 (file)
@@ -27,7 +27,12 @@ import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
 import jalview.gui.JvSwingUtils;
 import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.WSMenuEntryProviderI;
+import jalview.ws.api.JalviewServiceEndpointProviderI;
+import jalview.ws.api.MultipleSequenceAlignmentI;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.gui.MsaWSThread;
+import jalview.ws.params.ArgumentI;
 import jalview.ws.params.WsParamSetI;
 
 import java.awt.event.ActionEvent;
@@ -40,23 +45,28 @@ import javax.swing.JMenu;
 import javax.swing.JMenuItem;
 import javax.swing.ToolTipManager;
 
-import compbio.data.msa.MsaWS;
-import compbio.metadata.Argument;
-
 /**
- * DOCUMENT ME!
+ * MsaWSClient
+ * 
+ * Instantiates web service menu items for multiple alignment services, and
+ * holds logic for constructing a web service thread.
  * 
- * @author $author$
+ * TODO remove dependency on Jws2Client methods for creating AACon service UI
+ * elements.
+ * 
+ * @author Jim Procter et al
  * @version $Revision$
  */
-public class MsaWSClient extends Jws2Client
+public class MsaWSClient extends Jws2Client implements WSMenuEntryProviderI
 {
   /**
-   * server is a WSDL2Java generated stub for an archetypal MsaWSI service.
+   * server is a proxy class implementing the core methods for submitting,
+   * monitoring and retrieving results from a multiple sequence alignment
+   * service
    */
-  MsaWS server;
+  MultipleSequenceAlignmentI server;
 
-  public MsaWSClient(Jws2Instance sh, String altitle,
+  public MsaWSClient(ServiceWithParameters sh, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
           boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
@@ -66,7 +76,8 @@ public class MsaWSClient extends Jws2Client
     // TODO Auto-generated constructor stub
   }
 
-  public MsaWSClient(Jws2Instance sh, WsParamSetI preset, String altitle,
+  public MsaWSClient(ServiceWithParameters sh, WsParamSetI preset,
+          String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
           boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
@@ -92,8 +103,8 @@ public class MsaWSClient extends Jws2Client
    *          DOCUMENT ME!
    */
 
-  public MsaWSClient(Jws2Instance sh, WsParamSetI preset,
-          List<Argument> arguments, boolean editParams, String altitle,
+  public MsaWSClient(ServiceWithParameters sh, WsParamSetI preset,
+          List<ArgumentI> arguments, boolean editParams, String altitle,
           jalview.datamodel.AlignmentView msa, boolean submitGaps,
           boolean preserveOrder, AlignmentI seqdataset,
           AlignFrame _alignFrame)
@@ -104,25 +115,29 @@ public class MsaWSClient extends Jws2Client
       return;
     }
 
-    if (!(sh.service instanceof MsaWS))
+    if (!(sh instanceof JalviewServiceEndpointProviderI
+            && ((JalviewServiceEndpointProviderI) sh)
+                    .getEndpoint() instanceof MultipleSequenceAlignmentI))
     {
       // redundant at mo - but may change
       JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
               MessageManager.formatMessage(
                       "label.service_called_is_not_msa_service",
                       new String[]
-                      { sh.serviceType }),
+                      { sh.getName() }),
               MessageManager.getString("label.internal_jalview_error"),
               JvOptionPane.WARNING_MESSAGE);
 
       return;
     }
-    server = (MsaWS) sh.service;
+    serviceHandle = sh;
+    server = (MultipleSequenceAlignmentI) ((JalviewServiceEndpointProviderI) sh)
+            .getEndpoint();
     if ((wsInfo = setWebService(sh, false)) == null)
     {
       JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager
               .formatMessage("label.msa_service_is_unknown", new String[]
-              { sh.serviceType }),
+              { sh.getName() }),
               MessageManager.getString("label.internal_jalview_error"),
               JvOptionPane.WARNING_MESSAGE);
 
@@ -214,16 +229,28 @@ public class MsaWSClient extends Jws2Client
 
   @Override
   public void attachWSMenuEntry(JMenu rmsawsmenu,
-          final Jws2Instance service, final AlignFrame alignFrame)
+          final ServiceWithParameters service, final AlignFrame alignFrame)
   {
-    if (registerAAConWSInstance(rmsawsmenu, service, alignFrame))
+    if (Jws2ClientFactory.registerAAConWSInstance(rmsawsmenu,
+                    service, alignFrame))
     {
       // Alignment dependent analysis calculation WS gui
       return;
     }
+    serviceHandle = service;
     setWebService(service, true); // headless
+    attachWSMenuEntry(rmsawsmenu, alignFrame);
+  }
+
+  @Override
+  public void attachWSMenuEntry(JMenu wsmenu, AlignFrame alignFrame)
+  {
     boolean finished = true, submitGaps = false;
-    JMenu msawsmenu = rmsawsmenu;
+    /**
+     * temp variables holding msa service submenu or root service menu
+     */
+    JMenu msawsmenu = wsmenu;
+    JMenu rmsawsmenu = wsmenu;
     String svcname = WebServiceName;
     if (svcname.endsWith("WS"))
     {
@@ -236,7 +263,8 @@ public class MsaWSClient extends Jws2Client
       rmsawsmenu.add(msawsmenu);
       calcName = "";
     }
-    boolean hasparams = service.hasParameters();
+    boolean hasparams = serviceHandle.hasParameters();
+    ServiceWithParameters service = (ServiceWithParameters) serviceHandle;
     do
     {
       String action = "Align ";
index c7fad05..d789dda 100644 (file)
@@ -37,7 +37,7 @@ public class ParameterUtils
   public static List<String> writeParameterSet(List<Option> optSet,
           String pseparator)
   {
-    List<String> pset = new ArrayList<String>();
+    List<String> pset = new ArrayList<>();
     for (Option o : optSet)
     {
       pset.add(o.toCommand(pseparator));
@@ -64,7 +64,7 @@ public class ParameterUtils
   public static List<Option> processParameters(List<String> params,
           RunnerConfig options, String pseparator)
   {
-    List<Option> chosenOptions = new ArrayList<Option>();
+    List<Option> chosenOptions = new ArrayList<>();
     for (String param : params)
     {
       String oname = null;
diff --git a/src/jalview/ws/jws2/PreferredServiceChangeListener.java b/src/jalview/ws/jws2/PreferredServiceChangeListener.java
new file mode 100644 (file)
index 0000000..ff959ca
--- /dev/null
@@ -0,0 +1,9 @@
+package jalview.ws.jws2;
+
+import jalview.ws.api.ServiceWithParameters;
+
+@FunctionalInterface
+public interface PreferredServiceChangeListener
+{
+  public void preferredServiceChanged(ServiceWithParameters newValue);
+}
diff --git a/src/jalview/ws/jws2/PreferredServiceRegistry.java b/src/jalview/ws/jws2/PreferredServiceRegistry.java
new file mode 100644 (file)
index 0000000..45af925
--- /dev/null
@@ -0,0 +1,355 @@
+package jalview.ws.jws2;
+
+import jalview.bin.Cache;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvSwingUtils;
+import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
+
+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.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+
+public class PreferredServiceRegistry
+{
+
+  private static PreferredServiceRegistry us = new PreferredServiceRegistry();
+
+  public static PreferredServiceRegistry getRegistry()
+  {
+    if (us == null)
+    {
+      us = new PreferredServiceRegistry();
+    }
+    return us;
+  }
+
+  List<ServiceWithParameters> ourServices = new ArrayList<>();
+
+  /**
+   * forget about any known services
+   */
+  public void clearServices()
+  {
+    ourServices.clear();
+  }
+
+  public void populateWSMenuEntry(List<ServiceWithParameters> services,
+          PreferredServiceChangeListener changeListener, JMenu menu,
+          final AlignFrame alignFrame, String typeFilter)
+  {
+    /**
+     * eventually, JWS2 services will appear under the same align/etc submenus.
+     * for moment we keep them separate.
+     */
+    ourServices.addAll(services);
+    JMenu atpoint;
+    
+    List<ServiceWithParameters> oneshotServices = new ArrayList<>();
+    List<ServiceWithParameters> interactiveServices = new ArrayList<>();
+    Map<String, ServiceWithParameters> preferredHosts = new HashMap<>();
+    Map<String, List<ServiceWithParameters>> alternates = new HashMap<>();
+    
+    for (var service : services) 
+    {
+      if (service.isInteractiveUpdate())
+        interactiveServices.add(service);
+      else
+        oneshotServices.add(service);
+    }
+    for (var service : interactiveServices)
+    {
+      if (!preferredHosts.containsKey(service.getName()))
+      {
+        var preferred = getPreferredServiceFor(alignFrame, service.getName());
+        preferredHosts.put(service.getName(), (preferred != null) ? preferred : service);
+      }
+      var ph = alternates.getOrDefault(service.getName(), new ArrayList<>());
+      if (!preferredHosts.containsValue(service)) 
+      {
+        ph.add(service);
+        alternates.putIfAbsent(service.getName(), ph);
+      }
+    }
+
+    // create GUI element for classic services
+    addEnumeratedServices(menu, alignFrame, oneshotServices);
+    // and the instantaneous services
+    for (final ServiceWithParameters service : preferredHosts.values())
+    {
+      atpoint = JvSwingUtils.findOrCreateMenu(menu,
+              service.getServiceType());
+      if (atpoint.getItemCount() > 1)
+      {
+        // previous service of this type already present
+        atpoint.addSeparator();
+      }
+      JMenuItem hitm;
+      atpoint.add(hitm = new JMenuItem(service.getHostURL()));
+      hitm.setForeground(Color.blue);
+      hitm.addActionListener(e -> Desktop.showUrl(service.getHostURL()));
+      hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
+              MessageManager.getString("label.open_jabaws_web_page")));
+
+      service.attachWSMenuEntry(atpoint, alignFrame);
+      if (alternates.containsKey(service.getName()))
+      {
+        atpoint.add(hitm = new JMenu(
+                MessageManager.getString("label.switch_server")));
+        hitm.setToolTipText(JvSwingUtils.wrapTooltip(false,
+                MessageManager.getString("label.choose_jabaws_server")));
+        for (final ServiceWithParameters sv : alternates
+                .get(service.getName()))
+        {
+          JMenuItem itm;
+          hitm.add(itm = new JMenuItem(sv.getHostURL()));
+          itm.setForeground(Color.blue);
+          itm.addActionListener(e -> {
+            setPreferredServiceFor(alignFrame, sv.getName(), sv.getServiceType(), sv);
+            changeListener.preferredServiceChanged(sv);
+          });
+        }
+      }
+    }
+  }
+
+  /**
+   * add services using the Java 2.5/2.6/2.7 system which optionally creates
+   * submenus to index by host and service program type
+   */
+  private void addEnumeratedServices(final JMenu jws2al,
+          final AlignFrame alignFrame,
+          List<ServiceWithParameters> enumerableServices)
+  {
+    boolean byhost = Cache.getDefault("WSMENU_BYHOST", false),
+            bytype = Cache.getDefault("WSMENU_BYTYPE", false);
+    /**
+     * eventually, JWS2 services will appear under the same align/etc submenus.
+     * for moment we keep them separate.
+     */
+    JMenu atpoint;
+
+    List<String> hostLabels = new ArrayList<>();
+    Hashtable<String, String> lasthostFor = new Hashtable<>();
+    Hashtable<String, ArrayList<ServiceWithParameters>> hosts = new Hashtable<>();
+    ArrayList<String> hostlist = new ArrayList<>();
+    for (ServiceWithParameters service : enumerableServices)
+    {
+      ArrayList<ServiceWithParameters> hostservices = hosts
+              .get(service.getHostURL());
+      if (hostservices == null)
+      {
+        hosts.put(service.getHostURL(), hostservices = new ArrayList<>());
+        hostlist.add(service.getHostURL());
+      }
+      hostservices.add(service);
+    }
+    // now add hosts in order of the given array
+    for (String host : hostlist)
+    {
+      ServiceWithParameters orderedsvcs[] = hosts.get(host)
+              .toArray(new ServiceWithParameters[1]);
+      String sortbytype[] = new String[orderedsvcs.length];
+      for (int i = 0; i < sortbytype.length; i++)
+      {
+        sortbytype[i] = orderedsvcs[i].getName();
+      }
+      jalview.util.QuickSort.sort(sortbytype, orderedsvcs);
+      for (final ServiceWithParameters service : orderedsvcs)
+      {
+        atpoint = JvSwingUtils.findOrCreateMenu(jws2al,
+                service.getAction());
+        String type = service.getName();
+        if (byhost)
+        {
+          atpoint = JvSwingUtils.findOrCreateMenu(atpoint, host);
+          if (atpoint.getToolTipText() == null)
+          {
+            atpoint.setToolTipText(MessageManager
+                    .formatMessage("label.services_at", new String[]
+                    { host }));
+          }
+        }
+        if (bytype)
+        {
+          atpoint = JvSwingUtils.findOrCreateMenu(atpoint, type);
+          if (atpoint.getToolTipText() == null)
+          {
+            atpoint.setToolTipText(service.getActionText());
+          }
+        }
+        if (!byhost && !hostLabels.contains(
+                host + service.getName() + service.getActionText()))
+        // !hostLabels.contains(host + (bytype ?
+        // service.serviceType+service.getActionText() : "")))
+        {
+          // add a marker indicating where this service is hosted
+          // relies on services from the same host being listed in a
+          // contiguous
+          // group
+          JMenuItem hitm;
+          if (hostLabels.contains(host))
+          {
+            atpoint.addSeparator();
+          }
+          else
+          {
+            hostLabels.add(host);
+          }
+          if (lasthostFor.get(service.getAction()) == null
+                  || !lasthostFor.get(service.getAction()).equals(host))
+          {
+            atpoint.add(hitm = new JMenuItem(host));
+            hitm.setForeground(Color.blue);
+            hitm.addActionListener(new ActionListener()
+            {
+
+              @Override
+              public void actionPerformed(ActionEvent e)
+              {
+                Desktop.showUrl(service.getHostURL());
+              }
+            });
+            hitm.setToolTipText(
+                    JvSwingUtils.wrapTooltip(true, MessageManager
+                            .getString("label.open_jabaws_web_page")));
+            lasthostFor.put(service.getAction(), host);
+          }
+          hostLabels
+                  .add(host + service.getName() + service.getActionText());
+        }
+
+        service.attachWSMenuEntry(atpoint, alignFrame);
+      }
+    }
+  }
+
+  /**
+   * pick the user's preferred service based on a set of URLs (jaba server
+   * locations) and service URIs (specifying version and service interface
+   * class)
+   * 
+   * @param serviceURL
+   * @return null or best match for given uri/ls.
+   */
+  public ServiceWithParameters getPreferredServiceFor(String[] serviceURLs)
+  {
+    HashSet<String> urls = new HashSet<>();
+    urls.addAll(Arrays.asList(serviceURLs));
+    ServiceWithParameters match = null;
+
+    if (ourServices != null)
+    {
+      for (ServiceWithParameters svc : ourServices)
+      {
+        // TODO getNameURI Should return a versioned URI for the service, but
+        // doesn't as of 2.11
+        if (urls.contains(svc.getNameURI()))
+        {
+          if (match == null)
+          {
+            // for moment we always pick service from server ordered first in
+            // user's preferences
+            match = svc;
+          }
+          if (urls.contains(svc.getUri()))
+          {
+            // stop and return - we've matched type URI and URI for service
+            // endpoint
+            return svc;
+          }
+        }
+      }
+    }
+    return match;
+  }
+
+  Map<String, Map<String, String>> preferredServiceMap = new HashMap<>();
+
+  /**
+   * get current preferred endpoint of the given Jabaws service, or global
+   * default
+   * 
+   * @param af
+   *          null or a specific alignFrame
+   * @param serviceName
+   *          ServiceWithParameters.getName() for service
+   * @return null if no service of this type is available, the preferred service
+   *         for the serviceType and af if specified and if defined.
+   */
+  public ServiceWithParameters getPreferredServiceFor(AlignFrame af,
+          String serviceName)
+  {
+    String serviceurl = null;
+    synchronized (preferredServiceMap)
+    {
+      String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
+      Map<String, String> prefmap = preferredServiceMap.get(afid);
+      if (afid.length() > 0 && prefmap == null)
+      {
+        // recover global setting, if any
+        prefmap = preferredServiceMap.get("");
+      }
+      if (prefmap != null)
+      {
+        serviceurl = prefmap.get(serviceName);
+      }
+
+    }
+    ServiceWithParameters response = null;
+    for (ServiceWithParameters svc : ourServices)
+    {
+      if (svc.getName().equals(serviceName))
+      {
+        if (serviceurl == null || serviceurl.equals(svc.getHostURL()))
+        {
+          response = svc;
+          break;
+        }
+      }
+    }
+    return response;
+  }
+
+  public void setPreferredServiceFor(AlignFrame af, String serviceName,
+          String serviceAction, ServiceWithParameters selectedServer)
+  {
+    // TODO: pull out and generalise for the selectedServer's attributes
+    String afid = (af == null) ? "" : af.getViewport().getSequenceSetId();
+    if (preferredServiceMap == null)
+    {
+      preferredServiceMap = new HashMap<>();
+    }
+    Map<String, String> prefmap = preferredServiceMap.get(afid);
+    if (prefmap == null)
+    {
+      prefmap = new HashMap<>();
+      preferredServiceMap.put(afid, prefmap);
+    }
+    prefmap.put(serviceName, selectedServer.getHostURL());
+    prefmap.put(serviceAction, selectedServer.getHostURL());
+  }
+
+  public void setPreferredServiceFor(String serviceType,
+          String serviceAction, ServiceWithParameters selectedServer)
+  {
+    setPreferredServiceFor(null, serviceType, serviceAction,
+            selectedServer);
+  }
+
+  public boolean contains(ServiceWithParameters service)
+  {
+    return ourServices.contains(service);
+  }
+
+}
diff --git a/src/jalview/ws/jws2/SeqAnnotationServiceCalcWorker.java b/src/jalview/ws/jws2/SeqAnnotationServiceCalcWorker.java
new file mode 100644 (file)
index 0000000..4c807e1
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the 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.jws2;
+
+import jalview.analysis.AlignSeq;
+import jalview.analysis.AlignmentAnnotationUtils;
+import jalview.analysis.SeqsetUtils;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureColourI;
+import jalview.api.PollableAlignCalcWorkerI;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.ContiguousI;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.IProgressIndicator;
+import jalview.gui.IProgressIndicatorHandler;
+import jalview.gui.JvOptionPane;
+import jalview.gui.WebserviceInfo;
+import jalview.schemes.FeatureSettingsAdapter;
+import jalview.schemes.ResidueProperties;
+import jalview.util.MapList;
+import jalview.util.MessageManager;
+import jalview.workers.AlignCalcWorker;
+import jalview.ws.JobStateSummary;
+import jalview.ws.api.CancellableI;
+import jalview.ws.api.JalviewServiceEndpointProviderI;
+import jalview.ws.api.JobId;
+import jalview.ws.api.SequenceAnnotationServiceI;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.api.WSAnnotationCalcManagerI;
+import jalview.ws.gui.AnnotationWsJob;
+import jalview.ws.jws2.dm.AAConSettings;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SeqAnnotationServiceCalcWorker extends AlignCalcWorker
+        implements WSAnnotationCalcManagerI, PollableAlignCalcWorkerI
+{
+
+  protected ServiceWithParameters service;
+
+  protected WsParamSetI preset;
+
+  protected List<ArgumentI> arguments;
+
+  protected IProgressIndicator guiProgress;
+
+  protected boolean submitGaps = true;
+
+  /**
+   * by default, we filter out non-standard residues before submission
+   */
+  protected boolean filterNonStandardResidues = true;
+
+  /**
+   * Recover any existing parameters for this service
+   */
+  protected void initViewportParams()
+  {
+    if (getCalcId() != null)
+    {
+      ((jalview.gui.AlignViewport) alignViewport).setCalcIdSettingsFor(
+              getCalcId(),
+              new AAConSettings(true, service, this.preset, arguments),
+              true);
+    }
+  }
+
+  /**
+   * 
+   * @return null or a string used to recover all annotation generated by this
+   *         worker
+   */
+  public String getCalcId()
+  {
+    return service.getAlignAnalysisUI() == null ? null
+            : service.getAlignAnalysisUI().getCalcId();
+  }
+
+  public WsParamSetI getPreset()
+  {
+    return preset;
+  }
+
+  public List<ArgumentI> getArguments()
+  {
+    return arguments;
+  }
+
+  /**
+   * reconfigure and restart the AAConClient. This method will spawn a new
+   * thread that will wait until any current jobs are finished, modify the
+   * parameters and restart the conservation calculation with the new values.
+   * 
+   * @param newpreset
+   * @param newarguments
+   */
+  public void updateParameters(final WsParamSetI newpreset,
+          final List<ArgumentI> newarguments)
+  {
+    preset = newpreset;
+    arguments = newarguments;
+    calcMan.startWorker(this);
+    initViewportParams();
+  }
+  protected boolean alignedSeqs = true;
+
+  protected boolean nucleotidesAllowed = false;
+
+  protected boolean proteinAllowed = false;
+
+  /**
+   * record sequences for mapping result back to afterwards
+   */
+  protected boolean bySequence = false;
+
+  protected Map<String, SequenceI> seqNames;
+
+  // TODO: convert to bitset
+  protected boolean[] gapMap;
+
+  int realw;
+
+  protected int start;
+
+  int end;
+
+  private AlignFrame alignFrame;
+
+  public boolean[] getGapMap()
+  {
+    return gapMap;
+  }
+
+  public SeqAnnotationServiceCalcWorker(ServiceWithParameters service,
+          AlignFrame alignFrame,
+          WsParamSetI preset, List<ArgumentI> paramset)
+  {
+    super(alignFrame.getCurrentView(), alignFrame.alignPanel);
+    // TODO: both these fields needed ?
+    this.alignFrame = alignFrame;
+    this.guiProgress = alignFrame;
+    this.preset = preset;
+    this.arguments = paramset;
+    this.service = service;
+    try
+    {
+      annotService = (jalview.ws.api.SequenceAnnotationServiceI) ((JalviewServiceEndpointProviderI) service)
+              .getEndpoint();
+    } catch (ClassCastException cce)
+    {
+      annotService = null;
+      JvOptionPane.showMessageDialog(Desktop.getInstance(),
+              MessageManager.formatMessage(
+                      "label.service_called_is_not_an_annotation_service",
+                      new String[]
+                      { service.getName() }),
+              MessageManager.getString("label.internal_jalview_error"),
+              JvOptionPane.WARNING_MESSAGE);
+
+    }
+    cancellable = CancellableI.class.isInstance(annotService);
+    // configure submission flags
+    proteinAllowed = service.isProteinService();
+    nucleotidesAllowed = service.isNucleotideService();
+    alignedSeqs = service.isNeedsAlignedSequences();
+    bySequence = !service.isAlignmentAnalysis();
+    filterNonStandardResidues = service.isFilterSymbols();
+    min_valid_seqs = service.getMinimumInputSequences();
+    submitGaps = service.isAlignmentAnalysis();
+
+    if (service.isInteractiveUpdate())
+    {
+      initViewportParams();
+    }
+  }
+
+  /**
+   * 
+   * @return true if the submission thread should attempt to submit data
+   */
+  public boolean hasService()
+  {
+    return annotService != null;
+  }
+
+  protected SequenceAnnotationServiceI annotService;
+  protected final boolean cancellable;
+
+  volatile JobId rslt = null;
+
+  AnnotationWsJob running = null;
+
+  private int min_valid_seqs;
+
+
+  private long progressId = -1;
+  JobStateSummary job = null;
+  WebserviceInfo info = null;
+  List<SequenceI> seqs = null;
+  
+  @Override public void startUp() throws Throwable
+  {
+    if (alignViewport.isClosed())
+    {
+      abortAndDestroy();
+      return;
+    }
+    if (!hasService())
+    {
+      return;
+    }
+
+    StringBuffer msg = new StringBuffer();
+    job = new JobStateSummary();
+    info = new WebserviceInfo("foo", "bar", false);
+
+    seqs = getInputSequences(
+            alignViewport.getAlignment(),
+            bySequence ? alignViewport.getSelectionGroup() : null);
+
+    if (seqs == null || !checkValidInputSeqs(seqs))
+    {
+      jalview.bin.Cache.log.debug(
+              "Sequences for analysis service were null or not valid");
+      return;
+    }
+
+    if (guiProgress != null)
+    {
+      guiProgress.setProgressBar(service.getActionText(),
+              progressId = System.currentTimeMillis());
+    }
+    jalview.bin.Cache.log.debug("submitted " + seqs.size()
+            + " sequences to " + service.getActionText());
+
+    rslt = annotService.submitToService(seqs, getPreset(),
+            getArguments());
+    if (rslt == null)
+    {
+      return;
+    }
+    // TODO: handle job submission error reporting here.
+    Cache.log.debug("Service " + service.getUri() + "\nSubmitted job ID: "
+            + rslt);
+    ;
+    // ///
+    // otherwise, construct WsJob and any UI handlers
+    running = new AnnotationWsJob();
+    running.setJobHandle(rslt);
+    running.setSeqNames(seqNames);
+    running.setStartPos(start);
+    running.setSeqs(seqs);
+    job.updateJobPanelState(info, "", running);
+    if (guiProgress != null)
+    {
+      guiProgress.registerHandler(progressId,
+              new IProgressIndicatorHandler()
+              {
+
+                @Override
+                public boolean cancelActivity(long id)
+                {
+                  calcMan.cancelWorker(SeqAnnotationServiceCalcWorker.this);
+                  return true;
+                }
+
+                @Override
+                public boolean canCancel()
+                {
+                  return cancellable;
+                }
+              });
+    }
+  }
+  
+  @Override public boolean poll() throws Throwable
+  {
+    boolean finished = false;
+    
+    Cache.log.debug("Updating status for annotation service.");
+    annotService.updateStatus(running);
+    job.updateJobPanelState(info, "", running);
+    if (running.isSubjobComplete())
+    {
+      Cache.log.debug(
+              "Finished polling analysis service job: status reported is "
+                      + running.getState());
+      finished = true;
+    }
+    else
+    {
+      Cache.log.debug("Status now " + running.getState());
+    }
+
+    // pull any stats - some services need to flush log output before
+    // results are available
+    Cache.log.debug("Updating progress log for annotation service.");
+
+    try
+    {
+      annotService.updateJobProgress(running);
+    } catch (Throwable thr)
+    {
+      Cache.log.debug("Ignoring exception during progress update.",
+              thr);
+    }
+    Cache.log.trace("Result of poll: " + running.getStatus());
+    
+    
+    if (finished)
+    {
+      Cache.log.debug("Job poll loop exited. Job is " + running.getState());
+      if (running.isFinished())
+      {
+        // expect there to be results to collect
+        // configure job with the associated view's feature renderer, if one
+        // exists.
+        // TODO: here one would also grab the 'master feature renderer' in order
+        // to enable/disable
+        // features automatically according to user preferences
+        running.setFeatureRenderer(
+                ((jalview.gui.AlignmentPanel) ap).cloneFeatureRenderer());
+        Cache.log.debug("retrieving job results.");
+        final Map<String, FeatureColourI> featureColours = new HashMap<>();
+        final Map<String, FeatureMatcherSetI> featureFilters = new HashMap<>();
+        List<AlignmentAnnotation> returnedAnnot = annotService
+                .getAnnotationResult(running.getJobHandle(), seqs,
+                        featureColours, featureFilters);
+
+        Cache.log.debug("Obtained " + (returnedAnnot == null ? "no rows"
+                : ("" + returnedAnnot.size())));
+        Cache.log.debug("There were " + featureColours.size()
+                + " feature colours and " + featureFilters.size()
+                + " filters defined.");
+
+        // TODO
+        // copy over each annotation row reurned and also defined on each
+        // sequence, excluding regions not annotated due to gapMap/column
+        // visibility
+
+        // update calcId if it is not already set on returned annotation
+        if (returnedAnnot != null)
+        {
+          for (AlignmentAnnotation aa : returnedAnnot)
+          {
+            // assume that any CalcIds already set
+            if (getCalcId() != null && aa.getCalcId() == null
+                    || "".equals(aa.getCalcId()))
+            {
+              aa.setCalcId(getCalcId());
+            }
+            // autocalculated annotation are created by interactive alignment
+            // analysis services
+            aa.autoCalculated = service.isAlignmentAnalysis()
+                    && service.isInteractiveUpdate();
+          }
+        }
+
+        running.setAnnotation(returnedAnnot);
+
+        if (running.hasResults())
+        {
+          jalview.bin.Cache.log.debug("Updating result annotation from Job "
+                  + rslt + " at " + service.getUri());
+          updateResultAnnotation(true);
+          if (running.isTransferSequenceFeatures())
+          {
+            // TODO
+            // look at each sequence and lift over any features, excluding
+            // regions
+            // not annotated due to gapMap/column visibility
+
+            jalview.bin.Cache.log.debug(
+                    "Updating feature display settings and transferring features from Job "
+                            + rslt + " at " + service.getUri());
+            // TODO: consider merge rather than apply here
+            alignViewport.applyFeaturesStyle(new FeatureSettingsAdapter()
+            {
+              @Override
+              public FeatureColourI getFeatureColour(String type)
+              {
+                return featureColours.get(type);
+              }
+
+              @Override
+              public FeatureMatcherSetI getFeatureFilters(String type)
+              {
+                return featureFilters.get(type);
+              }
+
+              @Override
+              public boolean isFeatureDisplayed(String type)
+              {
+                return featureColours.containsKey(type);
+              }
+
+            });
+            // TODO: JAL-1150 - create sequence feature settings API for
+            // defining
+            // styles and enabling/disabling feature overlay on alignment panel
+
+            if (alignFrame.alignPanel == ap)
+            {
+              alignViewport.setShowSequenceFeatures(true);
+              alignFrame.setMenusForViewport();
+            }
+          }
+          ap.adjustAnnotationHeight();
+        }
+      }
+      Cache.log.debug("Annotation Service Worker thread finished.");
+
+    }
+    
+    return finished;
+  }
+  
+  @Override public void cancel()
+  {
+    cancelCurrentJob();
+  }
+  
+  @Override public void done()
+  {
+    if (ap != null)
+    {
+      if (guiProgress != null && progressId != -1)
+      {
+        guiProgress.removeProgressBar(progressId);
+      }
+      // TODO: may not need to paintAlignment again !
+      ap.paintAlignment(false, false);
+    }
+  }
+
+  /**
+   * validate input for dynamic/non-dynamic update context TODO: move to
+   * analysis interface ?
+   * @param seqs
+   * 
+   * @return true if input is valid
+   */
+  boolean checkValidInputSeqs(List<SequenceI> seqs)
+  {
+    int nvalid = 0;
+    for (SequenceI sq : seqs)
+    {
+      if (sq.getStart() <= sq.getEnd()
+              && (sq.isProtein() ? proteinAllowed : nucleotidesAllowed))
+      {
+        if (submitGaps
+                || sq.getLength() == (sq.getEnd() - sq.getStart() + 1))
+        {
+          nvalid++;
+        }
+      }
+    }
+    return nvalid >= min_valid_seqs;
+  }
+
+  public void cancelCurrentJob()
+  {
+    try
+    {
+      String id = running.getJobId();
+      if (cancellable && ((CancellableI) annotService).cancel(running))
+      {
+        System.err.println("Cancelled job " + id);
+      }
+      else
+      {
+        System.err.println("Job " + id + " couldn't be cancelled.");
+      }
+    } catch (Exception q)
+    {
+      q.printStackTrace();
+    }
+  }
+
+  /**
+   * Interactive updating. Analysis calculations that work on the currently
+   * displayed alignment data should cancel existing jobs when the input data
+   * has changed.
+   * 
+   * @return true if a running job should be cancelled because new input data is
+   *         available for analysis
+   */
+  boolean isInteractiveUpdate()
+  {
+    return service.isInteractiveUpdate();
+  }
+
+  /**
+   * decide what sequences will be analysed TODO: refactor to generate
+   * List<SequenceI> for submission to service interface
+   * 
+   * @param alignment
+   * @param inputSeqs
+   * @return
+   */
+  public List<SequenceI> getInputSequences(AlignmentI alignment,
+          AnnotatedCollectionI inputSeqs)
+  {
+    if (alignment == null || alignment.getWidth() <= 0
+            || alignment.getSequences() == null || alignment.isNucleotide()
+                    ? !nucleotidesAllowed
+                    : !proteinAllowed)
+    {
+      return null;
+    }
+    if (inputSeqs == null || inputSeqs.getWidth() <= 0
+            || inputSeqs.getSequences() == null
+            || inputSeqs.getSequences().size() < 1)
+    {
+      inputSeqs = alignment;
+    }
+
+    List<SequenceI> seqs = new ArrayList<>();
+
+    int minlen = 10;
+    int ln = -1;
+    if (bySequence)
+    {
+      seqNames = new HashMap<>();
+    }
+    gapMap = new boolean[0];
+    start = inputSeqs.getStartRes();
+    end = inputSeqs.getEndRes();
+    // TODO: URGENT! unify with JPred / MSA code to handle hidden regions
+    // correctly
+    // TODO: push attributes into WsJob instance (so they can be safely
+    // persisted/restored
+    for (SequenceI sq : (inputSeqs.getSequences()))
+    {
+      if (bySequence
+              ? sq.findPosition(end + 1)
+                      - sq.findPosition(start + 1) > minlen - 1
+              : sq.getEnd() - sq.getStart() > minlen - 1)
+      {
+        String newname = SeqsetUtils.unique_name(seqs.size() + 1);
+        // make new input sequence with or without gaps
+        if (seqNames != null)
+        {
+          seqNames.put(newname, sq);
+        }
+        SequenceI seq;
+        if (submitGaps)
+        {
+          seqs.add(seq = new jalview.datamodel.Sequence(newname,
+                  sq.getSequenceAsString()));
+          if (gapMap == null || gapMap.length < seq.getLength())
+          {
+            boolean[] tg = gapMap;
+            gapMap = new boolean[seq.getLength()];
+            System.arraycopy(tg, 0, gapMap, 0, tg.length);
+            for (int p = tg.length; p < gapMap.length; p++)
+            {
+              gapMap[p] = false; // init as a gap
+            }
+          }
+          for (int apos : sq.gapMap())
+          {
+            char sqc = sq.getCharAt(apos);
+            if (!filterNonStandardResidues
+                    || (sq.isProtein() ? ResidueProperties.aaIndex[sqc] < 20
+                            : ResidueProperties.nucleotideIndex[sqc] < 5))
+            {
+              gapMap[apos] = true; // aligned and real amino acid residue
+            }
+            ;
+          }
+        }
+        else
+        {
+          // TODO: add ability to exclude hidden regions
+          seqs.add(seq = new jalview.datamodel.Sequence(newname,
+                  AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
+                          sq.getSequenceAsString(start, end + 1))));
+          // for annotation need to also record map to sequence start/end
+          // position in range
+          // then transfer back to original sequence on return.
+        }
+        if (seq.getLength() > ln)
+        {
+          ln = seq.getLength();
+        }
+      }
+    }
+    if (alignedSeqs && submitGaps)
+    {
+      realw = 0;
+      for (int i = 0; i < gapMap.length; i++)
+      {
+        if (gapMap[i])
+        {
+          realw++;
+        }
+      }
+      // try real hard to return something submittable
+      // TODO: some of AAcon measures need a minimum of two or three amino
+      // acids at each position, and AAcon doesn't gracefully degrade.
+      for (int p = 0; p < seqs.size(); p++)
+      {
+        SequenceI sq = seqs.get(p);
+        // strip gapped columns
+        char[] padded = new char[realw],
+                orig = sq.getSequence();
+        for (int i = 0, pp = 0; i < realw; pp++)
+        {
+          if (gapMap[pp])
+          {
+            if (orig.length > pp)
+            {
+              padded[i++] = orig[pp];
+            }
+            else
+            {
+              padded[i++] = '-';
+            }
+          }
+        }
+        seqs.set(p, new jalview.datamodel.Sequence(sq.getName(),
+                new String(padded)));
+      }
+    }
+    return seqs;
+  }
+
+  @Override
+  public void updateAnnotation()
+  {
+    updateResultAnnotation(false);
+  }
+
+  public void updateResultAnnotation(boolean immediate)
+  {
+    if ((immediate || !calcMan.isWorking(this)) && running != null
+            && running.hasResults())
+    {
+      List<AlignmentAnnotation> ourAnnot = running.getAnnotation(),
+              newAnnots = new ArrayList<>();
+      //
+      // update graphGroup for all annotation
+      //
+      /**
+       * find a graphGroup greater than any existing ones this could be a method
+       * provided by alignment Alignment.getNewGraphGroup() - returns next
+       * unused graph group
+       */
+      int graphGroup = 1;
+      if (alignViewport.getAlignment().getAlignmentAnnotation() != null)
+      {
+        for (AlignmentAnnotation ala : alignViewport.getAlignment()
+                .getAlignmentAnnotation())
+        {
+          if (ala.graphGroup > graphGroup)
+          {
+            graphGroup = ala.graphGroup;
+          }
+        }
+      }
+      /**
+       * update graphGroup in the annotation rows returned from service
+       */
+      // TODO: look at sequence annotation rows and update graph groups in the
+      // case of reference annotation.
+      for (AlignmentAnnotation ala : ourAnnot)
+      {
+        if (ala.graphGroup > 0)
+        {
+          ala.graphGroup += graphGroup;
+        }
+        SequenceI aseq = null;
+
+        /**
+         * transfer sequence refs and adjust gapmap
+         */
+        if (ala.sequenceRef != null)
+        {
+          SequenceI seq = running.getSeqNames()
+                  .get(ala.sequenceRef.getName());
+          aseq = seq;
+          while (seq.getDatasetSequence() != null)
+          {
+            seq = seq.getDatasetSequence();
+          }
+        }
+        Annotation[] resAnnot = ala.annotations,
+                gappedAnnot = new Annotation[Math.max(
+                        alignViewport.getAlignment().getWidth(),
+                        gapMap.length)];
+        for (int p = 0, ap = start; ap < gappedAnnot.length; ap++)
+        {
+          if (gapMap != null && gapMap.length > ap && !gapMap[ap])
+          {
+            gappedAnnot[ap] = new Annotation("", "", ' ', Float.NaN);
+          }
+          else if (p < resAnnot.length)
+          {
+            gappedAnnot[ap] = resAnnot[p++];
+          }
+        }
+        ala.sequenceRef = aseq;
+        ala.annotations = gappedAnnot;
+        AlignmentAnnotation newAnnot = getAlignViewport().getAlignment()
+                .updateFromOrCopyAnnotation(ala);
+        if (aseq != null)
+        {
+
+          aseq.addAlignmentAnnotation(newAnnot);
+          newAnnot.adjustForAlignment();
+
+          AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(
+                  newAnnot, newAnnot.label, newAnnot.getCalcId());
+        }
+        newAnnots.add(newAnnot);
+
+      }
+      for (SequenceI sq : running.getSeqs())
+      {
+        if (!sq.getFeatures().hasFeatures()
+                && (sq.getDBRefs() == null || sq.getDBRefs().size() == 0))
+        {
+          continue;
+        }
+        running.setTransferSequenceFeatures(true);
+        SequenceI seq = running.getSeqNames().get(sq.getName());
+        SequenceI dseq;
+        ContiguousI seqRange = seq.findPositions(start, end);
+
+        while ((dseq = seq).getDatasetSequence() != null)
+        {
+          seq = seq.getDatasetSequence();
+        }
+        List<ContiguousI> sourceRange = new ArrayList();
+        if (gapMap != null && gapMap.length >= end)
+        {
+          int lastcol = start, col = start;
+          do
+          {
+            if (col == end || !gapMap[col])
+            {
+              if (lastcol <= (col - 1))
+              {
+                seqRange = seq.findPositions(lastcol, col);
+                sourceRange.add(seqRange);
+              }
+              lastcol = col + 1;
+            }
+          } while (++col <= end);
+        }
+        else
+        {
+          sourceRange.add(seq.findPositions(start, end));
+        }
+        int i = 0;
+        int source_startend[] = new int[sourceRange.size() * 2];
+
+        for (ContiguousI range : sourceRange)
+        {
+          source_startend[i++] = range.getBegin();
+          source_startend[i++] = range.getEnd();
+        }
+        Mapping mp = new Mapping(
+                new MapList(source_startend, new int[]
+                { seq.getStart(), seq.getEnd() }, 1, 1));
+        dseq.transferAnnotation(sq, mp);
+
+      }
+      updateOurAnnots(newAnnots);
+    }
+  }
+
+  protected void updateOurAnnots(List<AlignmentAnnotation> ourAnnot)
+  {
+    List<AlignmentAnnotation> our = ourAnnots;
+    ourAnnots = ourAnnot;
+    AlignmentI alignment = alignViewport.getAlignment();
+    if (our != null)
+    {
+      if (our.size() > 0)
+      {
+        for (AlignmentAnnotation an : our)
+        {
+          if (!ourAnnots.contains(an))
+          {
+            // remove the old annotation
+            alignment.deleteAnnotation(an);
+          }
+        }
+      }
+      our.clear();
+    }
+
+    // validate rows and update Alignmment state
+    for (AlignmentAnnotation an : ourAnnots)
+    {
+      alignViewport.getAlignment().validateAnnotation(an);
+    }
+    // TODO: may need a menu refresh after this
+    // af.setMenusForViewport();
+    ap.adjustAnnotationHeight();
+
+  }
+
+  public SequenceAnnotationServiceI getService()
+  {
+    return annotService;
+  }
+
+}
index 67e3338..6939db4 100644 (file)
@@ -25,8 +25,8 @@ import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.JvSwingUtils;
 import jalview.util.MessageManager;
-import jalview.ws.jws2.dm.AAConSettings;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.params.AutoCalcSetting;
 import jalview.ws.params.WsParamSetI;
 import jalview.ws.uimodel.AlignAnalysisUIText;
 
@@ -51,7 +51,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
     // TODO Auto-generated constructor stub
   }
 
-  public SequenceAnnotationWSClient(final Jws2Instance sh,
+  public SequenceAnnotationWSClient(final ServiceWithParameters sh,
           AlignFrame alignFrame, WsParamSetI preset, boolean editParams)
   {
     super(alignFrame, preset, null);
@@ -61,7 +61,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
   // dan think. Do I need to change this method to run RNAalifold through the
   // GUI
 
-  public void initSequenceAnnotationWSClient(final Jws2Instance sh,
+  public void initSequenceAnnotationWSClient(final ServiceWithParameters sh,
           AlignFrame alignFrame, WsParamSetI preset, boolean editParams)
   {
     // dan changed! dan test. comment out if conditional
@@ -82,9 +82,24 @@ public class SequenceAnnotationWSClient extends Jws2Client
       // columns
 
       List<AlignCalcWorkerI> clnts = alignFrame.getViewport()
-              .getCalcManager().getRegisteredWorkersOfClass(clientClass);
-      AbstractJabaCalcWorker worker;
-      if (clnts == null || clnts.size() == 0)
+              .getCalcManager()
+              .getWorkersOfClass(SeqAnnotationServiceCalcWorker.class);
+
+      SeqAnnotationServiceCalcWorker worker = null;
+      if (clnts != null)
+      {
+        for (AlignCalcWorkerI _worker : clnts)
+        {
+          worker = (SeqAnnotationServiceCalcWorker) _worker;
+          if (worker.hasService()
+                  && worker.getService().getClass().equals(clientClass))
+          {
+            break;
+          }
+          worker = null;
+        }
+      }
+      if (worker == null)
       {
         if (!processParams(sh, editParams))
         {
@@ -92,12 +107,8 @@ public class SequenceAnnotationWSClient extends Jws2Client
         }
         try
         {
-          worker = (AbstractJabaCalcWorker) (clientClass
-                  .getConstructor(new Class[]
-                  { Jws2Instance.class, AlignFrame.class, WsParamSetI.class,
-                      List.class })
-                  .newInstance(new Object[]
-                  { sh, alignFrame, this.preset, paramset }));
+          worker = new SeqAnnotationServiceCalcWorker(sh, alignFrame, this.preset,
+                  paramset);
         } catch (Exception x)
         {
           x.printStackTrace();
@@ -105,13 +116,13 @@ public class SequenceAnnotationWSClient extends Jws2Client
                   MessageManager.getString("error.implementation_error"),
                   x);
         }
-        alignFrame.getViewport().getCalcManager().registerWorker(worker);
-        alignFrame.getViewport().getCalcManager().startWorker(worker);
-
+        alignFrame.getViewport().getCalcManager().registerWorker(worker); // also
+                                                                          // starts
+                                                                          // the
+                                                                          // worker
       }
       else
       {
-        worker = (AbstractJabaCalcWorker) clnts.get(0);
         if (editParams)
         {
           paramset = worker.getArguments();
@@ -128,7 +139,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
         worker.updateParameters(this.preset, paramset);
       }
     }
-    if (sh.action.toLowerCase().contains("disorder"))
+    if (!sh.isInteractiveUpdate())
     {
       // build IUPred style client. take sequences, returns annotation per
       // sequence.
@@ -138,14 +149,14 @@ public class SequenceAnnotationWSClient extends Jws2Client
       }
 
       alignFrame.getViewport().getCalcManager().startWorker(
-              new AADisorderClient(sh, alignFrame, preset, paramset));
+              new SeqAnnotationServiceCalcWorker(sh, alignFrame, preset, paramset));
     }
   }
 
-  public SequenceAnnotationWSClient(AAConSettings fave,
+  public SequenceAnnotationWSClient(AutoCalcSetting fave,
           AlignFrame alignFrame, boolean b)
   {
-    super(alignFrame, fave.getPreset(), fave.getJobArgset());
+    super(alignFrame, fave.getPreset(), fave.getArgumentSet());
     initSequenceAnnotationWSClient(fave.getService(), alignFrame,
             fave.getPreset(), b);
   }
@@ -156,18 +167,24 @@ public class SequenceAnnotationWSClient extends Jws2Client
    * @see jalview.ws.jws2.Jws2Client#attachWSMenuEntry(javax.swing.JMenu,
    * jalview.ws.jws2.jabaws2.Jws2Instance, jalview.gui.AlignFrame)
    */
-  public void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
+  @Override
+  public void attachWSMenuEntry(JMenu wsmenu,
+          final ServiceWithParameters service,
           final AlignFrame alignFrame)
   {
-    if (registerAAConWSInstance(wsmenu, service, alignFrame))
+    if (Jws2ClientFactory.registerAAConWSInstance(wsmenu,
+            service, alignFrame))
     {
       // Alignment dependent analysis calculation WS gui
       return;
     }
     boolean hasparams = service.hasParameters();
-    // Assume name ends in WS
-    String calcName = service.serviceType.substring(0,
-            service.serviceType.length() - 2);
+    String calcName = service.getName();
+    if (calcName.endsWith("WS"))
+    {
+      // Remove "WS" suffix
+      calcName = calcName.substring(0, calcName.length() - 2);
+    }
 
     JMenuItem annotservice = new JMenuItem(MessageManager.formatMessage(
             "label.calcname_with_default_settings", new String[]
@@ -178,7 +195,8 @@ public class SequenceAnnotationWSClient extends Jws2Client
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        new SequenceAnnotationWSClient(service, alignFrame, null, false);
+        new SequenceAnnotationWSClient(service, alignFrame,
+                null, false);
       }
     });
     wsmenu.add(annotservice);
@@ -193,9 +211,11 @@ public class SequenceAnnotationWSClient extends Jws2Client
 
       annotservice.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent e)
         {
-          new SequenceAnnotationWSClient(service, alignFrame, null, true);
+          new SequenceAnnotationWSClient(service, alignFrame,
+                  null, true);
         }
       });
       wsmenu.add(annotservice);
@@ -217,9 +237,11 @@ public class SequenceAnnotationWSClient extends Jws2Client
                   + "</strong><br/>" + preset.getDescription()));
           methodR.addActionListener(new ActionListener()
           {
+            @Override
             public void actionPerformed(ActionEvent e)
             {
-              new SequenceAnnotationWSClient(service, alignFrame, preset,
+              new SequenceAnnotationWSClient(service,
+                      alignFrame, preset,
                       false);
             }
 
@@ -234,7 +256,7 @@ public class SequenceAnnotationWSClient extends Jws2Client
     {
       annotservice = new JMenuItem(
               MessageManager.getString("label.view_documentation"));
-      if (service.docUrl != null)
+      if (service != null && service.hasDocumentationUrl())
       {
         annotservice.addActionListener(new ActionListener()
         {
@@ -242,13 +264,14 @@ public class SequenceAnnotationWSClient extends Jws2Client
           @Override
           public void actionPerformed(ActionEvent arg0)
           {
-            Desktop.getInstance().showUrl(service.docUrl);
+            Desktop.getInstance().showUrl(service.getDocumentationUrl());
           }
         });
         annotservice.setToolTipText(
                 JvSwingUtils.wrapTooltip(true, MessageManager.formatMessage(
                         "label.view_service_doc_url", new String[]
-                        { service.docUrl, service.docUrl })));
+                        { service.getDocumentationUrl(),
+                            service.getDocumentationUrl() })));
         wsmenu.add(annotservice);
       }
     }
index 708787e..fa56874 100644 (file)
  */
 package jalview.ws.jws2.dm;
 
-import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.JabaPreset;
 import jalview.ws.jws2.ParameterUtils;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.WsParamSetI;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import compbio.metadata.Argument;
 import compbio.metadata.Option;
 
 /**
@@ -42,76 +38,13 @@ import compbio.metadata.Option;
  */
 public class AAConSettings extends jalview.ws.params.AutoCalcSetting
 {
-  Jws2Instance service;
-
-  public AAConSettings(boolean autoUpdate, Jws2Instance service,
+  public AAConSettings(boolean autoUpdate, ServiceWithParameters service2,
           WsParamSetI preset, List<ArgumentI> jobArgset)
   {
-    super(preset, jobArgset, autoUpdate);
-    this.service = service;
-  }
-
-  public Jws2Instance getService()
-  {
-    return service;
-  }
-
-  public void setService(Jws2Instance service)
-  {
-    this.service = service;
-    if (preset != null)
-    {
-      // migrate preset to new service
-      for (String url : preset.getApplicableUrls())
-      {
-        if (url.equals(service.getUri()))
-        {
-          return;
-        }
-      }
-      WsParamSetI pr = service.getParamStore().getPreset(preset.getName());
-      if (pr instanceof JabaPreset && preset instanceof JabaPreset)
-      {
-        // easy - Presets are identical (we assume)
-        preset = pr;
-        return;
-      }
-      List<ArgumentI> oldargs = new ArrayList<ArgumentI>(),
-              newargs = new ArrayList<ArgumentI>();
-      oldargs.addAll(preset.getArguments());
-      // need to compare parameters
-      for (ArgumentI newparg : pr.getArguments())
-      {
-        if (!oldargs.remove(newparg))
-        {
-          newargs.add(newparg);
-        }
-      }
-      if (oldargs.size() == 0 && newargs.size() == 0)
-      {
-        // exact match.
-        preset = pr;
-        return;
-      }
-      // Try even harder to migrate arguments.
-      throw new Error(MessageManager
-              .getString("error.parameter_migration_not_implemented_yet"));
-    }
-  }
-
-  public List<Argument> getJobArgset()
-  {
-    return jobArgset == null ? null
-            : JabaParamStore.getJabafromJwsArgs(jobArgset);
-  }
-
-  public void setJobArgset(List<Argument> jobArgset)
-  {
-    // TODO: test if parameters valid for service
-    this.jobArgset = jobArgset == null ? null
-            : JabaParamStore.getJwsArgsfromJaba(jobArgset);
+    super(service2, preset, jobArgset, autoUpdate);
   }
 
+  @Override
   public String getWsParamFile()
   {
     List<Option> opts = null;
@@ -138,16 +71,4 @@ public class AAConSettings extends jalview.ws.params.AutoCalcSetting
     }
     return pset.toString();
   }
-
-  @Override
-  public String getServiceURI()
-  {
-    return service.getServiceTypeURI();
-  }
-
-  @Override
-  public String[] getServiceURLs()
-  {
-    return new String[] { service.getUri() };
-  }
 }
index cbfbd3b..f1f5014 100644 (file)
@@ -117,4 +117,10 @@ public class JabaOption implements jalview.ws.params.OptionI
     return opt;
   }
 
+  @Override
+  public List<String> getDisplayNames()
+  {
+    return null; // not supported for Jaba options
+  }
+
 }
diff --git a/src/jalview/ws/jws2/jabaws2/AAConClient.java b/src/jalview/ws/jws2/jabaws2/AAConClient.java
new file mode 100644 (file)
index 0000000..18b6ce1
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the 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.jws2.jabaws2;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.util.MessageManager;
+import jalview.ws.uimodel.AlignAnalysisUIText;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import compbio.data.sequence.Score;
+
+public class AAConClient extends JabawsAnnotationInstance
+{
+  // configuration for factory
+  public static String getServiceActionText()
+  {
+    return "calculating Amino acid consensus using AACon service";
+  }
+
+
+
+  private static String CALC_ID = "jabaws2.AACon";
+
+  public static AlignAnalysisUIText getAlignAnalysisUIText()
+  {
+    return new AlignAnalysisUIText(
+            compbio.ws.client.Services.AAConWS.toString(),
+            AAConClient.class, CALC_ID, false, true, true, true,
+            true, 2, MessageManager.getString("label.aacon_calculations"),
+            MessageManager.getString("tooltip.aacon_calculations"),
+            MessageManager.getString("label.aacon_settings"),
+            MessageManager.getString("tooltip.aacon_settings"));
+  }
+
+  // instance
+  public AAConClient(Jws2Instance handle)
+  {
+    super(handle);
+  }
+
+  @Override
+  List<AlignmentAnnotation> annotationFromScoreManager(AlignmentI seqs,
+          Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters)
+  {
+    return aacons_annotation(seqs.getWidth(), seqs, null);
+  }
+
+  private List<AlignmentAnnotation> aacons_annotation(int alWidth,
+          AlignmentI alignViewport, boolean[] gapMap)
+  {
+    Map<String, TreeSet<Score>> scoremap = scoremanager.asMap();
+    ArrayList<AlignmentAnnotation> ourAnnot = new ArrayList<>();
+    for (String score : scoremap.keySet())
+    {
+      Set<Score> scores = scoremap.get(score);
+      for (Score scr : scores)
+      {
+        if (scr.getRanges() != null && scr.getRanges().size() > 0)
+        {
+          /**
+           * annotation in range annotation = findOrCreate(scr.getMethod(),
+           * true, null, null); Annotation[] elm = new Annotation[alWidth];
+           * Iterator<Float> vals = scr.getScores().iterator(); for (Range rng :
+           * scr.getRanges()) { float val = vals.next().floatValue(); for (int i
+           * = rng.from; i <= rng.to; i++) { elm[i] = new Annotation("", "", '
+           * ', val); } } annotation.annotations = elm;
+           * annotation.validateRangeAndDisplay();
+           */
+        }
+        else
+        {
+          createAnnotationRowsForScores(alignViewport, null, ourAnnot,
+                  getCalcId(),
+                  scr.getScores().size(), scr);
+        }
+      }
+    }
+    return ourAnnot;
+  }
+
+}
diff --git a/src/jalview/ws/jws2/jabaws2/AADisorderClient.java b/src/jalview/ws/jws2/jabaws2/AADisorderClient.java
new file mode 100644 (file)
index 0000000..a221aa0
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the 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.jws2.jabaws2;
+
+import jalview.analysis.AlignmentAnnotationUtils;
+import jalview.api.FeatureColourI;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.GraphLine;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.schemes.FeatureColour;
+import jalview.util.ColorUtils;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import compbio.data.sequence.Range;
+import compbio.data.sequence.Score;
+import compbio.data.sequence.ScoreManager.ScoreHolder;
+
+public class AADisorderClient extends JabawsAnnotationInstance
+{
+  // static configuration
+  public static String getServiceActionText()
+  {
+    return "Submitting amino acid sequences for disorder prediction.";
+  }
+
+  // minSeq = 1; protein only, no gaps
+
+  // instance
+  public AADisorderClient(Jws2Instance handle)
+  {
+    super(handle);
+
+  }
+
+  @Override
+  List<AlignmentAnnotation> annotationFromScoreManager(AlignmentI seqs,
+          Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters)
+  {
+
+    Map<String, String[]> featureTypeMap = featureMap.get(our.getName());
+    Map<String, Map<String, Object>> annotTypeMap = annotMap
+            .get(our.getName());
+    boolean dispFeatures = false;
+    Map<String, SequenceFeature> fc = new Hashtable<>(),
+            fex = new Hashtable();
+    List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
+    int graphGroup = 1, lastAnnot = 0;
+
+    for (SequenceI seq : seqs.getSequences())
+    {
+      String seqId = seq.getName();
+      boolean sameGroup = false;
+      SequenceI dseq, aseq;
+      int base = seq.findPosition(0) - 1;
+      aseq = seq;
+      while ((dseq = seq).getDatasetSequence() != null)
+      {
+        seq = seq.getDatasetSequence();
+      }
+      ScoreHolder scores = null;
+      try
+      {
+        scores = scoremanager.getAnnotationForSequence(seqId);
+      } catch (Exception q)
+      {
+        Cache.log.info("Couldn't recover disorder prediction for sequence "
+                + seq.getName() + "(Prediction name was " + seqId + ")"
+                + "\nSee http://issues.jalview.org/browse/JAL-1319 for one possible reason why disorder predictions might fail.",
+                q);
+      }
+      float last = Float.NaN, val = Float.NaN;
+      if (scores != null && scores.scores != null)
+      {
+        for (Score scr : scores.scores)
+        {
+
+          if (scr.getRanges() != null && scr.getRanges().size() > 0)
+          {
+            Iterator<Float> vals = scr.getScores().iterator();
+            // make features on sequence
+            for (Range rn : scr.getRanges())
+            {
+              // TODO: Create virtual feature settings
+              SequenceFeature sf;
+              String[] type = featureTypeMap.get(scr.getMethod());
+              if (type == null)
+              {
+                // create a default type for this feature
+                type = new String[] {
+                    typeName + " (" + scr.getMethod() + ")",
+                    our.getActionText() };
+              }
+              if (vals.hasNext())
+              {
+                val = vals.next().floatValue();
+                sf = new SequenceFeature(type[0], type[1], base + rn.from,
+                        base + rn.to, val, methodName);
+              }
+              else
+              {
+                sf = new SequenceFeature(type[0], type[1], base + rn.from,
+                        base + rn.to, methodName);
+              }
+              dseq.addSequenceFeature(sf);
+              // mark feature as requiring a graduated colourscheme if has
+              // variable scores
+              if (!Float.isNaN(last) && !Float.isNaN(val) && last != val)
+              {
+                fc.put(sf.getType(), sf);
+              } else 
+              {
+                fex.put(sf.getType(), sf);
+              }
+              last = val;
+              dispFeatures = true;
+            }
+          }
+          else
+          {
+            if (scr.getScores().size() == 0)
+            {
+              continue;
+            }
+            String typename, calcName;
+            AlignmentAnnotation annot = createAnnotationRowsForScores(
+                    seqs, null, ourAnnot,
+                    typename = our.getName() + " (" + scr.getMethod() + ")",
+                    calcName = our.getNameURI() + "/" + scr.getMethod(),
+                    aseq, base + 1, scr);
+            annot.graph = AlignmentAnnotation.LINE_GRAPH;
+
+            Map<String, Object> styleMap = (annotTypeMap == null) ? null
+                    : annotTypeMap.get(scr.getMethod());
+
+            annot.visible = (styleMap == null
+                    || styleMap.get(INVISIBLE) == null);
+            double[] thrsh = (styleMap == null) ? null
+                    : (double[]) styleMap.get(THRESHOLD);
+            float[] range = (styleMap == null) ? null
+                    : (float[]) styleMap.get(RANGE);
+            if (range != null)
+            {
+              annot.graphMin = range[0];
+              annot.graphMax = range[1];
+            }
+            if (styleMap == null || styleMap.get(DONTCOMBINE) == null)
+            {
+              {
+                if (!sameGroup)
+                {
+                  graphGroup++;
+                  sameGroup = true;
+                }
+
+                annot.graphGroup = graphGroup;
+              }
+            }
+
+            annot.description = "<html>" + our.getActionText()
+                    + " - raw scores";
+            if (thrsh != null)
+            {
+              String threshNote = (thrsh[0] > 0 ? "Above " : "Below ")
+                      + thrsh[1] + " indicates disorder";
+              annot.threshold = new GraphLine((float) thrsh[1], threshNote,
+                      Color.red);
+              annot.description += "<br/>" + threshNote;
+            }
+            annot.description += "</html>";
+            Color col = ColorUtils
+                    .createColourFromName(typeName + scr.getMethod());
+            for (int p = 0, ps = annot.annotations.length; p < ps; p++)
+            {
+              if (annot.annotations[p] != null)
+              {
+                annot.annotations[p].colour = col;
+              }
+            }
+            annot._linecolour = col;
+            // finally, update any dataset annotation
+            AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(annot,
+                    typename, calcName);
+          }
+        }
+      }
+      if (lastAnnot + 1 == ourAnnot.size())
+      {
+        // remove singleton alignment annotation row
+        ourAnnot.get(lastAnnot).graphGroup = -1;
+      }
+    }
+    {
+      if (dispFeatures)
+      {
+        // TODO: virtual feature settings
+        // feature colours need to merged with current viewport's colours
+        // simple feature colours promoted to colour-by-score ranges using
+        // currently assigned or created feature colour
+        for (String ft : fex.keySet())
+        {
+          Color col = ColorUtils.createColourFromName(ft);
+          // set graduated color as fading to white for minimum, and
+          // autoscaling to values on alignment
+          
+          FeatureColourI ggc;
+          if (fc.get(ft) != null)
+          {
+            ggc = new FeatureColour(col, Color.white, col,
+
+                  Color.white, Float.MIN_VALUE, Float.MAX_VALUE);
+            ggc.setAutoScaled(true);
+          }
+          else
+          {
+            ggc = new FeatureColour(col);
+          }
+          featureColours.put(ft, ggc);
+        }
+
+      }
+      return ourAnnot;
+    }
+  }
+
+  private static final String THRESHOLD = "THRESHOLD";
+
+  private static final String RANGE = "RANGE";
+
+  String typeName;
+
+  String methodName;
+
+  String groupName;
+
+  private static Map<String, Map<String, String[]>> featureMap;
+
+  private static Map<String, Map<String, Map<String, Object>>> annotMap;
+
+  private static String DONTCOMBINE = "DONTCOMBINE";
+
+  private static String INVISIBLE = "INVISIBLE";
+  static
+  {
+    // TODO: turn this into some kind of configuration file that's a bit easier
+    // to edit
+    featureMap = new HashMap<>();
+    Map<String, String[]> fmap;
+    featureMap.put(compbio.ws.client.Services.IUPredWS.toString(),
+            fmap = new HashMap<>());
+    fmap.put("Glob",
+            new String[]
+            { "Globular Domain", "Predicted globular domain" });
+    featureMap.put(compbio.ws.client.Services.JronnWS.toString(),
+            fmap = new HashMap<>());
+    featureMap.put(compbio.ws.client.Services.DisemblWS.toString(),
+            fmap = new HashMap<>());
+    fmap.put("REM465", new String[] { "REM465", "Missing density" });
+    fmap.put("HOTLOOPS", new String[] { "HOTLOOPS", "Flexible loops" });
+    fmap.put("COILS", new String[] { "COILS", "Random coil" });
+    featureMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
+            fmap = new HashMap<>());
+    fmap.put("GlobDoms",
+            new String[]
+            { "Globular Domain", "Predicted globular domain" });
+    fmap.put("Disorder",
+            new String[]
+            { "Protein Disorder", "Probable unstructured peptide region" });
+    Map<String, Map<String, Object>> amap;
+    annotMap = new HashMap<>();
+    annotMap.put(compbio.ws.client.Services.GlobPlotWS.toString(),
+            amap = new HashMap<>());
+    amap.put("Dydx", new HashMap<String, Object>());
+    amap.get("Dydx").put(DONTCOMBINE, DONTCOMBINE);
+    amap.get("Dydx").put(THRESHOLD, new double[] { 1, 0 });
+    amap.get("Dydx").put(RANGE, new float[] { -1, +1 });
+
+    amap.put("SmoothedScore", new HashMap<String, Object>());
+    amap.get("SmoothedScore").put(INVISIBLE, INVISIBLE);
+    amap.put("RawScore", new HashMap<String, Object>());
+    amap.get("RawScore").put(INVISIBLE, INVISIBLE);
+    annotMap.put(compbio.ws.client.Services.DisemblWS.toString(),
+            amap = new HashMap<>());
+    amap.put("COILS", new HashMap<String, Object>());
+    amap.put("HOTLOOPS", new HashMap<String, Object>());
+    amap.put("REM465", new HashMap<String, Object>());
+    amap.get("COILS").put(THRESHOLD, new double[] { 1, 0.516 });
+    amap.get("COILS").put(RANGE, new float[] { 0, 1 });
+
+    amap.get("HOTLOOPS").put(THRESHOLD, new double[] { 1, 0.6 });
+    amap.get("HOTLOOPS").put(RANGE, new float[] { 0, 1 });
+    amap.get("REM465").put(THRESHOLD, new double[] { 1, 0.1204 });
+    amap.get("REM465").put(RANGE, new float[] { 0, 1 });
+
+    annotMap.put(compbio.ws.client.Services.IUPredWS.toString(),
+            amap = new HashMap<>());
+    amap.put("Long", new HashMap<String, Object>());
+    amap.put("Short", new HashMap<String, Object>());
+    amap.get("Long").put(THRESHOLD, new double[] { 1, 0.5 });
+    amap.get("Long").put(RANGE, new float[] { 0, 1 });
+    amap.get("Short").put(THRESHOLD, new double[] { 1, 0.5 });
+    amap.get("Short").put(RANGE, new float[] { 0, 1 });
+    annotMap.put(compbio.ws.client.Services.JronnWS.toString(),
+            amap = new HashMap<>());
+    amap.put("JRonn", new HashMap<String, Object>());
+    amap.get("JRonn").put(THRESHOLD, new double[] { 1, 0.5 });
+    amap.get("JRonn").put(RANGE, new float[] { 0, 1 });
+  }
+
+}
diff --git a/src/jalview/ws/jws2/jabaws2/JabawsAnnotationInstance.java b/src/jalview/ws/jws2/jabaws2/JabawsAnnotationInstance.java
new file mode 100644 (file)
index 0000000..a52b515
--- /dev/null
@@ -0,0 +1,279 @@
+package jalview.ws.jws2.jabaws2;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.util.MessageManager;
+import jalview.ws.api.JobId;
+import jalview.ws.api.SequenceAnnotationServiceI;
+import jalview.ws.jws2.JabaParamStore;
+import jalview.ws.jws2.JabaPreset;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import compbio.data.msa.SequenceAnnotation;
+import compbio.data.sequence.FastaSequence;
+import compbio.data.sequence.Score;
+import compbio.data.sequence.ScoreManager;
+import compbio.metadata.JobSubmissionException;
+import compbio.metadata.WrongParameterException;
+
+public abstract class JabawsAnnotationInstance
+        extends JabawsServiceInstance<SequenceAnnotation>
+        implements SequenceAnnotationServiceI
+{
+
+  /**
+   * holds last results obtained when non-null. TODO: remove this as a field ?
+   */
+  protected ScoreManager scoremanager = null;
+
+  public JabawsAnnotationInstance(Jws2Instance handle)
+  {
+    super(handle);
+  }
+
+
+  /**
+   * 
+   * @return the calcId for this Jabaws Service (convenience method).
+   * 
+   *         TODO: decide if this is really convenient since manager and
+   *         instance have same method !
+   */
+  public String getCalcId()
+  {
+    return our.getAlignAnalysisUI() == null ? null
+            : our.getAlignAnalysisUI().getCalcId();
+  }
+
+  @Override
+  public JobId submitToService(List<SequenceI> seqs, WsParamSetI preset,
+          List<ArgumentI> arguments) throws Throwable
+  {
+    String rslt = null;
+    scoremanager = null;
+    List<FastaSequence> jabaseqs = new ArrayList(seqs.size());
+    for (SequenceI seq : seqs)
+    {
+      jabaseqs.add(
+              new FastaSequence(seq.getName(), seq.getSequenceAsString()));
+    }
+    if (preset == null && arguments == null)
+    {
+      rslt = service.analize(jabaseqs);
+    }
+    if (preset != null)
+    {
+      if (preset instanceof JabaPreset)
+      {
+        // TODO: verify behaviour is really the same, since preset analyze was
+        // never called in Jalview 2.11.x
+        rslt = service.presetAnalize(jabaseqs,
+                ((JabaPreset) preset).getJabaPreset());
+      }
+      else
+      {
+        rslt = service.customAnalize(jabaseqs,
+                JabaParamStore.getJabafromJwsArgs(preset.getArguments()));
+      }
+    }
+    else if (arguments != null && arguments.size() > 0)
+    {
+      try
+      {
+        rslt = service.customAnalize(jabaseqs,
+                JabaParamStore.getJabafromJwsArgs(arguments));
+      } catch (WrongParameterException x)
+      {
+        throw new JobSubmissionException(MessageManager.getString(
+                "exception.jobsubmission_invalid_params_set"), x);
+
+      }
+    }
+
+    if (rslt == null)
+    {
+      return null;
+    }
+    return new JobId(our.getServiceType(), our.getName(), rslt);
+  }
+
+
+  @Override
+  public
+  List<AlignmentAnnotation> getAnnotationResult(JobId job,
+          List<SequenceI> seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters) throws Throwable
+  {
+    if (scoremanager == null)
+    {
+      // TODO: raise annotation unavailable exception ?
+      scoremanager = service.getAnnotation(job.getJobId());
+    }
+    if (scoremanager == null)
+    {
+      return List.of();
+    }
+    /**
+     * dummy alignment to perform annotation on
+     */
+    AlignmentI newal = new Alignment(seqs.toArray(new SequenceI[0]));
+    List<AlignmentAnnotation> ourAnnot = annotationFromScoreManager(newal,
+            featureColours, featureFilters);
+    return ourAnnot;
+  }
+
+  /**
+   * service specific annotation creation method
+   * 
+   * @param seqs
+   *          - sequences to be annotated with results
+   * @param featureColours
+   *          - - updated with any colours imported during result processing
+   * @param featureFilters
+   *          - updated with any filters imported during result processing
+   * 
+   * @return
+   */
+  abstract List<AlignmentAnnotation> annotationFromScoreManager(
+          AlignmentI seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters);
+
+
+  /**
+   * create and complete an annotation row from a JABAWS score object
+   * 
+   * @param alignViewport
+   * @param gapMap
+   * @param ourAnnot
+   * @param calcId
+   * @param alWidth
+   * @param scr
+   */
+
+  protected void createAnnotationRowsForScores(AlignmentI al_result,
+          boolean[] gapMap, List<AlignmentAnnotation> ourAnnot,
+          String calcId,
+          int alWidth, Score scr)
+  {
+    // simple annotation row
+    AlignmentAnnotation annotation = al_result
+            .findOrCreateAnnotation(scr.getMethod(), calcId, true, null,
+                    null);
+    if (gapMap == null || alWidth == gapMap.length) // scr.getScores().size())
+    {
+      constructAnnotationFromScore(gapMap, annotation, 0,
+              alWidth, scr);
+      ourAnnot.add(annotation);
+    }
+  }
+
+  /**
+   * create a sequence associated annotation row for JABAWS score object scr
+   * 
+   * @param alignViewport
+   * @param gapMap
+   * @param ourAnnot
+   * @param typeName
+   * @param calcId
+   * @param dseq
+   * @param base
+   * @param scr
+   * @return
+   */
+  protected AlignmentAnnotation createAnnotationRowsForScores(
+          AlignmentI alignment, boolean[] gapMap,
+          List<AlignmentAnnotation> ourAnnot, String typeName,
+          String calcId, SequenceI dseq, int base, Score scr)
+  {
+    System.out.println("Creating annotation on dseq:" + dseq.getStart()
+            + " base is " + base + " and length=" + dseq.getLength()
+            + " == " + scr.getScores().size());
+    // AlignmentAnnotation annotation = new AlignmentAnnotation(
+    // scr.getMethod(), typeName, new Annotation[]
+    // {}, 0, -1, AlignmentAnnotation.LINE_GRAPH);
+    // annotation.setCalcId(calcId);
+    AlignmentAnnotation annotation = alignment
+            .findOrCreateAnnotation(typeName, calcId, false, dseq, null);
+    constructAnnotationFromScore(gapMap, annotation, 0, dseq.getLength(),
+            scr);
+    annotation.createSequenceMapping(dseq, base, false);
+    annotation.adjustForAlignment();
+    dseq.addAlignmentAnnotation(annotation);
+    ourAnnot.add(annotation);
+    return annotation;
+  }
+
+  /**
+   * create column annotation elements from Jabaws score object
+   * 
+   * @param gapMap
+   * @param annotation
+   * @param base
+   * @param alWidth
+   * @param scr
+   *          JABAWS score object
+   */
+  protected void constructAnnotationFromScore(boolean[] gapMap,
+          AlignmentAnnotation annotation,
+          int base, int alWidth, Score scr)
+  {
+    Annotation[] elm = new Annotation[alWidth];
+    Iterator<Float> vals = scr.getScores().iterator();
+    float m = 0f, x = 0f;
+    for (int i = 0; vals.hasNext(); i++)
+    {
+      float val = vals.next().floatValue();
+      if (i == 0)
+      {
+        m = val;
+        x = val;
+      }
+      else
+      {
+        if (m > val)
+        {
+          m = val;
+        }
+        ;
+        if (x < val)
+        {
+          x = val;
+        }
+      }
+      // if we're at a gapped column then skip to next ungapped position
+      if (gapMap != null && gapMap.length > 0)
+      {
+        // if gapMap is a different length to the result then it may be out of
+        // sync with the job.
+        while (i < gapMap.length && !gapMap[i])
+        {
+          elm[i++] = new Annotation("", "", ' ', Float.NaN);
+        }
+      }
+      elm[i] = new Annotation("", "" + val, ' ', val);
+    }
+
+    annotation.annotations = elm;
+    annotation.belowAlignment = true;
+    if (x < 0)
+    {
+      x = 0;
+    }
+    x += (x - m) * 0.1;
+    annotation.graphMax = x;
+    annotation.graphMin = m;
+    annotation.validateRangeAndDisplay();
+  }
+
+}
diff --git a/src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java b/src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java
new file mode 100644 (file)
index 0000000..cbb4b05
--- /dev/null
@@ -0,0 +1,105 @@
+package jalview.ws.jws2.jabaws2;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.ws.api.CancellableI;
+import jalview.ws.api.JobId;
+import jalview.ws.api.MultipleSequenceAlignmentI;
+import jalview.ws.jws2.JabaParamStore;
+import jalview.ws.jws2.JabaPreset;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.InvalidArgumentException;
+import jalview.ws.params.WsParamSetI;
+
+import java.io.IOError;
+import java.rmi.ServerError;
+import java.util.ArrayList;
+import java.util.List;
+
+import compbio.data.sequence.Alignment;
+import compbio.data.sequence.FastaSequence;
+import compbio.metadata.ResultNotAvailableException;
+
+public class JabawsMsaInstance
+        extends JabawsServiceInstance<compbio.data.msa.MsaWS>
+        implements MultipleSequenceAlignmentI, CancellableI
+{
+  @Override
+  public JobId align(List<SequenceI> toalign, WsParamSetI parameters,
+          List<ArgumentI> arguments) throws Throwable
+  {
+    List<compbio.data.sequence.FastaSequence> seqs = new ArrayList<>();
+    for (SequenceI seq : toalign)
+    {
+      seqs.add(new FastaSequence(seq.getName(), seq.getSequenceAsString()));
+    }
+    String jobid = null;
+    if (parameters != null)
+    {
+      if (parameters instanceof JabaPreset)
+      {
+        jobid = service.presetAlign(seqs,
+                ((JabaPreset) parameters).getJabaPreset());
+      }
+      else
+      {
+        jobid = service.customAlign(seqs, JabaParamStore
+                .getJabafromJwsArgs(parameters.getArguments()));
+      }
+    }
+    else if (arguments != null && arguments.size() > 0)
+    {
+      jobid = service.customAlign(seqs,
+              JabaParamStore.getJabafromJwsArgs(arguments));
+    }
+    else
+    {
+      jobid = service.align(seqs);
+    }
+
+    if (jobid == null)
+    {
+      return null;
+    }
+    return new JobId(our.getServiceType(), our.getName(), jobid);
+  }
+
+  @Override
+  public AlignmentI getAlignmentFor(JobId jobId)
+          throws InvalidArgumentException, ServerError, IOError
+  {
+    Alignment alignment = null;
+    try
+    {
+      alignment = service.getResult(jobId.getJobId());
+    } catch (ResultNotAvailableException rnotav)
+    {
+
+      // TODO - migrate JABA exception
+      // throw new ServerError("Couldn't get result for job",rnotav);
+    }
+    SequenceI[] alseqs;
+    int alseq_l = 0;
+    if (alignment.getSequences().size() == 0)
+    {
+      return null;
+    }
+
+    alseqs = new SequenceI[alignment.getSequences().size()];
+    for (compbio.data.sequence.FastaSequence seq : alignment.getSequences())
+    {
+      alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence());
+    }
+    AlignmentI jv_al = new jalview.datamodel.Alignment(alseqs);
+    jv_al.setGapCharacter(alignment.getMetadata().getGapchar());
+    return jv_al;
+
+  }
+
+  public JabawsMsaInstance(Jws2Instance handle)
+  {
+    super(handle);
+  }
+
+}
diff --git a/src/jalview/ws/jws2/jabaws2/JabawsMsaInterfaceAlignCalcWorker.java b/src/jalview/ws/jws2/jabaws2/JabawsMsaInterfaceAlignCalcWorker.java
new file mode 100644 (file)
index 0000000..edcc05c
--- /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.ws.jws2.jabaws2;
+
+import jalview.gui.AlignFrame;
+import jalview.ws.jws2.SeqAnnotationServiceCalcWorker;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
+
+public abstract class JabawsMsaInterfaceAlignCalcWorker
+        extends SeqAnnotationServiceCalcWorker
+{
+
+  public JabawsMsaInterfaceAlignCalcWorker(Jws2Instance service,
+          AlignFrame alignFrame, WsParamSetI preset,
+          List<ArgumentI> paramset)
+  {
+    super(service, alignFrame, preset, paramset);
+    // TODO Auto-generated constructor stub
+  }
+
+  // TODO: REFACTOR if needed !
+  // may be able to get away with overriding run() only, but maybe not.
+  /***
+   * @SuppressWarnings("unchecked") protected MsaWS msaservice;
+   * 
+   * protected Alignment msascoreset;
+   * 
+   * public JabawsMsaInterfaceAlignCalcWorker(AlignViewportI alignViewport,
+   * AlignmentViewPanel alignPanel) { super(alignViewport, alignPanel); }
+   * 
+   * public JabawsMsaInterfaceAlignCalcWorker(Jws2Instance service, AlignFrame
+   * alignFrame, WsParamSetI preset, List<ArgumentI> paramset) {
+   * this(alignFrame.getCurrentView(), alignFrame.alignPanel); this.guiProgress
+   * = alignFrame; this.preset = preset; this.arguments = paramset; this.service
+   * = service; msaservice = (MsaWS) service.service;
+   * 
+   * }
+   * 
+   * @Override ChunkHolder pullExecStatistics(String rslt, long rpos) { return
+   *           msaservice.pullExecStatistics(rslt, rpos); }
+   * 
+   * @Override boolean collectAnnotationResultsFor(String rslt) throws
+   *           ResultNotAvailableException { msascoreset =
+   *           msaservice.getResult(rslt); if (msascoreset != null) { return
+   *           true; } return false; }
+   * 
+   * @Override boolean cancelJob(String rslt) throws Exception { return
+   *           msaservice.cancelJob(rslt); }
+   * 
+   * @Override protected JobStatus getJobStatus(String rslt) throws Exception {
+   *           return msaservice.getJobStatus(rslt); }
+   * 
+   * @Override boolean hasService() { return msaservice != null; }
+   * 
+   * @Override protected boolean isInteractiveUpdate() { return false; // this
+   *           instanceof AAConClient; }
+   * 
+   * @Override protected String submitToService(
+   *           List<compbio.data.sequence.FastaSequence> seqs) throws
+   *           JobSubmissionException { String rslt; if (preset == null &&
+   *           arguments == null) { rslt = msaservice.align(seqs); } else { try
+   *           { rslt = msaservice.customAlign(seqs, getJabaArguments()); }
+   *           catch (WrongParameterException x) { throw new
+   *           JobSubmissionException(MessageManager.getString(
+   *           "exception.jobsubmission_invalid_params_set"), x); } } return
+   *           rslt; }
+   * 
+   *           protected void createAnnotationRowsForScores(
+   *           List<AlignmentAnnotation> ourAnnot, String calcId, int alWidth,
+   *           Score scr) { // simple annotation row AlignmentAnnotation
+   *           annotation = alignViewport.getAlignment()
+   *           .findOrCreateAnnotation(scr.getMethod(), calcId, true, null,
+   *           null); if (alWidth == gapMap.length) // scr.getScores().size()) {
+   *           constructAnnotationFromScore(annotation, 0, alWidth, scr);
+   *           ourAnnot.add(annotation); } }
+   * 
+   *           protected AlignmentAnnotation createAnnotationRowsForScores(
+   *           List<AlignmentAnnotation> ourAnnot, String typeName, String
+   *           calcId, SequenceI dseq, int base, Score scr) {
+   *           System.out.println("Creating annotation on dseq:" +
+   *           dseq.getStart() + " base is " + base + " and length=" +
+   *           dseq.getLength() + " == " + scr.getScores().size()); //
+   *           AlignmentAnnotation annotation = new AlignmentAnnotation( //
+   *           scr.getMethod(), typeName, new Annotation[] // {}, 0, -1,
+   *           AlignmentAnnotation.LINE_GRAPH); // annotation.setCalcId(calcId);
+   *           AlignmentAnnotation annotation = alignViewport.getAlignment()
+   *           .findOrCreateAnnotation(typeName, calcId, false, dseq, null);
+   *           constructAnnotationFromScore(annotation, 0, dseq.getLength(),
+   *           scr); annotation.createSequenceMapping(dseq, base, false);
+   *           annotation.adjustForAlignment();
+   *           dseq.addAlignmentAnnotation(annotation);
+   *           ourAnnot.add(annotation); return annotation; }
+   * 
+   *           private void constructAnnotationFromScore(AlignmentAnnotation
+   *           annotation, int base, int alWidth, Score scr) { Annotation[] elm
+   *           = new Annotation[alWidth]; Iterator<Float> vals =
+   *           scr.getScores().iterator(); float m = 0f, x = 0f; for (int i = 0;
+   *           vals.hasNext(); i++) { float val = vals.next().floatValue(); if
+   *           (i == 0) { m = val; x = val; } else { if (m > val) { m = val; } ;
+   *           if (x < val) { x = val; } } // if we're at a gapped column then
+   *           skip to next ungapped position if (gapMap != null &&
+   *           gapMap.length > 0) { while (!gapMap[i]) { elm[i++] = new
+   *           Annotation("", "", ' ', Float.NaN); } } elm[i] = new
+   *           Annotation("", "" + val, ' ', val); }
+   * 
+   *           annotation.annotations = elm; annotation.belowAlignment = true;
+   *           if (x < 0) { x = 0; } x += (x - m) * 0.1; annotation.graphMax =
+   *           x; annotation.graphMin = m; annotation.validateRangeAndDisplay();
+   *           }
+   ***/
+}
diff --git a/src/jalview/ws/jws2/jabaws2/JabawsServiceInstance.java b/src/jalview/ws/jws2/jabaws2/JabawsServiceInstance.java
new file mode 100644 (file)
index 0000000..9e8cefa
--- /dev/null
@@ -0,0 +1,212 @@
+package jalview.ws.jws2.jabaws2;
+
+import jalview.bin.Cache;
+import jalview.gui.WebserviceInfo;
+import jalview.util.MessageManager;
+import jalview.ws.gui.WsJob;
+import jalview.ws.gui.WsJob.JobState;
+import jalview.ws.jws2.JabaParamStore;
+import jalview.ws.jws2.JabaPreset;
+import jalview.ws.jws2.dm.JabaWsParamSet;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import compbio.metadata.Argument;
+import compbio.metadata.ChunkHolder;
+import compbio.metadata.JobStatus;
+import compbio.metadata.Preset;
+
+/**
+ * Base class for JABAWS service instances. Provides helper methods for
+ * interfacing with Jalview.
+ * 
+ * @author jprocter
+ *
+ */
+public class JabawsServiceInstance<T extends compbio.data.msa.JManagement>
+        implements
+        jalview.ws.api.JalviewWebServiceI, jalview.ws.api.CancellableI
+{
+  /**
+   * our service instance handler generated by the discoverer
+   */
+  Jws2Instance our;
+  protected T service;
+  protected Map<JobStatus, JobState> jwsState = new HashMap<>();
+
+  @Override
+  public boolean cancel(WsJob job)
+  {
+    service.cancelJob(job.getJobId());
+    // if the Jaba server indicates the job can't be cancelled, its
+    // because its running on the server's local execution engine
+    // so we just close the window anyway.
+  
+    return true;
+  }
+
+
+  public JabawsServiceInstance(Jws2Instance handle)
+  {
+    our = handle;
+    service = (T) handle.service;
+  }
+
+  @Override
+  public void updateStatus(WsJob job)
+  {
+    JobStatus jwsstatus = service.getJobStatus(job.getJobId());
+    job.setState(jwsState.get(jwsstatus));
+  }
+
+  @Override
+  public boolean updateJobProgress(WsJob job) throws Exception
+  {
+    StringBuilder response = new StringBuilder(job.getStatus());
+    long lastchunk = job.getNextChunk();
+    if (lastchunk == -1)
+    {
+      Cache.log.debug("No more status messages for job " + job.getJobId());
+      return false;
+    }
+    boolean changed = false;
+    do
+    {
+      ChunkHolder chunk = service.pullExecStatistics(job.getJobId(),
+              lastchunk);
+      if (chunk != null)
+      {
+        changed |= chunk.getChunk().length() > 0;
+        response.append(chunk.getChunk());
+        lastchunk = chunk.getNextPosition();
+        try
+        {
+          Thread.sleep(50);
+        } catch (InterruptedException x)
+        {
+        }
+        ;
+      }
+      ;
+      job.setnextChunk(lastchunk);
+    } while (lastchunk >= 0 && job.getNextChunk() != lastchunk);
+    if (job instanceof WsJob)
+    {
+      // TODO decide if WsJob will be the bean for all ng-webservices
+      job.setStatus(response.toString());
+    }
+    return changed;
+  }
+
+  {
+    jwsState.put(JobStatus.CANCELLED, JobState.CANCELLED);
+    jwsState.put(JobStatus.COLLECTED, JobState.FINISHED);
+    jwsState.put(JobStatus.FAILED, JobState.FAILED);
+    jwsState.put(JobStatus.FINISHED, JobState.FINISHED);
+    jwsState.put(JobStatus.PENDING, JobState.QUEUED);
+    jwsState.put(JobStatus.RUNNING, JobState.RUNNING);
+    jwsState.put(JobStatus.STARTED, JobState.RUNNING);
+    jwsState.put(JobStatus.SUBMITTED, JobState.SUBMITTED);
+    jwsState.put(JobStatus.UNDEFINED, JobState.UNKNOWN);
+  }
+
+  public boolean isPresetJob(WsJob job)
+  {
+    return job.getPreset() != null && job.getPreset() instanceof JabaPreset;
+  }
+
+  public Preset getServerPreset(WsJob job)
+  {
+    return (isPresetJob(job))
+            ? ((JabaPreset) job.getPreset()).getJabaPreset()
+            : null;
+  }
+
+  public List<Argument> getJabaArguments(WsParamSetI preset)
+  {
+    List<Argument> newargs = new ArrayList<>();
+    if (preset != null)
+    {
+      if (preset instanceof JabaWsParamSet)
+      {
+        newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
+      }
+      else
+      {
+        newargs.addAll(
+                JabaParamStore.getJabafromJwsArgs(preset.getArguments()));
+      }
+    }
+    return newargs;
+  }
+
+  @Override
+  public boolean handleSubmitError(Throwable _lex, WsJob j,
+          WebserviceInfo wsInfo) throws Exception, Error
+  {
+    if (_lex instanceof compbio.metadata.UnsupportedRuntimeException)
+    {
+      wsInfo.appendProgressText(MessageManager.formatMessage(
+              "info.job_couldnt_be_run_server_doesnt_support_program",
+              new String[]
+              { _lex.getMessage() }));
+      wsInfo.warnUser(_lex.getMessage(),
+              MessageManager.getString("warn.service_not_supported"));
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      wsInfo.setStatus(j.getJobnum(),
+              WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      return true;
+    }
+    if (_lex instanceof compbio.metadata.LimitExceededException)
+    {
+      wsInfo.appendProgressText(MessageManager.formatMessage(
+              "info.job_couldnt_be_run_exceeded_hard_limit", new String[]
+              { _lex.getMessage() }));
+      wsInfo.warnUser(_lex.getMessage(),
+              MessageManager.getString("warn.input_is_too_big"));
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+      wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
+      return true;
+    }
+    if (_lex instanceof compbio.metadata.WrongParameterException)
+    {
+      wsInfo.warnUser(_lex.getMessage(),
+              MessageManager.getString("warn.invalid_job_param_set"));
+      wsInfo.appendProgressText(MessageManager.formatMessage(
+              "info.job_couldnt_be_run_incorrect_param_setting",
+              new String[]
+              { _lex.getMessage() }));
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+      wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR);
+      return true;
+    }
+    // pass on to generic error handler
+    return false;
+  }
+
+  @Override
+  public boolean handleCollectionException(Exception ex, WsJob msjob,
+          WebserviceInfo wsInfo)
+  {
+    if (ex instanceof compbio.metadata.ResultNotAvailableException)
+    {
+      // job has failed for some reason - probably due to invalid
+      // parameters
+      Cache.log.debug(
+              "Results not available for finished job - marking as broken job.",
+              ex);
+      String status = msjob.getStatus();
+
+      msjob.setStatus(status
+              + "\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n"
+              + ex.getLocalizedMessage());
+      msjob.setState(WsJob.JobState.BROKEN);
+      return true;
+    }
+    return false;
+  }
+}
index 7954db0..47fb9c6 100644 (file)
  */
 package jalview.ws.jws2.jabaws2;
 
-import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.util.MessageManager;
+import jalview.ws.api.JalviewServiceEndpointProviderI;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.MsaWSClient;
-import jalview.ws.jws2.SequenceAnnotationWSClient;
 import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.ParamManager;
 
 import java.io.Closeable;
-
-import javax.swing.JMenu;
+import java.net.URL;
 
 import compbio.data.msa.JABAService;
 import compbio.data.msa.MsaWS;
@@ -38,20 +37,12 @@ import compbio.data.msa.SequenceAnnotation;
 import compbio.metadata.PresetManager;
 import compbio.metadata.RunnerConfig;
 
-public class Jws2Instance implements AutoCloseable
+public class Jws2Instance extends ServiceWithParameters
+        implements JalviewServiceEndpointProviderI, AutoCloseable
 {
-  public String hosturl;
-
-  public String serviceType;
-
-  public String action;
 
   public JABAService service;
 
-  public String description;
-
-  public String docUrl;
-
   /**
    * 
    * @param hosturl
@@ -69,20 +60,40 @@ public class Jws2Instance implements AutoCloseable
   public Jws2Instance(String hosturl, String serviceType, String action,
           String description, JABAService service)
   {
-    super();
-    this.hosturl = hosturl;
-    this.serviceType = serviceType;
+    super(action, action, serviceType, description, hosturl);
     this.service = service;
-    this.action = action;
-    this.description = description;
+    if (service instanceof MsaWS<?>)
+    {
+      style = ServiceClient.MSAWSCLIENT;
+    }
+    else if (service instanceof SequenceAnnotation<?>)
+    {
+      style = ServiceClient.SEQUENCEANNOTATIONWSCLIENT;
+    }
+
     int p = description.indexOf("MORE INFORMATION:");
     if (p > -1)
     {
-      docUrl = description.substring(description.indexOf("http", p)).trim();
+      String docUrl = description.substring(description.indexOf("http", p))
+              .trim();
       if (docUrl.indexOf('\n') > -1)
       {
         docUrl = docUrl.substring(0, docUrl.indexOf("\n")).trim();
       }
+      if (docUrl.length() > 0)
+      {
+        try
+        {
+          URL url = new URL(docUrl);
+          if (url != null)
+          {
+            setDocumentationUrl(docUrl);
+          }
+        } catch (Exception x)
+        {
+
+        }
+      }
 
     }
   }
@@ -115,32 +126,12 @@ public class Jws2Instance implements AutoCloseable
       } catch (Exception ex)
       {
         System.err.println("Exception when retrieving presets for service "
-                + serviceType + " at " + hosturl);
+                + getServiceType() + " at " + getHostURL());
       }
     }
     return presets;
   }
 
-  public String getHost()
-  {
-    return hosturl;
-    /*
-     * try { URL serviceurl = new URL(hosturl); if (serviceurl.getPort()!=80) {
-     * return serviceurl.getHost()+":"+serviceurl.getPort(); } return
-     * serviceurl.getHost(); } catch (Exception e) {
-     * System.err.println("Failed to parse service URL '" + hosturl +
-     * "' as a valid URL!"); } return null;
-     */
-  }
-
-  /**
-   * @return short description of what the service will do
-   */
-  public String getActionText()
-  {
-    return action + " with " + serviceType;
-  }
-
   /**
    * non-thread safe - blocks whilst accessing service to get complete set of
    * available options and parameters
@@ -160,7 +151,7 @@ public class Jws2Instance implements AutoCloseable
     throw new Error(MessageManager.formatMessage(
             "error.implementation_error_runner_config_not_available",
             new String[]
-            { serviceType, service.getClass().toString() }));
+            { getServiceType(), service.getClass().toString() }));
   }
 
   @Override
@@ -179,6 +170,7 @@ public class Jws2Instance implements AutoCloseable
     // super.finalize();
   }
 
+  @Override
   public ParamDatastoreI getParamStore()
   {
     if (paramStore == null)
@@ -198,17 +190,9 @@ public class Jws2Instance implements AutoCloseable
     return paramStore;
   }
 
-  public String getUri()
-  {
-    // this is only valid for Jaba 1.0 - this formula might have to change!
-    return hosturl
-            + (hosturl.lastIndexOf("/") == (hosturl.length() - 1) ? ""
-                    : "/")
-            + serviceType;
-  }
-
   private boolean hasParams = false, lookedForParams = false;
 
+  @Override
   public boolean hasParameters()
   {
     if (!lookedForParams)
@@ -225,28 +209,62 @@ public class Jws2Instance implements AutoCloseable
     return hasParams;
   }
 
-  public void attachWSMenuEntry(JMenu atpoint, AlignFrame alignFrame)
+  /**
+   * initialise a parameter store for this service
+   * 
+   * @param userParameterStore
+   *          - the user ParamManager (e.g. Desktop.getUserParameterStore() )
+   */
+  @Override
+  public void initParamStore(ParamManager userParameterStore)
   {
-    if (service instanceof MsaWS<?>)
-    {
-      new MsaWSClient().attachWSMenuEntry(atpoint, this, alignFrame);
-    }
-    else if (service instanceof SequenceAnnotation<?>)
+    if (paramStore == null)
     {
-      new SequenceAnnotationWSClient().attachWSMenuEntry(atpoint, this,
-              alignFrame);
+      paramStore = new JabaParamStore(this, userParameterStore);
     }
   }
 
-  public String getServiceTypeURI()
+  /**
+   * an object that implements one or more interfaces in jalview.ws.api
+   * 
+   * @return
+   */
+  @Override
+  public Object getEndpoint()
   {
-    return "java:" + serviceType;
-  }
-
-  jalview.ws.uimodel.AlignAnalysisUIText aaui;
+    if (service instanceof MsaWS<?>)
+    {
+      if (aaui != null)
+      {
+        throw new Error(
+                "JABAWS MsaWS based instant calculation not implemented.");
 
-  public jalview.ws.uimodel.AlignAnalysisUIText getAlignAnalysisUI()
-  {
-    return aaui;
+      }
+      else
+      {
+        return new JabawsMsaInstance(this);
+      }
+    }
+    else
+    {
+      if (service instanceof compbio.data.msa.SequenceAnnotation)
+      {
+        if (aaui != null)
+        {
+          try
+          {
+            // probably a factory would be nicer but..
+            return aaui.getClient().getConstructor(getClass())
+                    .newInstance(this);
+          } catch (Throwable t)
+          {
+            throw new Error("Implementation Error in web service framework",
+                    t);
+          }
+        }
+        return new AADisorderClient(this);
+      }
+      return null;
+    }
   }
 }
index 1983ff5..8eeef4d 100644 (file)
@@ -22,8 +22,7 @@ package jalview.ws.jws2.jabaws2;
 
 import jalview.bin.ApplicationSingletonProvider;
 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
-import jalview.ws.jws2.AAConClient;
-import jalview.ws.jws2.RNAalifoldClient;
+
 import jalview.ws.uimodel.AlignAnalysisUIText;
 
 import java.util.HashMap;
@@ -62,9 +61,9 @@ public class Jws2InstanceFactory implements ApplicationSingletonI
     {
       aaConGUI = new HashMap<>();
       aaConGUI.put(compbio.ws.client.Services.AAConWS.toString(),
-              AAConClient.getAlignAnalysisUITest());
+              AAConClient.getAlignAnalysisUIText());
       aaConGUI.put(compbio.ws.client.Services.RNAalifoldWS.toString(),
-              RNAalifoldClient.getAlignAnalysisUITest());
+              RNAalifoldClient.getAlignAnalysisUIText());
       // ignore list for JABAWS services not supported in jalview ...
       ignoreGUI = new HashSet<>();
     }
@@ -101,7 +100,7 @@ public class Jws2InstanceFactory implements ApplicationSingletonI
     getInstance().init();
     Jws2Instance svc = new Jws2Instance(jwsservers, serviceType,
             category_rewrite(name), description, service);
-    svc.aaui = getInstance().aaConGUI.get(serviceType.toString());
+    svc.setAlignAnalysisUI(getInstance().aaConGUI.get(serviceType.toString()));
     return svc;
   }
 
  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
  * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
-package jalview.ws.jws2;
+package jalview.ws.jws2.jabaws2;
 
+import jalview.api.FeatureColourI;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Annotation;
-import jalview.gui.AlignFrame;
+import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.util.MessageManager;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.params.WsParamSetI;
 import jalview.ws.uimodel.AlignAnalysisUIText;
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
 
-import compbio.data.sequence.FastaSequence;
 import compbio.data.sequence.RNAStructReader.AlifoldResult;
 import compbio.data.sequence.RNAStructScoreManager;
 import compbio.data.sequence.Range;
 import compbio.data.sequence.Score;
-import compbio.metadata.Argument;
 
 /**
  * Client for the JABA RNA Alifold Service
@@ -49,29 +48,10 @@ import compbio.metadata.Argument;
  * 
  */
 
-public class RNAalifoldClient extends JabawsCalcWorker
+public class RNAalifoldClient extends JabawsAnnotationInstance
 {
 
-  String methodName;
-
-  AlignFrame af;
-
-  // keeps track of whether the RNAalifold result includes base contact
-  // probabilities
-  boolean bpScores;
-
-  public RNAalifoldClient(Jws2Instance sh, AlignFrame alignFrame,
-          WsParamSetI preset, List<Argument> paramset)
-  {
-    super(sh, alignFrame, preset, paramset);
-    af = alignFrame;
-    methodName = sh.serviceType;
-    alignedSeqs = true;
-    submitGaps = true;
-    nucleotidesAllowed = true;
-    proteinAllowed = false;
-    initViewportParams();
-  }
+  // configuration
 
   @Override
   public String getCalcId()
@@ -81,93 +61,89 @@ public class RNAalifoldClient extends JabawsCalcWorker
 
   private static String CALC_ID = "jalview.ws.jws2.RNAalifoldClient";
 
-  public static AlignAnalysisUIText getAlignAnalysisUITest()
+  public static AlignAnalysisUIText getAlignAnalysisUIText()
   {
     return new AlignAnalysisUIText(
             compbio.ws.client.Services.RNAalifoldWS.toString(),
-            jalview.ws.jws2.RNAalifoldClient.class, CALC_ID, true, false,
-            true, MessageManager.getString("label.rnalifold_calculations"),
+            jalview.ws.jws2.jabaws2.RNAalifoldClient.class, CALC_ID, true,
+            false, true, true, false, 2,
+            MessageManager.getString("label.rnalifold_calculations"),
             MessageManager.getString("tooltip.rnalifold_calculations"),
             MessageManager.getString("label.rnalifold_settings"),
             MessageManager.getString("tooltip.rnalifold_settings"));
   }
 
-  @Override
-  public String getServiceActionText()
+  public static String getServiceActionText()
   {
     return "Submitting RNA alignment for Secondary Structure prediction using "
             + "RNAalifold Service";
   }
 
-  @Override
-  boolean checkValidInputSeqs(boolean dynamic, List<FastaSequence> seqs)
+  // instance
+
+  public RNAalifoldClient(Jws2Instance handle)
   {
-    return (seqs.size() > 1);
+    super(handle);
   }
 
   @Override
-  public void updateResultAnnotation(boolean immediate)
+  List<AlignmentAnnotation> annotationFromScoreManager(AlignmentI seqs,
+          Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters)
   {
-
-    if (immediate || !calcMan.isWorking(this) && scoremanager != null)
+    List<AlignmentAnnotation> ourAnnot = new ArrayList<>();
+
+    // Unpack the ScoreManager
+    List<String> structs = ((RNAStructScoreManager) scoremanager)
+            .getStructs();
+    List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
+            .getData();
+
+    // test to see if this data object contains base pair contacts
+    Score fscore = data.get(0).first();
+    boolean bpScores = (fscore.getMethod()
+            .equals(AlifoldResult.contactProbabilities.toString()));
+
+    // add annotation for the consensus sequence alignment
+    createAnnotationRowforScoreHolder(seqs, null,
+            ourAnnot,
+            getCalcId(), structs.get(0), null, null);
+
+    // Add annotations for the mfe Structure
+    createAnnotationRowforScoreHolder(seqs, null,
+            ourAnnot,
+            getCalcId(), structs.get(1), data.get(1), null);
+
+    // decide whether to add base pair contact probability histogram
+    int count = 2;
+    if (bpScores)
     {
+      createAnnotationRowforScoreHolder(seqs, null,
+              ourAnnot,
+              getCalcId(), structs.get(2), data.get(0), data.get(2));
+      count++;
+    }
 
-      List<AlignmentAnnotation> ourAnnot = new ArrayList<AlignmentAnnotation>();
-
-      // Unpack the ScoreManager
-      List<String> structs = ((RNAStructScoreManager) scoremanager)
-              .getStructs();
-      List<TreeSet<Score>> data = ((RNAStructScoreManager) scoremanager)
-              .getData();
-
-      // test to see if this data object contains base pair contacts
-      Score fscore = data.get(0).first();
-      this.bpScores = (fscore.getMethod()
-              .equals(AlifoldResult.contactProbabilities.toString()));
-
-      // add annotation for the consensus sequence alignment
-      createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
-              structs.get(0), null, null);
-
-      // Add annotations for the mfe Structure
-      createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
-              structs.get(1), data.get(1), null);
-
-      // decide whether to add base pair contact probability histogram
-      int count = 2;
-      if (bpScores)
-      {
-        createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
-                structs.get(2), data.get(0), data.get(2));
-        count++;
-      }
-
-      // Now loop for the rest of the Annotations (if there it isn't stochastic
-      // output
-      // only the centroid and MEA structures remain anyway)
-      for (int i = count; i < structs.size(); i++)
-      {
-        // The ensemble values should be displayed in the description of the
-        // first (or all?) Stochastic Backtrack Structures.
-        if (!data.get(i).first().getMethod()
-                .equals(AlifoldResult.ensembleValues.toString()))
-        {
-
-          createAnnotationRowforScoreHolder(ourAnnot, getCalcId(),
-                  structs.get(i), data.get(i), null);
-        }
-      }
-
-      if (ourAnnot.size() > 0)
+    // Now loop for the rest of the Annotations (if there it isn't stochastic
+    // output
+    // only the centroid and MEA structures remain anyway)
+    for (int i = count; i < structs.size(); i++)
+    {
+      // The ensemble values should be displayed in the description of the
+      // first (or all?) Stochastic Backtrack Structures.
+      if (!data.get(i).first().getMethod()
+              .equals(AlifoldResult.ensembleValues.toString()))
       {
 
-        updateOurAnnots(ourAnnot);
-        ap.adjustAnnotationHeight();
+        createAnnotationRowforScoreHolder(seqs, null, ourAnnot,
+                getCalcId(), structs.get(i), data.get(i), null);
       }
     }
+    return ourAnnot;
   }
 
-  protected void createAnnotationRowforScoreHolder(
+  private static void createAnnotationRowforScoreHolder(
+          AlignmentI alignment, boolean[] gapMap,
           List<AlignmentAnnotation> ourAnnot, String calcId, String struct,
           TreeSet<Score> data, TreeSet<Score> descriptionData)
   {
@@ -194,10 +170,10 @@ public class RNAalifoldClient extends JabawsCalcWorker
     String typename = typenameAndDescription[0];
     String description = typenameAndDescription[1];
 
-    AlignmentAnnotation annotation = alignViewport.getAlignment()
+    AlignmentAnnotation annotation = alignment
             .findOrCreateAnnotation(typename, calcId, false, null, null);
 
-    constructAnnotationFromScoreHolder(annotation, struct, data);
+    constructAnnotationFromScoreHolder(gapMap, annotation, struct, data);
 
     /*
      * update annotation description with the free Energy, frequency in ensemble
@@ -211,15 +187,12 @@ public class RNAalifoldClient extends JabawsCalcWorker
 
     annotation.belowAlignment = false;
     // annotation.showAllColLabels = true;
-
-    alignViewport.getAlignment().validateAnnotation(annotation);
-    af.setMenusForViewport();
-
+    annotation.validateRangeAndDisplay();
     ourAnnot.add(annotation);
   }
 
-  private AlignmentAnnotation constructAnnotationFromScoreHolder(
-          AlignmentAnnotation annotation, String struct,
+  private static AlignmentAnnotation constructAnnotationFromScoreHolder(
+          boolean[] gapMap, AlignmentAnnotation annotation, String struct,
           TreeSet<Score> data)
   {
     Annotation[] anns = new Annotation[gapMap != null ? gapMap.length + 1
@@ -231,7 +204,7 @@ public class RNAalifoldClient extends JabawsCalcWorker
 
       // The base pair probabilities are stored in a set in scoreholder. we want
       // a map
-      LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<Range, Float>();
+      LinkedHashMap<Range, Float> basePairs = new LinkedHashMap<>();
       for (Score score : data)
       {
         // The Score objects contain a set of size one containing the range and
@@ -307,7 +280,7 @@ public class RNAalifoldClient extends JabawsCalcWorker
     return annotation;
   }
 
-  private String[] constructTypenameAndDescription(Score score)
+  private static String[] constructTypenameAndDescription(Score score)
   {
     String description = "";
     String typename = "";
@@ -374,10 +347,10 @@ public class RNAalifoldClient extends JabawsCalcWorker
 
   // Check whether, at position i there is a base contact and return all the
   // contacts at this position. Should be in order of descending probability.
-  private LinkedHashMap<Range, Float> isContact(
+  private static LinkedHashMap<Range, Float> isContact(
           LinkedHashMap<Range, Float> basePairs, int i)
   {
-    LinkedHashMap<Range, Float> contacts = new LinkedHashMap<Range, Float>();
+    LinkedHashMap<Range, Float> contacts = new LinkedHashMap<>();
 
     for (Range contact : basePairs.keySet())
     {
@@ -393,10 +366,11 @@ public class RNAalifoldClient extends JabawsCalcWorker
     return contacts;
   }
 
-  private char isSS(char chr)
+  private static char isSS(char chr)
   {
     String regex = "\\(|\\)|\\{|\\}|\\[|\\]";
     char ss = (Pattern.matches(regex, Character.toString(chr))) ? 'S' : ' ';
     return ss;
   }
+
 }
index 1554a7b..a5cb473 100644 (file)
@@ -30,6 +30,15 @@ public interface ArgumentI
 
   /**
    * 
+   * @return display name of this argument
+   */
+  default String getLabel()
+  {
+    return getName();
+  };
+
+  /**
+   * 
    * @return current value for the argument (may equal the name)
    */
   String getValue();
index 29aeef9..68ec7a6 100644 (file)
  */
 package jalview.ws.params;
 
+import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
+
+import java.util.ArrayList;
 import java.util.List;
 
-public abstract class AutoCalcSetting
+public class AutoCalcSetting
 {
 
   protected boolean autoUpdate;
@@ -31,9 +35,13 @@ public abstract class AutoCalcSetting
 
   protected List<ArgumentI> jobArgset;
 
-  public AutoCalcSetting(WsParamSetI preset2, List<ArgumentI> jobArgset2,
+  protected ServiceWithParameters service;
+
+  public AutoCalcSetting(ServiceWithParameters service2,
+          WsParamSetI preset2, List<ArgumentI> jobArgset2,
           boolean autoUpdate2)
   {
+    service = service2;
     autoUpdate = autoUpdate2;
     preset = preset2;
     jobArgset = jobArgset2;
@@ -66,25 +74,117 @@ public abstract class AutoCalcSetting
   }
 
   /**
+   * TODO: refactor to ServiceWithParameters ?
    * 
    * @return characteristic URI for this service. The URI should reflect the
    *         type and version of this service, enabling the service client code
    *         to recover the correct client for this calculation.
    */
-  public abstract String getServiceURI();
+  public String getServiceURI()
+  {
+    return service.getNameURI();
+  }
 
   /**
+   * TODO: refactor to ServiceWithParameters ?
+   * 
    * return any concrete service endpoints associated with this calculation.
    * built in services should return a zero length array
    * 
    * @return
    */
-  public abstract String[] getServiceURLs();
+  public String[] getServiceURLs()
+  {
+    return new String[] { service.getUri() };
+  }
 
   /**
+   * default WsParamFile generator method - clients with custom formats should
+   * override and implement their own
    * 
    * @return stringified representation of the parameters for this setting
    */
-  public abstract String getWsParamFile();
+  public String getWsParamFile()
+  {
+    List<ArgumentI> opts = null;
+    if (jobArgset != null)
+    {
+      opts = jobArgset;
+    }
+    else
+    {
+      if (preset != null)
+      {
+        opts = preset.getArguments();
+      }
+    }
+    if (opts == null || opts.size() == 0)
+    {
+      return "";
+    }
+    StringBuffer pset = new StringBuffer();
+    for (ArgumentI ps : opts)
+    {
+      pset.append(ps.getName() + "\t" + ps.getValue());
+      pset.append("\n");
+    }
+    return pset.toString();
+  }
+  public ServiceWithParameters getService()
+  {
+    return service;
+  }
+
+  public void setService(ServiceWithParameters service)
+  {
+    this.service = service;
+    if (preset != null)
+    {
+      // check if we need to migrate preset to a new service URL
+      for (String url : preset.getApplicableUrls())
+      {
+        if (url.equals(service.getUri()))
+        {
+          // preset already verified
+          return;
+        }
+      }
+      WsParamSetI pr = service.getParamStore().getPreset(preset.getName());
+  
+      // TODO: decide of this distinction between preset and args are needed.
+      //
+      // if (pr instanceof JabaPreset && preset instanceof JabaPreset)
+      // {
+      // // easy - Presets are identical (we assume)
+      // preset = pr;
+      // return;
+      // }
+  
+      // this verifies that all arguments in the existing preset are the same as
+      // the parameters for the preset provided by the service parameter store.
+      // ie the LastUsed settings or a predefined preset.
+  
+      List<ArgumentI> oldargs = new ArrayList<>(),
+              newargs = new ArrayList<>();
+      oldargs.addAll(preset.getArguments());
+      // need to compare parameters
+      for (ArgumentI newparg : pr.getArguments())
+      {
+        if (!oldargs.remove(newparg))
+        {
+          newargs.add(newparg);
+        }
+      }
+      if (oldargs.size() == 0 && newargs.size() == 0)
+      {
+        // exact match.
+        preset = pr;
+        return;
+      }
+      // Try even harder to migrate arguments.
+      throw new Error(MessageManager
+              .getString("error.parameter_migration_not_implemented_yet"));
+    }
+  }
 
 }
index 2c5386d..af8ae27 100644 (file)
@@ -25,15 +25,49 @@ import java.util.List;
 
 public interface OptionI extends ArgumentI
 {
-
+  /**
+   * Answers a URL with further details for this option, or null if none is
+   * known
+   * 
+   * @return
+   */
   URL getFurtherDetails();
 
+  /**
+   * Answers true if the option is mandatory (a value must be chosen), false if
+   * it is optional
+   * 
+   * @return
+   */
   boolean isRequired();
 
+  /**
+   * Answers the description of the option
+   * 
+   * @return
+   */
   String getDescription();
 
+  /**
+   * Answers a list of possible values that may be chosen for the option (or
+   * null if not applicable)
+   * 
+   * @return
+   */
   List<String> getPossibleValues();
 
-  OptionI copy();
+  /**
+   * Answers a list of display names corresponding to the possible values that
+   * may be chosen for the option (or null if not applicable)
+   * 
+   * @return
+   */
+  List<String> getDisplayNames();
 
+  /**
+   * Answers a new Option with a copy of the settings of this one
+   * 
+   * @return
+   */
+  OptionI copy();
 }
index da46745..d1bdc98 100644 (file)
@@ -29,7 +29,7 @@ public interface ValueConstrainI
 
   public enum ValueType
   {
-    Integer, Float, String
+    Integer, Float, String, Double, File
   };
 
   ValueType getType();
index f80ff77..df17296 100644 (file)
  */
 package jalview.ws.params.simple;
 
-import jalview.ws.params.OptionI;
-
 import java.net.URL;
 import java.util.Arrays;
 
-public class BooleanOption extends Option implements OptionI
+public class BooleanOption extends Option
 {
 
   public BooleanOption(String name, String descr, boolean required,
-          boolean defVal, boolean val, URL link)
+      Boolean defVal, Boolean val, URL link)
   {
+    super(name, descr, required, (defVal != null && defVal ? name : null),
+        (val != null && val ? name : null), Arrays.asList(name), link);
+  }
 
-    super(name, descr, required, (defVal ? name : ""), (val ? name : ""),
-            Arrays.asList(new String[]
-            { name }), link);
+  public BooleanOption(String name, String description, String label,
+      boolean isrequired, Boolean defValue, String reprValue, URL link)
+  {
+    super(name, description, label, isrequired,
+        defValue != null && defValue ? reprValue : null,
+        defValue != null && defValue ? reprValue : null,
+        Arrays.asList(reprValue), link);
   }
 
+  public BooleanOption(String name, String description, String label,
+      boolean isrequired, Boolean defValue, URL link)
+  {
+    this(name, description, label, isrequired, defValue, String.valueOf(true), link);
+  }
 }
diff --git a/src/jalview/ws/params/simple/DoubleParameter.java b/src/jalview/ws/params/simple/DoubleParameter.java
new file mode 100644 (file)
index 0000000..6b76170
--- /dev/null
@@ -0,0 +1,76 @@
+package jalview.ws.params.simple;
+
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.ValueConstrainI;
+
+/**
+ * 
+ * @author TZVanaalten
+ *
+ */
+public class DoubleParameter extends Option implements ParameterI
+{
+  double defval;
+
+  double min;
+
+  double max;
+
+  @Override
+  public ValueConstrainI getValidValue()
+  {
+    return new ValueConstrainI()
+    {
+      @Override
+      public ValueType getType()
+      {
+        return ValueType.Double;
+      }
+
+      @Override
+      public Number getMin()
+      {
+        return min < max ? min : null;
+      }
+
+      @Override
+      public Number getMax()
+      {
+        return min < max ? max : null;
+      }
+    };
+  }
+
+  public DoubleParameter(DoubleParameter parm)
+  {
+    super(parm);
+    max = parm.max;
+    min = parm.min;
+  }
+
+  public DoubleParameter(String name, String description, boolean required,
+          Double defValue, double min, double max)
+  {
+    super(name, description, required, String.valueOf(defValue), null, null,
+            null);
+    defval = defValue;
+    this.min = min;
+    this.max = max;
+  }
+
+  public DoubleParameter(String name, String description, boolean required,
+          Double defValue, Double value, double min, double max)
+  {
+    super(name, description, required, String.valueOf(defValue),
+            String.valueOf(value), null, null);
+    defval = defValue;
+    this.min = min;
+    this.max = max;
+  }
+
+  @Override
+  public DoubleParameter copy()
+  {
+    return new DoubleParameter(this);
+  }
+}
diff --git a/src/jalview/ws/params/simple/FileParameter.java b/src/jalview/ws/params/simple/FileParameter.java
new file mode 100644 (file)
index 0000000..aa8e7ad
--- /dev/null
@@ -0,0 +1,47 @@
+package jalview.ws.params.simple;
+
+import jalview.ws.params.ValueConstrainI;
+
+/**
+ * A class that represents a file parameter. User entry options should include
+ * direct input of a file path as text, or file selection using a file browser.
+ * 
+ * @author gmcarstairs
+ *
+ */
+public class FileParameter extends StringParameter
+{
+
+  public FileParameter(String name, String description, boolean required,
+          String defValue, String value)
+  {
+    super(name, description, required, defValue, value);
+  }
+
+  @Override
+  public ValueConstrainI getValidValue()
+  {
+    return new ValueConstrainI()
+    {
+
+      @Override
+      public ValueType getType()
+      {
+        return ValueType.File;
+      }
+
+      @Override
+      public Number getMax()
+      {
+        return null;
+      }
+
+      @Override
+      public Number getMin()
+      {
+        return null;
+      }
+    };
+  }
+
+}
index fb34e89..b3a01b2 100644 (file)
@@ -31,8 +31,11 @@ public class IntegerParameter extends Option implements ParameterI
 {
   int defval;
 
-  int min, max;
+  int min;
 
+  int max;
+
+  @Override
   public ValueConstrainI getValidValue()
   {
     return new ValueConstrainI()
@@ -47,27 +50,13 @@ public class IntegerParameter extends Option implements ParameterI
       @Override
       public Number getMin()
       {
-        if (min < max)
-        {
-          return min;
-        }
-        else
-        {
-          return null;
-        }
+        return min < max ? min : null;
       }
 
       @Override
       public Number getMax()
       {
-        if (min < max)
-        {
-          return max;
-        }
-        else
-        {
-          return null;
-        }
+        return min < max ? max : null;
       }
     };
   }
diff --git a/src/jalview/ws/params/simple/LogarithmicParameter.java b/src/jalview/ws/params/simple/LogarithmicParameter.java
new file mode 100644 (file)
index 0000000..af80181
--- /dev/null
@@ -0,0 +1,80 @@
+package jalview.ws.params.simple;
+
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.ValueConstrainI;
+
+/**
+ * A model for a numeric-valued parameter which should be displayed using a
+ * logarithmic scale
+ * 
+ * @author TZVanaalten
+ */
+public class LogarithmicParameter extends Option implements ParameterI
+{
+  final double defval;
+
+  final double min;
+
+  final double max;
+
+  @Override
+  public ValueConstrainI getValidValue()
+  {
+    return new ValueConstrainI()
+    {
+
+      @Override
+      public ValueType getType()
+      {
+        return ValueType.Double;
+      }
+
+      @Override
+      public Number getMin()
+      {
+        return min < max ? min : null;
+      }
+
+      @Override
+      public Number getMax()
+      {
+        return min < max ? max : null;
+      }
+    };
+  }
+
+  public LogarithmicParameter(LogarithmicParameter parm)
+  {
+    super(parm);
+    max = parm.max;
+    min = parm.min;
+    defval = 0D;
+  }
+
+  public LogarithmicParameter(String name, String description,
+          boolean required, Double defValue, double min, double max)
+  {
+    super(name, description, required, String.valueOf(defValue), null, null,
+            null);
+    defval = defValue;
+    this.min = min;
+    this.max = max;
+  }
+
+  public LogarithmicParameter(String name, String description,
+          boolean required, Double defValue, double value, double min,
+          double max)
+  {
+    super(name, description, required, String.valueOf(defValue),
+            String.valueOf(value), null, null);
+    defval = defValue;
+    this.min = min;
+    this.max = max;
+  }
+
+  @Override
+  public LogarithmicParameter copy()
+  {
+    return new LogarithmicParameter(this);
+  }
+}
index 653359f..40e3804 100644 (file)
@@ -24,20 +24,135 @@ import jalview.ws.params.OptionI;
 
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 public class Option implements OptionI
 {
+  String name;
 
-  String name, value, defvalue, description;
+  String label;
 
-  ArrayList<String> possibleVals = new ArrayList<String>();
+  /*
+   * current value in string format, or "null" if undefined
+   */
+  String value;
+
+  /*
+   * default value in string format, or "null" if undefined
+   */
+  String defvalue;
+
+  String description;
+
+  List<String> possibleVals;
+
+  /*
+   * optional display names corresponding to possibleVals
+   */
+  List<String> displayVals;
 
   boolean required;
 
   URL fdetails;
 
+  /**
+   * Copy constructor
+   * 
+   * @param opt
+   */
+  public Option(Option opt)
+  {
+    name = opt.name;
+    label = opt.label;
+    value = opt.value;
+    defvalue = opt.defvalue;
+    description = opt.description;
+    if (opt.possibleVals != null)
+    {
+      possibleVals = new ArrayList<>(opt.possibleVals);
+    }
+    required = opt.required;
+    // URLs are singletons - so we copy by reference. nasty but true.
+    fdetails = opt.fdetails;
+  }
+
+  public Option()
+  {
+  }
+
+  public Option(String name, String description, String label, boolean isrequired,
+      String defValue, String val, List<String> possibleVals, URL fdetails)
+  {
+    this(name, description, isrequired, defValue, val, possibleVals, fdetails);
+    this.label = label;
+  }
+
+  /**
+   * Constructor including display names for possible values
+   * 
+   * @param name2
+   * @param description2
+   * @param isrequired
+   * @param defValue
+   * @param val
+   * @param possibleVals
+   * @param fdetails
+   */
+  public Option(String name2, String description2, boolean isrequired,
+          String defValue, String val, List<String> possibleVals,
+          List<String> displayNames, URL fdetails)
+  {
+    name = name2;
+    description = description2;
+    this.value = val;
+    this.required = isrequired;
+    this.defvalue = defValue;
+    if (possibleVals != null)
+    {
+      this.possibleVals = new ArrayList<>(possibleVals);
+    }
+    if (displayNames != null)
+    {
+      this.displayVals = new ArrayList<>(displayNames);
+    }
+    this.fdetails = fdetails;
+  }
+
+  /**
+   * Constructor
+   * 
+   * @param name2
+   * @param description2
+   * @param isrequired
+   * @param defValue
+   * @param val
+   * @param possibleVals
+   * @param fdetails
+   */
+  public Option(String name2, String description2, boolean isrequired,
+          String defValue, String val, List<String> possibleVals,
+          URL fdetails)
+  {
+    this(name2, description2, isrequired, defValue, val, possibleVals, null,
+            fdetails);
+  }
+
+  @Override
+  public OptionI copy()
+  {
+    Option opt = new Option(this);
+    return opt;
+  }
+
+  /**
+   * toString method to help identify options in the debugger only
+   */
+  @Override
+  public String toString()
+  {
+    return this.getClass().getName() + ":" + name;
+  }
+
   @Override
   public String getName()
   {
@@ -45,6 +160,12 @@ public class Option implements OptionI
   }
 
   @Override
+  public String getLabel()
+  {
+    return label != null ? label : name;
+  }
+
+  @Override
   public String getValue()
   {
     return value == null ? defvalue : value;
@@ -80,49 +201,9 @@ public class Option implements OptionI
     return possibleVals;
   }
 
-  public Option(Option opt)
-  {
-    name = new String(opt.name);
-    if (opt.value != null)
-      value = new String(opt.value);
-    if (opt.defvalue != null)
-      defvalue = new String(opt.defvalue);
-    if (opt.description != null)
-      description = new String(opt.description);
-    if (opt.possibleVals != null)
-    {
-      possibleVals = (ArrayList<String>) opt.possibleVals.clone();
-    }
-    required = opt.required;
-    // URLs are singletons - so we copy by reference. nasty but true.
-    fdetails = opt.fdetails;
-  }
-
-  public Option()
-  {
-  }
-
-  public Option(String name2, String description2, boolean isrequired,
-          String defValue, String value, Collection<String> possibleVals,
-          URL fdetails)
-  {
-    name = name2;
-    description = description2;
-    this.value = value;
-    this.required = isrequired;
-    this.defvalue = defValue;
-    if (possibleVals != null)
-    {
-      this.possibleVals = new ArrayList<String>();
-      this.possibleVals.addAll(possibleVals);
-    }
-    this.fdetails = fdetails;
-  }
-
   @Override
-  public OptionI copy()
+  public List<String> getDisplayNames()
   {
-    Option opt = new Option(this);
-    return opt;
+    return displayVals;
   }
 }
diff --git a/src/jalview/ws/params/simple/Parameter.java b/src/jalview/ws/params/simple/Parameter.java
deleted file mode 100644 (file)
index e2c81a6..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ws.params.simple;
-
-import jalview.ws.params.OptionI;
-import jalview.ws.params.ParameterI;
-import jalview.ws.params.ValueConstrainI;
-
-public abstract class Parameter extends Option
-        implements OptionI, ParameterI
-{
-  ValueConstrainI validator;
-
-  @Override
-  public ValueConstrainI getValidValue()
-  {
-    return validator;
-  }
-
-  public Parameter(Parameter parm)
-  {
-    super(parm);
-  }
-
-  public Parameter(ValueConstrainI validator)
-  {
-    super();
-    this.validator = validator;
-  }
-
-  @Override
-  public abstract Parameter copy();
-}
  */
 package jalview.ws.params.simple;
 
-public class StringChoiceParameter extends Option
+import java.util.List;
+
+/**
+ * A parameter with a choice of possible options, preferred to be rendered as
+ * radio buttons if possible
+ */
+public class RadioChoiceParameter extends StringParameter
 {
 
+  /**
+   * Constructor
+   * 
+   * @param name
+   * @param description
+   * @param options
+   * @param def
+   */
+  public RadioChoiceParameter(String name, String description,
+          List<String> options, String def)
+  {
+    super(name, description, true, def, def, options, null);
+  }
 }
diff --git a/src/jalview/ws/params/simple/StringParameter.java b/src/jalview/ws/params/simple/StringParameter.java
new file mode 100644 (file)
index 0000000..d3d899c
--- /dev/null
@@ -0,0 +1,88 @@
+package jalview.ws.params.simple;
+
+import jalview.ws.params.ParameterI;
+import jalview.ws.params.ValueConstrainI;
+
+import java.util.List;
+
+public class StringParameter extends Option implements ParameterI
+{
+  @Override
+  public ValueConstrainI getValidValue()
+  {
+    return new StringValueConstrain();
+  }
+
+  @Override
+  public ParameterI copy()
+  {
+    return new StringParameter(this);
+  }
+
+  private class StringValueConstrain implements ValueConstrainI
+  {
+
+    @Override
+    public ValueType getType()
+    {
+      return ValueType.String;
+    }
+
+    @Override
+    public Number getMax()
+    {
+      return null;
+    }
+
+    @Override
+    public Number getMin()
+    {
+      return null;
+    }
+
+  }
+
+  public StringParameter(StringParameter parm)
+  {
+    this.name = parm.name;
+    this.defvalue = parm.defvalue;
+    this.possibleVals = parm.possibleVals;
+    this.displayVals = parm.displayVals;
+  }
+
+  public StringParameter(String name, String description, boolean required,
+          String defValue)
+  {
+    super(name, description, required, String.valueOf(defValue), null, null,
+            null);
+    this.defvalue = defValue;
+  }
+
+  public StringParameter(String name, String description, boolean required,
+          String defValue, String value)
+  {
+    super(name, description, required, String.valueOf(defValue),
+            String.valueOf(value), null, null);
+    this.defvalue = defValue;
+  }
+
+  /**
+   * Constructor for a parameter with a list of possible values and (optionally)
+   * corresponding display names
+   * 
+   * @param name2
+   * @param description2
+   * @param isrequired
+   * @param defValue
+   * @param value
+   * @param possibleVals
+   * @param displayNames
+   */
+  public StringParameter(String name2, String description2,
+          boolean isrequired, String defValue, String value,
+          List<String> possibleVals, List<String> displayNames)
+  {
+    super(name2, description2, isrequired, defValue, value, possibleVals,
+            displayNames, null);
+  }
+}
index 5bfe3b5..8414da5 100644 (file)
@@ -40,9 +40,9 @@ import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.util.EntityUtils;
 import org.apache.james.mime4j.MimeException;
 import org.apache.james.mime4j.parser.MimeStreamParser;
-
 /**
  * data source instantiated from the response of an httpclient request.
  * 
@@ -116,23 +116,22 @@ public class HttpResultSet extends FileParse implements AutoCloseable
     }
     jalview.io.packed.JalviewDataset ds = restJob.newJalviewDataset();
     // Decide how we deal with content.
-    if (en instanceof MultipartEntity)
+    // TODO : verify we are detecting a multipart response correctly
+    if (en.getContentType().getValue().startsWith("multipart/form-data"))
     {
       // Multipart messages should be properly typed, so we parse them as we go.
-      MultipartEntity mpe = (MultipartEntity) en;
-      // multipart
       JalviewMimeContentHandler handler = new JalviewMimeContentHandler(ds);
       MimeStreamParser parser = new MimeStreamParser();
       parser.setContentHandler(handler);
       try
       {
-        parser.parse(mpe.getContent());
+        parser.parse(en.getContent());
       } catch (MimeException me)
       {
         error = true;
         errormessage = "Couldn't parse message from web service.";
         Cache.log.warn("Failed to parse MIME multipart content", me);
-        en.consumeContent();
+        EntityUtils.consume(en);
       }
       return new ParsePackedSet().getAlignment(ds,
               handler.getJalviewDataProviders());
@@ -186,7 +185,7 @@ public class HttpResultSet extends FileParse implements AutoCloseable
       {
         Cache.log.error("Can't handle encoding '" + enc
                 + "' for response from webservice.", e);
-        en.consumeContent();
+        EntityUtils.consume(en);
         error = true;
         errormessage = "Can't handle encoding for response from webservice";
         return;
index 88431a6..c83879a 100644 (file)
@@ -30,7 +30,6 @@ import jalview.ws.params.simple.Option;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -58,9 +57,9 @@ public abstract class InputType
   {
     NUC, PROT, MIX;
 
-    public static Collection<String> toStringValues()
+    public static List<String> toStringValues()
     {
-      Collection<String> c = new ArrayList<String>();
+      List<String> c = new ArrayList<>();
       for (molType type : values())
       {
         c.add(type.toString());
@@ -75,7 +74,7 @@ public abstract class InputType
 
   public int max = 0; // unbounded
 
-  protected ArrayList<Class> inputData = new ArrayList<Class>();
+  protected List<Class> inputData = new ArrayList<>();
 
   /**
    * initialise the InputType with a list of jalview data classes that the
@@ -104,7 +103,9 @@ public abstract class InputType
   public boolean validFor(RestJob restJob)
   {
     if (!validFor(restJob.rsd))
+    {
       return false;
+    }
     for (Class cl : inputData)
     {
       if (!restJob.hasDataOfType(cl))
@@ -118,7 +119,9 @@ public abstract class InputType
   public boolean validFor(RestServiceDescription restServiceDescription)
   {
     if (!restServiceDescription.inputParams.values().contains(this))
+    {
       return false;
+    }
 
     return true;
   }
@@ -270,7 +273,7 @@ public abstract class InputType
 
   public List<OptionI> getBaseOptions()
   {
-    ArrayList<OptionI> opts = new ArrayList<OptionI>();
+    ArrayList<OptionI> opts = new ArrayList<>();
     opts.add(new IntegerParameter("min",
             "Minimum number of data of this type", true, 1, min, 0, -1));
     opts.add(new IntegerParameter("max",
@@ -295,7 +298,7 @@ public abstract class InputType
   public void configureFromArgumentI(List<ArgumentI> currentSettings)
           throws InvalidArgumentException
   {
-    ArrayList<String> urltoks = new ArrayList<String>();
+    List<String> urltoks = new ArrayList<>();
     String rg;
     for (ArgumentI arg : currentSettings)
     {
index 5d1a288..2d39db5 100644 (file)
@@ -30,15 +30,14 @@ import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
 import jalview.gui.WebserviceInfo;
-import jalview.io.packed.DataProvider.JvDataType;
 import jalview.util.MessageManager;
 import jalview.ws.WSClient;
 import jalview.ws.WSClientI;
 import jalview.ws.WSMenuEntryProviderI;
+import jalview.ws.rest.clientdefs.ShmrRestClient;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.Hashtable;
 import java.util.Vector;
 
 import javax.swing.JMenu;
@@ -120,12 +119,12 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
   {
     WebServiceJobTitle = MessageManager
             .formatMessage("label.webservice_job_title", new String[]
-            { service.details.Action, service.details.Name });
-    WebServiceName = service.details.Name;
+            { service.details.getAction(), service.details.getName() });
+    WebServiceName = service.details.getName();
     WebServiceReference = "No reference - go to url for more info";
-    if (service.details.description != null)
+    if (service.details.getDescription() != null)
     {
-      WebServiceReference = service.details.description;
+      WebServiceReference = service.details.getDescription();
     }
     if (!headless)
     {
@@ -162,10 +161,10 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
   public void attachWSMenuEntry(final JMenu wsmenu,
           final AlignFrame alignFrame)
   {
-    JMenuItem submit = new JMenuItem(service.details.Name);
+    JMenuItem submit = new JMenuItem(service.details.getName());
     submit.setToolTipText(MessageManager
             .formatMessage("label.rest_client_submit", new String[]
-            { service.details.Action, service.details.Name }));
+            { service.details.getAction(), service.details.getName() }));
     submit.addActionListener(new ActionListener()
     {
 
@@ -360,46 +359,6 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
     }
   }
 
-  public static RestClient makeShmmrRestClient()
-  {
-    String action = "Analysis",
-            description = "Sequence Harmony and Multi-Relief (Brandt et al. 2010)",
-            name = MessageManager.getString("label.multiharmony");
-    Hashtable<String, InputType> iparams = new Hashtable<String, InputType>();
-    jalview.ws.rest.params.JobConstant toolp;
-    // toolp = new jalview.ws.rest.JobConstant("tool","jalview");
-    // iparams.put(toolp.token, toolp);
-    // toolp = new jalview.ws.rest.params.JobConstant("mbjob[method]","shmr");
-    // iparams.put(toolp.token, toolp);
-    // toolp = new
-    // jalview.ws.rest.params.JobConstant("mbjob[description]","step 1");
-    // iparams.put(toolp.token, toolp);
-    // toolp = new jalview.ws.rest.params.JobConstant("start_search","1");
-    // iparams.put(toolp.token, toolp);
-    // toolp = new jalview.ws.rest.params.JobConstant("blast","0");
-    // iparams.put(toolp.token, toolp);
-
-    jalview.ws.rest.params.Alignment aliinput = new jalview.ws.rest.params.Alignment();
-    // SHMR server has a 65K limit for content pasted into the 'ali' parameter,
-    // so we always upload our files.
-    aliinput.token = "ali_file";
-    aliinput.writeAsFile = true;
-    iparams.put(aliinput.token, aliinput);
-    jalview.ws.rest.params.SeqGroupIndexVector sgroups = new jalview.ws.rest.params.SeqGroupIndexVector();
-    sgroups.setMinsize(2);
-    sgroups.min = 2;// need at least two group defined to make a partition
-    iparams.put("groups", sgroups);
-    sgroups.token = "groups";
-    sgroups.sep = " ";
-    RestServiceDescription shmrService = new RestServiceDescription(action,
-            description, name,
-            "http://zeus.few.vu.nl/programs/shmrwww/index.php?tool=jalview", // ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1",
-            "?tool=jalview", iparams, true, false, '-');
-    // a priori knowledge of the data returned from the service
-    shmrService.addResultDatatype(JvDataType.ANNOTATION);
-    return new RestClient(shmrService);
-  }
-
   public AlignmentPanel recoverAlignPanelForView()
   {
     AlignmentPanel[] aps = Desktop
@@ -429,13 +388,13 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
   {
     if (services == null)
     {
-      services = new Vector<String>();
+      services = new Vector<>();
       try
       {
         for (RestServiceDescription descr : RestServiceDescription
-                .parseDescriptions(
-                        jalview.bin.Cache.getDefault(RSBS_SERVICES,
-                                makeShmmrRestClient().service.toString())))
+                .parseDescriptions(jalview.bin.Cache.getDefault(
+                        RSBS_SERVICES,
+                        ShmrRestClient.makeShmmrRestClient().service.toString())))
         {
           services.add(descr.toString());
         }
@@ -458,7 +417,7 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
 
   public String getAction()
   {
-    return service.details.Action;
+    return service.details.getAction();
   }
 
   public RestServiceDescription getRestDescription()
@@ -468,7 +427,7 @@ public static final String RSBS_SERVICES = "RSBS_SERVICES";
 
   public static Vector<String> getRsbsDescriptions()
   {
-    Vector<String> rsbsDescrs = new Vector<String>();
+    Vector<String> rsbsDescrs = new Vector<>();
     for (RestClient rsbs : getRestClients())
     {
       rsbsDescrs.add(rsbs.getRestDescription().toString());
index acb7904..f60ff0c 100644 (file)
@@ -59,8 +59,6 @@ import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntity;
 import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.EntityUtils;
 
 public class RestJobThread extends AWSThread
@@ -216,9 +214,6 @@ public class RestJobThread extends AWSThread
   protected void doHttpReq(Stage stg, RestJob rj, String postUrl)
           throws Exception
   {
-    StringBuffer respText = new StringBuffer();
-    // con.setContentHandlerFactory(new
-    // jalview.ws.io.mime.HttpContentHandler());
     HttpRequestBase request = null;
     String messages = "";
     if (stg == Stage.SUBMIT)
@@ -253,7 +248,6 @@ public class RestJobThread extends AWSThread
     {
       DefaultHttpClient httpclient = new DefaultHttpClient();
 
-      HttpContext localContext = new BasicHttpContext();
       HttpResponse response = null;
       try
       {
@@ -287,39 +281,21 @@ public class RestJobThread extends AWSThread
         Cache.log.debug("Processing result set.");
         processResultSet(rj, response, request);
         break;
+
       case 202:
-        rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
-                + "<a href=" + rj.getJobId() + "\">" + rj.getJobId()
-                + "</a><br>";
-        rj.running = true;
+        markJobAsRunning(rj);
         break;
+
+      case 201:
+        // Created - redirect may be present. Fallthrough to 302
       case 302:
-        Header[] loc;
-        if (!rj.isSubmitted()
-                && (loc = response
-                        .getHeaders(HTTPConstants.HEADER_LOCATION)) != null
-                && loc.length > 0)
-        {
-          if (loc.length > 1)
-          {
-            Cache.log.warn("Ignoring additional " + (loc.length - 1)
-                    + " location(s) provided in response header ( next one is '"
-                    + loc[1].getValue() + "' )");
-          }
-          rj.setJobId(loc[0].getValue());
-          rj.setSubmitted(true);
-        }
+        extractJobId(rj, response);
         completeStatus(rj, response);
         break;
       case 500:
-        // Failed.
-        rj.setSubmitted(true);
-        rj.setAllowedServerExceptions(0);
-        rj.setSubjobComplete(true);
-        rj.error = true;
-        rj.running = false;
-        completeStatus(rj, response,
-                "" + getStage(stg) + "failed. Reason below:\n");
+        markAsFailed(rj, response);
+        completeStatus(rj, response, "" + getStage(stg)
+                + "failed. Reason below:\n");
         break;
       default:
         // Some other response. Probably need to pop up the content in a window.
@@ -346,6 +322,64 @@ public class RestJobThread extends AWSThread
     }
   }
 
+  private void markAsFailed(RestJob rj, HttpResponse response)
+  {
+    // Failed.
+    rj.setSubmitted(true);
+    rj.setAllowedServerExceptions(0);
+    rj.setSubjobComplete(true);
+    rj.error = true;
+    rj.running = false;
+  }
+
+  /**
+   * set the jobRunning flag and post a link to the physical result page encoded
+   * in rj.getJobId()
+   * 
+   * @param rj
+   */
+  private void markJobAsRunning(RestJob rj)
+  {
+    rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
+            + "<a href="
+            + rj.getJobId()
+            + "\">"
+            + rj.getJobId()
+            + "</a><br>";
+    rj.running = true;
+  }
+
+  /**
+   * extract the job ID URL from the redirect page. Does nothing if job is
+   * already running.
+   * 
+   * @param rj
+   * @param response
+   */
+  private void extractJobId(RestJob rj, HttpResponse response)
+  {
+    Header[] loc;
+    if (!rj.isSubmitted())
+    {
+
+      // redirect URL - typical for IBIVU type jobs.
+      if ((loc = response.getHeaders(HTTPConstants.HEADER_LOCATION)) != null
+              && loc.length > 0)
+      {
+        if (loc.length > 1)
+        {
+          Cache.log
+                  .warn("Ignoring additional "
+                          + (loc.length - 1)
+                          + " location(s) provided in response header ( next one is '"
+                          + loc[1].getValue() + "' )");
+        }
+        rj.setJobId(loc[0].getValue());
+        rj.setSubmitted(true);
+      }
+    }
+  }
+
   /**
    * job has completed. Something valid should be available from con
    * 
@@ -575,12 +609,12 @@ public class RestJobThread extends AWSThread
     /**
      * alignment panels derived from each alignment set returned by service.
      */
-    ArrayList<jalview.gui.AlignmentPanel> destPanels = new ArrayList<jalview.gui.AlignmentPanel>();
+    ArrayList<jalview.gui.AlignmentPanel> destPanels = new ArrayList<>();
     /**
      * list of instructions for how to process each distinct alignment set
      * returned by the job set
      */
-    ArrayList<AddDataTo> resultDest = new ArrayList<AddDataTo>();
+    ArrayList<AddDataTo> resultDest = new ArrayList<>();
     /**
      * when false, zeroth pane is panel derived from input deta.
      */
@@ -599,9 +633,9 @@ public class RestJobThread extends AWSThread
     boolean vsepjobs = restClient.service.isVseparable();
     // total number of distinct alignment sets generated by job set.
     int numAlSets = 0, als = 0;
-    List<AlignmentI> destAls = new ArrayList<AlignmentI>();
-    List<jalview.datamodel.HiddenColumns> destColsel = new ArrayList<jalview.datamodel.HiddenColumns>();
-    List<List<NewickFile>> trees = new ArrayList<List<NewickFile>>();
+    List<AlignmentI> destAls = new ArrayList<>();
+    List<jalview.datamodel.HiddenColumns> destColsel = new ArrayList<>();
+    List<List<NewickFile>> trees = new ArrayList<>();
 
     do
     {
@@ -660,7 +694,7 @@ public class RestJobThread extends AWSThread
 
               if (alset.trees != null)
               {
-                trees.add(new ArrayList<NewickFile>(alset.trees));
+                trees.add(new ArrayList<>(alset.trees));
               }
               else
               {
@@ -688,8 +722,8 @@ public class RestJobThread extends AWSThread
        */
       int vrestjob = 0;
       // Destination alignments for all result data.
-      ArrayList<SequenceGroup> visgrps = new ArrayList<SequenceGroup>();
-      Hashtable<String, SequenceGroup> groupNames = new Hashtable<String, SequenceGroup>();
+      ArrayList<SequenceGroup> visgrps = new ArrayList<>();
+      Hashtable<String, SequenceGroup> groupNames = new Hashtable<>();
       ArrayList<AlignmentAnnotation> visAlAn = null;
       for (nvertsep = 0; nvertsep < nvertseps; nvertsep++)
       {
@@ -953,7 +987,7 @@ public class RestJobThread extends AWSThread
                 }
                 if (visAlAn == null)
                 {
-                  visAlAn = new ArrayList<AlignmentAnnotation>();
+                  visAlAn = new ArrayList<>();
                 }
                 AlignmentAnnotation visan = null;
                 for (AlignmentAnnotation v : visAlAn)
@@ -1037,8 +1071,9 @@ public class RestJobThread extends AWSThread
       HiddenColumns destcs;
       String alTitle = MessageManager
               .formatMessage("label.webservice_job_title_on", new String[]
-              { restClient.service.details.Action,
-                  restClient.service.details.Name, restClient.viewTitle });
+              { restClient.service.details.getAction(),
+                  restClient.service.details.getName(),
+                  restClient.viewTitle });
       switch (action)
       {
       case newAlignment:
@@ -1248,7 +1283,7 @@ public class RestJobThread extends AWSThread
    */
   public boolean isValid()
   {
-    ArrayList<String> _warnings = new ArrayList<String>();
+    ArrayList<String> _warnings = new ArrayList<>();
     boolean validt = true;
     if (jobs != null)
     {
index 5533406..b07f3b6 100644 (file)
@@ -23,6 +23,7 @@ package jalview.ws.rest;
 import jalview.datamodel.SequenceI;
 import jalview.io.packed.DataProvider.JvDataType;
 import jalview.util.StringUtils;
+import jalview.ws.api.UIinfo;
 import jalview.ws.rest.params.Alignment;
 import jalview.ws.rest.params.AnnotationFile;
 import jalview.ws.rest.params.SeqGroupIndexVector;
@@ -66,10 +67,7 @@ public class RestServiceDescription
           boolean vseparable, char gapCharacter)
   {
     super();
-    this.details = new UIinfo();
-    details.Action = action == null ? "" : action;
-    details.description = description == null ? "" : description;
-    details.Name = name == null ? "" : name;
+    this.details = new UIinfo(action, action, name, description, postUrl);
     this.postUrl = postUrl == null ? "" : postUrl;
     this.urlSuffix = urlSuffix == null ? "" : urlSuffix;
     if (inputParams != null)
@@ -98,56 +96,11 @@ public class RestServiceDescription
     // TODO - robust diff that includes constants and reordering of URL
     // diff |= !(postUrl.equals(other.postUrl));
     // diff |= !inputParams.equals(other.inputParams);
-    diff |= !details.Name.equals(other.details.Name);
-    diff |= !details.Action.equals(other.details.Action);
-    diff |= !details.description.equals(other.details.description);
+    diff |= !details.equals(other.details);
     return !diff;
   }
 
-  /**
-   * Service UI Info { Action, Specific Name of Service, Brief Description }
-   */
-
-  public class UIinfo
-  {
-    public String getAction()
-    {
-      return Action;
-    }
-
-    public void setAction(String action)
-    {
-      Action = action;
-    }
-
-    public String getName()
-    {
-      return Name;
-    }
-
-    public void setName(String name)
-    {
-      Name = name;
-    }
-
-    public String getDescription()
-    {
-      return description;
-    }
-
-    public void setDescription(String description)
-    {
-      this.description = description;
-    }
-
-    String Action;
-
-    String Name;
-
-    String description;
-  }
-
-  public UIinfo details = new UIinfo();
+  public UIinfo details;
 
   public String getAction()
   {
@@ -238,7 +191,7 @@ public class RestServiceDescription
   /**
    * input info given as key/value pairs - mapped to post arguments
    */
-  Map<String, InputType> inputParams = new HashMap<String, InputType>();
+  Map<String, InputType> inputParams = new HashMap<>();
 
   /**
    * assigns the given inputType it to its corresponding input parameter token
@@ -455,7 +408,7 @@ public class RestServiceDescription
     }
     StringTokenizer st = new StringTokenizer(outstring, ";");
     String tok = "";
-    resultData = new ArrayList<JvDataType>();
+    resultData = new ArrayList<>();
     while (st.hasMoreTokens())
     {
       try
@@ -479,7 +432,7 @@ public class RestServiceDescription
 
   private String getServiceIOProperties()
   {
-    ArrayList<String> vls = new ArrayList<String>();
+    ArrayList<String> vls = new ArrayList<>();
     if (isHseparable())
     {
       vls.add("hseparable");
@@ -496,17 +449,18 @@ public class RestServiceDescription
             ",");
   }
 
+  @Override
   public String toString()
   {
     StringBuffer result = new StringBuffer();
     result.append("|");
-    result.append(details.Name);
+    result.append(details.getName());
     result.append('|');
-    result.append(details.Action);
+    result.append(details.getAction());
     result.append('|');
-    if (details.description != null)
+    if (details.getDescription() != null)
     {
-      result.append(details.description);
+      result.append(details.getDescription());
     }
     ;
     // list job input flags
@@ -567,9 +521,8 @@ public class RestServiceDescription
     {
       p++;
     }
-    details.Name = list[p];
-    details.Action = list[p + 1];
-    details.description = list[p + 2];
+    String action = list[p + 1], name = list[p], descrip = list[p + 2];
+
     invalid |= !configureFromServiceInputProperties(list[p + 3], warnings);
     if (list.length - p > 5 && list[p + 5] != null
             && list[p + 5].trim().length() > 5)
@@ -589,6 +542,7 @@ public class RestServiceDescription
         p += 5;
       }
     }
+    details = new UIinfo(action, action, name, descrip, postUrl);
     return invalid ? -1 : p;
   }
 
@@ -667,7 +621,7 @@ public class RestServiceDescription
     int lastp = 0;
     String url = new String();
     Matcher prms = PARAM_ENCODED_URL_PATTERN.matcher(ipurl);
-    Map<String, InputType> iparams = new Hashtable<String, InputType>();
+    Map<String, InputType> iparams = new Hashtable<>();
     InputType jinput;
     while (prms.find())
     {
@@ -728,7 +682,7 @@ public class RestServiceDescription
         jinput = (InputType) (type.getConstructor().newInstance());
         if (iprm.equalsIgnoreCase(jinput.getURLtokenPrefix()))
         {
-          ArrayList<String> al = new ArrayList<String>();
+          ArrayList<String> al = new ArrayList<>();
           for (String prprm : StringUtils.separatorListToArray(iprmparams,
                   ","))
           {
@@ -838,7 +792,7 @@ public class RestServiceDescription
     return jobId + urlSuffix;
   }
 
-  private List<JvDataType> resultData = new ArrayList<JvDataType>();
+  private List<JvDataType> resultData = new ArrayList<>();
 
   /**
    * 
@@ -852,7 +806,7 @@ public class RestServiceDescription
   {
     if (resultData == null)
     {
-      resultData = new ArrayList<JvDataType>();
+      resultData = new ArrayList<>();
     }
     resultData.add(dt);
   }
@@ -883,7 +837,7 @@ public class RestServiceDescription
           String services) throws Exception
   {
     String[] list = StringUtils.separatorListToArray(services, "|");
-    List<RestServiceDescription> svcparsed = new ArrayList<RestServiceDescription>();
+    List<RestServiceDescription> svcparsed = new ArrayList<>();
     int p = 0, lastp = 0;
     StringBuffer warnings = new StringBuffer();
     do
diff --git a/src/jalview/ws/rest/clientdefs/ShmrRestClient.java b/src/jalview/ws/rest/clientdefs/ShmrRestClient.java
new file mode 100644 (file)
index 0000000..986d760
--- /dev/null
@@ -0,0 +1,54 @@
+package jalview.ws.rest.clientdefs;
+
+import jalview.io.packed.DataProvider.JvDataType;
+import jalview.util.MessageManager;
+import jalview.ws.rest.InputType;
+import jalview.ws.rest.RestClient;
+import jalview.ws.rest.RestServiceDescription;
+import java.util.Hashtable;
+
+public class ShmrRestClient
+{
+
+  public static RestClient makeShmmrRestClient()
+  {
+    String action = "Analysis", description = "Sequence Harmony and Multi-Relief (Brandt et al. 2010)", name = MessageManager
+            .getString("label.multiharmony");
+    Hashtable<String, InputType> iparams = new Hashtable<String, InputType>();
+    jalview.ws.rest.params.JobConstant toolp;
+    // toolp = new jalview.ws.rest.JobConstant("tool","jalview");
+    // iparams.put(toolp.token, toolp);
+    // toolp = new jalview.ws.rest.params.JobConstant("mbjob[method]","shmr");
+    // iparams.put(toolp.token, toolp);
+    // toolp = new
+    // jalview.ws.rest.params.JobConstant("mbjob[description]","step 1");
+    // iparams.put(toolp.token, toolp);
+    // toolp = new jalview.ws.rest.params.JobConstant("start_search","1");
+    // iparams.put(toolp.token, toolp);
+    // toolp = new jalview.ws.rest.params.JobConstant("blast","0");
+    // iparams.put(toolp.token, toolp);
+  
+    jalview.ws.rest.params.Alignment aliinput = new jalview.ws.rest.params.Alignment();
+    // SHMR server has a 65K limit for content pasted into the 'ali' parameter,
+    // so we always upload our files.
+    aliinput.token = "ali_file";
+    aliinput.writeAsFile = true;
+    iparams.put(aliinput.token, aliinput);
+    jalview.ws.rest.params.SeqGroupIndexVector sgroups = new jalview.ws.rest.params.SeqGroupIndexVector();
+    sgroups.setMinsize(2);
+    sgroups.min = 2;// need at least two group defined to make a partition
+    iparams.put("groups", sgroups);
+    sgroups.token = "groups";
+    sgroups.sep = " ";
+    RestServiceDescription shmrService = new RestServiceDescription(
+            action,
+            description,
+            name,
+            "http://zeus.few.vu.nl/programs/shmrwww/index.php?tool=jalview",// ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1",
+            "?tool=jalview", iparams, true, false, '-');
+    // a priori knowledge of the data returned from the service
+    shmrService.addResultDatatype(JvDataType.ANNOTATION);
+    return new RestClient(shmrService);
+  }
+
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaAnnotationServiceInstance.java b/src/jalview/ws/slivkaws/SlivkaAnnotationServiceInstance.java
new file mode 100644 (file)
index 0000000..cc5c1e4
--- /dev/null
@@ -0,0 +1,93 @@
+package jalview.ws.slivkaws;
+
+import jalview.api.FeatureColourI;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.io.AnnotationFile;
+import jalview.io.DataSourceType;
+import jalview.io.FeaturesFile;
+import jalview.util.MessageManager;
+import jalview.ws.api.JobId;
+import jalview.ws.api.SequenceAnnotationServiceI;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws.uimodel.AlignAnalysisUIText;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
+public class SlivkaAnnotationServiceInstance extends SlivkaWSInstance implements SequenceAnnotationServiceI
+{
+  public SlivkaAnnotationServiceInstance(SlivkaClient client,
+          SlivkaService service, boolean conservation)
+  {
+    super(client, service, !conservation ? "Protein sequence analysis"
+        : "Alignment Conservation");
+    if (conservation)
+    {
+      setAlignAnalysisUI(new AlignAnalysisUIText(getName(),
+              SlivkaAnnotationServiceInstance.class,
+              "Slivka.AACons", false, true, true, true, true, 2,
+              MessageManager.getString("label.aacon_calculations"),
+              MessageManager.getString("tooltip.aacon_calculations"),
+              MessageManager.getString("label.aacon_settings"),
+              MessageManager.getString("tooltip.aacon_settings")));
+    }
+    style = ServiceClient.SEQUENCEANNOTATIONWSCLIENT;
+  }
+
+  @Override
+  public JobId submitToService(List<SequenceI> seqs, WsParamSetI preset, List<ArgumentI> paramset) throws Throwable
+  {
+    return super.submit(seqs, preset, paramset);
+  }
+
+  @Override
+  public List<AlignmentAnnotation> getAnnotationResult(JobId job,
+          List<SequenceI> seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters) throws Throwable
+  {
+    RemoteFile annotFile = null;
+    RemoteFile featFile = null;
+    try
+    {
+      List<RemoteFile> files = client.getJobResults(job.getJobId());
+      for (RemoteFile f : files)
+      {
+        if (f.getMimeType().equals("application/jalview-annotations"))
+        {
+          annotFile = f;
+        }
+        else if (f.getMimeType().equals("application/jalview-features"))
+        {
+          featFile = f;
+        }
+      }
+    } catch (IOException e)
+    {
+      throw new IOError(e);
+    }
+    Alignment aln = new Alignment(seqs.toArray(new SequenceI[0]));
+    if (annotFile == null
+        || !new AnnotationFile().readAnnotationFile(aln, annotFile.getURL().toString(), DataSourceType.URL))
+    {
+      Cache.log.debug("No annotation from slivka job\n" + annotFile);
+    }
+    if (featFile == null
+        || !new FeaturesFile(featFile.getURL().toString(), DataSourceType.URL).parse(aln, featureColours, true))
+    {
+      Cache.log.debug("No features from slivka job\n" + featFile);
+    }
+    return Arrays.asList(aln.getAlignmentAnnotation());
+  }
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaDatastore.java b/src/jalview/ws/slivkaws/SlivkaDatastore.java
new file mode 100644 (file)
index 0000000..0922d13
--- /dev/null
@@ -0,0 +1,88 @@
+package jalview.ws.slivkaws;
+
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
+public class SlivkaDatastore implements ParamDatastoreI
+{
+  private SlivkaParamSet defaultPreset;
+  private List<WsParamSetI> presets = new ArrayList<>();
+
+  SlivkaDatastore(SlivkaService service) throws IOException {
+    defaultPreset = new SlivkaParamSet(service);
+  }
+
+  @Override
+  public List<WsParamSetI> getPresets()
+  {
+    return presets;
+  }
+
+  @Override
+  public WsParamSetI getPreset(String name)
+  {
+    for (WsParamSetI preset : presets)
+    {
+      if (preset.getName().equals(name))
+      {
+        return preset;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public List<ArgumentI> getServiceParameters()
+  {
+    return new ArrayList<>(defaultPreset.getArguments());
+  }
+
+  @Override
+  public boolean presetExists(String name)
+  {
+    for (WsParamSetI preset : presets)
+    {
+      if (preset.getName().equals(name))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public void deletePreset(String name)
+  {
+  }
+
+  @Override
+  public void storePreset(String presetName, String text, List<ArgumentI> jobParams)
+  {
+  }
+
+  @Override
+  public void updatePreset(String oldName, String presetName, String text, List<ArgumentI> jobParams)
+  {
+  }
+
+  @Override
+  public WsParamSetI parseServiceParameterFile(String name, String description, String[] serviceURL, String parameters)
+      throws IOException
+  {
+    return null;
+  }
+
+  @Override
+  public String generateServiceParameterFile(WsParamSetI pset) throws IOException
+  {
+    return null;
+  }
+
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java b/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java
new file mode 100644 (file)
index 0000000..a65e93e
--- /dev/null
@@ -0,0 +1,60 @@
+package jalview.ws.slivkaws;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FormatAdapter;
+import jalview.ws.api.JobId;
+import jalview.ws.api.MultipleSequenceAlignmentI;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.InvalidArgumentException;
+import jalview.ws.params.WsParamSetI;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.rmi.ServerError;
+import java.util.List;
+
+import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
+public class SlivkaMsaServiceInstance extends SlivkaWSInstance implements MultipleSequenceAlignmentI
+{
+  SlivkaMsaServiceInstance(SlivkaClient client, SlivkaService service) {
+    super(client, service, "Sequence Alignment");
+    style = ServiceClient.MSAWSCLIENT;
+  }
+
+  @Override
+  public JobId align(List<SequenceI> toalign, WsParamSetI parameters, List<ArgumentI> list) throws Throwable
+  {
+    return super.submit(toalign, parameters, list);
+  }
+
+  @Override
+  public AlignmentI getAlignmentFor(JobId jobId) throws InvalidArgumentException, ServerError, IOError
+  {
+    List<RemoteFile> files;
+    try
+    {
+      files = client.getJobResults(jobId.getJobId());
+      for (RemoteFile f : files)
+      {
+        if (f.getMimeType().equals("application/clustal"))
+        {
+          return new FormatAdapter().readFile(f.getURL().toString(), DataSourceType.URL, FileFormat.Clustal);
+        }
+        else if (f.getMimeType().equals("application/fasta"))
+        {
+          return new FormatAdapter().readFile(f.getURL().toString(), DataSourceType.URL, FileFormat.Fasta);
+        }
+      }
+    } catch (IOException e)
+    {
+      throw new IOError(e);
+    }
+    return null;
+  }
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaParamSet.java b/src/jalview/ws/slivkaws/SlivkaParamSet.java
new file mode 100644 (file)
index 0000000..7e81684
--- /dev/null
@@ -0,0 +1,142 @@
+package jalview.ws.slivkaws;
+
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.DoubleParameter;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.StringParameter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import uk.ac.dundee.compbio.slivkaclient.BooleanField;
+import uk.ac.dundee.compbio.slivkaclient.ChoiceField;
+import uk.ac.dundee.compbio.slivkaclient.DecimalField;
+import uk.ac.dundee.compbio.slivkaclient.FormField;
+import uk.ac.dundee.compbio.slivkaclient.IntegerField;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaForm;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+import uk.ac.dundee.compbio.slivkaclient.TextField;
+
+
+
+public class SlivkaParamSet implements WsParamSetI
+{
+  private SlivkaService service;
+  private List<ArgumentI> args = new ArrayList<>();
+
+  SlivkaParamSet(SlivkaService service) throws IOException {
+    this.service = service;
+    SlivkaForm form = service.getForm();
+    for (FormField field : form.getFields())
+    {
+      switch (field.getType()) {
+      case BOOLEAN:
+        BooleanField boolField = (BooleanField) field;
+        args.add(new BooleanOption(
+            field.getName(), field.getDescription(), field.getLabel(),
+            field.isRequired(), boolField.getDefault(), null
+        ));
+        break;
+      case TEXT:
+        TextField textField = (TextField) field;
+        args.add(new StringParameter(
+            field.getName(), field.getDescription(), field.isRequired(),
+            textField.getDefault(), textField.getDefault()
+        ));
+        break;
+      case INTEGER:
+        IntegerField intField = (IntegerField) field;
+        args.add(new IntegerParameter(
+            field.getName(), field.getDescription(), field.isRequired(),
+            intField.getDefault(), intField.getMin(), intField.getMax()
+        ));
+        break;
+      case DECIMAL:
+        DecimalField doubleField = (DecimalField) field;
+        args.add(new DoubleParameter(
+            field.getName(), field.getDescription(), field.isRequired(),
+            doubleField.getDefault(), doubleField.getMin(),
+            doubleField.getMax()
+        ));
+        break;
+      case CHOICE:
+        ChoiceField choiceField = (ChoiceField) field;
+        List<String> choices = new ArrayList<>(choiceField.getChoices());
+        if (field.hasMultipleValues()) {
+          int counter = 0;
+          for (String choice : choices) {
+            args.add(new BooleanOption(
+                String.format("%s$%d", field.getName(), counter++),
+                field.getDescription(), choice, field.isRequired(),
+                choice.equals(choiceField.getDefault()), choice,
+                null
+            ));
+          }
+        }
+        else
+        {
+          args.add(new StringParameter(
+              field.getName(), field.getDescription(),
+              field.isRequired(), choiceField.getDefault(), choiceField.getDefault(),
+              choices, choices
+          ));
+        }
+        break;
+      case FILE:
+      default:
+        continue;
+      }
+    }
+  }
+
+  @Override
+  public String getName()
+  {
+    return "Default";
+  }
+
+  @Override
+  public String getDescription()
+  {
+    return "";
+  }
+
+  @Override
+  public String[] getApplicableUrls()
+  {
+    return new String[] { service.getURL().toString() };
+  }
+
+  @Override
+  public String getSourceFile()
+  {
+    return null;
+  }
+
+  @Override
+  public void setSourceFile(String newfile)
+  {
+  }
+
+  @Override
+  public boolean isModifiable()
+  {
+    return true;
+  }
+
+  @Override
+  public List<ArgumentI> getArguments()
+  {
+    return args;
+  }
+
+  @Override
+  public void setArguments(List<ArgumentI> args)
+  {
+    throw new RuntimeException();
+  }
+
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java
new file mode 100644 (file)
index 0000000..cd296c6
--- /dev/null
@@ -0,0 +1,218 @@
+package jalview.ws.slivkaws;
+
+import jalview.bin.Cache;
+import jalview.ws.ServiceChangeListener;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.api.ServiceWithParameters;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
+public class SlivkaWSDiscoverer implements WSDiscovererI
+{
+  private static final String SLIVKA_HOST_URLS = "SLIVKAHOSTURLS";
+
+  private static final String COMPBIO_SLIVKA = "https://www.compbio.dundee.ac.uk/slivka/";
+
+  private static SlivkaWSDiscoverer instance = null;
+
+  private List<ServiceWithParameters> services = List.of();
+
+  private SlivkaWSDiscoverer()
+  {
+  }
+
+  public static SlivkaWSDiscoverer getInstance()
+  {
+    if (instance == null)
+    {
+      instance = new SlivkaWSDiscoverer();
+    }
+    return instance;
+  }
+
+  private Set<ServiceChangeListener> serviceListeners = new CopyOnWriteArraySet<>();
+
+  @Override
+  public void addServiceChangeListener(ServiceChangeListener l)
+  {
+    serviceListeners.add(l);
+  }
+
+  @Override
+  public void removeServiceChangeListener(ServiceChangeListener l)
+  {
+    serviceListeners.remove(l);
+  }
+
+  public void notifyServiceListeners(List<ServiceWithParameters> services)
+  {
+    for (var listener : serviceListeners)
+    {
+      listener.servicesChanged(this, services);
+    }
+  }
+
+  private final ExecutorService executor = Executors.newSingleThreadExecutor();
+  private Vector<Future<?>> discoveryTasks = new Vector<>();
+
+  public CompletableFuture<WSDiscovererI> startDiscoverer()
+  {
+    CompletableFuture<WSDiscovererI> task = CompletableFuture
+            .supplyAsync(() -> {
+              reloadServices();
+              return SlivkaWSDiscoverer.this;
+            }, executor);
+    discoveryTasks.add(task);
+    return task;
+  }
+
+  private List<ServiceWithParameters> reloadServices()
+  {
+    Cache.log.info("Reloading Slivka services");
+    notifyServiceListeners(Collections.emptyList());
+    ArrayList<ServiceWithParameters> instances = new ArrayList<>();
+
+    for (String url : getServiceUrls())
+    {
+      Cache.log.info(url);
+      SlivkaClient client;
+      client = new SlivkaClient(url);
+      try
+      {
+        for (SlivkaService service : client.getServices())
+        {
+          SlivkaWSInstance newinstance = null;
+          for (String classifier : service.classifiers)
+          {
+            if (classifier.contains("Multiple sequence alignment"))
+            {
+              newinstance = new SlivkaMsaServiceInstance(client, service);
+            }
+            if (classifier.contains("Protein sequence analysis")
+                && newinstance == null)
+            {
+              newinstance = new SlivkaAnnotationServiceInstance(client,
+                  service, false);
+            }
+            if (classifier
+                .contains("Sequence alignment analysis (conservation)"))
+            {
+              newinstance = new SlivkaAnnotationServiceInstance(client,
+                  service, true);
+            }
+          }
+          if (newinstance != null)
+          {
+            instances.add(newinstance);
+          }
+        }
+      } catch (IOException e)
+      {
+        e.printStackTrace();
+        continue;
+      }
+    }
+
+    services = instances;
+    notifyServiceListeners(instances);
+    Cache.log.info("Slivka services reloading finished");
+    return instances;
+  }
+
+  @Override
+  public List<ServiceWithParameters> getServices()
+  {
+    return services;
+  }
+
+  @Override
+  public boolean hasServices()
+  {
+    return !isRunning() && services.size() > 0;
+  }
+
+  @Override
+  public boolean isRunning()
+  {
+    return !discoveryTasks.stream().allMatch(Future::isDone);
+  }
+
+  @Override
+  public void setServiceUrls(List<String> wsUrls)
+  {
+    if (wsUrls != null && !wsUrls.isEmpty())
+    {
+      Cache.setProperty(SLIVKA_HOST_URLS, String.join(",", wsUrls));
+    }
+    else
+    {
+      Cache.removeProperty(SLIVKA_HOST_URLS);
+    }
+  }
+
+  @Override
+  public List<String> getServiceUrls()
+  {
+    String surls = Cache.getDefault(SLIVKA_HOST_URLS, COMPBIO_SLIVKA);
+    String[] urls = surls.split(",");
+    ArrayList<String> valid = new ArrayList<>(urls.length);
+    for (String url : urls)
+    {
+      try
+      {
+        new URL(url);
+        valid.add(url);
+      } catch (MalformedURLException e)
+      {
+        Cache.log.warn("Problem whilst trying to make a URL from '"
+            + ((url != null) ? url : "<null>") + "'");
+        Cache.log.warn(
+            "This was probably due to a malformed comma separated list"
+                + " in the " + SLIVKA_HOST_URLS
+                + " entry of $(HOME)/.jalview_properties)");
+        Cache.log.debug("Exception was ", e);
+      }
+    }
+    return valid;
+  }
+
+  @Override
+  public boolean testServiceUrl(URL url)
+  {
+    return getServerStatusFor(url.toString()) == STATUS_OK;
+  }
+
+  @Override
+  public int getServerStatusFor(String url)
+  {
+    try
+    {
+      List<?> services = new SlivkaClient(url).getServices();
+      return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK;
+    } catch (IOException e)
+    {
+      Cache.log.error("Slivka could not retrieve services list", e);
+      return STATUS_INVALID;
+    }
+  }
+
+  @Override
+  public String getErrorMessages()
+  {
+    // TODO Auto-generated method stub
+    return "";
+  }
+}
diff --git a/src/jalview/ws/slivkaws/SlivkaWSInstance.java b/src/jalview/ws/slivkaws/SlivkaWSInstance.java
new file mode 100644 (file)
index 0000000..33c1205
--- /dev/null
@@ -0,0 +1,232 @@
+package jalview.ws.slivkaws;
+
+import jalview.datamodel.SequenceI;
+import jalview.gui.WebserviceInfo;
+import jalview.ws.api.JalviewServiceEndpointProviderI;
+import jalview.ws.api.JalviewWebServiceI;
+import jalview.ws.api.JobId;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.gui.WsJob;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.ParamManager;
+import jalview.ws.params.WsParamSetI;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import uk.ac.dundee.compbio.slivkaclient.FieldType;
+import uk.ac.dundee.compbio.slivkaclient.FormField;
+import uk.ac.dundee.compbio.slivkaclient.FormValidationException;
+import uk.ac.dundee.compbio.slivkaclient.JobState;
+import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaForm;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+import uk.ac.dundee.compbio.slivkaclient.ValidationException;
+
+public abstract class SlivkaWSInstance extends ServiceWithParameters
+    implements JalviewServiceEndpointProviderI, JalviewWebServiceI
+{
+  protected final SlivkaClient client;
+
+  protected final SlivkaService service;
+
+  protected SlivkaDatastore store = null;
+
+  protected static final EnumMap<JobState, WsJob.JobState> stateMap = new EnumMap<>(JobState.class);
+  {
+    stateMap.put(JobState.PENDING, WsJob.JobState.QUEUED);
+    stateMap.put(JobState.REJECTED, WsJob.JobState.INVALID);
+    stateMap.put(JobState.ACCEPTED, WsJob.JobState.QUEUED);
+    stateMap.put(JobState.QUEUED, WsJob.JobState.QUEUED);
+    stateMap.put(JobState.RUNNING, WsJob.JobState.RUNNING);
+    stateMap.put(JobState.COMPLETED, WsJob.JobState.FINISHED);
+    stateMap.put(JobState.INTERRUPED, WsJob.JobState.CANCELLED);
+    stateMap.put(JobState.DELETED, WsJob.JobState.CANCELLED);
+    stateMap.put(JobState.FAILED, WsJob.JobState.FAILED);
+    stateMap.put(JobState.ERROR, WsJob.JobState.SERVERERROR);
+    stateMap.put(JobState.UNKNOWN, WsJob.JobState.UNKNOWN);
+  }
+  protected final Set<WsJob.JobState> failedStates = new HashSet<>(Arrays.asList(
+      WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED,
+      WsJob.JobState.SERVERERROR, WsJob.JobState.CANCELLED
+  ));
+
+  public SlivkaWSInstance(SlivkaClient client, SlivkaService service, String action)
+  {
+    super(service.getName(), action, service.getLabel(), "Slivka", client.getUrl().toString());
+    this.client = client;
+    this.service = service;
+  }
+
+  protected final JobId submit(List<SequenceI> sequences,
+          WsParamSetI preset, List<ArgumentI> args) throws Throwable
+  {
+    SlivkaForm form = service.getForm();
+    Optional<FormField> inputField = form.getFields().stream()
+            .filter(f -> f.getType() == FieldType.FILE).findFirst();
+    if (inputField.isPresent())
+    {
+      StringBuilder builder = new StringBuilder();
+      for (SequenceI seq : sequences)
+      {
+        builder.append(">").append(seq.getName()).append("\n")
+                .append(seq.getSequence()).append("\n");
+      }
+      InputStream stream = new ByteArrayInputStream(
+              builder.toString().getBytes());
+      RemoteFile file = client.uploadFile(stream, "input.fa",
+              "application/fasta");
+      form.insert(inputField.get().getName(), file);
+    }
+    if (args != null)
+    {
+      for (ArgumentI arg : args)
+      {
+        // multiple choice field names are name$number to avoid duplications
+        // the number is stripped here
+        String fieldName = arg.getName().split("\\$", 2)[0];
+        FormField field = form.getField(fieldName);
+        if (field.getType() == FieldType.BOOLEAN)
+        {
+          form.insert(fieldName,
+                  (arg.getValue() != null && !arg.getValue().isBlank())
+                          ? true
+                          : false);
+        }
+        else
+        {
+          form.insert(fieldName, arg.getValue());
+        }
+      }
+    }
+    return new JobId(service.getName(), service.getName(), form.submit());
+  }
+
+  @Override
+  public final void updateStatus(WsJob job)
+  {
+    try
+    {
+      job.setState(stateMap.get(client.getJobState(job.getJobId())));
+    } catch (IOException e)
+    {
+      throw new IOError(e);
+    }
+  }
+
+  @Override
+  public final boolean updateJobProgress(WsJob job) throws IOException
+  {
+    List<RemoteFile> files = client.getJobResults(job.getJobId());
+    Optional<RemoteFile> logFile = files.stream()
+            .filter(f -> f.getLabel().equals("log")).findFirst();
+    boolean newContent = false;
+    if (logFile.isPresent())
+    {
+      ByteArrayOutputStream output = new ByteArrayOutputStream();
+      logFile.get().writeTo(output);
+      if (output.size() > job.getNextChunk())
+      {
+        newContent = true;
+        job.setStatus(output.toString("UTF-8"));
+        job.setnextChunk(output.size());
+      }
+    }
+    if (failedStates.contains(job.getJobState()))
+    {
+      Optional<RemoteFile> errLogFile = files.stream()
+              .filter(f -> f.getLabel().equals("error-log")).findFirst();
+      if (errLogFile.isPresent())
+      {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        errLogFile.get().writeTo(output);
+        if (output.size() > 0)
+        {
+          newContent = true;
+          job.setStatus(job.getStatus() + "\n" + output.toString("UTF-8"));
+        }
+      }
+    }
+    return newContent;
+  }
+
+  @Override
+  public final boolean handleSubmitError(Throwable _lex, WsJob j, WebserviceInfo wsInfo)
+  {
+    if (_lex instanceof FormValidationException)
+    {
+      FormValidationException formError = (FormValidationException) _lex;
+      String[] messages = new String[formError.getErrors().size()];
+      int i = 0;
+      for (ValidationException e : formError.getErrors())
+      {
+        messages[i++] = String.format("%s: %s,", e.getField().getName(), e.getMessage());
+      }
+      j.setState(WsJob.JobState.INVALID);
+      j.setStatus(String.join(", ", messages));
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public final boolean handleCollectionException(Exception e, WsJob msjob, WebserviceInfo wsInfo)
+  {
+    // TODO
+    return false;
+  }
+
+  final SlivkaService getService()
+  {
+    return service;
+  }
+
+  @Override
+  public final Object getEndpoint()
+  {
+    return this;
+  }
+
+  @Override
+  public final void initParamStore(ParamManager userParameterStore)
+  {
+    if (store == null)
+    {
+      try
+      {
+        store = new SlivkaDatastore(service);
+      } catch (IOException e)
+      {
+        throw new IOError(e);
+      }
+    }
+  }
+
+  @Override
+  public boolean hasParameters()
+  {
+    return true;
+  }
+
+  @Override
+  public final ParamDatastoreI getParamStore()
+  {
+    if (store == null)
+    {
+      initParamStore(null);
+    }
+    return store;
+  }
+
+}
index 9518eaa..c0bef07 100644 (file)
  */
 package jalview.ws.uimodel;
 
+/**
+ * configures annotation worker style web service clients
+ * 
+ * @author jprocter
+ *
+ */
 public class AlignAnalysisUIText
 {
 
@@ -54,6 +60,9 @@ public class AlignAnalysisUIText
     return isPr;
   }
 
+  /**
+   * @return true if service can accept sequences with gaps
+   */
   public boolean isAA()
   {
     return isAA;
@@ -63,9 +72,19 @@ public class AlignAnalysisUIText
 
   private boolean isAA;
 
+  private boolean filterSymbols;
+
+
+  private boolean needsAlignedSeqs;
+
+  private int min_valid_seqs;
+
+
   public AlignAnalysisUIText(String serviceType, Class<?> client,
           String calcId, boolean acceptNucl, boolean acceptProt,
-          boolean acceptGaps, String toggle, String toggleTooltip,
+          boolean acceptGaps, boolean alignedSeq,
+          boolean filterNonStandardSymbols, int minSeq, String toggle,
+          String toggleTooltip,
           String settings, String settingsTooltip)
   {
     this.serviceType = serviceType;
@@ -73,11 +92,35 @@ public class AlignAnalysisUIText
     isNa = acceptNucl;
     isPr = acceptProt;
     isAA = acceptGaps;
+    this.needsAlignedSeqs = alignedSeq;
+    this.filterSymbols = filterNonStandardSymbols;
     this.client = client;
     this.AAconToggle = toggle;
     this.AAconToggleTooltip = toggleTooltip;
     this.AAeditSettings = settings;
     this.AAeditSettingsTooltip = settingsTooltip;
+    this.min_valid_seqs = minSeq;
+  }
+
+  /**
+   * 
+   * @return true if non-standard nucleotides and amino acids should be replaced
+   *         or omitted
+   * 
+   */
+  public boolean isFilterSymbols()
+  {
+    return filterSymbols;
+  }
+
+  /**
+   * 
+   * @return true if service needs sequences all the same length (ie padded with
+   *         gaps if necessary)
+   */
+  public boolean isNeedsAlignedSeqs()
+  {
+    return needsAlignedSeqs;
   }
 
   public Class getClient()
@@ -130,4 +173,9 @@ public class AlignAnalysisUIText
     AAeditSettingsTooltip = aAeditSettingsTooltip;
   }
 
+  public int getMinimumSequences()
+  {
+    return min_valid_seqs;
+  }
+
 }
index cb90984..3a1520a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 35f78f3..ac5e9a1 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 6f5ef65..7875ac8 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 6780323..4b3ef32 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 5edb2e8..8544216 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 68ebf9b..26f98a0 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 39fc0c3..b737c9a 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index c92f72c..af7764f 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 0c21215..328e432 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 36b454f..33722cd 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 0ea2491..e1a7b05 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
@@ -96,6 +96,7 @@ import javax.xml.datatype.XMLGregorianCalendar;
  *                         &lt;/complexContent>
  *                       &lt;/complexType>
  *                     &lt;/element>
+ *                     &lt;element name="hmmerProfile" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
  *                   &lt;/sequence>
  *                   &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
  *                   &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
@@ -1945,6 +1946,7 @@ public class JalviewModel {
      *             &lt;/complexContent>
      *           &lt;/complexType>
      *         &lt;/element>
+     *         &lt;element name="hmmerProfile" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
      *       &lt;/sequence>
      *       &lt;attribute name="colour" type="{http://www.w3.org/2001/XMLSchema}int" />
      *       &lt;attribute name="start" use="required" type="{http://www.w3.org/2001/XMLSchema}int" />
@@ -1964,7 +1966,8 @@ public class JalviewModel {
         "features",
         "pdbids",
         "hiddenSequences",
-        "rnaViewer"
+        "rnaViewer",
+        "hmmerProfile"
     })
     public static class JSeq {
 
@@ -1976,6 +1979,8 @@ public class JalviewModel {
         protected List<Integer> hiddenSequences;
         @XmlElement(namespace = "www.jalview.org")
         protected List<JalviewModel.JSeq.RnaViewer> rnaViewer;
+        @XmlElement(namespace = "www.jalview.org")
+        protected String hmmerProfile;
         @XmlAttribute(name = "colour")
         protected Integer colour;
         @XmlAttribute(name = "start", required = true)
@@ -2106,6 +2111,30 @@ public class JalviewModel {
         }
 
         /**
+         * Gets the value of the hmmerProfile property.
+         * 
+         * @return
+         *     possible object is
+         *     {@link String }
+         *     
+         */
+        public String getHmmerProfile() {
+            return hmmerProfile;
+        }
+
+        /**
+         * Sets the value of the hmmerProfile property.
+         * 
+         * @param value
+         *     allowed object is
+         *     {@link String }
+         *     
+         */
+        public void setHmmerProfile(String value) {
+            this.hmmerProfile = value;
+        }
+
+        /**
          * Gets the value of the colour property.
          * 
          * @return
index c43e04c..8fea467 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 1a31d82..ef08f78 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 5ebeb7e..be17af9 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 9db4ea3..5bb3d66 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index e0b2127..55ca7cd 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 6234f32..dca3b94 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index d5132ab..b5005fa 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index b842947..8b53f2e 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 6aee6ac..025c91f 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index aef7543..2b94a3d 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 1b3d6d4..3e64568 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 5d341c3..1f1c2a0 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 659eab9..3cab774 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 
index 3ed532d..fd74613 100644 (file)
@@ -2,7 +2,7 @@
 // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
 // Any modifications to this file will be lost upon recompilation of the source schema. 
-// Generated on: 2019.06.07 at 02:21:15 PM BST 
+// Generated on: 2019.07.10 at 12:10:00 PM BST 
 //
 
 @javax.xml.bind.annotation.XmlSchema(namespace = "www.vamsas.ac.uk/jalview/version2", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
diff --git a/swingjs/README.txt b/swingjs/README.txt
deleted file mode 100644 (file)
index f45850b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-The swingjs directory contains the current transpiler (net.sf.j2s.core.jar) 
-and the run-time core site files (SwingJS-site.zip)
-
-In addition are version directories -- for example, ver/3.1.1 and ver/3.2.1
-
-The second of these, ver/3.2.1, adds Java 8 functionality.
-
-
index 52b640a..0babbc7 100644 (file)
Binary files a/swingjs/SwingJS-site.zip and b/swingjs/SwingJS-site.zip differ
index df5be44..2bddf77 100644 (file)
@@ -1 +1 @@
-20201206115202 
+20201210125356 
diff --git a/swingjs/ver/3.2.4/DEV_NOTES.txt b/swingjs/ver/3.2.4/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.4/SwingJS-site.zip b/swingjs/ver/3.2.4/SwingJS-site.zip
deleted file mode 100644 (file)
index 88ffc19..0000000
Binary files a/swingjs/ver/3.2.4/SwingJS-site.zip and /dev/null differ
diff --git a/swingjs/ver/3.2.4/_j2sclasslist.txt b/swingjs/ver/3.2.4/_j2sclasslist.txt
deleted file mode 100644 (file)
index e35111e..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/SB.js
-javax/net/ssl/HttpsUrlConnection.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/FormatData_en.js
-sun/util/resources/LocaleData.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.4/net.sf.j2s.core.jar b/swingjs/ver/3.2.4/net.sf.j2s.core.jar
deleted file mode 100644 (file)
index e0cee1d..0000000
Binary files a/swingjs/ver/3.2.4/net.sf.j2s.core.jar and /dev/null differ
diff --git a/swingjs/ver/3.2.4/timestamp b/swingjs/ver/3.2.4/timestamp
deleted file mode 100644 (file)
index 5847eb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-20191108205610 
diff --git a/swingjs/ver/3.2.5/DEV_NOTES.txt b/swingjs/ver/3.2.5/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.5/SwingJS-site.zip b/swingjs/ver/3.2.5/SwingJS-site.zip
deleted file mode 100644 (file)
index bec75f1..0000000
Binary files a/swingjs/ver/3.2.5/SwingJS-site.zip and /dev/null differ
diff --git a/swingjs/ver/3.2.5/_j2sclasslist.txt b/swingjs/ver/3.2.5/_j2sclasslist.txt
deleted file mode 100644 (file)
index e98f45d..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/Image.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/net/HttpURLConnection.js
-java/net/URLStreamHandler.js
-javax/net/ssl/HttpsUrlConnection.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/Rdr.js
-javajs/util/SB.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/Icon.js
-javax/swing/ImageIcon.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/awt/image/DataStealer.js
-sun/awt/image/IntegerComponentRaster.js
-sun/awt/image/IntegerInterleavedRaster.js
-sun/awt/image/SunWritableRaster.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/FormatData_en.js
-sun/util/resources/LocaleData.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSImage.js
-swingjs/JSImagekit.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.5/net.sf.j2s.core.jar b/swingjs/ver/3.2.5/net.sf.j2s.core.jar
deleted file mode 100644 (file)
index e769633..0000000
Binary files a/swingjs/ver/3.2.5/net.sf.j2s.core.jar and /dev/null differ
diff --git a/swingjs/ver/3.2.5/timestamp b/swingjs/ver/3.2.5/timestamp
deleted file mode 100644 (file)
index c1407cb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-20191202082005 
diff --git a/swingjs/ver/3.2.7/DEV_NOTES.txt b/swingjs/ver/3.2.7/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.7/_j2sclasslist.txt b/swingjs/ver/3.2.7/_j2sclasslist.txt
deleted file mode 100644 (file)
index e98f45d..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/Image.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/net/HttpURLConnection.js
-java/net/URLStreamHandler.js
-javax/net/ssl/HttpsUrlConnection.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/Rdr.js
-javajs/util/SB.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/Icon.js
-javax/swing/ImageIcon.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/awt/image/DataStealer.js
-sun/awt/image/IntegerComponentRaster.js
-sun/awt/image/IntegerInterleavedRaster.js
-sun/awt/image/SunWritableRaster.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/FormatData_en.js
-sun/util/resources/LocaleData.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSImage.js
-swingjs/JSImagekit.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.7/net.sf.j2s.core.jar b/swingjs/ver/3.2.7/net.sf.j2s.core.jar
deleted file mode 100644 (file)
index dd8bbf2..0000000
Binary files a/swingjs/ver/3.2.7/net.sf.j2s.core.jar and /dev/null differ
diff --git a/swingjs/ver/3.2.7/timestamp b/swingjs/ver/3.2.7/timestamp
deleted file mode 100644 (file)
index e49e2f5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-20200205074936 
diff --git a/swingjs/ver/3.2.8/DEV_NOTES.txt b/swingjs/ver/3.2.8/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.8/_j2sclasslist.txt b/swingjs/ver/3.2.8/_j2sclasslist.txt
deleted file mode 100644 (file)
index 076f300..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/Image.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/net/HttpURLConnection.js
-java/net/URLStreamHandler.js
-javax/net/ssl/HttpsUrlConnection.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/Rdr.js
-javajs/util/SB.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/Icon.js
-javax/swing/ImageIcon.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/awt/image/DataStealer.js
-sun/awt/image/IntegerComponentRaster.js
-sun/awt/image/IntegerInterleavedRaster.js
-sun/awt/image/SunWritableRaster.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/en/FormatData_en.js
-sun/util/resources/LocaleData.js
-sun/util/locale/BaseLocale.js
-sun/util/locale/LocaleUtils.js
-sun/util/locale/provider/LocaleProviderAdapter.js
-sun/util/locale/provider/LocaleDataMetaInfo.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSImage.js
-swingjs/JSImagekit.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.8/net.sf.j2s.core.jar b/swingjs/ver/3.2.8/net.sf.j2s.core.jar
deleted file mode 100644 (file)
index feb8ed3..0000000
Binary files a/swingjs/ver/3.2.8/net.sf.j2s.core.jar and /dev/null differ
diff --git a/swingjs/ver/3.2.8/timestamp b/swingjs/ver/3.2.8/timestamp
deleted file mode 100644 (file)
index b833ece..0000000
+++ /dev/null
@@ -1 +0,0 @@
-20200220124544 
diff --git a/swingjs/ver/3.2.9-j11/DEV_NOTES.txt b/swingjs/ver/3.2.9-j11/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.9-j11/_j2sclasslist.txt b/swingjs/ver/3.2.9-j11/_j2sclasslist.txt
deleted file mode 100644 (file)
index 076f300..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/Image.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/net/HttpURLConnection.js
-java/net/URLStreamHandler.js
-javax/net/ssl/HttpsUrlConnection.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/Rdr.js
-javajs/util/SB.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/Icon.js
-javax/swing/ImageIcon.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/awt/image/DataStealer.js
-sun/awt/image/IntegerComponentRaster.js
-sun/awt/image/IntegerInterleavedRaster.js
-sun/awt/image/SunWritableRaster.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/en/FormatData_en.js
-sun/util/resources/LocaleData.js
-sun/util/locale/BaseLocale.js
-sun/util/locale/LocaleUtils.js
-sun/util/locale/provider/LocaleProviderAdapter.js
-sun/util/locale/provider/LocaleDataMetaInfo.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSImage.js
-swingjs/JSImagekit.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.9-j11/net.sf.j2s.core.jar b/swingjs/ver/3.2.9-j11/net.sf.j2s.core.jar
deleted file mode 100644 (file)
index 2a1593d..0000000
Binary files a/swingjs/ver/3.2.9-j11/net.sf.j2s.core.jar and /dev/null differ
diff --git a/swingjs/ver/3.2.9/DEV_NOTES.txt b/swingjs/ver/3.2.9/DEV_NOTES.txt
deleted file mode 100644 (file)
index 751d81c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This is sources/net.sf.j2s.java.core/dist/DEV_NOTES.txt
-
-_j2sclasslist.txt 
-
-the list of .js files concatenated into coreswingjs.js and minified to coreswingjs.z.js
-
-
-SwingJS-site.zip
-
-the full site directory for SwingJS including all files not in the test/ directory.
diff --git a/swingjs/ver/3.2.9/_j2sclasslist.txt b/swingjs/ver/3.2.9/_j2sclasslist.txt
deleted file mode 100644 (file)
index 076f300..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-java/applet/Applet.js
-java/applet/AppletContext.js
-java/applet/AppletStub.js
-java/applet/JSApplet.js
-java/awt/ActiveEvent.js
-java/awt/Adjustable.js
-java/awt/AWTEvent.js
-java/awt/AWTEventMulticaster.js
-java/awt/AWTKeyStroke.js
-java/awt/BasicStroke.js
-java/awt/BorderLayout.js
-java/awt/Button.js
-java/awt/Color.js
-java/awt/color/ColorSpace.js
-java/awt/Component.js
-java/awt/ComponentOrientation.js
-java/awt/ContainerOrderFocusTraversalPolicy.js
-java/awt/Container.js
-java/awt/Cursor.js
-java/awt/DefaultFocusTraversalPolicy.js
-java/awt/DefaultKeyboardFocusManager.js
-java/awt/Dialog.js
-java/awt/Dimension.js
-java/awt/dnd/peer/DropTargetPeer.js
-java/awt/event/ActionListener.js
-java/awt/event/AdjustmentEvent.js
-java/awt/event/AdjustmentListener.js
-java/awt/event/AWTEventListener.js
-java/awt/event/ComponentAdapter.js
-java/awt/event/ComponentEvent.js
-java/awt/event/ComponentListener.js
-java/awt/event/ContainerListener.js
-java/awt/event/FocusEvent.js
-java/awt/event/FocusListener.js
-java/awt/event/HierarchyBoundsListener.js
-java/awt/event/HierarchyListener.js
-java/awt/event/InputEvent.js
-java/awt/event/InputMethodListener.js
-java/awt/event/InvocationEvent.js
-java/awt/event/ItemEvent.js
-java/awt/event/ItemListener.js
-java/awt/event/KeyListener.js
-java/awt/event/MouseEvent.js
-java/awt/event/MouseListener.js
-java/awt/event/MouseMotionListener.js
-java/awt/event/MouseWheelListener.js
-java/awt/event/TextListener.js
-java/awt/event/WindowAdapter.js
-java/awt/event/WindowEvent.js
-java/awt/event/WindowFocusListener.js
-java/awt/event/WindowListener.js
-java/awt/event/WindowStateListener.js
-java/awt/EventDispatchThread.js
-java/awt/EventFilter.js
-java/awt/EventQueue.js
-java/awt/EventQueueItem.js
-java/awt/FlowLayout.js
-java/awt/FocusTraversalPolicy.js
-java/awt/Font.js
-java/awt/font/FontRenderContext.js
-java/awt/FontMetrics.js
-java/awt/Frame.js
-java/awt/geom/AffineTransform.js
-java/awt/geom/Dimension2D.js
-java/awt/geom/Path2D.js
-java/awt/geom/PathIterator.js
-java/awt/geom/Point2D.js
-java/awt/geom/Rectangle2D.js
-java/awt/geom/RectangularShape.js
-java/awt/geom/RectIterator.js
-java/awt/GraphicsCallback.js
-java/awt/GraphicsConfiguration.js
-java/awt/GraphicsDevice.js
-java/awt/GraphicsEnvironment.js
-java/awt/Image.js
-java/awt/image/ImageObserver.js
-java/awt/Insets.js
-java/awt/ItemSelectable.js
-java/awt/JSComponent.js
-java/awt/JSDialog.js
-java/awt/JSFrame.js
-java/awt/JSPanel.js
-java/awt/KeyboardFocusManager.js
-java/awt/KeyEventDispatcher.js
-java/awt/KeyEventPostProcessor.js
-java/awt/Label.js
-java/awt/LayoutManager.js
-java/awt/LayoutManager2.js
-java/awt/LightweightDispatcher.js
-java/awt/Paint.js
-java/awt/Panel.js
-java/awt/peer/ComponentPeer.js
-java/awt/peer/ContainerPeer.js
-java/awt/peer/FramePeer.js
-java/awt/peer/KeyboardFocusManagerPeer.js
-java/awt/peer/LightweightPeer.js
-java/awt/peer/WindowPeer.js
-java/awt/Point.js
-java/awt/Queue.js
-java/awt/Rectangle.js
-java/awt/RenderingHints.js
-java/awt/Scrollbar.js
-java/awt/ScrollPane.js
-java/awt/Shape.js
-java/awt/Stroke.js
-java/awt/TextArea.js
-java/awt/TextComponent.js
-java/awt/TextField.js
-java/awt/Toolkit.js
-java/awt/Transparency.js
-java/awt/Window.js
-java/beans/ChangeListenerMap.js
-java/beans/PropertyChangeEvent.js
-java/beans/PropertyChangeListener.js
-java/beans/PropertyChangeSupport.js
-java/lang/AbstractStringBuilder.js
-java/lang/Class.js
-java/lang/Enum.js
-java/lang/Iterable.js
-java/lang/reflect/Constructor.js
-java/lang/reflect/Method.js
-java/lang/StringBuffer.js
-java/lang/StringBuilder.js
-java/lang/Thread.js
-java/lang/ThreadGroup.js
-java/math/RoundingMode.js
-java/net/URL.js
-java/net/URLStreamHandlerFactory.js
-java/net/HttpURLConnection.js
-java/net/URLStreamHandler.js
-javax/net/ssl/HttpsUrlConnection.js
-java/text/CharacterIterator.js
-java/text/DecimalFormat.js
-java/text/DecimalFormatSymbols.js
-java/text/DigitList.js
-java/text/FieldPosition.js
-java/text/Format.js
-java/text/NumberFormat.js
-java/util/AbstractCollection.js
-java/util/AbstractList.js
-java/util/AbstractMap.js
-java/util/AbstractSequentialList.js
-java/util/AbstractSet.js
-java/util/ArrayList.js
-java/util/Arrays.js
-java/util/Collection.js
-java/util/Collections.js
-java/util/Comparator.js
-java/util/Deque.js
-java/util/Dictionary.js
-java/util/Enumeration.js
-java/util/EventListener.js
-java/util/EventObject.js
-java/util/HashMap.js
-java/util/HashSet.js
-java/util/Hashtable.js
-java/util/IdentityHashMap.js
-java/util/Iterator.js
-java/util/LinkedHashMap.js
-java/util/LinkedList.js
-java/util/List.js
-java/util/ListResourceBundle.js
-java/util/Locale.js
-java/util/Map.js
-java/util/Objects.js
-java/util/Queue.js
-java/util/Random.js
-java/util/RandomAccess.js
-java/util/ResourceBundle.js
-java/util/Set.js
-java/util/TimSort.js
-java/util/Vector.js
-javajs/api/JSFunction.js
-javajs/util/AjaxURLConnection.js
-javajs/util/AjaxURLStreamHandlerFactory.js
-javajs/util/AU.js
-javajs/util/JSThread.js
-javajs/util/Lst.js
-javajs/util/PT.js
-javajs/util/Rdr.js
-javajs/util/SB.js
-javax/swing/AbstractAction.js
-javax/swing/AbstractButton.js
-javax/swing/AbstractListModel.js
-javax/swing/Action.js
-javax/swing/ActionMap.js
-javax/swing/AncestorNotifier.js
-javax/swing/ArrayTable.js
-javax/swing/border/AbstractBorder.js
-javax/swing/border/BevelBorder.js
-javax/swing/border/Border.js
-javax/swing/border/CompoundBorder.js
-javax/swing/border/EmptyBorder.js
-javax/swing/border/EtchedBorder.js
-javax/swing/border/LineBorder.js
-javax/swing/border/TitledBorder.js
-javax/swing/BorderFactory.js
-javax/swing/BoundedRangeModel.js
-javax/swing/BoxLayout.js
-javax/swing/ButtonGroup.js
-javax/swing/ButtonModel.js
-javax/swing/ClientPropertyKey.js
-javax/swing/ComboBoxModel.js
-javax/swing/DefaultBoundedRangeModel.js
-javax/swing/DefaultButtonModel.js
-javax/swing/DefaultComboBoxModel.js
-javax/swing/DefaultSingleSelectionModel.js
-javax/swing/DropMode.js
-javax/swing/event/AncestorEvent.js
-javax/swing/event/AncestorListener.js
-javax/swing/event/CaretEvent.js
-javax/swing/event/CaretListener.js
-javax/swing/event/ChangeEvent.js
-javax/swing/event/ChangeListener.js
-javax/swing/event/DocumentEvent.js
-javax/swing/event/DocumentListener.js
-javax/swing/event/EventListenerList.js
-javax/swing/event/ListDataEvent.js
-javax/swing/event/ListDataListener.js
-javax/swing/event/UndoableEditEvent.js
-javax/swing/event/UndoableEditListener.js
-javax/swing/FocusManager.js
-javax/swing/InternalFrameFocusTraversalPolicy.js
-javax/swing/LayoutComparator.js
-javax/swing/LayoutFocusTraversalPolicy.js
-javax/swing/SortingFocusTraversalPolicy.js
-javax/swing/SwingContainerOrderFocusTraversalPolicy.js
-javax/swing/SwingDefaultFocusTraversalPolicy.js
-javax/swing/Icon.js
-javax/swing/ImageIcon.js
-javax/swing/InputMap.js
-javax/swing/JApplet.js
-javax/swing/JButton.js
-javax/swing/JCheckBox.js
-javax/swing/JCheckBoxMenuItem.js
-javax/swing/JComboBox.js
-javax/swing/JComponent.js
-javax/swing/JFrame.js
-javax/swing/JLabel.js
-javax/swing/JLayeredPane.js
-javax/swing/JMenu.js
-javax/swing/JMenuBar.js
-javax/swing/JMenuItem.js
-javax/swing/JPanel.js
-javax/swing/JPopupMenu.js
-javax/swing/JRadioButtonMenuItem.js
-javax/swing/JRootPane.js
-javax/swing/JScrollBar.js
-javax/swing/JScrollPane.js
-javax/swing/JSeparator.js
-javax/swing/JTextArea.js
-javax/swing/JTextField.js
-javax/swing/JToggleButton.js
-javax/swing/JViewport.js
-javax/swing/KeyboardManager.js
-javax/swing/KeyStroke.js
-javax/swing/ListModel.js
-javax/swing/LookAndFeel.js
-javax/swing/MenuElement.js
-javax/swing/MutableComboBoxModel.js
-javax/swing/plaf/ActionMapUIResource.js
-javax/swing/plaf/basic/BasicBorders.js
-javax/swing/plaf/BorderUIResource.js
-javax/swing/plaf/ColorUIResource.js
-javax/swing/plaf/ComponentUI.js
-javax/swing/plaf/DimensionUIResource.js
-javax/swing/plaf/FontUIResource.js
-javax/swing/plaf/InputMapUIResource.js
-javax/swing/plaf/InsetsUIResource.js
-javax/swing/plaf/UIResource.js
-javax/swing/RepaintManager.js
-javax/swing/RootPaneContainer.js
-javax/swing/Scrollable.js
-javax/swing/ScrollPaneConstants.js
-javax/swing/ScrollPaneLayout.js
-javax/swing/SingleSelectionModel.js
-javax/swing/SizeRequirements.js
-javax/swing/SwingConstants.js
-javax/swing/SwingPaintEventDispatcher.js
-javax/swing/SwingUtilities.js
-javax/swing/text/AbstractDocument.js
-javax/swing/text/AttributeSet.js
-javax/swing/text/Caret.js
-javax/swing/text/DefaultCaret.js
-javax/swing/text/DefaultEditorKit.js
-javax/swing/text/Document.js
-javax/swing/text/EditorKit.js
-javax/swing/text/Element.js
-javax/swing/text/GapContent.js
-javax/swing/text/GapVector.js
-javax/swing/text/JTextComponent.js
-javax/swing/text/MutableAttributeSet.js
-javax/swing/text/PlainDocument.js
-javax/swing/text/PlainView.js
-javax/swing/text/Position.js
-javax/swing/text/Segment.js
-javax/swing/text/SegmentCache.js
-javax/swing/text/SimpleAttributeSet.js
-javax/swing/text/Style.js
-javax/swing/text/StyleConstants.js
-javax/swing/text/StyleContext.js
-javax/swing/text/TabExpander.js
-javax/swing/text/TextAction.js
-javax/swing/text/Utilities.js
-javax/swing/text/View.js
-javax/swing/tree/TreeNode.js
-javax/swing/UIDefaults.js
-javax/swing/UIManager.js
-javax/swing/undo/AbstractUndoableEdit.js
-javax/swing/undo/CompoundEdit.js
-javax/swing/undo/UndoableEdit.js
-javax/swing/ViewportLayout.js
-javax/swing/WindowConstants.js
-sun/awt/AppContext.js
-sun/awt/AWTAutoShutdown.js
-sun/awt/CausedFocusEvent.js
-sun/awt/ComponentFactory.js
-sun/awt/KeyboardFocusManagerPeerProvider.js
-sun/awt/MostRecentKeyValue.js
-sun/awt/MostRecentThreadAppContext.js
-sun/awt/PaintEventDispatcher.js
-sun/awt/PostEventQueue.js
-sun/awt/RequestFocusController.js
-sun/awt/SunToolkit.js
-sun/awt/WindowClosingListener.js
-sun/awt/WindowClosingSupport.js
-sun/awt/image/DataStealer.js
-sun/awt/image/IntegerComponentRaster.js
-sun/awt/image/IntegerInterleavedRaster.js
-sun/awt/image/SunWritableRaster.js
-sun/font/FontDesignMetrics.js
-sun/swing/DefaultLookup.js
-sun/swing/SwingLazyValue.js
-sun/text/resources/FormatData.js
-sun/text/resources/en/FormatData_en.js
-sun/util/resources/LocaleData.js
-sun/util/locale/BaseLocale.js
-sun/util/locale/LocaleUtils.js
-sun/util/locale/provider/LocaleProviderAdapter.js
-sun/util/locale/provider/LocaleDataMetaInfo.js
-swingjs/a2s/A2SContainer.js
-swingjs/a2s/A2SEvent.js
-swingjs/a2s/A2SListener.js
-swingjs/a2s/Applet.js
-swingjs/a2s/Button.js
-swingjs/a2s/Label.js
-swingjs/a2s/Panel.js
-swingjs/a2s/Scrollbar.js
-swingjs/a2s/ScrollPane.js
-swingjs/a2s/TextArea.js
-swingjs/a2s/TextField.js
-swingjs/api/Interface.js
-swingjs/api/js/DOMNode.js
-swingjs/api/js/HTML5CanvasContext2D.js
-swingjs/api/js/JSInterface.js
-swingjs/jquery/JQueryUI.js
-swingjs/JSApp.js
-swingjs/JSAppletThread.js
-swingjs/JSAppletViewer.js
-swingjs/JSFocusPeer.js
-swingjs/JSFontMetrics.js
-swingjs/JSFrameViewer.js
-swingjs/JSGraphics2D.js
-swingjs/JSGraphicsConfiguration.js
-swingjs/JSGraphicsEnvironment.js
-swingjs/JSImage.js
-swingjs/JSImagekit.js
-swingjs/JSMouse.js
-swingjs/JSNullComponentPeer.js
-swingjs/JSScreenDevice.js
-swingjs/JSThreadGroup.js
-swingjs/JSToolkit.js
-swingjs/JSUtil.js
-swingjs/plaf/ButtonListener.js
-swingjs/plaf/DefaultMenuLayout.js
-swingjs/plaf/HTML5LookAndFeel.js
-swingjs/plaf/JSAppletUI.js
-swingjs/plaf/JSButtonUI.js
-swingjs/plaf/JSCheckBoxMenuItemUI.js
-swingjs/plaf/JSCheckBoxUI.js
-swingjs/plaf/JSComboBoxUI.js
-swingjs/plaf/JSComponentUI.js
-swingjs/plaf/JSEventHandler.js
-swingjs/plaf/JSFrameUI.js
-swingjs/plaf/JSGraphicsUtils.js
-swingjs/plaf/JSLabelUI.js
-swingjs/plaf/JSLayeredPaneUI.js
-swingjs/plaf/JSLightweightUI.js
-swingjs/plaf/JSMenuBarUI.js
-swingjs/plaf/JSMenuItemUI.js
-swingjs/plaf/JSMenuUI.js
-swingjs/plaf/JSPanelUI.js
-swingjs/plaf/JSPopupMenuSeparatorUI.js
-swingjs/plaf/JSPopupMenuUI.js
-swingjs/plaf/JSRadioButtonMenuItemUI.js
-swingjs/plaf/JSRadioButtonUI.js
-swingjs/plaf/JSRootPaneUI.js
-swingjs/plaf/JSScrollBarUI.js
-swingjs/plaf/JSScrollPaneUI.js
-swingjs/plaf/JSSeparatorUI.js
-swingjs/plaf/JSSliderUI.js
-swingjs/plaf/JSTextAreaUI.js
-swingjs/plaf/JSTextFieldUI.js
-swingjs/plaf/JSTextUI.js
-swingjs/plaf/JSTextViewUI.js
-swingjs/plaf/JSViewportUI.js
-swingjs/plaf/JSWindowUI.js
-swingjs/plaf/LazyActionMap.js
-swingjs/plaf/Resizer.js
-swingjs/plaf/TextListener.js
-
-
diff --git a/swingjs/ver/3.2.9/net.sf.j2s.core-j11.jar b/swingjs/ver/3.2.9/net.sf.j2s.core-j11.jar
deleted file mode 100644 (file)
index 303fea5..0000000
Binary files a/swingjs/ver/3.2.9/net.sf.j2s.core-j11.jar and /dev/null differ
index 93c95ce..14cc526 100644 (file)
@@ -25,13 +25,21 @@ import static org.testng.AssertJUnit.assertNull;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.Profile;
 import jalview.datamodel.ProfileI;
+import jalview.datamodel.Profiles;
 import jalview.datamodel.ProfilesI;
 import jalview.datamodel.ResidueCount;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
 
 import java.util.Hashtable;
 
@@ -40,6 +48,7 @@ import org.testng.annotations.Test;
 
 public class AAFrequencyTest
 {
+  HiddenMarkovModel hmm;
 
   @BeforeClass(alwaysRun = true)
   public void setUpJvOptionPane()
@@ -48,6 +57,17 @@ public class AAFrequencyTest
     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
   }
 
+  @BeforeClass(alwaysRun = true)
+  public void setUp() throws IOException, MalformedURLException
+  {
+    /*
+     * load a dna (ACGT) HMM file to a HiddenMarkovModel
+     */
+    HMMFile hmmFile = new HMMFile(new FileParse(
+            "test/jalview/io/test_MADE1_hmm.txt", DataSourceType.FILE));
+    hmm = hmmFile.getHMM();
+  }
+
   @Test(groups = { "Functional" })
   public void testCalculate_noProfile()
   {
@@ -415,4 +435,93 @@ public class AAFrequencyTest
         encoded2, 58, encoded1, 25, encoded3, 7 };
     org.testng.Assert.assertEquals(extracted, expected);
   }
+
+  @Test(groups = { "Functional" })
+  public void testExtractHMMProfile()
+          throws MalformedURLException, IOException
+  {
+    int[] expected = { 0, 4, 100, 'T', 71, 'C', 12, 'G', 9, 'A', 9 };
+    int[] actual = AAFrequency.extractHMMProfile(hmm, 17, false, false);
+    for (int i = 0; i < actual.length; i++)
+    {
+      if (i == 2)
+      {
+        assertEquals(actual[i], expected[i]);
+      }
+      else
+      {
+        assertEquals(actual[i], expected[i]);
+      }
+    }
+
+    int[] expected2 = { 0, 4, 100, 'A', 85, 'C', 0, 'G', 0, 'T', 0 };
+    int[] actual2 = AAFrequency.extractHMMProfile(hmm, 2, true, false);
+    for (int i = 0; i < actual2.length; i++)
+    {
+      if (i == 2)
+      {
+        assertEquals(actual[i], expected[i]);
+      }
+      else
+      {
+        assertEquals(actual[i], expected[i]);
+      }
+    }
+
+    assertNull(AAFrequency.extractHMMProfile(null, 98978867, true, false));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetAnalogueCount()
+  {
+    /*
+     * 'T' in column 0 has emission probability 0.7859, scales to 7859
+     */
+    int count = AAFrequency.getAnalogueCount(hmm, 0, 'T', false, false);
+    assertEquals(7859, count);
+
+    /*
+     * same with 'use info height': value is multiplied by log ratio
+     * log(value / background) / log(2) = log(0.7859/0.25)/0.693
+     * = log(3.1)/0.693 = 1.145/0.693 = 1.66
+     * so value becomes 1.2987 and scales up to 12987
+     */
+    count = AAFrequency.getAnalogueCount(hmm, 0, 'T', false, true);
+    assertEquals(12987, count);
+
+    /*
+     * 'G' in column 20 has emission probability 0.75457, scales to 7546
+     */
+    count = AAFrequency.getAnalogueCount(hmm, 20, 'G', false, false);
+    assertEquals(7546, count);
+
+    /*
+     * 'G' in column 1077 has emission probability 0.0533, here
+     * ignored (set to 0) since below background of 0.25
+     */
+    count = AAFrequency.getAnalogueCount(hmm, 1077, 'G', true, false);
+    assertEquals(0, count);
+  }
+
+  @Test(groups = { "Functional" })
+  public void testCompleteInformation()
+  {
+    ProfileI prof1 = new Profile(1, 0, 100, "A");
+    ProfileI prof2 = new Profile(1, 0, 100, "-");
+
+    ProfilesI profs = new Profiles(new ProfileI[] { prof1, prof2 });
+    Annotation ann1 = new Annotation(6.5f);
+    Annotation ann2 = new Annotation(0f);
+    Annotation[] annots = new Annotation[] { ann1, ann2 };
+    SequenceI seq = new Sequence("", "AA", 0, 0);
+    seq.setHMM(hmm);
+    AlignmentAnnotation annot = new AlignmentAnnotation("", "", annots);
+    annot.setSequenceRef(seq);
+    AAFrequency.completeInformation(annot, profs, 0, 1);
+    float ic = annot.annotations[0].value;
+    assertEquals(0.91532f, ic, 0.0001f);
+    ic = annot.annotations[1].value;
+    assertEquals(0f, ic, 0.0001f);
+    int i = 0;
+  }
 }
index 16ca70d..a1623f6 100644 (file)
@@ -23,6 +23,7 @@ package jalview.analysis.scoremodels;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
+import jalview.api.AlignViewportI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.datamodel.Alignment;
@@ -32,7 +33,6 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
@@ -280,7 +280,7 @@ public class FeatureDistanceModelTest
   public void testFindDistances_withParams()
   {
     AlignFrame af = setupAlignmentView();
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
     AlignmentView view = viewport.getAlignmentView(false);
 
     ScoreModelI sm = new FeatureDistanceModel();
index 19a725e..ade9150 100644 (file)
@@ -49,6 +49,11 @@ public class AlignmentAnnotationTests
     createAnnotation(sq);
     AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
     alc = new AlignmentAnnotation(alo);
+
+    // TODO: this only tests string equals (which is unreliable), should use
+    // refactored tests from StockholmFileTest
+    Assert.assertEquals(alc.toString(), alo.toString());
+
     for (String key : alo.getProperties())
     {
       assertEquals("Property mismatch", alo.getProperty(key),
index 14e74e4..a3f9096 100644 (file)
@@ -1351,7 +1351,35 @@ public class AlignmentTest
             "Temperature Factor", null, false, seq, null);
     assertNotNull(ala);
     assertEquals(seq, ala.sequenceRef);
-    assertEquals("", ala.calcId);
+    assertEquals("", ala.getCalcId());
+  }
+
+  @Test(groups = {"Functional"})
+  public void testUpdateFromOrAddAnnotation()
+  {
+    SequenceI seq = new Sequence("seq1", "FRMLPSRT-A--L-");
+    AlignmentI alignment = new Alignment(new SequenceI[] { seq });
+
+    AlignmentAnnotation ala = alignment.findOrCreateAnnotation(
+            "Temperature Factor", null, false, seq, null);
+
+    assertNotNull(ala);
+    assertEquals(seq, ala.sequenceRef);
+    assertEquals("", ala.getCalcId());
+
+    // Assuming findOrCreateForNullCalcId passed then this should work
+
+    assertTrue(ala == alignment.updateFromOrCopyAnnotation(ala));
+    AlignmentAnnotation updatedAla = new AlignmentAnnotation(ala);
+    updatedAla.description = "updated Description";
+    Assert.assertTrue(
+            ala == alignment.updateFromOrCopyAnnotation(updatedAla));
+    Assert.assertEquals(ala.toString(), updatedAla.toString());
+    updatedAla.calcId = "newCalcId";
+    AlignmentAnnotation newUpdatedAla = alignment
+            .updateFromOrCopyAnnotation(updatedAla);
+    Assert.assertTrue(updatedAla != newUpdatedAla);
+    Assert.assertEquals(updatedAla.toString(), newUpdatedAla.toString());
   }
 
   @Test(groups = "Functional")
index b201c7e..9be344c 100644 (file)
@@ -23,10 +23,10 @@ package jalview.datamodel;
 import static org.testng.Assert.assertEquals;
 
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
+import jalview.viewmodel.AlignmentViewport;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -60,7 +60,7 @@ public class AlignmentViewTest
   {
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             ">s1\n0123456789\n", DataSourceType.PASTE);
-    AlignViewport av = af.getViewport();
+    AlignmentViewport av = af.getViewport();
     AlignmentView view = av.getAlignmentView(true);
 
     /*
diff --git a/test/jalview/datamodel/HMMNodeTest.java b/test/jalview/datamodel/HMMNodeTest.java
new file mode 100644 (file)
index 0000000..f2aef06
--- /dev/null
@@ -0,0 +1,42 @@
+package jalview.datamodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class HMMNodeTest
+{
+  private HiddenMarkovModel hmm;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUp() throws MalformedURLException, IOException
+  {
+    /*
+     * load hmm model of a Kinase domain to a HiddenMarkovModel
+     */
+    HMMFile file = new HMMFile(new FileParse(
+            "test/jalview/io/test_PKinase_hmm.txt", DataSourceType.FILE));
+    hmm = file.getHMM();
+  }
+
+  @Test(groups="Functional")
+  public void testGetMaxMatchEmissionIdex()
+  {
+    assertEquals(hmm.getAlphabetType(), "amino");
+    String symbols = hmm.getSymbols();
+
+    assertEquals(hmm.getNode(1).getMaxMatchEmissionIndex(),
+            symbols.indexOf('Y'));
+
+    assertEquals(hmm.getNode(17).getMaxMatchEmissionIndex(),
+            symbols.indexOf('K'));
+  }
+}
diff --git a/test/jalview/datamodel/HiddenMarkovModelTest.java b/test/jalview/datamodel/HiddenMarkovModelTest.java
new file mode 100644 (file)
index 0000000..65241b4
--- /dev/null
@@ -0,0 +1,162 @@
+package jalview.datamodel;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+import jalview.schemes.ResidueProperties;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class HiddenMarkovModelTest {
+
+  HiddenMarkovModel hmm;
+
+  HiddenMarkovModel alignmentHmm;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUp() throws MalformedURLException, IOException
+  {
+    /*
+     * load hmm model of a Kinase domain to a HiddenMarkovModel
+     */
+    HMMFile file = new HMMFile(new FileParse(
+            "test/jalview/io/test_PKinase_hmm.txt", DataSourceType.FILE));
+    hmm = file.getHMM();
+
+    // used to check if consensus sequence is automatically aligned with alignment
+    HMMFile alignmentTest = new HMMFile(
+            new FileParse("test/jalview/io/HMMAlignmentTestHMM.hmm",
+                    DataSourceType.FILE));
+    alignmentHmm = alignmentTest.getHMM();
+  }
+
+  @Test(groups = "Functional")
+  public void testGetMatchEmissionProbabilities()
+          throws MalformedURLException, IOException
+  {
+    /*
+     * raw value in file is 3.67403
+     * saved as probability e^-X = 0.05259 
+     */
+    double mep = hmm.getMatchEmissionProbability(0, 'R');
+    assertEquals(mep, 0.02537400637, 0.0001d);
+    assertEquals(mep, Math.pow(Math.E, -3.67403), 0.0001d);
+
+    mep = hmm.getMatchEmissionProbability(19, 'W');
+    assertEquals(mep, 0.00588228492, 0.0001d);
+    assertEquals(mep, Math.pow(Math.E, -5.13581), 0.0001d);
+
+    // column 160 is a gapped region of the model
+    mep = hmm.getMatchEmissionProbability(160, 'G');
+    assertEquals(mep, 0D, 0.0001d);
+
+    mep = hmm.getMatchEmissionProbability(475, 'A');
+    assertEquals(mep, 0.04995163708, 0.0001d);
+    assertEquals(mep, Math.pow(Math.E, -2.99670), 0.0001d);
+  }
+  
+  @Test(groups = "Functional")
+  public void testGetInsertEmissionProbabilities()
+  {
+    double iep = hmm.getInsertEmissionProbability(2, 'A');
+    assertEquals(iep, Math.pow(Math.E, -2.68618), 0.0001d);
+    // symbol is not case-sensitive
+    assertEquals(iep, hmm.getInsertEmissionProbability(2, 'a'));
+
+    iep = hmm.getInsertEmissionProbability(5, 'T');
+    assertEquals(iep, Math.pow(Math.E, -2.77519), 0.0001d);
+
+    // column 161 is gapped in the hmm
+    iep = hmm.getInsertEmissionProbability(161, 'K');
+    assertEquals(iep, 0D, 0.0001d);
+
+    iep = hmm.getInsertEmissionProbability(472, 'L');
+    assertEquals(iep, Math.pow(Math.E, -2.69355), 0.0001d);
+  }
+
+  @Test(groups = "Functional")
+  public void testGetStateTransitionProbabilities()
+  {
+    // * in model file treated as negative infinity
+    double stp = hmm.getStateTransitionProbability(475,
+            HiddenMarkovModel.MATCHTODELETE);
+    assertEquals(stp, Double.NEGATIVE_INFINITY);
+
+    // file value is 5.01631, saved as e^-5.01631
+    stp = hmm.getStateTransitionProbability(8,
+            HiddenMarkovModel.MATCHTOINSERT);
+    assertEquals(stp, Math.pow(Math.E, -5.01631), 0.0001D);
+
+    stp = hmm.getStateTransitionProbability(36,
+            HiddenMarkovModel.MATCHTODELETE);
+    assertEquals(stp, Math.pow(Math.E, -5.73865), 0.0001D);
+
+    stp = hmm.getStateTransitionProbability(22,
+            HiddenMarkovModel.INSERTTOMATCH);
+    assertEquals(stp, Math.pow(Math.E, -0.61958), 0.0001D);
+
+    stp = hmm.getStateTransitionProbability(80,
+            HiddenMarkovModel.INSERTTOINSERT);
+    assertEquals(stp, Math.pow(Math.E, -0.77255), 0.0001D);
+
+    stp = hmm.getStateTransitionProbability(475,
+            HiddenMarkovModel.DELETETOMATCH);
+    assertEquals(stp, 1D, 0.0001D);
+
+    stp = hmm.getStateTransitionProbability(218,
+            HiddenMarkovModel.DELETETODELETE);
+    assertEquals(stp, Math.pow(Math.E, -0.95510), 0.0001D);
+  }
+  
+  @Test(groups = "Functional")
+  public void testGetConsensusSequence()
+  {
+    SequenceI seq = hmm.getConsensusSequence();
+    String subStr = seq.getSequenceAsString().substring(0, 10);
+    assertEquals(subStr, "yelleklGsG");
+    subStr = seq.getSequenceAsString().substring(150, 161);
+    assertEquals(subStr, "-dllk------");
+
+    // test to see if consensus sequence maps to alignment correctly
+    // see HMMAlignmentTest.sto for corresponding alignment file
+    SequenceI seq2 = alignmentHmm.getConsensusSequence();
+    assertEquals(seq2.getCharAt(0), '-');
+    assertEquals(seq2.getCharAt(7), '-');
+    assertEquals(seq2.getCharAt(8), 's');
+
+  }
+
+  /**
+   * A rather pointless test that reproduces the code implemented and asserts
+   * the result is the same...
+   */
+  @Test(groups = "Functional")
+  public void testGetInformationContent()
+  {
+    /*
+     * information measure is sum over all symbols of 
+     * emissionProb * log(emissionProb / background) / log(2)
+     */
+    Map<Character, Float> uniprotFreqs = ResidueProperties.backgroundFrequencies
+            .get("amino");
+    int col = 4;
+    float expected = 0f;
+    for (char aa : hmm.getSymbols().toCharArray())
+    {
+      double mep = hmm.getMatchEmissionProbability(col, aa);
+      float background = uniprotFreqs.get(aa);
+      expected += mep * Math.log(mep / background);
+    }
+    expected /= Math.log(2D);
+
+    float actual = hmm.getInformationContent(col);
+    assertEquals(actual, expected, 0.0001d);
+  }
+}
index 11b993d..efd71e6 100644 (file)
@@ -31,6 +31,7 @@ import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
 
 import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.util.List;
 
@@ -487,7 +488,7 @@ public class HiddenSequencesTest
      * represent seqs 2-4 with seq3
      * this hides seq2 and seq4 but not seq3
      */
-    AlignViewport av = new AlignViewport(al);
+    AlignmentViewport av = new AlignViewport(al);
     SequenceGroup sg = new SequenceGroup();
     sg.addSequence(seqs[1], false);
     sg.addSequence(seqs[2], false);
index 4eb6dbf..9a8f93d 100644 (file)
@@ -27,6 +27,8 @@ import static org.testng.Assert.assertTrue;
 import jalview.datamodel.ResidueCount.SymbolCounts;
 import jalview.gui.JvOptionPane;
 
+import java.util.Arrays;
+
 import org.junit.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -69,6 +71,7 @@ public class ResidueCountTest
     assertEquals(rc.getCount('N'), 1);
     assertEquals(rc.getCount('?'), 0);
     assertEquals(rc.getCount('-'), 0);
+    assertEquals(rc.getTotalResidueCount(), 11);
 
     assertFalse(rc.isCountingInts());
     assertFalse(rc.isUsingOtherData());
@@ -90,6 +93,7 @@ public class ResidueCountTest
     assertEquals(rc.getCount(' '), 4);
     assertEquals(rc.getCount('-'), 4);
     assertEquals(rc.getCount('.'), 4);
+    assertEquals(rc.getTotalResidueCount(), 0);
     assertFalse(rc.isUsingOtherData());
     assertFalse(rc.isCountingInts());
   }
@@ -158,6 +162,7 @@ public class ResidueCountTest
     assertEquals(rc.getCount('m'), 13);
     assertEquals(rc.getCount('G'), 0);
     assertEquals(rc.getCount('-'), 0);
+    assertEquals(rc.getTotalResidueCount(), 27);
 
     assertFalse(rc.isCountingInts());
     assertFalse(rc.isUsingOtherData());
@@ -439,4 +444,23 @@ public class ResidueCountTest
     assertEquals(rc.getCount('?'), 6);
     assertEquals(rc.getCount('!'), 7);
   }
+
+  @Test(groups = "Functional")
+  public void testConstructor_forSequences()
+  {
+    SequenceI seq1 = new Sequence("seq1", "abcde--. FCD");
+    SequenceI seq2 = new Sequence("seq2", "ab.kKqBd-.");
+    ResidueCount rc = new ResidueCount(Arrays.asList(seq1, seq2));
+
+    assertEquals(rc.getGapCount(), 7);
+    assertEquals(rc.getTotalResidueCount(), 15); // excludes gaps
+    assertEquals(rc.getCount('a'), 2);
+    assertEquals(rc.getCount('A'), 2);
+    assertEquals(rc.getCount('B'), 3);
+    assertEquals(rc.getCount('c'), 2);
+    assertEquals(rc.getCount('D'), 3);
+    assertEquals(rc.getCount('f'), 1);
+    assertEquals(rc.getCount('K'), 2);
+    assertEquals(rc.getCount('Q'), 1);
+  }
 }
index 8419d4c..e0f4eba 100644 (file)
@@ -244,7 +244,7 @@ public class SequenceGroupTest
     sg.setDisplayBoxes(false);
     sg.setDisplayText(false);
     sg.setColourText(true);
-    sg.isDefined = true;
+    PA.setValue(sg, "isDefined", true);
     sg.setShowNonconserved(true);
     sg.setOutlineColour(Color.red);
     sg.setIdColour(Color.blue);
@@ -309,7 +309,7 @@ public class SequenceGroupTest
   {
     SequenceI s1 = new Sequence("abcde", "fg");
     SequenceI s2 = new Sequence("foo", "bar");
-    List<SequenceI> seqs = new ArrayList<SequenceI>();
+    List<SequenceI> seqs = new ArrayList<>();
     seqs.add(s1);
     seqs.add(s2);
     SequenceGroup sg = new SequenceGroup(seqs);
index 7238d27..e7cdc6a 100644 (file)
@@ -47,6 +47,7 @@ import jalview.commands.EditCommand.Action;
 import jalview.datamodel.PDBEntry.Type;
 import jalview.gui.JvOptionPane;
 import jalview.util.MapList;
+
 import junit.extensions.PA;
 
 public class SequenceTest
@@ -297,8 +298,6 @@ public class SequenceTest
      * invalid inputs
      */
     assertNull(sq.findPositions(6, 5));
-    assertNull(sq.findPositions(0, 5));
-    assertNull(sq.findPositions(-1, 5));
 
     /*
      * all gapped ranges
@@ -341,6 +340,16 @@ public class SequenceTest
     assertEquals(new Range(11, 12), sq.findPositions(5, 10)); // DE
     assertEquals(new Range(8, 13), sq.findPositions(1, 13)); // the lot
     assertEquals(new Range(8, 13), sq.findPositions(1, 99));
+
+    /**
+     * now try on a sequence with no gaps
+     */
+    sq.createDatasetSequence();
+    assertEquals(new Range(8, 13),
+            sq.getDatasetSequence().findPositions(1, 99));
+    assertEquals(new Range(8, 13),
+            sq.getDatasetSequence().findPositions(0, 99));
+
   }
 
   /**
index e51527a..31bd214 100644 (file)
@@ -35,6 +35,7 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import jalview.api.AlignViewportI;
 import jalview.api.FeatureColourI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
@@ -56,6 +57,7 @@ import jalview.schemes.JalviewColourScheme;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
 
 public class AlignFrameTest
 {
@@ -207,7 +209,7 @@ public class AlignFrameTest
   @Test(groups = "Functional")
   public void testChangeColour_background_groupsAndThresholds()
   {
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     AlignmentI al = av.getAlignment();
 
     /*
@@ -341,7 +343,7 @@ public class AlignFrameTest
   @Test(groups = "Functional")
   public void testColourThresholdActions()
   {
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     AlignmentI al = av.getAlignment();
 
     /*
@@ -514,7 +516,7 @@ public class AlignFrameTest
   @Test(groups = "Functional")
   public void testNewView_colourThresholds()
   {
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     AlignmentI al = av.getAlignment();
 
     /*
@@ -579,7 +581,7 @@ public class AlignFrameTest
      */
     af.newView_actionPerformed(null);
     assertEquals(af.alignPanel.getViewName(), "View 1");
-    AlignViewport av2 = af.getViewport();
+    AlignmentViewport av2 = af.getViewport();
     assertNotSame(av, av2);
     assertSame(av2, af.alignPanel.av);
     rs = av2.getResidueShading();
index 60e10d1..9c1a412 100644 (file)
@@ -27,6 +27,7 @@ import static org.testng.AssertJUnit.assertNotSame;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import jalview.api.AlignViewportI;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -54,6 +55,7 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.PIDColourScheme;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MapList;
+import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.workers.AlignCalcManager;
 
@@ -69,7 +71,7 @@ public class AlignViewportTest
 
   AlignmentI al;
 
-  AlignViewport testee;
+  AlignmentViewport testee;
 
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
@@ -414,7 +416,7 @@ public class AlignViewportTest
   {
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     SequenceGroup sg1 = new SequenceGroup();
     SequenceGroup sg2 = new SequenceGroup();
     SequenceGroup sg3 = new SequenceGroup();
@@ -443,8 +445,9 @@ public class AlignViewportTest
     jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.FALSE.toString());
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
-    AlignViewport av = af.getViewport();
-    Assert.assertNull(av.getAlignmentGapAnnotation(), "Preference did not disable occupancy row.");
+    AlignViewportI av = af.getViewport();
+    Assert.assertNull(av.getAlignmentGapAnnotation(),
+            "Preference did not disable occupancy row.");
     int c = 0;
     for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
             null, "Occupancy"))
@@ -458,7 +461,8 @@ public class AlignViewportTest
     af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     av = af.getViewport();
-    Assert.assertNotNull(av.getAlignmentGapAnnotation(), "Preference did not enable occupancy row.");
+    Assert.assertNotNull(av.getAlignmentGapAnnotation(),
+            "Preference did not enable occupancy row.");
     c = 0;
     for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null,
             null, av.getAlignmentGapAnnotation().label))
index ca9ac22..edf8d40 100644 (file)
@@ -2,17 +2,17 @@ package jalview.gui;
 
 import static org.testng.Assert.assertEquals;
 
+import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceGroup;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
-
 import javax.swing.JTextArea;
 
-import junit.extensions.PA;
-
 import org.testng.annotations.Test;
 
+import junit.extensions.PA;
+
 public class PairwiseAlignmentPanelTest
 {
   @Test(groups = "Functional")
@@ -20,7 +20,7 @@ public class PairwiseAlignmentPanelTest
   {
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
     AlignmentI al = viewport.getAlignment();
 
     /*
@@ -58,7 +58,7 @@ public class PairwiseAlignmentPanelTest
     String seqs = ">Q93XJ9_SOLTU/23-29\nL-KAISNV\n>FER1_PEA/26-32\nV-TTTKAF\n";
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqs,
             DataSourceType.PASTE);
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
 
     PairwiseAlignPanel testee = new PairwiseAlignPanel(viewport);
 
index 4a5c248..49f9d7f 100644 (file)
@@ -249,6 +249,7 @@ public class PopupMenuTest
     // PDB.secondary structure on Sequence0
     AlignmentAnnotation annotation = new AlignmentAnnotation(
             "secondary structure", "", 0);
+    annotation.annotations = new Annotation[] { new Annotation(2f) };
     annotation.setCalcId("PDB");
     seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
     if (addToSequence)
@@ -263,6 +264,7 @@ public class PopupMenuTest
     // PDB.Temp on Sequence1
     annotation = new AlignmentAnnotation("Temp", "", 0);
     annotation.setCalcId("PDB");
+    annotation.annotations = new Annotation[] { new Annotation(2f) };
     seqs.get(1).getDatasetSequence().addAlignmentAnnotation(annotation);
     if (addToSequence)
     {
@@ -276,6 +278,7 @@ public class PopupMenuTest
     // JMOL.secondary structure on Sequence0
     annotation = new AlignmentAnnotation("secondary structure", "", 0);
     annotation.setCalcId("Jmol");
+    annotation.annotations = new Annotation[] { new Annotation(2f) };
     seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
     if (addToSequence)
     {
index 359377a..d3d6476 100644 (file)
@@ -22,6 +22,7 @@ package jalview.gui;
 
 import static org.testng.Assert.assertEquals;
 
+import jalview.api.AlignViewportI;
 import jalview.bin.Jalview;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -41,7 +42,7 @@ import org.testng.annotations.Test;
 public class SequenceRendererTest
 {
   AlignmentI al;
-  AlignViewport av;
+  AlignViewportI av;
 
   SequenceI seq1;
 
diff --git a/test/jalview/hmmer/HMMERTest.java b/test/jalview/hmmer/HMMERTest.java
new file mode 100644 (file)
index 0000000..04cc3be
--- /dev/null
@@ -0,0 +1,134 @@
+package jalview.hmmer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.io.HMMFile;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.simple.Option;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class HMMERTest {
+
+  AlignFrame frame;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpBeforeClass() throws Exception
+  {
+    /*
+     * NB: check HMMER_PATH in testProps.jvprops is valid for
+     * the machine on which this runs
+     */
+    Jalview.main(
+            new String[]
+    { "-noquestionnaire", "-nonews", "-props",
+                "test/jalview/hmmer/testProps.jvprops", "-open",
+                "examples/uniref50.fa" });
+    frame = Desktop.getAlignFrames()[0];
+  }
+
+  @AfterClass(alwaysRun = true)
+  public static void tearDownAfterClass() throws Exception
+  {
+    Desktop.getInstance().closeAll_actionPerformed(null);
+  }
+
+  /**
+   * Test with a dependency on locally installed hmmbuild binaries
+   * 
+   * @throws MalformedURLException
+   * @throws IOException
+   */
+  @Test(groups = "External")
+  public void testHMMBuildThenHMMAlign()
+          throws MalformedURLException, IOException
+  {
+    /*
+     * run hmmbuild
+     */
+    testHMMBuild();
+    List<SequenceI> hmms = frame.getViewport().getAlignment()
+            .getHmmSequences();
+    assertFalse(hmms.isEmpty());
+
+    /*
+     * now run hmmalign - by default with respect to the added HMM profile
+     */
+    testHMMAlign();
+  }
+
+  public void testHMMBuild()
+  {
+    /*
+     * set up argument to run hmmbuild for the alignment
+     */
+    ArrayList<ArgumentI> params = new ArrayList<>();
+    String argName = MessageManager.getString("label.hmmbuild_for");
+    String argValue = MessageManager.getString("label.alignment");
+    params.add(
+            new Option(argName, null, false, null, argValue, null, null));
+
+    HMMBuild builder = new HMMBuild(frame, params);
+    builder.run();
+
+    SequenceI seq = frame.getViewport().getAlignment().getSequenceAt(0);
+    HiddenMarkovModel hmm = seq.getHMM();
+    assertNotNull(hmm);
+
+    assertEquals(hmm.getLength(), 148);
+    assertEquals(hmm.getAlphabetType(), "amino");
+    assertEquals(hmm.getName(), "Alignment_HMM");
+    assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES),
+            "0.648193");
+  }
+
+  public void testHMMAlign()
+  {
+    HmmerCommand thread = new HMMAlign(frame,
+            new ArrayList<ArgumentI>());
+    thread.run();
+
+    AlignFrame[] alignFrames = Desktop.getAlignFrames();
+    if (alignFrames == null)
+    {
+      fail("No align frame loaded");
+    }
+
+    /*
+     * now have the original align frame, and another for realigned sequences
+     */
+    assertEquals(alignFrames.length, 2);
+    AlignmentI original = alignFrames[0].getViewport().getAlignment();
+    assertNotNull(original);
+    AlignmentI realigned = alignFrames[1].getViewport().getAlignment();
+    assertNotNull(realigned);
+    assertFalse(original.getHmmSequences().isEmpty());
+    assertFalse(realigned.getHmmSequences().isEmpty());
+
+    SequenceI ferCapan = original.findName("FER_CAPAN");
+    assertTrue(ferCapan.getSequenceAsString().startsWith("MA------SVSAT"));
+
+    SequenceI ferCapanRealigned = realigned.findName("FER_CAPAN");
+    assertTrue(ferCapanRealigned.getSequenceAsString()
+            .startsWith("-------m-A----SVSAT"));
+  }
+}
+
diff --git a/test/jalview/hmmer/testProps.jvprops b/test/jalview/hmmer/testProps.jvprops
new file mode 100644 (file)
index 0000000..05cd493
--- /dev/null
@@ -0,0 +1,88 @@
+#---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_OCCUPANCY=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
+DAS_LOCAL_SOURCE=
+SCREEN_HEIGHT=650
+ANNOTATIONCOLOUR_MAX=ff0000
+AUTO_CALC_CONSENSUS=true
+FASTA_JVSUFFIX=true
+DAS_ACTIVE_SOURCE=uniprot\t
+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.dasregistry.org/das/ # retired 01/05/2015
+DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/
+logs.Jalview.level=DEBUG
+HMMER_PATH=/Users/gmcarstairs/software/hmmer-3.1b2-macosx-intel/binaries
index 677a6e9..faf05d3 100644 (file)
@@ -55,7 +55,7 @@ public class FileFormatsTest
   @Test(groups = "Functional")
   public void testGetReadableFormats()
   {
-    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, BSML]";
+    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3, BSML]";
     FileFormats formats = FileFormats.getInstance();
     assertEquals(formats.getReadableFormats().toString(), expected);
   }
@@ -63,26 +63,26 @@ public class FileFormatsTest
   @Test(groups = "Functional")
   public void testGetWritableFormats()
   {
-    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]";
+    String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]";
     FileFormats formats = FileFormats.getInstance();
     assertEquals(formats.getWritableFormats(true).toString(), expected);
-    expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Jalview]";
+    expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Jalview, HMMER3]";
     assertEquals(formats.getWritableFormats(false).toString(), expected);
   }
 
   @Test(groups = "Functional")
   public void testDeregisterFileFormat()
   {
-    String writable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]";
-    String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, BSML]";
+    String writable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]";
+    String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3, BSML]";
     FileFormats formats = FileFormats.getInstance();
     System.out.println(formats.getReadableFormats().toString());
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
 
     formats.deregisterFileFormat(FileFormat.Fasta.getName());
-    writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]";
-    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, BSML]";
+    writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]";
+    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3, BSML]";
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
 
@@ -90,8 +90,8 @@ public class FileFormatsTest
      * re-register the format: it gets added to the end of the list
      */
     formats.registerFileFormat(FileFormat.Fasta);
-    writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Fasta]";
-    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, BSML, Fasta]";
+    writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3, Fasta]";
+    readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3, BSML, Fasta]";
     assertEquals(formats.getWritableFormats(true).toString(), writable);
     assertEquals(formats.getReadableFormats().toString(), readable);
   }
index 968901f..84bd714 100644 (file)
@@ -1,5 +1,9 @@
 package jalview.io;
 
+import static org.testng.Assert.assertEquals;
+
+import jalview.bin.Cache;
+
 import org.junit.Assert;
 import org.testng.annotations.Test;
 
@@ -19,4 +23,34 @@ public class FileLoaderTest
     // Data source type expected to be DataSourceType.URL
     Assert.assertEquals(DataSourceType.URL, fileLoader.protocol);
   }
+
+  @Test(groups = "Functional")
+  public void testUpdateRecentlyOpened()
+  {
+    // ensure properties file is read-only
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+
+    String recent = "RECENT_FILE";
+    Cache.removeProperty(recent);
+
+    String prop = FileLoader.updateRecentlyOpened("a/b/c",
+            DataSourceType.FILE);
+    assertEquals(prop, "a/b/c");
+
+    prop = FileLoader.updateRecentlyOpened("d/e/f", DataSourceType.FILE);
+    assertEquals(prop, "d/e/f\ta/b/c");
+
+    // revisiting a file moves it to the top of the list
+    prop = FileLoader.updateRecentlyOpened("a/b/c", DataSourceType.FILE);
+    assertEquals(prop, "a/b/c\td/e/f");
+    
+    // history list is limited to the most recent 11 items
+    for (int i = 0; i < 20; i++)
+    {
+      prop = FileLoader.updateRecentlyOpened(String.format("%d.fa", i),
+              DataSourceType.FILE);
+    }
+    assertEquals(prop,
+            "19.fa\t18.fa\t17.fa\t16.fa\t15.fa\t14.fa\t13.fa\t12.fa\t11.fa\t10.fa\t9.fa");
+  }
 }
index b500266..3812a09 100644 (file)
@@ -56,8 +56,17 @@ public class FormatAdapterTest
   {
     try
     {
-      AlignmentI al = new FormatAdapter().readFile("examples/uniref50.fa",
+      AlignmentI al;
+      if (format == FileFormat.HMMER3)
+      {
+        al = new FormatAdapter().readFile("examples/uniref50.hmm",
+                DataSourceType.FILE, FileFormat.HMMER3);
+      }
+      else
+      {
+        al = new FormatAdapter().readFile("examples/uniref50.fa",
               DataSourceType.FILE, FileFormat.Fasta);
+      }
 
       /*
        * 'gap' is the gap character used in the alignment data file here,
@@ -73,8 +82,9 @@ public class FormatAdapterTest
       AlignmentI reloaded = new FormatAdapter().readFile(formatted,
               DataSourceType.PASTE, format);
       List<SequenceI> reread = reloaded.getSequences();
-      assertEquals("Wrong number of reloaded sequences", seqs.length,
-              reread.size());
+        assertEquals("Wrong number of reloaded sequences", seqs.length,
+                reread.size());
+
 
       int i = 0;
       for (SequenceI seq : reread)
@@ -131,7 +141,7 @@ public class FormatAdapterTest
   @DataProvider(name = "formats")
   static Object[][] getFormats()
   {
-    List<FileFormatI> both = new ArrayList<FileFormatI>();
+    List<FileFormatI> both = new ArrayList<>();
     for (FileFormatI format : FileFormats.getInstance().getFormats())
     {
       if (format.isReadable() && format.isWritable()
diff --git a/test/jalview/io/HMMAlignmentTest.sto b/test/jalview/io/HMMAlignmentTest.sto
new file mode 100644 (file)
index 0000000..f0f1f4a
--- /dev/null
@@ -0,0 +1,16 @@
+# STOCKHOLM 1.0
+#=GS Q7XA98_TRIPR/1-152   DR UNIPROT ; Q7XA98 
+#=GS FER1_PEA/1-149       DR UNIPROT ; P09911 
+#=GS Q93XJ9_SOLTU/1-144   DR UNIPROT ; Q93XJ9 
+#=GS FER_CAPAN/1-144      DR UNIPROT ; Q9ZTS2 
+#=GS FER1_SOLLC/1-144     DR UNIPROT ; Q43517 
+#=GS FER_CAPAA/1-97       DR UNIPROT ; P83527 
+FER_CAPAA/1-97             ------------------------------------------------------------------------ASYKVKLITPDGPIEFDCPDDVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDGNFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-
+FER_CAPAN/1-144            MA------SVSATMISTSFMPRKPAVTSL-KPIPNVGE--ALFGLKS-A--NGGKVTCMASYKVKLITPDGPIEFDCPDNVYILDQAEEAGHDLPYSCRAGSCSSCAGKIAGGAVDQTDGNFLDDDQLEEGWVLTCVAYPQSDVTIETHKEAELVG-
+FER1_SOLLC/1-144           -------------MA------SISGTMISTSFLPRKPAVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMASYKVKLITPEGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGSVDQSDGNFLDEDQEAAGFVLTCVAYPKGDVTIETHKEEELTA-
+Q93XJ9_SOLTU/1-144         --------MA------SISGTMISTSFLPRKPVVTSL-KAISNVGE--ALFGLKS-G--RNGRITCMASYKVKLITPDGPIEFECPDDVYILDQAEEEGHDLPYSCRAGSCSSCAGKVTAGTVDQSDGKFLDDDQEAAGFVLTCVAYPKCDVTIETHKEEELTA-
+FER1_PEA/1-149             -------------MATT---PALYGTAVSTSFLRTQPMPMSV-TTTKAFSN--GFLGLKT-SLKRGDLAVAMASYKVKLVTPDGTQEFECPSDVYILDHAEEVGIDLPYSCRAGSCSSCAGKVVGGEVDQSDGSFLDDEQIEAGFVLTCVAYPTSDVVIETHKEEDLTA-
+Q7XA98_TRIPR/1-152         -------------MATT---PALYGTAVSTSFMRRQPVPMSV-ATTTTTKAFPSGFGLKSVSTKRGDLAVAMATYKVKLITPEGPQEFDCPDDVYILDHAEEVGIELPYSCRAGSCSSCAGKVVNGNVNQEDGSFLDDEQIEGGWVLTCVAFPTSDVTIETHKEEELTA-
+#=GC SS_cons                                                                              EEE    EEEEEEEE    HHHHH          e    e  e EE     EE          HHHH E   e  EE   EEEEE         
+#=GC Iron_Sulphur_Contacts -------------------------------------------------------------------------------------------------e----e--e-----------------------------e---------------------
+//
diff --git a/test/jalview/io/HMMAlignmentTestHMM.hmm b/test/jalview/io/HMMAlignmentTestHMM.hmm
new file mode 100644 (file)
index 0000000..649f5f9
--- /dev/null
@@ -0,0 +1,478 @@
+HMMER3/f [3.2 | June 2018]
+NAME  Alignment_HMM
+LENG  152
+ALPH  amino
+RF    no
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Fri Jun  7 14:44:10 2019
+NSEQ  6
+EFFN  2.071289
+CKSUM 2312940853
+STATS LOCAL MSV      -10.2278  0.70920
+STATS LOCAL VITERBI  -10.8843  0.70920
+STATS LOCAL FORWARD   -4.3996  0.70920
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   2.41432  3.67931  2.75921  2.60121  3.50018  2.76530  3.83614  2.93106  2.71371  2.66765  3.66760  3.24838  3.26026  3.17831  3.19279  2.51076  2.65615  2.59873  5.09464  3.62512
+          2.68544  4.42237  2.77531  2.73135  3.46365  2.40524  3.72506  3.29365  2.67752  2.69366  4.24294  2.90358  2.73751  3.18158  2.89812  2.37898  2.77531  2.98530  4.58488  3.61515
+          0.78057  1.55851  1.10441  0.67815  0.70837  0.00000        *
+      1   2.59800  4.39329  3.63625  3.18787  3.71456  3.43841  4.11392  3.03068  3.09157  2.71409  1.85445  3.48425  4.00395  3.44434  3.39575  1.59145  2.94832  2.79270  5.21434  3.95539      9 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02133  4.25401  4.97636  0.61958  0.77255  0.98598  0.46693
+      2   1.50579  4.32755  4.18645  3.78216  3.88559  3.56425  4.59767  2.41074  3.70275  2.69336  3.78707  3.89382  4.19613  3.99133  3.94010  2.99086  3.05698  1.28977  5.52248  4.31320     10 v - - -
+          2.68550  4.42242  2.77537  2.73141  3.46371  2.40530  3.72512  3.29371  2.67758  2.69372  4.24707  2.90364  2.73757  3.18164  2.89818  2.37841  2.77443  2.98536  4.58494  3.61520
+          0.90209  1.16285  1.26696  1.01535  0.44985  0.39057  1.12909
+      3   3.42707  4.91214  4.61207  4.26925  3.52422  4.22326  4.89422  2.75377  4.00666  2.06722  0.68834  4.47974  4.70831  4.36739  4.15005  3.81331  3.75358  2.81142  5.41119  4.20659     14 M - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01938  4.34894  5.07129  0.61958  0.77255  0.90177  0.52062
+      4   1.43643  4.42503  4.31312  3.86585  3.75424  3.86050  4.64018  1.40277  3.76673  2.49922  3.64972  4.05060  4.39156  4.05997  3.99981  3.25891  3.19718  2.11006  5.45161  4.24039     15 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.14665  4.34894  2.09167  0.61958  0.77255  0.90177  0.52062
+      5   2.37098  4.31475  3.56770  3.24979  4.37798  3.10030  4.31086  3.75066  3.26247  3.47251  4.31621  3.42494  3.83407  3.57718  3.57680  1.30947  1.53387  3.24501  5.72919  4.50336     16 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02198  4.22428  4.94663  0.61958  0.77255  0.54114  0.87248
+      6   2.50652  4.44141  3.83949  3.54853  4.61304  3.23185  4.57545  3.99871  3.56049  3.72110  4.55726  3.64948  3.99392  3.85973  3.84879  1.49216  1.01986  3.44946  5.96659  4.76085     17 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24086  4.47354  1.59630  0.61958  0.77255  0.76398  0.62700
+      7   2.65517  4.36127  3.81549  3.38335  3.69064  3.54500  4.25486  1.58799  3.30272  2.65201  3.68407  3.64162  4.10535  3.63002  3.58335  1.61226  3.00284  2.44965  5.24306  3.98781     18 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02133  4.25401  4.97636  0.61958  0.77255  0.98598  0.46693
+      8   2.74723  4.45808  3.83003  3.43336  1.55716  3.57739  4.01030  3.12129  3.39844  2.75883  3.78862  3.64312  4.13759  3.66183  3.66464  1.60155  3.09781  2.89427  4.64509  3.10366     19 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02133  4.25401  4.97636  0.61958  0.77255  0.98598  0.46693
+      9   2.65532  4.43699  3.65638  3.26130  3.78761  1.68622  4.19753  3.09268  3.18548  2.76736  1.66329  3.54773  4.04431  3.53861  3.47551  2.87376  3.01742  2.85730  5.28180  4.04464     20 m - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02133  4.25401  4.97636  0.61958  0.77255  0.55834  0.84900
+     10   2.62413  4.55150  3.73217  3.46502  4.58891  3.32606  4.53947  3.93771  3.48022  3.66044  4.54532  3.64966  1.08714  3.81713  3.77509  2.80225  1.57704  3.45878  5.93284  4.72852     21 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01709  4.47354  5.19589  0.61958  0.77255  0.51701  0.90709
+     11   1.99709  4.68552  3.40260  2.84388  3.94615  3.60689  3.90388  3.32023  2.73340  2.98773  2.29384  3.29447  4.03205  3.12399  2.03393  2.35985  2.99523  3.04365  5.29921  4.03061     22 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     12   3.03612  4.58206  4.17469  3.58665  3.60032  4.09338  4.33760  1.51772  1.94651  1.71212  3.50362  3.91731  4.43832  3.70785  3.50867  3.39096  3.26453  2.43051  5.23091  4.03724     23 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     13   2.76197  4.70799  3.41034  2.96484  3.84310  3.56022  4.02290  3.51807  2.97071  3.16868  4.04204  3.37800  2.07618  3.30589  3.36146  1.59778  3.07503  3.20545  5.27554  2.20871     24 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     14   1.42932  4.46589  4.02364  3.69643  4.72988  1.43294  4.68906  4.13282  3.71549  3.83309  4.64260  3.74322  4.03851  3.97444  4.00639  2.72003  1.63454  3.53847  6.07503  4.89460     25 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     15   2.63382  4.43500  3.98903  3.52691  4.05377  3.47381  4.41118  3.21360  3.46955  3.09630  4.00516  3.71495  4.11115  3.75748  3.76367  1.74048  1.56254  1.69711  5.50933  4.30015     26 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     16   1.97870  4.28154  4.12278  3.55312  2.14335  3.81420  4.17500  2.68382  3.44988  2.41995  2.61784  3.79310  4.21338  3.68984  3.66833  3.11084  1.96434  2.49922  4.91664  3.71472     27 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     17   2.91846  4.34842  4.48199  3.90988  3.46317  4.07572  4.44144  1.98330  3.78456  1.67828  3.41359  4.10010  4.43748  4.00384  3.95399  2.01206  3.16092  1.64497  5.07625  3.88829     28 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     18   2.70635  4.56892  3.60528  3.14080  3.96671  3.53723  4.15403  3.33644  3.10057  1.82443  3.93202  3.49380  2.11690  3.43662  3.45226  1.62468  3.04334  3.04998  5.39218  4.13558     29 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.26457  4.57201  1.50451  0.61958  0.77255  0.62415  0.76726
+     19   2.81401  4.82005  3.48128  2.94818  4.34473  3.53963  3.92028  3.69738  2.45527  3.31575  4.19707  3.33652  4.04563  3.10077  1.62480  2.90920  1.49986  3.36258  5.52959  4.29493     30 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01981  4.32725  5.04960  0.61958  0.77255  0.42245  1.06549
+     20   2.99742  5.17558  3.29695  2.86766  4.77169  3.64255  3.98284  4.20460  1.15211  3.71930  4.54717  3.31939  4.14896  3.12831  2.80934  1.59962  3.28379  3.79417  5.81941  4.54197     31 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     21   3.28763  4.90910  4.31235  3.99239  1.36983  4.02580  4.37777  3.48169  3.95787  2.96396  4.13543  4.15449  1.08518  4.20039  4.16663  3.51751  3.64052  3.33099  4.84797  3.27396     32 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     22   3.45018  4.70771  5.41218  4.85806  3.55317  4.84496  5.27184  1.41698  4.72877  1.42021  2.43827  4.98314  5.05481  4.81112  4.77841  4.21177  3.68367  1.42720  5.55642  4.46185     33 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     23   2.82485  4.73326  3.55705  3.00955  4.05482  3.65786  4.00613  3.34731  2.73677  3.06317  3.96177  3.42018  1.80573  3.23126  2.02314  2.96454  3.09977  1.95730  5.39957  4.14889     34 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     24   2.86127  5.09016  3.19616  2.69781  4.52201  3.59071  3.86031  3.94606  2.49967  3.49458  4.30305  1.96704  4.04133  2.99863  1.96172  2.88186  1.74316  3.56959  5.66035  4.34483     35 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     25   2.78170  4.95829  3.16704  2.62944  4.23097  3.58469  3.79757  3.63325  2.16991  3.23781  4.05928  3.13605  3.98936  2.12578  2.95429  2.00470  3.01690  2.13727  5.47298  4.15357     36 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     26   2.74867  4.60831  3.61740  3.20842  4.05654  1.87017  4.23901  3.42440  3.19407  1.83184  4.02720  3.54846  1.75260  3.52860  3.53526  2.92904  3.10347  3.12934  5.47730  4.23070     37 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24245  4.57201  1.58496  0.61958  0.77255  0.62415  0.76726
+     27   2.23893  4.60373  3.28448  1.87774  3.79882  3.57859  3.83870  3.03021  2.72644  2.79800  2.80144  3.21864  3.97823  3.06477  3.13889  2.82027  2.92566  2.31720  5.19891  3.92417     38 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.34327  4.34894  1.28144  0.61958  0.77255  0.43345  1.04488
+     28   2.73943  4.82202  3.20350  2.68202  4.15055  3.52581  3.79474  3.47895  1.71004  3.13955  3.99838  3.15504  2.24076  2.96517  2.84990  2.80694  2.99350  2.43471  5.40910  4.11885     39 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01981  4.32725  5.04960  0.61958  0.77255  0.92238  0.50679
+     29   1.67523  4.32939  3.80070  3.28713  3.65556  3.52435  4.14641  2.82922  3.20444  2.62909  2.04920  3.56786  4.04881  3.50886  3.50296  2.86733  2.23962  2.60434  5.15734  3.94638     40 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01981  4.32725  5.04960  0.61958  0.77255  0.42245  1.06549
+     30   1.66814  4.43166  3.95026  3.47077  3.91143  3.54985  4.34218  1.84764  3.41576  2.94090  3.86903  3.70285  4.13774  3.70337  3.71262  1.58997  3.04021  2.78308  5.38688  4.17260     41 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     31   2.86839  4.40063  4.28613  3.75197  3.53211  3.91378  4.39907  2.56140  3.63254  1.42290  3.49235  3.96842  4.35205  3.89101  3.84593  1.98860  3.14663  1.72465  5.13588  3.93489     42 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.33933  4.57201  1.28224  0.61958  0.77255  0.62415  0.76726
+     32   2.99338  4.73521  3.52318  3.19423  1.49578  3.74751  3.84834  3.30385  3.23971  2.88691  3.93859  1.69947  4.23548  3.52506  3.56009  3.13754  3.28417  3.09751  4.46980  2.84938     43 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02133  4.25401  4.97636  0.61958  0.77255  0.39057  1.12909
+     33   2.26113  4.65266  3.39149  2.85535  3.96561  2.14052  3.94035  3.32256  2.32255  3.01451  3.87297  3.29920  4.01793  3.16391  3.22857  2.83216  2.44156  2.03814  5.33010  4.05751     44 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     34   2.14527  4.45044  3.76875  3.26603  3.85788  2.04177  4.18979  3.17104  3.21967  1.81090  3.81461  3.56903  4.08500  3.51989  3.54833  2.88152  1.96723  2.89522  5.29995  4.07724     45 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     35   2.77531  5.06924  3.07796  1.89721  4.35250  3.56090  3.75513  2.86917  1.82937  3.33902  4.13804  3.06897  3.95918  2.88565  2.93068  2.78088  2.17797  3.41042  5.54533  4.19589     46 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24245  4.57201  1.58496  0.61958  0.77255  0.62415  0.76726
+     36   2.66334  4.78591  3.14690  2.69736  4.34791  3.40164  3.87711  3.75678  2.10710  3.36111  4.18006  3.15163  3.92504  3.04074  3.00575  1.44108  2.29363  3.36678  5.57460  4.27063     47 s - - -
+          2.68590  4.42232  2.77527  2.73130  3.46361  2.40520  3.72502  3.29361  2.67748  2.69362  4.24697  2.90308  2.73747  3.18154  2.89808  2.37894  2.77488  2.98526  4.58484  3.61510
+          0.44576  1.04019  5.07129  0.13971  2.03720  0.43345  1.04488
+     37   1.35032  4.33598  4.11743  3.57274  2.66462  3.74950  4.26894  2.70612  3.48547  2.58049  3.54278  3.80339  4.21776  3.73820  3.72893  3.07578  2.40333  2.07300  5.08335  3.87699     49 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.26457  4.57201  1.50451  0.61958  0.77255  0.62415  0.76726
+     38   2.67849  4.67202  3.20606  2.69337  3.93262  2.63512  3.80028  3.31587  2.17250  1.96311  3.82914  3.16211  3.94141  3.00575  3.00084  2.28900  2.93113  3.03056  5.26473  3.98290     50 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01981  4.32725  5.04960  0.61958  0.77255  0.92238  0.50679
+     39   2.23745  4.71916  3.05672  2.16980  2.23785  3.50580  3.78395  3.31902  2.66523  2.97723  3.83443  2.49003  3.93379  2.99259  3.10154  2.77864  2.93862  3.03813  5.25364  3.93663     51 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.29014  4.32725  1.43280  0.61958  0.77255  0.42245  1.06549
+     40   2.71194  4.71147  3.14073  2.76488  2.63325  1.94411  3.91859  3.50545  2.86219  3.15174  4.02297  1.82298  3.98451  3.17614  3.28134  2.81220  3.01803  3.18804  5.26894  3.87083     52 n - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01895  4.37135  5.09369  0.61958  0.77255  0.87955  0.53609
+     41   2.64945  4.49564  3.49208  3.06414  3.88051  1.81354  4.08661  3.23766  3.04151  1.74255  3.84911  3.42067  2.61702  3.37781  3.38586  2.83194  2.98495  2.96040  5.30850  4.06003     53 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01895  4.37135  5.09369  0.61958  0.77255  0.44572  1.02266
+     42   2.20625  4.93221  3.17339  2.72120  4.55189  1.72555  3.94981  3.99413  1.81667  3.55820  4.34814  3.19358  3.98997  3.09380  3.14134  2.24894  3.05082  3.55894  5.74349  4.41072     54 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     43   2.73118  4.74977  3.26283  2.70881  2.98752  2.82347  3.82752  3.34686  1.92589  2.48911  3.84846  3.19660  3.99345  3.02672  3.10018  2.03919  2.96671  3.06691  5.29037  3.99373     55 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24245  4.57201  1.58496  0.61958  0.77255  0.62415  0.76726
+     44   3.21892  4.54748  4.94678  4.39384  1.84065  4.45647  4.69231  2.23828  4.25181  1.55834  3.19076  4.52046  4.72563  4.36468  4.33750  3.79737  3.45238  1.39236  5.03910  3.75691     56 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01938  4.34894  5.07129  0.61958  0.77255  0.43345  1.04488
+     45   2.63358  4.56206  3.94281  3.76669  4.90587  0.86987  4.83032  4.31802  3.87414  4.03413  4.86498  3.81723  4.11786  4.13859  4.13012  2.82336  1.52160  3.69008  6.22345  5.06760     57 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24245  4.57201  1.58496  0.61958  0.77255  0.62415  0.76726
+     46   3.01864  1.79566  4.69259  4.19257  3.41038  4.04365  4.66782  2.43586  3.98238  1.14404  3.36027  4.28885  4.50409  4.22027  4.10902  3.45690  3.32610  2.36331  5.19668  3.99182     58 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01938  4.34894  5.07129  0.61958  0.77255  0.90177  0.52062
+     47   2.96377  4.89266  3.53249  2.95386  4.04795  3.74350  3.88142  3.34726  1.40052  2.91530  1.93101  3.37640  4.14009  3.07637  2.67530  3.06693  3.18523  3.14375  5.36699  4.12971     59 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01938  4.34894  5.07129  0.61958  0.77255  0.43345  1.04488
+     48   1.77870  4.80105  3.33239  2.80291  4.36522  3.47131  3.95619  3.78270  2.73318  3.38875  4.19761  3.24889  3.98437  3.11824  1.99740  1.90727  2.40269  3.38967  5.61455  4.31002     60 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.21961  4.57201  1.67756  0.61958  0.77255  0.62415  0.76726
+     49   2.60823  4.64033  3.22015  2.80894  4.20933  3.36458  3.98710  3.59284  2.85357  3.27469  4.11620  1.86137  3.93152  3.18866  3.26591  1.65119  2.95563  2.38198  5.53276  4.23147     61 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01895  4.37135  5.09369  0.61958  0.77255  0.44572  1.02266
+     50   2.74410  4.67335  3.45404  3.06703  3.90844  1.64792  4.12669  3.60477  3.11681  3.26108  4.13393  3.44191  4.09025  3.43093  3.49590  1.86622  3.09650  3.26485  5.35022  1.97056     62 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.11556  4.57201  2.31473  0.61958  0.77255  0.62415  0.76726
+     51   2.95370  5.14232  3.38998  2.75626  4.47479  3.70680  3.76608  3.85318  1.57496  2.58800  4.21663  3.22595  4.07617  2.90174  1.75899  2.96747  2.46355  3.52788  5.54040  4.28024     63 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01709  4.47354  5.19589  0.61958  0.77255  0.76398  0.62700
+     52   2.97237  4.48471  4.17487  3.61038  3.68717  4.08286  4.40175  1.59509  2.09243  2.51779  3.58882  3.93788  4.44245  3.78487  3.66371  3.38387  3.21319  1.46639  5.29622  4.08064     64 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01709  4.47354  5.19589  0.61958  0.77255  0.51701  0.90709
+     53   3.16272  5.37499  3.59177  2.92070  4.82565  3.84597  3.83774  4.18579  1.50049  3.63868  4.47141  3.36065  4.21246  2.96157  1.48253  3.15294  1.98320  3.83770  5.70684  4.49260     65 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     54   2.69126  2.25915  3.80687  3.28606  3.66656  2.21575  4.13449  3.01259  3.21697  1.80809  3.65267  2.64888  4.11014  3.51421  3.51970  2.94231  2.98955  2.76835  5.12838  3.90654     66 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     55   2.75976  4.54905  2.30455  2.95518  3.70676  2.79648  3.96957  2.00953  2.95066  2.74085  2.27446  3.39166  4.08996  3.25986  3.33214  2.95036  2.99901  2.76002  5.14787  3.89753     67 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     56   1.92745  4.55633  3.54968  2.99110  3.77370  3.65270  3.97236  3.10509  2.88439  2.02402  3.71145  3.40529  4.07525  3.24934  2.56281  2.91984  1.98149  2.86151  5.18773  3.94368     68 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     57   1.83228  4.53823  3.61230  3.10354  4.02012  3.49038  4.12836  2.50681  3.07752  3.08124  3.94943  3.45725  2.07017  3.39222  3.45240  1.83561  2.99081  3.04929  5.41506  4.16867     69 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     58   2.75895  4.66749  2.12963  2.81059  3.81488  3.63897  3.90096  3.17855  2.82626  2.89854  3.77788  3.28020  4.04584  3.14685  3.24113  2.89220  2.45960  2.10817  5.21741  2.34581     70 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     59   1.87134  2.92490  3.41990  2.89562  4.22753  2.00930  4.00910  3.62340  1.87199  3.26968  4.10116  3.31508  4.00325  3.20209  3.23675  2.78496  2.99855  3.26410  5.53516  4.25405     71 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.62415  0.76726
+     60   2.89677  4.42989  4.26135  3.71893  3.52156  3.94729  4.39343  2.57065  3.59726  2.35872  1.80824  3.96209  2.13460  3.86316  3.82140  3.27132  3.16554  1.68431  5.14387  3.95469     72 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01548  4.57201  5.29435  0.61958  0.77255  0.40804  1.09349
+     61   1.57565  4.67644  3.61371  3.07202  3.92167  3.75428  4.06548  1.97069  1.96866  2.90804  3.83592  3.49072  4.17868  3.32201  3.23603  3.03786  3.11158  2.81687  5.33764  4.09102     73 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     62   2.78306  4.91407  3.16080  1.90266  4.17861  3.59010  3.85833  3.57055  2.67830  2.17323  4.03601  3.16932  4.01281  3.02684  3.12616  1.86668  2.50737  3.25963  5.47226  4.15166     74 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     63   3.70553  4.96355  5.18038  4.77967  1.51175  4.68042  4.04025  1.78081  4.59062  2.70856  3.92100  4.53151  4.97996  4.54894  4.56550  4.02683  3.92721  3.14972  4.19952  1.17802     75 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     64   2.92406  5.37226  1.90980  2.50543  4.72545  3.56703  3.85582  4.19183  1.50834  3.69445  4.47134  3.05483  4.03152  2.97675  3.09023  2.88240  2.07165  3.77594  5.84089  4.43845     76 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     65   2.78562  2.01948  4.55150  4.07045  3.82424  3.73349  4.63777  2.73929  3.93362  2.80343  3.79417  4.09169  2.08695  4.16452  4.09382  3.13564  3.15495  1.28567  5.38169  4.19434     77 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     66   3.00177  5.48795  1.87629  2.49660  4.83835  3.57687  3.90289  4.32338  1.47116  3.80689  4.58836  3.05453  2.14999  3.02804  3.16908  2.94349  3.25201  3.89612  5.94044  4.52232     78 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     67   2.97021  5.07355  1.83355  2.70799  4.34142  2.06896  4.05903  3.73788  2.99051  1.56224  4.26678  3.22685  4.13776  3.25977  3.46241  3.01746  3.25070  3.43787  5.68476  4.34458     79 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     68   2.80435  4.51738  3.70485  3.17345  3.71222  3.76651  4.10838  1.80977  3.12705  2.73704  3.66708  2.15696  2.34690  3.43898  3.47179  3.04517  3.05888  2.24183  5.18327  3.94621     80 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     69   3.21770  4.57086  4.97188  4.44662  3.86947  4.49942  5.05720  1.47430  4.33664  2.56546  3.72458  4.61110  4.86186  4.58040  4.51238  3.86070  1.54232  1.34555  5.64266  4.43926     81 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     70   2.95708  5.14521  2.99403  1.83121  4.19063  3.63668  3.92702  3.82818  2.78051  3.41772  4.26662  3.17833  1.74182  3.12106  3.22848  2.97355  3.20630  3.50738  5.52563  2.17177     82 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     71   2.81050  4.79261  2.28753  2.03040  2.37706  3.65659  3.90550  2.14897  2.80356  2.99311  3.87365  3.24848  4.06373  3.12317  3.23928  2.91155  3.04567  3.04162  5.32210  4.01594     83 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     72   2.93437  5.03828  3.04311  1.83946  4.30552  1.65755  3.99888  3.68879  2.85177  1.98910  4.20097  3.22855  4.11576  3.18781  3.28771  2.98470  3.19963  3.39021  5.62197  4.29753     84 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     73   2.73902  2.32080  1.99570  2.81784  4.32430  3.51217  4.01811  3.72234  2.87487  3.36392  4.18957  3.27606  1.98571  3.19798  3.31847  2.82453  2.44358  3.35784  5.62280  4.31413     85 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     74   2.87088  4.85397  3.36105  2.86591  4.06081  3.69200  3.97062  2.23427  2.75935  3.04437  3.96579  3.33519  2.30215  1.57203  3.13528  2.97368  3.12105  3.13247  5.42664  4.13968     86 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     75   1.84740  5.71599  1.70450  1.29585  5.04192  3.56048  4.02374  4.54881  2.96239  4.03556  4.84247  3.02480  4.13163  3.16811  3.53263  3.05937  3.42628  4.10758  6.18823  4.70375     87 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     76   3.06953  5.41519  1.80939  1.67828  1.68690  3.60061  3.98096  4.10134  2.91401  3.66294  4.51080  3.08865  4.12438  3.15808  3.43938  3.03000  3.32748  3.75306  5.79034  4.33444     88 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     77   3.03870  5.47436  1.90526  1.29548  4.76783  3.57223  3.95900  4.16399  2.84250  3.75797  4.57501  3.05039  4.09259  3.10162  3.37273  2.98560  3.29722  2.13649  5.96102  4.53077     89 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     78   1.74787  1.64658  4.29549  3.78786  3.51816  3.70291  4.33651  2.97775  3.65907  2.75066  3.68827  3.90525  4.24339  3.90389  3.85120  3.07083  3.08999  2.74475  5.04806  2.07593     90 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     79   2.75948  4.56996  3.79425  3.38335  4.06237  1.91193  4.35624  1.91599  3.36983  3.10692  4.02732  3.67147  1.55829  3.68001  3.68915  2.97218  3.12763  3.01951  5.50730  4.27905     91 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     80   2.84361  5.11662  1.88614  2.55687  4.33854  3.57668  2.26268  3.81219  2.65486  2.21008  4.20214  3.09171  4.01205  2.98715  3.13133  2.39282  3.08430  3.46799  5.59000  4.21533     92 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     81   4.05062  6.09585  0.25016  3.16592  5.63180  4.01455  4.88658  5.44743  4.14657  4.91966  5.97362  3.74150  4.71639  4.16606  4.71915  3.96503  4.42100  5.01815  6.60717  5.45534     93 D - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     82   3.04959  4.58334  4.21832  3.66721  3.55820  4.11355  4.41299  2.59646  3.48731  1.61108  3.47616  3.98523  4.47164  2.16526  3.73518  3.41507  3.28754  1.39698  5.22079  4.02388     94 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     83   1.82715  4.61744  3.67020  3.22382  3.72690  3.63976  4.15441  3.35282  3.20066  3.04408  3.94999  3.56979  2.08621  3.51946  3.54139  2.98757  3.12307  3.07635  5.20580  1.61753     95 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     84   2.90062  4.56201  3.71550  2.09080  3.49327  3.86304  4.08810  1.59101  3.18089  2.67620  3.64335  3.61449  4.25289  3.49651  3.50065  3.15073  3.13529  2.70012  5.01515  2.15048     96 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     85   2.86216  4.89215  3.16897  1.91855  4.11409  3.63867  3.95829  3.48538  2.81326  1.65439  4.02074  3.25472  4.09032  3.16123  3.23386  1.94184  3.11683  3.21094  5.46706  4.16201     97 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     86   3.02911  2.20051  1.43610  1.72118  4.75550  3.57025  3.97871  4.20820  2.86443  3.76403  4.57605  3.07440  4.09745  3.12563  3.38808  2.98631  3.29630  3.81727  5.95041  4.53316     98 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     87   2.95229  5.31841  3.20763  2.65443  4.67641  2.24293  2.35827  4.11573  2.37176  3.59677  4.38392  3.16553  4.07082  2.08202  1.87641  2.92797  3.16779  3.72847  5.70861  4.38173     99 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     88   0.89304  4.83593  3.52252  3.21237  4.28827  3.57365  1.98662  3.92815  3.18973  3.57384  4.45958  3.56834  4.20309  3.58992  3.52232  3.01049  3.26669  3.54231  5.67260  4.31414    100 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     89   3.32897  5.98995  1.59036  1.21041  5.29223  1.85016  4.13193  4.84216  3.17456  4.29824  5.13981  3.02434  4.20540  3.29334  3.80439  3.19395  3.62119  4.37723  6.44195  4.89720    101 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     90   2.86612  5.04422  3.04967  1.53080  4.31043  3.59969  3.90678  3.70979  2.72310  2.13413  4.17356  3.16516  4.05445  3.07158  3.17171  1.93423  3.11943  3.39271  5.59276  4.25151    102 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     91   2.33839  2.33319  3.66936  2.51274  3.71047  3.68123  4.05819  3.02481  3.07985  2.77576  3.67017  3.50531  2.35114  3.38402  3.43065  2.95965  3.00527  2.02342  5.15389  3.92054    103 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     92   2.77841  4.71648  3.50561  3.12657  4.00129  1.51312  4.19518  3.69627  3.18257  3.34991  4.21891  3.49374  4.13113  3.49456  3.56191  1.76331  3.14172  3.34204  5.43765  2.07352    104 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     93   2.80900  4.65790  3.51214  3.01139  3.79431  3.68037  2.38933  2.16836  2.94391  2.94776  3.84277  3.43128  4.12697  3.30452  3.30672  1.48154  3.07555  2.99103  5.22365  3.91367    105 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     94   3.04847  1.50371  1.61592  2.10236  4.66715  3.58851  4.05112  4.08665  2.97076  3.69723  4.53735  3.13921  4.13665  3.22062  3.48126  3.03480  3.33057  3.72643  5.91738  4.53055    106 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     95   1.88410  4.65574  3.78265  3.20892  3.82389  3.79819  4.09423  3.12221  2.89200  1.51545  3.75540  3.58503  4.21920  3.38078  2.03442  3.09778  3.14791  2.92061  5.27033  4.04785    107 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     96   1.54090  4.57715  3.92273  3.65745  4.90631  1.66510  4.74228  4.35275  3.75572  4.01671  4.81278  3.76174  1.32436  4.00941  4.06725  2.79701  3.13028  3.70679  6.22047  5.03095    108 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     97   2.97420  5.05368  3.30132  2.83355  4.07677  2.15834  3.92294  3.75113  1.76958  3.34315  4.20275  3.31006  4.15184  3.13365  2.98906  3.02497  3.21508  3.44631  5.40486  1.71904    109 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     98   2.82535  4.57572  4.10028  3.71301  4.03925  3.66632  4.58086  1.72884  3.64091  3.01747  4.04865  3.90026  4.29816  3.95980  3.90549  0.98108  3.22247  2.79320  5.58742  4.33006    110 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+     99   1.43514  0.82892  4.80681  4.58666  4.69417  3.39195  5.16406  3.80758  4.43086  3.75239  4.68183  4.17266  4.21161  4.63066  4.50594  2.88757  3.18548  3.35323  6.15457  5.03517    111 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    100   2.82498  4.95715  3.40974  2.94255  4.70228  1.94565  4.08107  4.14251  2.73685  3.69574  4.49749  3.36420  4.09658  3.23391  1.46522  1.83152  3.16614  3.68558  5.84898  4.56169    112 r - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    101   1.10475  4.52228  4.11576  3.83581  4.96435  1.64082  4.84380  4.42439  3.89199  4.08943  4.86937  3.83086  4.09259  4.12724  4.17193  1.57246  3.10246  3.72147  6.28518  5.11952    113 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    102   1.43394  1.83402  4.58768  4.30129  4.75045  1.21055  5.01466  4.12708  4.21833  3.87731  4.70556  4.01744  4.11929  4.41365  4.36995  2.77887  3.09436  3.53695  6.15056  5.02931    114 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    103   1.63449  4.47604  4.14466  3.71946  4.28385  3.44523  4.59529  3.45965  3.67241  3.33633  4.23051  3.81973  4.14313  3.94095  3.94969  1.28973  3.08609  1.71945  5.72686  4.53067    115 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    104   2.83251  1.48569  1.76496  3.05212  4.63546  1.87091  4.34311  4.05699  3.30285  3.71503  4.55202  3.45874  4.14769  3.56082  3.73402  2.94445  3.23212  3.61792  5.93755  4.65533    116 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    105   2.96957  5.32904  3.14366  2.65593  4.72494  3.66151  3.84186  4.16441  1.75186  3.64779  4.43821  3.16888  4.08411  1.93241  2.79580  1.59020  3.19856  3.76805  5.76348  4.43156    117 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    106   2.66373  4.49207  4.03296  3.57936  4.18285  3.48606  4.48323  3.36835  3.52695  3.23079  4.12951  3.75581  4.14350  3.81520  3.82610  1.34147  1.75798  1.80637  5.62511  4.41600    118 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    107   2.74792  1.62573  1.91234  3.05734  4.31516  3.50848  4.22275  3.63214  3.15497  3.36887  4.23026  3.44805  4.10111  3.45245  3.56167  2.88548  1.89159  3.28014  5.67623  4.40213    119 c - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    108   0.68941  4.56331  4.20169  4.04692  5.05279  1.58716  5.03141  4.47978  4.15844  4.19817  5.00681  3.95737  4.16246  4.36890  4.37009  2.84226  3.19149  3.77919  6.37750  5.25838    120 A - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    109   3.02964  5.08328  3.17150  3.12104  5.13170  0.81179  4.59407  4.73207  3.60754  4.31434  5.15959  1.65030  4.27627  3.83105  4.02354  3.11995  3.49284  4.12591  6.35429  5.05698    121 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    110   2.85780  4.78493  3.46807  2.92281  2.21689  3.71308  3.94679  3.34785  1.56806  3.01008  3.90816  3.37147  4.12450  3.18495  3.10090  2.97945  2.06570  3.09328  5.28703  3.97445    122 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    111   3.56792  4.79047  5.56843  5.05882  3.83185  5.08010  5.63680  1.72792  4.96256  1.47356  3.59353  5.21772  5.28003  5.11439  5.06846  4.48190  3.81459  0.88361  5.91262  4.77603    123 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    112   2.34885  4.88546  1.50680  2.76582  4.28202  3.57605  3.99821  3.49749  2.86169  3.28542  4.14261  3.25275  4.06485  3.17747  3.31619  2.88335  2.45367  2.13395  5.60583  4.28774    124 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    113   2.37560  5.43186  1.88002  2.44821  4.76975  2.31003  3.85108  4.26118  2.66530  3.74586  4.51061  2.44214  4.01416  2.00579  3.18288  2.86422  3.16817  3.82620  5.88838  4.45514    125 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    114   3.02825  5.34001  1.64973  2.62556  5.04958  1.43770  4.18261  4.55907  3.15840  4.08500  4.89492  3.15845  4.14205  3.34808  3.70413  1.79379  3.38532  4.04813  6.24427  4.81118    126 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    115   2.43421  5.39468  1.99800  2.11130  4.72686  3.53375  3.80066  4.21905  2.58750  3.69532  4.44801  2.47018  3.98139  1.98470  3.09824  2.34600  3.10833  3.78019  5.82949  4.40030    127 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    116   2.94597  4.44901  4.44561  3.93108  3.62623  2.15331  4.54520  2.49864  3.80946  1.67061  3.57798  4.11336  4.45736  4.06092  4.00094  3.35990  3.23101  1.30872  5.24560  4.04661    128 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    117   3.07108  5.65983  1.61666  1.64591  4.97722  3.55644  3.94110  4.49006  1.85258  3.95163  4.73218  2.37323  4.08443  3.06951  3.35115  2.98315  3.32751  4.04015  6.08373  4.61352    129 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    118   2.90641  5.14851  3.03065  1.82407  2.34336  3.62785  3.86089  3.81266  2.66227  3.36932  4.21751  3.14311  4.06155  1.65090  3.10716  2.91351  3.14323  3.49036  5.52105  4.11540    130 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    119   2.76255  4.86202  3.19852  2.29238  4.13565  2.23517  3.86729  3.53680  2.70242  2.16346  4.00273  3.18654  4.00924  3.04372  3.14909  2.07641  2.54383  3.22686  5.44173  4.12929    131 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    120   3.57941  5.58171  0.75523  3.12318  4.02169  3.96847  4.37908  4.42174  3.52990  3.92216  4.91170  3.63855  4.53554  3.76654  3.97529  3.57745  3.86789  4.12842  1.75169  3.95153    132 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    121   2.91174  5.02616  1.86612  2.75649  4.50983  1.54341  4.12514  3.82111  3.05693  3.54399  4.40141  3.25444  4.12333  3.31620  3.53368  2.97056  3.23532  1.93277  5.82328  4.48241    133 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    122   2.86459  5.20437  2.00723  2.52234  4.49985  3.55603  3.85351  3.95142  2.67319  2.15274  4.30753  2.15442  4.01247  2.99055  3.16622  2.05025  3.11283  3.57971  5.70819  4.32388    134 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    123   2.86858  4.64306  3.62963  3.12613  1.70785  3.76769  4.03967  3.15671  3.04812  2.80119  3.75818  3.52490  4.19369  2.11823  3.38968  3.05795  1.97932  2.94141  5.07338  3.71197    135 f - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    124   2.87729  2.25286  3.84987  2.10126  3.62200  3.85343  4.19223  2.84299  3.24572  1.47166  3.58556  3.69315  4.26287  3.56918  3.54313  3.15439  3.12814  2.66630  5.14969  3.92844    136 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    125   1.87554  4.89400  1.55330  2.83635  4.32557  3.59793  4.10822  3.41524  3.01358  3.31001  4.20357  3.31594  4.12580  3.30435  3.46699  2.95750  3.16753  1.90970  5.68921  4.37289    137 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    126   1.31978  5.65673  1.53971  2.00100  5.00455  3.56144  4.04702  4.49528  2.99731  4.00710  4.82437  3.04396  4.14090  3.19815  3.56394  3.06909  3.43192  4.06642  6.17533  4.70374    138 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    127   2.99154  5.46776  1.93424  1.79632  4.74629  2.13218  3.90636  4.24433  2.76518  3.75551  4.54564  3.02592  4.05721  3.04023  3.29236  2.93391  3.24309  3.83702  5.91396  2.21504    139 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    128   2.90782  4.87069  3.38284  2.90818  2.18962  3.72084  3.95729  3.47130  2.86207  3.05902  3.98760  3.36869  2.19368  1.63399  3.25068  3.00729  3.16046  3.21829  5.19587  3.77282    140 q - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    129   2.80387  4.50973  3.68288  2.53916  3.64508  3.79101  4.04638  2.09044  3.05762  2.30112  3.59386  3.52646  4.16714  2.16471  3.40576  3.04110  3.03585  1.93346  5.11678  3.88419    141 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    130   2.33816  4.92974  3.14216  1.79211  4.20735  3.58332  3.86460  3.60039  2.68643  2.17242  4.06142  3.16489  4.01325  3.03072  3.13839  1.97098  3.03629  3.28400  5.49619  4.17164    142 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    131   2.04954  5.30098  1.94774  2.15701  4.64724  2.73655  3.83132  4.12007  2.63294  3.63223  4.40230  3.02948  3.99372  2.95114  3.13793  2.82654  2.09314  3.70436  5.79378  4.38447    143 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    132   2.67461  1.98295  4.54536  4.13152  4.08175  1.38240  4.74089  3.14924  4.01069  3.12077  4.06082  4.04085  4.22311  4.23030  4.16807  2.96147  3.11654  1.64169  5.59063  4.41633    144 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    133   2.83984  4.25742  4.52040  3.93471  2.15049  3.96796  4.23092  2.63475  3.77248  2.37225  3.34682  4.03138  4.33444  3.94714  3.87337  3.27306  1.99292  1.78236  2.52955  3.47977    145 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    134   1.94019  4.61061  5.17838  4.67117  3.96915  4.65508  5.28276  1.37973  4.57265  2.60668  3.79310  4.80809  5.00205  4.81289  4.73487  4.03650  3.57041  1.05280  5.80976  4.59927    146 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    135   2.95269  4.69517  3.60665  1.97843  3.45446  3.85775  4.03090  3.11104  3.08550  1.51175  3.71657  3.54821  4.25024  3.42171  3.42726  3.14413  3.18521  2.92923  4.99169  2.16477    147 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    136   2.73695  4.65605  3.95869  3.70106  4.76353  3.44035  4.74373  4.12362  3.71195  3.84701  4.72350  3.83266  1.83108  4.03586  3.98938  2.92296  0.79061  3.61700  6.10688  4.92055    148 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    137   2.98616  1.77306  3.54257  2.96917  4.20397  3.77066  2.12431  3.65954  1.76469  3.27311  4.13902  3.40552  4.18321  3.14102  2.82770  3.07008  3.21991  3.37163  5.45841  4.17830    149 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    138   2.87318  2.27487  4.08101  3.51686  3.73262  3.86520  4.28384  2.71684  1.98443  2.72135  3.68760  3.80830  4.30540  3.67099  3.52284  3.18558  3.14569  1.41553  5.23503  4.02368    150 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    139   1.47784  5.66115  1.72234  1.61325  4.99518  3.55917  4.01510  4.49306  2.94403  3.99053  4.79675  3.03102  4.12373  3.15930  3.50625  3.04342  3.40107  4.05871  6.14898  4.67614    151 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    140   1.90208  4.30196  4.42388  3.85048  2.53064  3.96808  4.20458  2.66664  3.71202  2.43952  3.40720  3.98922  4.33968  3.90366  3.85104  3.27006  3.09799  1.78444  4.75310  1.94066    152 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    141   2.90716  5.18104  2.93680  1.74324  4.63204  3.55056  3.97551  4.06458  2.79684  3.63682  4.44671  3.14754  1.69442  3.12392  3.26513  2.91368  2.00011  3.66927  5.83669  4.46781    153 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    142   2.78359  4.49365  3.67376  3.10170  3.62714  3.76072  4.00455  2.07844  2.47123  1.90888  3.58652  3.50028  4.13823  2.73193  3.32251  3.01272  2.16843  2.73906  5.07658  3.84773    154 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    143   2.78538  4.94129  3.12446  1.90128  4.30138  2.71211  3.90968  3.70356  2.74123  3.32793  4.14951  3.17742  4.01886  3.07350  3.19942  1.81320  3.05695  2.10287  5.57786  4.24807    155 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01431  4.64966  5.37201  0.61958  0.77255  0.48576  0.95510
+    144   3.00331  5.31213  1.34717  2.61563  4.93207  1.88993  4.12688  4.41067  3.06726  3.95757  4.76779  3.14959  4.12417  3.28737  3.59771  2.99405  1.91587  3.94167  6.13257  4.71628    156 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.24219  4.64967  1.58216  0.61958  0.77255  0.48576  0.95510
+    145   2.90502  4.57765  3.77724  3.34069  3.46532  3.78667  1.98962  2.88032  3.15748  2.73793  3.75784  3.66796  4.25545  3.57022  3.42567  3.15372  3.18669  1.26808  5.01387  3.61579    157 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    146   2.75147  4.74628  3.34357  2.80400  4.07335  3.57581  3.87957  3.30949  1.78780  3.06148  3.94193  3.25653  4.01680  3.07201  2.96883  2.85636  1.75071  2.41258  5.38823  4.11449    158 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    147   3.00773  4.73948  3.43003  1.82450  3.89452  3.85717  4.23450  1.28531  3.14323  2.70935  3.80542  3.55715  4.30487  3.50591  3.49765  3.23918  3.26469  2.47035  5.46041  4.19035    159 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    148   3.57591  5.69104  2.89034  0.43897  5.13067  3.74172  4.42582  4.71128  3.39211  4.24880  5.23832  3.41868  4.38352  3.65470  3.83330  3.52091  3.89687  4.34990  6.18698  4.96489    160 E - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    149   2.88350  5.07456  2.83549  1.62789  4.53394  3.47506  3.97205  3.88890  2.80700  3.53770  4.39728  3.11273  4.03065  3.14364  3.24643  2.90638  1.35985  3.52987  5.77718  4.42810    161 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    150   3.16212  4.85727  3.80335  3.36209  3.16774  3.96001  1.35846  3.22944  3.06257  1.59155  3.82989  3.70773  4.37953  3.54897  3.31681  3.33732  3.40874  3.10705  4.77246  3.24032    162 h - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    151   2.94073  5.06198  3.33349  2.84187  4.57011  3.62118  3.89060  3.90975  1.20057  3.49273  4.35032  3.28330  4.09402  3.04189  2.67455  2.98263  1.83732  3.56058  5.65563  4.40287    163 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01794  4.42541  5.14776  0.61958  0.77255  0.82155  0.57937
+    152   1.71060  5.15430  2.74244  1.20101  4.65798  3.45089  3.98759  4.03463  2.85903  3.66257  4.51252  3.07555  4.02822  3.15387  3.33026  2.91028  3.22047  3.64649  5.88103  4.50506    164 e - - -
+          2.68526  4.42272  2.77529  2.72949  3.46401  2.40536  3.72542  3.29401  2.67788  2.69262  4.24737  2.90394  2.73787  3.18194  2.89848  2.37934  2.77449  2.98523  4.58524  3.61550
+          0.55049  0.85960        *  1.51709  0.24763  0.00000        *
+//
diff --git a/test/jalview/io/HMMFileTest.java b/test/jalview/io/HMMFileTest.java
new file mode 100644 (file)
index 0000000..cf74f55
--- /dev/null
@@ -0,0 +1,531 @@
+package jalview.io;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import jalview.datamodel.HMMNode;
+import jalview.datamodel.HiddenMarkovModel;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+public class HMMFileTest {
+
+  HMMFile fn3;
+
+  HMMFile pKinase;
+
+  HMMFile made1;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUp() throws IOException
+  {
+    fn3 = new HMMFile("test/jalview/io/test_fn3_hmm.txt",
+            DataSourceType.FILE);
+
+    pKinase = new HMMFile("test/jalview/io/test_PKinase_hmm.txt",
+            DataSourceType.FILE);
+
+    made1 = new HMMFile("test/jalview/io/test_MADE1_hmm.txt",
+            DataSourceType.FILE);
+  }
+
+  @Test(groups = "Functional")
+  public void testParse() throws IOException
+  {
+    HiddenMarkovModel hmm = pKinase.getHMM();
+    assertEquals(hmm.getName(), "Pkinase");
+    assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER), "PF00069.17");
+    assertEquals(hmm.getProperty(HMMFile.DESCRIPTION),
+            "Protein kinase domain");
+    assertEquals(hmm.getLength(), 260);
+    assertNull(hmm.getProperty(HMMFile.MAX_LENGTH));
+    assertEquals(hmm.getAlphabetType(), "amino");
+    assertFalse(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION));
+    assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.MAP));
+    assertEquals(hmm.getProperty(HMMFile.DATE), "Thu Jun 16 11:44:06 2011");
+    assertNull(hmm.getProperty(HMMFile.COMMAND_LOG));
+    assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "54");
+    assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES),
+            "3.358521");
+    assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3106786190");
+    assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD),
+            "70.30 70.30");
+    assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "70.30 70.30");
+    assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "70.20 70.20");
+  
+    assertEquals(hmm.getSymbols(), "ACDEFGHIKLMNPQRSTVWY");
+  
+    assertEquals(hmm.getMatchEmissionProbability(0, 'Y'), 0.16102, 0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(11, 'P'), 0.0130, 0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(24, 'I'), 0.02583, 0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(83, 'C'), 0.008549,
+            0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(332, 'E'), 0.07998,
+            0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(381, 'D'), 0.014465,
+            0.001d);
+    assertEquals(hmm.getMatchEmissionProbability(475, 'Y'), 0.02213,
+            0.001d);
+  
+    assertEquals(hmm.getInsertEmissionProbability(1, 'C'), 0.012, 0.001d);
+    assertEquals(hmm.getInsertEmissionProbability(14, 'H'), 0.02411,
+            0.001d);
+    assertEquals(hmm.getInsertEmissionProbability(23, 'L'), 0.06764,
+            0.001d);
+    assertEquals(hmm.getInsertEmissionProbability(90, 'D'), 0.0623, 0.001d);
+    assertEquals(hmm.getInsertEmissionProbability(374, 'T'), 0.0623,
+            0.001d);
+    assertEquals(hmm.getInsertEmissionProbability(470, 'P'), 0.0647,
+            0.001d);
+  
+    assertEquals(hmm.getStateTransitionProbability(2, 6), 0.3848, 0.001d);
+    assertEquals(hmm.getStateTransitionProbability(38, 3), 0.5382, 0.001d);
+    assertEquals(hmm.getStateTransitionProbability(305, 3), 0.2916, 0.001d);
+    assertEquals(hmm.getStateTransitionProbability(380, 0), 0.99, 0.001d);
+    assertEquals(hmm.getStateTransitionProbability(453, 1), 0.0066, 0.001d);
+  
+    assertEquals(hmm.getNodeMapPosition(3), 3);
+    assertEquals(hmm.getReferenceAnnotation(7), '-');
+    assertEquals(hmm.getConsensusResidue(23), 't');
+    assertEquals(hmm.getMaskedValue(30), '-');
+    assertEquals(hmm.getConsensusStructure(56), 'S');
+  
+    assertEquals(hmm.getNodeMapPosition(78), 136);
+    assertEquals(hmm.getReferenceAnnotation(93), '-');
+    assertEquals(hmm.getConsensusResidue(145), 'a');
+    assertEquals(hmm.getMaskedValue(183), '-');
+    assertEquals(hmm.getConsensusStructure(240), 'H');
+  }
+
+  /**
+   * Test that Jalview can parse an HMM file even with a bunch of 'mandatory'
+   * fields missing (including no MAP annotation or // terminator line)
+   * 
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testParse_minimalFile() throws IOException
+  {
+    /*
+     * ALPH is absent, alphabet inferred from HMM header line
+     * Optional COMPO line is absent
+     * first line after HMM is a guide line for readability
+     * next line is BEGIN node insert emissions
+     * next line is BEGIN node transitions
+     * next line is first sequence node match emissions 1.1 1.2 1.3
+     * next line is first sequence node insert emissions 1.4 1.5 1.6
+     * last line is first sequence node transitions
+     */
+    //@formatter:off
+    String hmmData = 
+            "HMMER3\n" +
+            "HMM P M J\n" +
+            // both spec and parser require a line after the HMM line
+            " m->m m->i m->d i->m i->i d->m d->d\n" +
+            " 0.1 0.2 0.3\n" + 
+            " 0.4 0.5 0.6 0.7 0.8 0.9 0.95\n" + 
+            " 1 1.1 1.2 1.3 - - - - -\n" + 
+            " 1.4 1.5 1.6\n" + 
+            " 1.7 1.8 1.9 2.0 2.1 2.2 2.3\n" +
+            " 2 1.01 1.02 1.03 - - - - -\n" + 
+            " 1.04 1.05 1.06\n" + 
+            " 1.7 1.8 1.9 2.0 2.1 2.2 2.3\n";
+    //@formatter:on
+    HMMFile parser = new HMMFile(hmmData, DataSourceType.PASTE);
+    HiddenMarkovModel hmm = parser.getHMM();
+    assertNotNull(hmm);
+    assertEquals(hmm.getSymbols(), "PMJ");
+    // no LENG property: this should return node count excluding BEGIN node
+    assertEquals(hmm.getLength(), 2);
+
+    // node 1 (implicitly mapped to column 0)
+    double prob = hmm.getMatchEmissionProbability(0, 'p');
+    assertEquals(prob, Math.pow(Math.E, -1.1));
+    prob = hmm.getInsertEmissionProbability(0, 'J');
+    assertEquals(prob, Math.pow(Math.E, -1.6));
+
+    // node 2 (implicitly mapped to column 1)
+    prob = hmm.getMatchEmissionProbability(1, 'M');
+    assertEquals(prob, Math.pow(Math.E, -1.02));
+    prob = hmm.getInsertEmissionProbability(1, 'm');
+    assertEquals(prob, Math.pow(Math.E, -1.05));
+  }
+  
+  @Test(groups = "Functional")
+  public void testParseHeaderLines_amino() throws IOException
+  {
+    FileReader fr = new FileReader(
+            new File("test/jalview/io/test_fn3_hmm.txt"));
+    BufferedReader br = new BufferedReader(fr);
+    HiddenMarkovModel hmm = new HiddenMarkovModel();
+    HMMFile testee = new HMMFile();
+    PA.setValue(testee, "hmm", hmm);
+    testee.parseHeaderLines(br);
+    br.close();
+    fr.close();
+  
+    assertEquals(hmm.getName(), "fn3");
+    assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER), "PF00041.13");
+    assertEquals(hmm.getProperty(HMMFile.DESCRIPTION),
+            "Fibronectin type III domain");
+    assertEquals(hmm.getProperty(HMMFile.LENGTH), "86");
+    assertNull(hmm.getProperty(HMMFile.MAX_LENGTH));
+    assertEquals(hmm.getAlphabetType(), "amino");
+    assertFalse(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION));
+    assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE));
+
+    assertTrue(hmm.getBooleanProperty(HMMFile.MAP));
+    assertEquals(hmm.getProperty(HMMFile.DATE), "Fri Jun 20 08:22:31 2014");
+    assertNull(hmm.getProperty(HMMFile.COMMAND_LOG));
+    assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "106");
+    assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES),
+            "11.415833");
+    assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3564431818");
+    assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD), "8.00 7.20");
+    assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "8.00 7.20");
+    assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "7.90 7.90");
+    assertEquals(hmm.getViterbi(), "-9.7737  0.71847");
+    assertEquals(hmm.getMSV(), "-9.4043  0.71847");
+    assertEquals(hmm.getForward(), "-3.8341  0.71847");
+  }
+  
+  @Test(groups = "Functional")
+  public void testParseHeaderLines_dna() throws IOException
+  {
+    FileReader fr = new FileReader(
+            new File("test/jalview/io/test_MADE1_hmm.txt"));
+    BufferedReader br = new BufferedReader(fr);
+    HiddenMarkovModel hmm = new HiddenMarkovModel();
+    HMMFile testee = new HMMFile();
+    PA.setValue(testee, "hmm", hmm);
+    testee.parseHeaderLines(br);
+    br.close();
+    fr.close();
+  
+    assertEquals(hmm.getName(), "MADE1");
+    assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER),
+            "DF0000629.2");
+    assertEquals(hmm.getProperty(HMMFile.DESCRIPTION),
+            "MADE1 (MAriner Derived Element 1), a TcMar-Mariner DNA transposon");
+    assertEquals(hmm.getProperty(HMMFile.LENGTH), "80");
+    assertEquals(hmm.getProperty(HMMFile.MAX_LENGTH), "426");
+    assertEquals(hmm.getAlphabetType(), "DNA");
+    assertTrue(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION));
+    assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE));
+    assertFalse(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE));
+    assertTrue(hmm.getBooleanProperty(HMMFile.MAP));
+    assertEquals(hmm.getProperty(HMMFile.DATE), "Tue Feb 19 20:33:41 2013");
+    assertNull(hmm.getProperty(HMMFile.COMMAND_LOG));
+    assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "1997");
+    assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), "3.911818");
+    assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3015610723");
+    assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD),
+            "2.324 4.234");
+    assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "2.343 1.212");
+    assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "2.354 5.456");
+    assertEquals(hmm.getViterbi(), "-9.3632  0.71858");
+    assertEquals(hmm.getMSV(), "-8.5786  0.71858");
+    assertEquals(hmm.getForward(), "-3.4823  0.71858");
+  }
+  
+  @Test(groups = "Functional")
+  public void testFillList() throws IOException
+  {
+    Scanner scanner1 = new Scanner("1.3 2.4 5.3 3.9 9.8 4.7 4.3 2.3 6.9");
+    ArrayList<Double> filledArray = new ArrayList<>();
+  
+    filledArray.add(0.27253);
+    filledArray.add(0.0907);
+    filledArray.add(0.00499);
+    filledArray.add(0.02024);
+    filledArray.add(0.00005);
+    filledArray.add(0.00909);
+    filledArray.add(0.01357);
+    filledArray.add(0.10026);
+    filledArray.add(0.001);
+  
+    double[] testList = HMMFile.parseDoubles(scanner1, 9);
+
+    for (int i = 0; i < 9; i++)
+    {
+      assertEquals(testList[i], filledArray.get(i), 0.001d);
+    }
+
+    filledArray.clear();
+    scanner1.close();
+  
+    Scanner scanner2 = new Scanner(
+            "1.346 5.554 35.345 5.64 1.4");
+    filledArray.add(0.2603);
+    filledArray.add(0.00387);
+    filledArray.add(0d);
+    filledArray.add(0.00355);
+    filledArray.add(0.2466);
+  
+    testList = HMMFile.parseDoubles(scanner2, 5);
+
+    for (int i = 0; i < 5; i++)
+    {
+      assertEquals(testList[i], filledArray.get(i), 0.001d);
+    }
+  }
+  
+  @Test(groups = "Functional")
+  public void testParseModel() throws IOException
+  {
+    FileReader fr = new FileReader(
+            new File("test/jalview/io/test_MADE1_hmm.txt"));
+    BufferedReader br = new BufferedReader(fr);
+    HiddenMarkovModel testHMM = new HiddenMarkovModel();
+    String line = null;
+    do
+    {
+      line = br.readLine(); // skip header lines up to HMM plus one
+    } while (!line.startsWith("HMM "));
+    br.readLine();
+
+    made1.parseModel(br);
+    testHMM = made1.getHMM();
+
+    br.close();
+    fr.close();
+  
+    assertEquals(testHMM.getMatchEmissionProbability(1, 'C'), 0.09267,
+            0.001d);
+    assertEquals(testHMM.getMatchEmissionProbability(25, 'G'), 0.07327,
+            0.001d);
+    assertEquals(testHMM.getMatchEmissionProbability(1092, 'C'), 0.04184,
+            0.001d);
+    assertEquals(testHMM.getMatchEmissionProbability(1107, 'G'), 0.07,
+            0.001d);
+  
+    assertEquals(testHMM.getInsertEmissionProbability(0, 'G'), 0.25,
+            0.001d);
+    assertEquals(testHMM.getInsertEmissionProbability(247, 'T'), 0.2776,
+            0.001d);
+    assertEquals(testHMM.getInsertEmissionProbability(1096, 'T'), 0.25,
+            0.001d);
+    assertEquals(testHMM.getInsertEmissionProbability(1111, 'T'), 0.25,
+            0.001d);
+
+    assertEquals(testHMM.getStateTransitionProbability(1, 0), 0.9634,
+            0.001d);
+    assertEquals(testHMM.getStateTransitionProbability(5, 1), 0.0203,
+            0.001d);
+    assertEquals(testHMM.getStateTransitionProbability(14, 3), 0.2515,
+            0.001d);
+    assertEquals(testHMM.getStateTransitionProbability(65, 4), 0.78808,
+            0.001d);
+    assertEquals(testHMM.getStateTransitionProbability(1080, 2), 0.01845,
+            0.001d);
+    assertEquals(testHMM.getStateTransitionProbability(1111, 6),
+            Double.NEGATIVE_INFINITY);
+  }
+  
+  @Test(groups = "Functional")
+  public void testParseAnnotations()
+  {
+    HMMFile testFile = new HMMFile();
+    HiddenMarkovModel hmm = new HiddenMarkovModel();
+    PA.setValue(testFile, "hmm", hmm);
+
+    List<HMMNode> nodes = new ArrayList<>();
+    nodes.add(new HMMNode()); // BEGIN node
+  
+    hmm.setProperty(HMMFile.CONSENSUS_RESIDUE, "yes");
+    hmm.setProperty(HMMFile.MAP, "yes");
+    hmm.setProperty(HMMFile.REFERENCE_ANNOTATION, "yes");
+    hmm.setProperty(HMMFile.CONSENSUS_STRUCTURE, "yes");
+    hmm.setProperty(HMMFile.MASKED_VALUE, "yes");
+    Scanner scanner = new Scanner("1345 t t t t");
+    HMMNode node = new HMMNode();
+    nodes.add(node);
+    testFile.parseAnnotations(scanner, node);
+  
+    hmm.setProperty(HMMFile.CONSENSUS_RESIDUE, "yes");
+    hmm.setProperty(HMMFile.MAP, "no");
+    hmm.setProperty(HMMFile.REFERENCE_ANNOTATION, "yes");
+    hmm.setProperty(HMMFile.CONSENSUS_STRUCTURE, "no");
+    hmm.setProperty(HMMFile.MASKED_VALUE, "no");
+    Scanner scanner2 = new Scanner("- y x - -");
+    node = new HMMNode();
+    nodes.add(node);
+    testFile.parseAnnotations(scanner2, node);
+
+    hmm.setNodes(nodes);
+
+    assertEquals(hmm.getNodeMapPosition(1), 1345);
+    assertEquals(hmm.getConsensusResidue(1), 't');
+    assertEquals(hmm.getReferenceAnnotation(1), 't');
+    assertEquals(hmm.getMaskedValue(1), 't');
+    assertEquals(hmm.getConsensusStructure(1), 't');
+  
+    scanner.close();
+  }
+  
+  /**
+   * tests to see if file produced by the output matches the file from the input
+   * 
+   * @throws IOException
+   */
+  @Test(groups = "Functional")
+  public void testPrint_roundTrip() throws IOException
+  {
+    String output = pKinase.print();
+    HMMFile pKinaseClone = new HMMFile(
+            new FileParse(output, DataSourceType.PASTE));
+    HiddenMarkovModel pKinaseHMM = pKinase.getHMM();
+    HiddenMarkovModel pKinaseCloneHMM = pKinaseClone.getHMM();
+  
+    checkModelsMatch(pKinaseHMM, pKinaseCloneHMM);
+  }
+
+  /**
+   * A helper method to check two HMM models have the same values
+   * 
+   * @param model1
+   * @param model2
+   */
+  protected void checkModelsMatch(HiddenMarkovModel model1,
+          HiddenMarkovModel model2)
+  {
+    assertEquals(model1.getLength(), model2.getLength());
+
+    for (int i = 0; i < model1.getLength(); i++)
+    {
+      String msg = "For Node" + i;
+      assertEquals(model1.getNode(i).getMatchEmissions(),
+              model2.getNode(i).getMatchEmissions(), msg);
+      assertEquals(model1.getNode(i).getInsertEmissions(),
+              model2.getNode(i).getInsertEmissions(), msg);
+      assertEquals(model1.getNode(i).getStateTransitions(),
+              model2.getNode(i).getStateTransitions(), msg);
+  
+      if (i > 0)
+      {
+        assertEquals(model1.getNodeMapPosition(i),
+                model2.getNodeMapPosition(i), msg);
+        assertEquals(model1.getReferenceAnnotation(i),
+                model2.getReferenceAnnotation(i), msg);
+        assertEquals(model1.getConsensusResidue(i),
+                model2.getConsensusResidue(i), msg);
+      }
+    }
+  }
+  
+  @Test(groups = "Functional")
+  public void testAppendProperties() throws FileNotFoundException
+  {
+    StringBuilder sb = new StringBuilder();
+    fn3.appendProperties(sb);
+
+    Scanner testScanner = new Scanner(sb.toString());
+  
+    String[] expected = new String[] { "HMMER3/f [3.1b1 | May 2013]",
+        "NAME  fn3", "ACC   PF00041.13",
+        "DESC  Fibronectin type III domain", "LENG  86", "ALPH  amino",
+        "RF    no", "MM    no", "CONS  yes", "CS    yes", "MAP   yes",
+        "DATE  Fri Jun 20 08:22:31 2014", "NSEQ  106", "EFFN  11.415833",
+        "CKSUM 3564431818", "GA    8.00 7.20", "TC    8.00 7.20",
+        "NC    7.90 7.90", "STATS LOCAL MSV       -9.4043  0.71847",
+        "STATS LOCAL VITERBI   -9.7737  0.71847",
+        "STATS LOCAL FORWARD   -3.8341  0.71847" };
+  
+    for (String value : expected)
+    {
+      assertEquals(testScanner.nextLine(), value);
+    }
+  
+    testScanner.close();
+  }
+  
+  @Test(groups = "Functional")
+  public void testAppendModelAsString() throws FileNotFoundException
+  {
+    StringBuilder sb = new StringBuilder();
+    fn3.appendModelAsString(sb);
+    String string = sb.toString();
+
+    assertEquals(findValue(2, 2, 2, string), "4.42225");
+    assertEquals(findValue(12, 14, 1, string), "2.79307");
+    assertEquals(findValue(6, 24, 3, string), "0.48576");
+    assertEquals(findValue(19, 33, 2, string), "4.58477");
+    assertEquals(findValue(20, 64, 2, string), "3.61505");
+    assertEquals(findValue(3, 72, 3, string), "6.81068");
+    assertEquals(findValue(10, 80, 2, string), "2.69355");
+    assertEquals(findValue(16, 65, 1, string), "2.81003");
+    assertEquals(findValue(14, 3, 1, string), "2.69012");
+    assertEquals(findValue(11, 32, 1, string), "4.34805");
+  }
+  
+  /**
+   * A helper method to find a token in the model string
+   * 
+   * @param symbolIndex
+   *          index of symbol being searched. First symbol has index 1.
+   * @param nodeIndex
+   *          index of node being searched. Begin node has index 0. First node
+   *          has index 1.
+   * @param line
+   *          index of line being searched in node. First line has index 1.
+   * @param model
+   *          string model being searched
+   * @return value at specified position
+   */
+  private String findValue(int symbolIndex, int nodeIndex, int line,
+          String model)
+  {
+    String value = "";
+    Scanner scanner = new Scanner(model);
+    scanner.nextLine();
+    scanner.nextLine();
+  
+    for (int lineIndex = 0; lineIndex < line - 1; lineIndex++)
+    {
+      scanner.nextLine();
+    }
+    for (int node = 0; node < nodeIndex; node++)
+    {
+      scanner.nextLine();
+      scanner.nextLine();
+      scanner.nextLine();
+    }
+  
+    for (int symbol = 0; symbol < symbolIndex; symbol++)
+    {
+      value = scanner.next();
+      if ("COMPO".equals(value))
+      {
+        scanner.next();
+      }
+      else if (value.length() < 7)
+      {
+        scanner.next();
+      }
+    }
+    scanner.close();
+    return value;
+  }
+}
+
index 5b74306..bb822a0 100644 (file)
@@ -371,10 +371,11 @@ public class StockholmFileTest
                           || (seq_original[i].getSequenceFeatures() != null && seq_new[in]
                                   .getSequenceFeatures() != null));
           // compare sequence features
-          if (seq_original[i].getSequenceFeatures() != null
+          if (!ignoreFeatures
+                  && seq_original[i].getSequenceFeatures() != null
                   && seq_new[in].getSequenceFeatures() != null)
           {
-            System.out.println("There are feature!!!");
+            System.out.println("Checking feature equivalence.");
             sequenceFeatures_original = seq_original[i]
                     .getSequenceFeatures();
             sequenceFeatures_new = seq_new[in].getSequenceFeatures();
diff --git a/test/jalview/io/test_MADE1_hmm.txt b/test/jalview/io/test_MADE1_hmm.txt
new file mode 100644 (file)
index 0000000..32231db
--- /dev/null
@@ -0,0 +1,268 @@
+HMMER3/f [3.1 | February 2013]
+NAME  MADE1
+ACC   DF0000629.2
+DESC  MADE1 (MAriner Derived Element 1), a TcMar-Mariner DNA transposon
+LENG  80
+MAXL  426
+ALPH  DNA
+RF    yes
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Tue Feb 19 20:33:41 2013
+NSEQ  1997
+EFFN  3.911818
+CKSUM 3015610723
+GA 2.324 4.234
+TC 2.343 1.212
+NC 2.354 5.456
+STATS LOCAL MSV       -8.5786  0.71858
+STATS LOCAL VITERBI   -9.3632  0.71858
+STATS LOCAL FORWARD   -3.4823  0.71858
+HMM          A        C        G        T   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   1.24257  1.59430  1.62906  1.16413
+          1.38629  1.38629  1.38629  1.38629
+          0.03960  3.94183  3.94183  1.46634  0.26236  0.00000        *
+      1   2.69765  2.44396  2.81521  0.24089      1 t x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03960  3.94183  3.94183  1.46634  0.26236  1.09861  0.40547
+      2   2.72939  2.37873  2.85832  0.24244      2 t x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03725  4.00179  4.00179  1.46634  0.26236  1.09861  0.40547
+      3   0.16099  3.16370  2.87328  2.99734      3 a x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03604  4.03416  4.03416  1.46634  0.26236  1.09861  0.40547
+      4   1.98862  2.42132  0.42649  2.10770      4 g x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03539  4.05203  4.05203  1.46634  0.26236  1.09861  0.40547
+      5   1.96369  2.69532  0.36534  2.32099      5 g x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03764  4.06427  3.92372  1.46634  0.26236  1.09861  0.40547
+      6   2.56994  2.11239  2.71946  0.30571      6 t x - -
+          1.37159  1.41129  1.39124  1.37159
+          0.03806  3.89715  4.07214  1.50442  0.25122  1.00714  0.45454
+      7   2.58388  2.10353  2.64646  0.31253     12 t x - -
+          1.38764  1.38524  1.38764  1.38465
+          0.03494  4.03864  4.09125  1.40070  0.28293  1.09237  0.40860
+      8   2.18552  2.70201  0.28821  2.64645     14 g x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03628  4.09157  3.96779  1.46634  0.26236  1.09861  0.40547
+      9   2.16916  2.82142  0.28427  2.60854     15 g x - -
+          1.38091  1.39033  1.38365  1.39033
+          0.03566  4.00237  4.08886  1.38021  0.28972  1.01958  0.44745
+     10   2.45517  2.15232  2.42886  0.34277     18 t x - -
+          1.39065  1.39065  1.39065  1.37335
+          0.03536  4.01212  4.09576  1.39554  0.28462  1.09775  0.40589
+     11   2.10260  2.95484  0.28160  2.64222     21 g x - -
+          1.36740  1.40555  1.40555  1.36740
+          0.03843  3.92069  4.02468  1.44733  0.26814  1.09856  0.40549
+     12   2.54740  0.30185  2.61355  2.21647     26 c x - -
+          1.38748  1.38276  1.38748  1.38748
+          0.03457  4.05446  4.09623  1.40847  0.28040  1.05496  0.42803
+     13   0.28443  2.72003  2.32214  2.48149     28 a x - -
+          1.38740  1.38740  1.38298  1.38740
+          0.03441  4.05976  4.10001  1.41198  0.27926  1.09780  0.40587
+     14   0.29412  2.55413  2.49679  2.35701     30 a x - -
+          1.38194  1.39067  1.38194  1.39067
+          0.03505  4.02482  4.10005  1.39522  0.28473  1.09929  0.40512
+     15   0.18837  2.99710  2.82270  2.77556     33 a x - -
+          1.39015  1.39472  1.37503  1.38539
+          0.03725  3.97815  4.02618  1.37955  0.28994  1.10102  0.40426
+     16   0.50816  2.05151  2.22111  1.82407     37 a x - -
+          1.36727  1.38730  1.39683  1.39405
+          0.04830  3.89881  3.61610  1.29026  0.32186  1.05306  0.42905
+     17   2.11260  2.73141  0.29747  2.64152     41 g x - -
+          1.36913  1.40376  1.40376  1.36913
+          0.03705  3.93681  4.08299  1.44872  0.26771  1.07479  0.41759
+     18   2.24459  1.90539  2.34054  0.43234     46 t x - -
+          1.33632  1.42493  1.39937  1.38665
+          0.04427  3.64574  4.06297  1.70501  0.20061  1.21309  0.35279
+     19   0.44322  2.17202  2.18055  2.03175     57 a x - -
+          1.41047  1.41471  1.36338  1.35797
+          0.03970  3.81957  4.07540  1.65588  0.21186  1.22788  0.34660
+     20   0.33340  2.42691  2.40824  2.25160     66 a x - -
+          1.29389  1.44615  1.37917  1.43324
+          0.04223  3.70146  4.09459  1.55158  0.23815  1.05880  0.42598
+     21   2.50563  1.98543  2.69601  0.33746     74 t x - -
+          1.39462  1.39462  1.42862  1.32990
+          0.04184  3.80216  3.98177  1.80466  0.17976  1.00279  0.45705
+     22   2.54484  1.97505  2.66483  0.33806     84 t x - -
+          1.39134  1.39489  1.38662  1.37246
+          0.03877  3.97504  3.95038  1.37620  0.29107  1.13932  0.38572
+     23   2.10159  2.83856  0.29282  2.61635     88 g x - -
+          1.39682  1.39682  1.35536  1.39682
+          0.05046  3.75402  3.65808  1.08330  0.41321  1.13019  0.39004
+     24   2.25298  0.61854  2.50691  1.29221     90 c x - -
+          1.35803  1.49605  1.46737  1.24379
+          0.06091  3.28322  3.83564  1.89752  0.16245  1.28788  0.32276
+     25   1.27819  2.23285  0.76242  1.91259    106 g x - -
+          1.29024  1.67349  1.68279  1.04597
+          0.05752  3.44263  3.73311  2.58671  0.07825  1.26818  0.33037
+     26   1.86925  2.58352  0.39466  2.33986    131 g x - -
+          1.31084  1.49412  1.46666  1.29002
+          0.04698  3.54257  4.07715  2.25245  0.11109  0.86163  0.54900
+     27   2.38297  1.93394  2.39162  0.39800    151 t x - -
+          1.33582  1.47359  1.44163  1.30411
+          0.04951  3.48445  4.03783  2.15951  0.12260  1.21681  0.35122
+     28   2.41717  2.17810  2.62774  0.32113    170 t x - -
+          1.36805  1.48060  1.37439  1.32840
+          0.04849  3.50958  4.05014  2.58370  0.07850  1.22399  0.34822
+     29   2.57764  2.35132  2.56552  0.28512    194 t x - -
+          1.43829  1.43458  1.24787  1.43829
+          0.04667  3.56670  4.05428  2.49706  0.08591  1.23744  0.34267
+     30   2.47248  2.07688  2.62257  0.33172    215 t x - -
+          1.25120  1.52623  1.70635  1.15531
+          0.08932  3.31524  3.01336  2.81842  0.06156  1.22909  0.34610
+     31   2.25937  2.13157  2.02027  0.43957    248 t x - -
+          1.18172  1.43522  1.72841  1.28150
+          0.07936  2.93117  3.77395  2.46269  0.08906  0.60457  0.79034
+     32   2.04508  2.84981  0.30490  2.58263    280 g x - -
+          1.17665  1.66785  1.66218  1.16056
+          0.05998  3.23615  3.96853  2.83684  0.06040  1.01952  0.44749
+     33   2.45103  0.38098  2.56776  1.87147    317 c x - -
+          1.24153  1.52524  1.60663  1.22783
+          0.05538  3.39046  3.90294  2.73920  0.06680  1.18729  0.36391
+     34   2.22082  0.36258  2.75077  2.02704    347 c x - -
+          1.15008  1.62014  1.86511  1.10673
+          0.06086  3.18178  4.04341  2.94504  0.05403  1.25991  0.33363
+     35   0.27033  2.66664  2.52541  2.43767    388 a x - -
+          1.24951  1.47565  1.41392  1.42074
+          0.07123  3.00373  3.95552  3.13655  0.04440  1.28173  0.32512
+     36   2.83107  2.41670  2.97197  0.22235    439 t x - -
+          1.37071  1.57683  1.38637  1.23972
+          0.05293  3.45216  3.91807  2.54402  0.08181  1.14651  0.38235
+     37   2.52322  2.25084  2.45909  0.31611    465 t x - -
+          1.26335  1.55077  1.59008  1.19965
+          0.07504  3.13329  3.55006  3.08962  0.04659  1.13108  0.38962
+     38   0.45807  2.30687  1.98940  2.03143    512 a x - -
+          1.15472  1.67511  1.53797  1.26320
+          0.09820  3.13076  2.99876  2.79197  0.06326  1.39915  0.28343
+     39   2.37471  0.42180  2.44763  1.80427    550 c x - -
+          1.23785  1.49058  1.48364  1.35502
+          0.06081  3.19472  4.01643  2.41851  0.09327  0.94671  0.49105
+     40   2.32826  1.95481  2.36781  0.40458    578 t x - -
+          1.36586  1.46001  1.43000  1.29720
+          0.05257  3.39673  4.03256  1.84862  0.17133  1.40979  0.27997
+     41   2.68669  2.13935  2.81520  0.28200    592 t x - -
+          1.34965  1.42793  1.45781  1.31633
+          0.04735  3.57826  3.99988  2.09424  0.13144  1.22129  0.34934
+     42   2.55904  2.16444  2.70859  0.29952    609 t x - -
+          1.12072  1.61936  1.63578  1.26895
+          0.07346  3.25910  3.42962  2.85641  0.05919  1.38363  0.28857
+     43   1.99923  1.61027  2.26343  0.57851    646 t x - -
+          1.32290  1.58747  1.61095  1.11018
+          0.06656  3.08568  3.97944  2.44774  0.09046  0.75593  0.63407
+     44   0.23887  2.79899  2.55209  2.60783    675 a x - -
+          1.18557  1.50323  1.59070  1.31590
+          0.05597  3.38637  3.88222  2.46900  0.08847  1.27945  0.32599
+     45   0.29593  2.53488  2.53903  2.32335    701 a x - -
+          1.08710  1.54222  1.59276  1.40430
+          0.07539  2.94521  3.91062  1.91623  0.15918  1.22327  0.34852
+     46   2.58352  2.40524  2.76700  0.25955    725 t x - -
+          1.19685  1.58503  1.74852  1.14293
+          0.06124  3.18279  4.02089  2.82961  0.06085  1.05474  0.42814
+     47   2.13251  2.88788  0.29508  2.50964    764 g x - -
+          1.20891  1.55463  1.68206  1.19000
+          0.06526  3.12574  3.94910  2.41448  0.09367  1.10396  0.40280
+     48   2.23841  2.99164  0.25118  2.72900    792 g x - -
+          1.26330  1.55339  1.52606  1.24355
+          0.05464  3.34968  4.01313  2.78872  0.06347  1.15133  0.38012
+     49   2.57533  0.32900  2.64632  2.01501    824 c x - -
+          1.35118  1.39828  1.40141  1.39516
+          0.04340  3.79297  3.91506  1.59549  0.22666  1.20075  0.35806
+     50   0.46433  2.04127  2.23437  2.00605    833 a x - -
+          1.23062  1.36903  1.62282  1.36182
+          0.05764  3.31530  3.92762  2.28791  0.10700  1.07910  0.41536
+     51   0.27513  2.77017  2.28518  2.57549    853 a x - -
+          1.27958  1.58726  1.46109  1.25394
+          0.05750  3.30072  3.96214  2.60776  0.07656  1.25708  0.33475
+     52   0.20149  2.86434  2.84551  2.69770    883 a x - -
+          1.23645  1.62259  1.71174  1.10368
+          0.05756  3.26729  4.02702  2.54508  0.08172  1.27391  0.32814
+     53   0.26982  2.65833  2.50477  2.46835    911 a x - -
+          1.36005  1.50358  1.48100  1.22550
+          0.06921  3.37553  3.42118  2.36646  0.09851  1.27560  0.32748
+     54   0.40022  2.19284  2.22687  2.20396    934 a x - -
+          1.12070  1.60472  1.53213  1.35895
+          0.05523  3.36752  3.94966  2.42917  0.09224  0.84774  0.55928
+     55   2.11356  0.46400  2.46442  1.79955    960 c x - -
+          1.23932  1.35913  1.50478  1.46331
+          0.05187  3.47055  3.94022  2.35854  0.09933  1.12102  0.39445
+     56   1.85868  0.79440  2.22069  1.25971    983 c x - -
+          1.21951  1.50212  1.51138  1.34185
+          0.06404  3.29054  3.69705  1.75742  0.18933  1.18410  0.36532
+     57   1.33272  2.32720  0.71452  1.90215    999 g x - -
+          1.12229  1.49343  1.56653  1.42255
+          0.04920  3.46654  4.08749  2.17995  0.11996  1.31769  0.31164
+     58   2.48337  0.43652  2.46331  1.68683   1017 c x - -
+          1.34704  1.55461  1.38112  1.28222
+          0.04823  3.61532  3.90311  2.20911  0.11631  1.00864  0.45368
+     59   0.41659  2.44509  1.93972  2.20507   1034 a x - -
+          1.38198  1.38198  1.39194  1.38932
+          0.03641  3.98130  4.06929  1.35873  0.29704  1.31330  0.31325
+     60   0.41612  2.39160  1.97116  2.21075   1037 a x - -
+          1.03649  1.46430  1.57421  1.57557
+          0.04769  3.52580  4.06641  2.32461  0.10294  0.84329  0.56263
+     61   2.66264  2.12302  2.82746  0.28581   1056 t x - -
+          1.36925  1.39635  1.38930  1.39048
+          0.04097  3.97400  3.84718  1.39433  0.28502  1.12205  0.39395
+     62   2.26510  2.13196  2.42551  0.37231   1060 t x - -
+          1.37965  1.39147  1.39147  1.38264
+          0.04082  3.91610  3.90805  1.24613  0.33914  0.95192  0.48776
+     63   0.41244  2.25761  2.16787  2.12907   1062 a x - -
+          1.34515  1.41203  1.41203  1.37753
+          0.04054  3.77835  4.08203  1.30483  0.31638  1.11819  0.39582
+     64   2.51464  0.37905  2.62296  1.82008   1068 c x - -
+          1.39543  1.38753  1.39233  1.37008
+          0.03854  3.90584  4.03535  1.36573  0.29463  1.13682  0.38689
+     65   2.16380  2.11332  2.18714  0.42765   1073 t x - -
+          1.38764  1.38471  1.38519  1.38764
+          0.03575  4.05376  4.03073  1.40080  0.28289  1.03825  0.43707
+     66   2.79349  2.39141  2.87271  0.23478   1075 t x - -
+          1.37227  1.39101  1.39101  1.39101
+          0.03597  4.01447  4.05827  1.39017  0.28639  1.06429  0.42308
+     67   2.82488  2.47749  2.93179  0.21887   1078 t x - -
+          1.38141  1.39112  1.38915  1.38353
+          0.03661  3.99477  4.04370  1.35958  0.29675  1.13439  0.38804
+     68   2.77679  2.30433  2.90694  0.24425   1081 t x - -
+          1.37593  1.38989  1.45520  1.32825
+          0.04447  3.68736  3.99242  1.76176  0.18843  0.98580  0.46703
+     69   2.47698  3.17398  0.19595  2.95437   1093 g x - -
+          1.38264  1.38264  1.39734  1.38264
+          0.05358  3.96553  3.40487  1.40348  0.28202  1.03112  0.44100
+     70   2.84327  0.27906  2.97336  2.00890   1097 c x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03412  4.08811  4.08811  1.46634  0.26236  0.69006  0.69625
+     71   0.21870  2.83638  2.69251  2.65798   1098 a x - -
+          1.37446  1.37942  1.39640  1.39509
+          0.03670  3.93983  4.09935  1.41905  0.27700  1.10002  0.40476
+     72   2.35233  0.46085  2.23804  1.78715   1103 c x - -
+          1.38536  1.38781  1.38781  1.38421
+          0.03493  4.03822  4.09272  1.39310  0.28542  1.09638  0.40658
+     73   2.57111  0.32543  2.74124  1.98892   1105 c x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03381  4.09688  4.09688  1.46634  0.26236  1.09626  0.40664
+     74   0.27014  2.61416  2.53262  2.47636   1106 a x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03461  4.09267  4.05587  1.46634  0.26236  1.09748  0.40603
+     75   0.52873  2.16549  1.91736  1.90409   1107 a x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03426  4.08396  4.08396  1.46634  0.26236  1.07423  0.41788
+     76   2.33134  0.38082  2.65861  1.90055   1108 c x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03466  4.07266  4.07266  1.46634  0.26236  1.09861  0.40547
+     77   2.20588  0.45134  2.35553  1.84373   1109 c x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03550  4.04912  4.04912  1.46634  0.26236  1.09861  0.40547
+     78   2.69018  2.22054  2.82311  0.26898   1110 t x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.03711  4.00561  4.00561  1.46634  0.26236  1.09861  0.40547
+     79   0.16248  3.15867  2.86159  2.98963   1111 a x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.04048  3.92018  3.92018  1.46634  0.26236  1.09861  0.40547
+     80   0.17484  3.04770  2.86638  2.88183   1112 a x - -
+          1.38629  1.38629  1.38629  1.38629
+          0.02045  3.90014        *  1.46634  0.26236  0.00000        *
+//
diff --git a/test/jalview/io/test_PKinase_hmm.txt b/test/jalview/io/test_PKinase_hmm.txt
new file mode 100644 (file)
index 0000000..e1ad9f9
--- /dev/null
@@ -0,0 +1,806 @@
+HMMER3/e [3.0 | March 2010]
+NAME  Pkinase
+ACC   PF00069.17
+DESC  Protein kinase domain
+LENG  260
+ALPH  amino
+RF    no
+CONS  yes
+CS    yes
+MAP   yes
+DATE  Thu Jun 16 11:44:06 2011
+NSEQ  54
+EFFN  3.358521
+CKSUM 3106786190
+GA    70.30 70.30
+TC    70.30 70.30
+NC    70.20 70.20
+STATS LOCAL MSV      -10.7215  0.70254
+STATS LOCAL VITERBI  -11.6541  0.70254
+STATS LOCAL FORWARD   -5.2305  0.70254
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   2.60017  4.19886  2.94089  2.63789  3.35087  2.89119  3.48337  2.79435  2.60265  2.43454  3.62613  3.06133  3.41286  3.09693  2.94507  2.65650  2.87761  2.67871  4.54052  3.43274
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.00000        *
+      1   2.91704  4.31028  4.76351  3.63148  2.10912  3.47710  4.39734  2.27639  3.96619  1.99282  3.42844  4.19567  4.43771  4.11903  3.67403  3.22736  3.14918  2.35905  3.32515  1.82622      1 y - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      2   2.77204  4.20708  3.06476  1.97968  4.66603  3.66509  3.19858  3.37903  2.25347  3.34018  4.38833  2.97180  4.05804  2.36838  2.43173  2.67542  2.50268  2.83403  5.78758  4.38976      2 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      3   2.90076  4.04294  3.31590  2.80413  3.08157  3.87481  4.12616  2.18958  2.49735  1.97194  3.73714  3.32717  3.98753  3.23115  3.12315  2.99137  2.62008  2.29426  5.21478  3.75979      3 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      4   2.89383  4.85429  3.10311  2.63174  3.71383  2.56808  3.47232  2.82076  2.61844  1.98342  3.72320  3.05498  4.17347  3.05527  3.32194  2.85608  2.93671  2.18878  5.40057  3.87183      4 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      5   2.68261  5.39185  2.80437  1.87471  4.73638  2.79887  3.69591  4.22191  2.19487  3.69685  4.08896  3.12413  3.70490  2.48424  2.08916  2.53260  3.02309  3.43812  5.82480  4.41426      5 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      6   2.77253  4.06085  3.07881  2.53373  4.10647  3.71564  3.68370  2.64290  2.00036  2.72968  4.17370  3.24239  3.08607  2.77632  2.72820  2.69921  2.54335  2.71931  5.60386  4.26496      6 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      7   3.42930  4.74416  5.34765  4.76823  3.71832  4.71430  5.09461  1.33015  3.54417  1.12594  3.33523  4.84641  5.00427  4.73010  4.64986  4.05097  3.66327  1.83083  5.51142  4.37013      7 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      8   2.57460  4.94286  4.00732  3.93216  5.40516  0.41612  5.15134  4.86315  4.18766  4.52736  5.33508  4.05990  4.45245  3.74651  4.46171  3.15888  3.14590  4.15180  6.71159  5.52767      8 G - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+      9   2.30218  5.38172  3.03799  2.02026  4.18991  3.65799  3.84554  3.67215  2.28945  3.68495  4.42365  2.84227  3.73039  2.44555  2.39428  2.00278  2.95859  3.63127  5.81726  4.40923      9 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     10   4.54226  6.07621  5.39207  5.44513  6.34643  0.07137  6.34600  6.33790  5.73770  5.76452  6.83374  5.56171  5.46536  5.98137  5.73783  4.76037  5.08470  5.67502  7.03864  6.52156     10 G - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     11   2.06444  5.37337  2.91595  2.40063  4.70969  2.61181  3.84889  4.18948  2.46835  3.67503  4.41668  2.62917  4.05392  2.88235  2.66711  2.00495  2.47288  3.39649  5.81159  4.40596     11 s - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     12   2.90920  4.46494  4.12493  3.14570  1.52027  3.22992  4.24969  2.92840  3.46467  2.66529  3.12827  3.55640  4.33979  3.72214  3.72236  2.53517  2.98442  2.55125  5.06498  2.30159     12 f - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     13   2.21104  4.80722  4.64199  4.55509  5.54982  0.52550  5.49025  5.04875  4.70671  4.72740  5.47955  4.30215  4.43233  4.84666  4.86038  1.95116  3.45005  4.17507  6.87595  5.79039     13 G - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     14   2.71551  3.46186  3.01248  2.27453  4.55840  3.55853  3.50842  3.55064  2.03335  3.34882  4.31847  3.17065  4.07218  2.83960  2.83653  2.25762  2.26864  2.61469  5.72841  4.35037     14 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     15   3.17885  3.97005  5.63014  5.16553  4.35293  4.89782  5.77682  2.09398  5.06494  2.94083  4.14496  5.20428  5.30924  5.30763  5.20260  4.32158  3.61414  0.44769  6.26043  5.04118     15 V - - E
+          2.68625  4.42232  2.77526  2.73102  3.46361  2.40519  3.72501  3.29361  2.67747  2.69306  4.24696  2.90353  2.73746  3.18153  2.89807  2.37893  2.77526  2.98499  4.58484  3.61510
+          0.09563  2.43065  5.73865  0.67073  0.71608  0.48576  0.95510
+     16   2.91101  3.31342  4.36759  3.41772  2.45121  4.01227  4.31421  2.75922  2.81772  2.31733  3.50420  3.69862  4.38187  3.88257  3.14725  3.02772  3.14303  2.46483  3.37889  1.69905     18 y - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     17   2.88484  5.28431  3.03179  2.31849  4.58595  3.47769  3.54625  2.98124  1.69233  2.43413  4.04064  3.16353  4.06907  2.72555  2.58277  2.55274  3.04512  3.20501  5.74377  4.36100     19 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     18   1.57125  2.56460  3.38436  3.39201  3.66458  2.34190  4.20526  2.93932  3.32823  2.44127  3.26099  3.74334  4.30466  3.60817  3.63469  3.01628  2.92537  2.55308  5.13581  3.91882     20 a - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     19   2.89298  4.40558  3.44708  2.63051  3.77015  3.77747  2.87940  2.57515  2.33949  2.85128  3.20054  3.37379  4.16367  2.65910  2.52913  2.67954  2.59930  2.46709  5.42679  3.74337     21 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     20   2.88350  5.37811  2.42858  2.28192  4.71668  3.65945  2.35349  4.19788  2.20596  2.91798  4.42054  2.38258  4.05280  2.81490  2.60119  2.77457  3.11461  3.76528  3.43428  3.80493     22 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     21   2.59359  5.30144  3.00667  2.46268  4.60954  3.67285  3.22394  2.91749  2.13087  2.60378  4.35201  3.05590  3.51881  2.48537  2.35096  2.62551  3.00998  2.84793  5.75687  4.36947     23 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     22   2.64500  5.38003  2.46961  2.36386  4.71962  2.36153  3.71093  3.77963  2.19342  3.27291  4.42213  2.49968  3.44456  2.94396  2.94770  2.23767  2.90215  3.58800  5.81601  3.79868     24 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     23   2.71410  5.35453  2.26257  2.17828  4.68327  3.06138  3.85215  3.65600  2.51871  3.65284  4.39957  2.64619  4.05631  2.95399  2.98284  2.41102  1.94961  3.19379  5.79713  3.78693     25 t - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03260  5.01631  3.67114  0.61958  0.77255  0.48576  0.95510
+     24   2.77509  4.50579  3.06414  2.40741  4.68877  2.10468  3.84020  4.16638  2.52713  3.65577  4.39945  2.31826  2.82304  2.55347  2.45557  2.51717  3.10489  3.55245  5.79545  3.68618     26 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.13496  4.99383  2.12471  0.61958  0.77255  0.54753  0.86365
+     25   2.82390  4.23357  2.59579  2.09029  4.65095  3.47120  3.53571  3.50264  1.93281  3.24335  4.10745  2.98984  3.99409  2.41262  2.43858  2.60001  2.84781  3.57090  5.75206  3.98239     27 k - - E
+          2.68634  4.42166  2.77510  2.73101  3.46370  2.40521  3.72473  3.29370  2.67713  2.69347  4.24706  2.90350  2.73742  3.18145  2.89817  2.37895  2.77536  2.98516  4.58493  3.61485
+          0.21086  2.33296  2.37401  1.37928  0.29003  0.81455  0.58490
+     26   2.79249  4.86773  3.27912  2.48247  3.81836  3.65430  3.86742  2.36980  2.31612  2.40000  3.66176  2.98804  3.52938  2.45192  2.80383  2.80149  2.71760  2.93241  5.39419  3.83742     36 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01259  4.77670  5.49905  0.61958  0.77255  0.27298  1.43175
+     27   2.94684  4.40681  4.93000  4.33270  2.14562  4.19543  4.43742  2.60780  4.12995  2.51432  3.32273  4.32339  4.55150  4.25562  4.15094  3.50804  3.26683  1.12964  4.39266  2.23526     37 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     28   0.67405  4.13502  4.78133  4.26234  4.00859  4.13420  4.88775  2.58668  4.14876  2.87877  3.59530  4.37511  4.66004  4.38446  4.34251  3.50924  3.44597  2.20111  5.62436  4.43519     38 A - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     29   2.77559  4.05359  4.82280  4.21814  3.45081  3.88127  4.46447  1.69887  3.29990  2.06046  2.92956  4.25618  4.49083  4.18293  4.07725  3.28739  3.19210  1.31639  4.98894  3.80930     39 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     30   4.13385  6.06880  4.58555  3.84767  5.73274  4.53840  4.41573  5.06650  0.32256  4.37802  5.30885  4.14872  4.92009  3.55775  2.54913  4.11741  4.25754  4.75872  6.25921  5.22828     40 K - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     31   2.53136  3.93442  3.55191  2.54113  3.59001  3.81267  3.67691  2.09853  2.22431  2.85063  3.63116  3.45300  4.19661  2.87681  2.71089  2.96116  2.67441  2.46338  5.34241  3.76111     41 i - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     32   2.80227  4.30542  4.81704  3.71619  2.31247  3.45194  4.41496  1.85614  4.00698  1.68898  3.06826  4.22398  4.44809  4.15126  4.03957  3.11345  3.01936  1.82478  4.92889  3.75130     42 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     33   2.72320  4.19698  2.89173  2.30854  4.21536  3.66470  3.63903  3.54937  1.81020  3.33297  4.38970  2.50126  3.12497  2.85129  2.61476  2.47307  2.93549  3.43057  4.63863  3.86554     43 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     34   2.73748  5.16363  3.24304  2.62749  4.42406  3.39882  3.64889  3.08793  1.75481  2.64054  4.22767  2.81684  3.49630  2.92572  2.69253  2.71691  2.78362  2.91622  5.65055  3.09244     44 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     35   2.82342  4.21564  2.57688  2.18304  4.09635  3.66104  3.29269  4.17416  2.24176  3.24419  4.40775  3.13331  3.02670  2.66210  2.30119  2.38622  2.91913  2.84969  5.80393  4.13733     45 e - - H
+          2.68618  4.42225  2.77520  2.73124  3.46354  2.40513  3.72495  3.29354  2.67741  2.69355  4.24690  2.90347  2.73731  3.18147  2.89801  2.37887  2.77520  2.98519  4.58477  3.61503
+          0.02362  3.90596  5.73865  0.48782  0.95182  0.48576  0.95510
+     36   2.81479  5.38805  2.34307  2.08229  3.84722  3.00939  3.24618  4.21561  2.24819  3.24444  4.42924  2.80965  3.63231  2.74299  2.65208  2.41080  2.72103  3.26063  5.82196  4.16400     47 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     37   2.42659  5.32934  2.94543  1.98753  4.27035  3.66735  3.85733  2.97282  2.27697  3.20526  3.75542  2.69174  3.50027  2.79550  2.45131  2.66535  2.70832  3.28701  5.77800  4.07668     48 e - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     38   2.82479  5.36482  2.46403  2.36491  4.23121  3.19666  3.53460  3.47934  2.01766  2.87145  4.06028  2.53791  3.88358  2.73438  2.79605  2.39315  2.94316  3.30320  5.80464  3.67777     49 k - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     39   2.81259  3.82036  2.58997  2.16257  3.93187  3.50795  3.44913  3.32347  2.23760  3.42042  3.43188  3.03914  3.18139  2.98833  2.90722  1.97318  3.04237  3.44327  4.85883  4.01646     50 s - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04017  5.01631  3.41907  0.61958  0.77255  0.48576  0.95510
+     40   2.75150  4.68420  2.78864  2.20581  3.96394  3.14028  3.85474  3.62649  2.17804  2.84544  3.93254  2.66146  3.79370  2.72658  2.87564  2.43841  2.71937  3.23202  3.36778  4.34996     51 k - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01020  4.98634  5.70869  0.61958  0.77255  0.56699  0.83755
+     41   2.52028  4.29421  2.93844  2.26593  3.28616  3.42961  3.89113  3.40312  1.92589  2.89626  3.59280  3.04537  4.08209  2.42956  3.02333  2.89065  2.87512  2.78376  5.62895  3.97726     52 k - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.06456  4.98634  2.88790  0.61958  0.77255  0.56699  0.83755
+     42   2.52102  4.66200  2.60886  2.12080  3.90563  3.43164  3.41299  3.76759  2.19798  2.95231  4.37667  2.71584  3.31098  2.66775  2.46389  2.65499  2.89357  3.57073  4.74853  4.36793     53 e - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.06881  4.93254  2.82535  0.61958  0.77255  0.69302  0.69327
+     43   2.65676  5.27743  2.81592  2.16715  4.59834  3.44096  3.79920  2.82354  2.10889  3.57233  3.78816  2.93522  4.00237  2.20078  2.58862  2.72374  2.99283  3.18643  5.72482  3.30249     54 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04191  4.87514  3.39892  0.61958  0.77255  0.80592  0.59181
+     44   2.46416  5.14935  3.14274  2.35064  4.42785  3.46788  3.62138  3.06885  2.39724  2.90472  4.00413  2.77252  4.01153  2.56699  2.69346  2.37713  2.33258  3.34725  5.62407  3.30627     55 t - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.15381  4.84499  2.00472  0.61958  0.77255  0.85820  0.55151
+     45   2.15178  5.11690  2.80767  2.47016  4.06926  3.56450  3.25874  3.42510  2.38373  2.72748  4.17388  2.58132  3.95629  2.68997  2.59104  2.52019  2.89357  3.10461  5.58730  3.84420     56 a - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.06869  4.70471  2.85898  0.61958  0.77255  1.05523  0.42788
+     46   2.33893  4.38200  3.78128  3.08857  2.87706  3.76539  4.03303  2.50172  2.82237  2.26545  3.48958  3.56901  4.14175  3.13269  2.43377  3.02211  2.55318  2.18677  4.40164  3.75633     57 v - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.07407  4.65033  2.78326  0.61958  0.77255  1.03937  0.43646
+     47   2.66580  4.77769  3.25859  2.69691  3.69577  3.61140  3.56963  3.36841  2.45062  2.28390  3.86113  2.83101  3.99793  3.01640  2.00932  2.40384  2.97180  2.98514  3.81809  4.01106     58 r - - H
+          2.68588  4.42292  2.77574  2.73101  3.46421  2.40561  3.72562  3.29362  2.67747  2.69305  4.24679  2.90348  2.73776  3.18179  2.89693  2.37874  2.77432  2.98554  4.58544  3.61510
+          0.56084  0.85690  5.33966  1.67148  0.20822  0.22069  1.61932
+     48   3.87852  6.35819  2.88185  0.33512  5.75300  3.98086  4.66680  5.41085  3.73193  4.87592  5.81368  3.19190  4.67406  3.86930  4.28895  3.74624  4.21685  4.94226  6.88673  5.40485     78 E - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     49   2.34469  4.06185  4.67394  3.74635  3.19070  3.72385  4.38165  1.69529  3.89930  1.68521  3.30505  3.88179  4.42519  3.50953  3.71087  3.12279  3.14596  1.99339  4.94125  3.41486     79 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     50   2.41611  3.92039  3.06862  2.24055  4.69692  3.38839  3.50460  4.17440  2.17094  3.43336  4.01855  2.84870  4.05421  2.22409  2.42800  2.49697  2.93959  3.48161  5.80403  3.10747     80 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     51   2.65097  4.31309  4.79937  4.19096  3.25102  4.08746  4.41763  1.57396  3.99634  1.77576  3.18772  3.58572  4.45127  4.14513  4.03729  2.91921  3.15786  1.73265  4.93848  3.33785     81 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     52   2.71474  4.35776  4.49839  3.90546  3.26558  3.60358  3.11363  2.58541  3.76519  1.24138  2.56017  3.78382  4.40165  3.77674  3.90460  2.91080  2.88501  2.43218  4.97232  3.44306     82 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     53   2.21717  5.37509  3.13954  2.36108  4.71254  3.44569  3.50643  4.19289  1.90576  2.89362  4.41783  2.84264  3.50886  2.51670  2.27883  2.73413  2.79427  3.37900  5.81221  4.40629     83 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     54   2.88332  4.76187  3.15794  2.34306  4.64959  3.18467  2.98724  4.11774  2.20976  2.84622  3.53657  2.69640  4.06011  2.81953  2.22587  2.26090  2.67755  3.39248  5.77872  3.89328     84 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     55   2.92075  3.71086  4.82119  4.21031  2.91851  4.08375  4.41406  2.48059  4.00923  1.14255  2.77088  4.22517  4.44739  4.15194  3.51737  2.79440  3.04088  2.14784  4.92583  3.58797     85 l - - H
+          2.68619  4.42231  2.77526  2.73130  3.46360  2.40505  3.72501  3.29360  2.67737  2.69361  4.24696  2.90322  2.73746  3.18153  2.89797  2.37878  2.77526  2.98514  4.58483  3.61509
+          0.21093  1.81438  3.60337  0.15203  1.95873  0.48576  0.95510
+     56   2.87228  4.32697  2.43695  2.52023  4.72535  3.09966  3.42727  4.21076  2.24746  3.68599  4.14994  2.21640  3.70120  2.45856  2.42604  2.20075  2.84715  3.77128  5.81417  4.40372     87 s - - S
+          2.68626  4.42233  2.77498  2.73131  3.46362  2.40515  3.72479  3.29362  2.67733  2.69363  4.24698  2.90355  2.73719  3.18141  2.89809  2.37895  2.77498  2.98527  4.58485  3.61511
+          0.08622  2.53438  5.71435  0.90816  0.51628  0.44628  1.02166
+     57   2.95437  4.05540  4.02453  3.66262  4.73022  3.00582  0.63840  4.27369  3.61156  3.92435  4.76053  3.90244  4.38221  3.97389  3.93213  2.36608  3.39859  3.79517  6.08861  4.80370     91 H - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     58   2.74925  4.59154  2.64384  2.02057  4.69046  3.19970  3.85151  4.16644  2.39568  3.65893  3.99620  3.06676  1.73396  2.95270  2.98758  2.52836  2.96698  3.57815  5.80119  4.39902     92 p - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     59   2.77600  3.63123  3.60742  3.04389  2.88763  3.83093  3.22852  3.27052  2.82124  2.96220  3.83761  1.44485  4.21384  3.33393  3.26463  3.06163  2.84916  2.86372  5.30436  2.85576     93 n - - S
+          2.68619  4.42226  2.77521  2.73125  3.46355  2.40506  3.72496  3.29355  2.67742  2.69356  4.24691  2.90348  2.73741  3.18148  2.89802  2.37880  2.77521  2.98520  4.58478  3.61504
+          0.02736  3.73933  5.73865  0.64347  0.74542  0.48576  0.95510
+     60   3.43736  4.73250  5.40681  4.85032  3.21534  3.89737  5.21348  0.72821  4.70181  2.29095  3.77438  4.92025  5.08011  4.86610  4.77171  4.12622  3.68020  1.72131  5.65218  4.46593     96 i - - B
+          2.68620  4.42119  2.77522  2.73126  3.46356  2.40515  3.72497  3.29356  2.67743  2.69357  4.24692  2.90349  2.73742  3.18149  2.89780  2.37889  2.77522  2.98521  4.58479  3.61505
+          0.04171  3.27988  5.73865  0.65380  0.73410  0.48576  0.95510
+     61   3.22247  3.52386  5.20134  4.62057  3.74032  4.49428  4.89197  1.38422  4.44333  2.03444  3.40884  4.64781  4.83078  4.60265  4.48778  3.55308  3.01459  1.16992  5.37248  4.18666     99 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     62   2.72238  4.59459  3.13585  2.30027  4.72566  3.17722  3.67251  4.20868  2.00822  3.53187  4.42604  2.97500  3.44674  2.41134  2.06447  2.53711  2.32763  3.77297  5.81907  4.41084    100 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     63   2.75790  4.02501  4.89076  4.27684  2.25991  4.10991  4.44304  2.31340  4.06541  1.38378  2.56521  4.26823  4.47075  4.19670  4.07763  3.42134  2.72551  2.21249  4.93572  3.01728    101 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     64   2.79378  4.36122  4.48297  3.70404  2.84684  4.03133  3.55103  1.94759  2.82835  1.82248  3.32801  4.05424  4.39941  3.70850  3.13439  3.15759  3.14407  2.41334  4.25902  2.30786    102 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     65   2.47264  4.33075  2.07830  2.03157  4.71750  2.27093  3.18950  4.19892  2.58523  3.68152  4.42156  3.04070  4.05295  2.84140  2.67254  2.59104  3.11515  3.76615  5.81569  3.60292    103 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     66   2.10377  4.03530  4.82986  4.21790  2.76136  4.07923  4.41023  2.08081  4.01359  2.30827  2.78821  4.22543  4.44340  4.15406  4.03913  2.38166  2.60707  1.97272  3.19782  3.33258    104 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     67   2.82605  3.67894  3.38070  3.01266  1.82001  3.97118  3.82789  2.76491  3.48734  2.34143  3.24926  3.10725  3.78017  3.42990  3.73647  2.98277  3.13977  2.32864  3.87637  2.72935    105 f - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04987  5.01631  3.16967  0.61958  0.77255  0.48576  0.95510
+     68   2.55964  4.21441  3.10666  1.94329  4.49707  3.21758  3.46239  3.37098  2.39709  3.00488  3.51821  3.06808  4.06187  2.54621  2.66989  2.75991  2.68522  3.13970  5.68635  3.14043    106 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02094  4.97674  4.28127  0.61958  0.77255  0.42506  1.06054
+     69   2.80310  5.38415  2.22807  2.18295  4.72718  3.65266  3.36574  4.21171  2.46641  3.56699  4.42536  2.57848  3.46451  2.86899  2.36310  2.58224  2.17995  3.52075  5.81804  3.65548    107 t - - E
+          2.68640  4.42162  2.77535  2.73147  3.46354  2.40551  3.72458  3.29233  2.67716  2.69348  4.24762  2.90375  2.73699  3.18187  2.89837  2.37858  2.77480  2.98522  4.58549  3.61548
+          0.36809  1.18844  5.72853  1.68950  0.20409  0.46837  0.98355
+     70   2.88244  5.39287  2.47300  2.29715  3.79460  2.82884  3.28660  4.22374  2.09832  3.69810  4.43357  2.45444  3.07035  2.85151  2.47539  2.34133  3.01376  3.78345  5.82560  4.10620    126 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     71   2.57798  5.39101  2.06614  2.42374  4.73510  2.82383  3.84381  4.22040  2.28304  3.69587  4.43195  2.62257  3.38372  2.71683  2.73886  2.29050  2.66881  3.34289  5.82427  4.18691    127 d - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     72   2.58231  5.35788  2.77781  2.22432  4.08337  3.66211  2.49021  4.16401  2.37240  3.16748  4.40241  2.52484  4.05523  2.76334  2.63486  2.49164  2.89823  3.30761  4.95167  3.05734    128 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     73   2.78575  3.74303  4.78141  4.17260  2.95491  4.07322  4.40160  1.89067  3.97854  1.60353  2.95383  3.71592  3.11906  4.12798  3.50390  3.07790  2.85145  2.24111  4.92509  2.91282    129 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     74   2.58399  2.76389  4.59675  3.99881  3.19843  4.04871  3.62339  2.65148  3.84111  2.12752  3.45456  3.62454  3.46238  4.02369  3.94739  2.79096  3.14543  2.42948  3.13888  1.74690    130 y - - E
+          2.68624  4.42096  2.77500  2.73129  3.46360  2.40508  3.72501  3.29360  2.67747  2.69353  4.24696  2.90343  2.73746  3.18153  2.89807  2.37893  2.77510  2.98525  4.58483  3.61509
+          0.10354  2.49668  4.13492  0.66960  0.71726  0.48576  0.95510
+     75   3.07392  4.44555  4.97084  3.81418  2.87255  4.25097  4.57886  1.74564  4.16653  1.31678  2.12605  4.39109  4.59167  3.71495  4.19337  3.56380  3.30386  2.29390  5.05348  3.89648    133 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.52175  0.90012
+     76   2.86449  3.41378  5.01300  4.41506  3.07458  4.28568  4.64425  1.49634  4.22335  2.27773  3.54368  4.43380  4.63588  3.70581  4.25773  3.60458  3.30826  1.19505  5.13861  3.95920    134 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.46390  0.99109
+     77   2.91733  4.35063  4.55668  3.96112  2.40516  4.04680  4.36140  2.56068  3.81048  1.70108  1.79340  3.59899  4.41359  3.09405  3.93172  3.15547  2.48177  2.59902  4.96582  3.78095    135 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     78   2.76564  5.57030  2.50020  1.03018  4.90220  3.70297  3.44513  4.39514  2.75995  3.87044  4.62325  3.16505  3.19754  2.75935  3.27129  2.65802  3.28146  3.95557  6.00401  4.57374    136 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     79   2.81579  3.90369  4.68991  4.08721  2.27644  4.06399  3.63829  2.69790  3.58050  1.84024  3.31248  4.16081  4.42953  4.07816  3.60709  3.36667  3.01039  2.57256  4.40465  1.54393    137 y - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     80   2.45920  2.17262  4.69646  4.09287  3.22405  3.32199  3.21264  2.59887  3.91610  2.06244  2.25581  4.16309  3.61702  4.08102  3.98811  3.14866  3.14614  2.03766  4.93767  3.46778    138 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04171  5.01631  3.37486  0.61958  0.77255  0.48576  0.95510
+     81   2.70314  5.37371  2.37994  1.91497  4.71601  2.93053  3.83161  4.20005  2.46492  3.55263  3.57885  2.58870  2.59223  2.74552  2.71928  2.69862  3.03649  3.29150  5.80804  4.39872    139 e - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01022  4.98481  5.70716  0.61958  0.77255  0.57090  0.83245
+     82   2.41993  3.72287  3.12898  2.52046  4.44831  1.89639  3.49536  3.62837  2.38762  3.31281  3.53904  2.44913  3.42379  3.00780  3.12891  2.87912  2.75467  3.52812  5.65946  3.81984    140 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.10979  4.98481  2.33166  0.61958  0.77255  0.57090  0.83245
+     83   2.77350  5.21303  2.43943  2.62703  4.54309  1.39496  3.89257  3.99092  2.60267  3.54085  4.32260  3.04209  4.06226  3.01831  3.03242  2.64588  2.77651  3.04353  5.73236  4.35922    141 g - - -
+          2.68631  4.42210  2.77537  2.73126  3.46359  2.40522  3.72475  3.29338  2.67758  2.69250  4.24657  2.90377  2.73770  3.18148  2.89796  2.37902  2.77541  2.98478  4.58507  3.61496
+          0.21230  1.67338  5.60865  1.39945  0.28334  0.33567  1.25476
+     84   2.88583  5.39491  1.79381  2.06461  4.73890  3.24821  3.51210  4.22442  2.47141  3.51906  4.43601  2.95989  3.57031  2.79057  2.82788  2.02605  2.91163  3.62254  5.82805  4.41723    147 d - - B
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     85   2.90986  4.42406  3.70533  3.66371  3.02577  3.99009  3.90749  2.78363  3.56278  1.02082  3.24022  3.34355  4.36146  3.52102  3.78389  3.13807  2.95820  2.60948  5.03043  3.48016    148 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     86   2.57337  4.10245  3.03950  2.95233  2.09915  3.53742  3.15959  3.37138  2.66519  2.44003  3.54971  3.10382  3.71714  3.06888  3.13958  2.44794  3.05039  3.11306  4.61969  3.07664    149 f - - H
+          2.68621  4.42228  2.77522  2.73126  3.46357  2.40516  3.72497  3.29357  2.67744  2.69358  4.24693  2.90350  2.73735  3.18149  2.89804  2.37890  2.77502  2.98521  4.58480  3.61458
+          0.24291  3.02648  1.78874  0.58545  0.81386  0.48576  0.95510
+     87   2.29362  5.30873  1.92419  2.32474  4.26868  3.43187  3.46788  4.12970  2.37357  3.61146  4.35100  2.92576  3.98105  2.69850  2.60197  2.47206  2.54407  3.69618  5.74493  3.96335    152 d - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01185  4.83724  5.55959  0.61958  0.77255  0.87096  0.54223
+     88   2.24696  4.24235  4.56569  3.96478  2.41045  3.97137  3.29432  2.27668  3.43922  2.04964  3.19406  4.05576  4.33743  3.97000  3.38896  3.27217  3.06100  2.23241  4.18296  2.20711    153 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01185  4.83724  5.55959  0.61958  0.77255  0.87096  0.54223
+     89   3.80243  5.01974  5.81731  5.27268  3.70245  5.26548  5.70409  1.30084  5.15744  0.98923  3.04180  5.42350  5.39649  5.16571  5.17462  4.65797  4.03105  1.75151  5.84473  4.80632    154 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01185  4.83724  5.55959  0.61958  0.77255  0.62617  0.76494
+     90   2.48275  5.13868  3.18520  2.44727  3.97540  3.65122  3.65677  3.36126  2.16734  3.30486  3.19390  3.06911  4.04233  2.41632  2.75033  2.25069  2.41675  3.09873  5.62108  3.69504    155 k - - H
+          2.68595  4.42186  2.77509  2.73103  3.46377  2.40517  3.72421  3.29387  2.67761  2.69368  4.24695  2.90368  2.73754  3.18175  2.89730  2.37895  2.77536  2.98514  4.58473  3.61505
+          0.63487  1.25520  1.68753  1.39580  0.28453  0.74756  0.64154
+     91   2.43987  5.24839  2.75312  2.20207  4.11839  3.54175  3.72993  4.06095  2.07671  3.34429  3.98666  2.75679  3.72576  2.60349  2.28520  2.46158  2.79062  3.43756  5.68761  3.81452    172 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01352  4.70589  5.42824  0.61958  0.77255  0.34096  1.24163
+     92   2.56414  5.37054  2.84426  2.11401  4.71382  2.70860  2.88683  4.19851  2.19051  3.14492  4.41168  2.55924  4.03189  2.79129  2.63798  2.35762  3.09530  3.76022  5.80426  3.44686    173 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01035  4.97167  5.69402  0.61958  0.77255  0.60365  0.79145
+     93   2.86527  4.78061  2.95620  2.59670  4.27271  1.99448  3.84571  3.48713  2.08881  3.39073  4.33266  2.46895  3.64059  2.84730  2.63768  2.84659  2.50396  3.24160  5.73764  4.35043    174 g - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01035  4.97167  5.69402  0.61958  0.77255  0.46145  0.99524
+     94   2.57883  3.45102  3.31966  2.70191  4.02973  3.16828  3.76144  3.12068  2.26544  3.06289  4.10647  2.81108  2.70638  2.99156  2.57108  2.49596  2.68439  2.78596  4.48656  4.03099    175 k - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01001  5.00539  5.72774  0.61958  0.77255  0.51640  0.90799
+     95   3.00846  4.37852  4.95050  4.33851  2.03946  4.18408  4.51243  2.07907  4.13124  1.32746  2.71567  3.86888  4.53472  4.25457  4.14405  3.49709  3.23945  2.15194  4.98866  3.35208    176 l - - T
+          2.68632  4.42239  2.77534  2.73137  3.46298  2.40515  3.72509  3.29351  2.67755  2.69332  4.24641  2.90361  2.73734  3.18136  2.89815  2.37881  2.77519  2.98532  4.58491  3.61446
+          0.13280  2.11108  5.72774  1.00017  0.45858  0.46707  0.98573
+     96   2.55096  5.39506  2.51329  2.14467  4.73966  3.20813  3.84532  4.22553  2.37049  3.70015  4.43599  2.79265  3.16832  2.74582  2.82569  1.88822  2.42672  3.78548  5.82793  4.41687    180 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     97   2.55253  5.00371  2.91674  1.56530  3.77486  3.74196  3.71669  3.18678  2.77868  2.90828  3.00031  3.29724  3.28640  3.12328  3.07027  2.76413  2.89289  3.32236  3.74938  3.48354    181 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     98   2.59075  4.32000  2.44335  2.15201  3.95693  3.12347  3.34011  3.83572  2.30797  3.16698  3.93315  2.75363  3.60071  2.81660  2.61665  2.70578  2.85000  3.34465  3.67935  4.00275    182 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+     99   2.65092  5.35978  2.44414  1.82235  4.69093  3.44711  3.03513  3.63938  2.46445  2.69072  4.40412  3.13476  3.87902  2.43027  2.99516  2.67955  2.75495  3.20344  5.80088  4.03299    183 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    100   1.86496  3.02665  4.71869  4.11439  3.41506  3.78632  4.39467  1.72869  3.93413  2.03606  3.25110  4.17623  4.43415  4.09606  3.42450  3.02051  2.94480  2.04904  4.94015  3.76003    184 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    101   2.66380  3.60669  3.09016  2.70629  3.97052  3.12773  3.91117  3.25572  1.80561  2.74214  4.19581  3.23071  4.10037  2.51557  2.19861  2.73033  3.11863  2.97558  5.62300  4.27841    185 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    102   2.65525  3.61780  2.73206  2.59880  2.91626  3.69337  3.17740  3.91061  2.06495  2.87551  3.62080  2.65252  4.08468  3.01717  2.55140  2.50072  2.84956  3.37543  5.67937  3.86408    186 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    103   2.78549  3.75825  4.89230  4.27707  2.37628  4.09576  4.42870  1.58181  4.06146  2.16353  2.83229  4.25917  4.45832  4.19107  4.06819  3.40747  3.15724  2.08428  3.94244  2.32199    187 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    104   1.91854  4.04767  4.83572  4.22341  2.21465  3.82491  4.41156  2.18264  4.01792  2.17430  2.43077  4.22827  4.44431  4.15736  4.04152  2.82624  2.88622  2.07903  4.25105  3.74133    188 a - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    105   2.59846  4.94560  3.39451  2.56515  3.67443  3.44440  3.79808  3.54150  2.22767  2.11264  4.02778  3.19297  4.14629  3.16161  2.51054  2.63727  2.68778  3.11215  4.13689  2.62651    189 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    106   2.71202  4.65478  2.93025  2.07602  4.70407  3.24619  3.70431  4.18261  2.58938  3.67040  4.10390  3.00747  4.05496  1.41184  3.00214  2.55548  2.74962  3.75459  5.80879  4.40428    190 q - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510  
+    107   3.40758  4.70636  5.39472  4.82751  3.82844  4.73217  5.15283  1.33187  4.66862  1.85779  2.55181  4.88258  5.03394  4.81634  4.72035  4.07618  2.46891  1.37416  5.58393  4.41648    191 i - - H 
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    108   2.29107  3.23763  4.81578  4.20571  3.00975  3.26830  4.41487  2.37700  4.00619  1.39060  3.28560  4.22330  4.44775  4.15070  4.03923  2.94875  3.15303  1.86969  4.92930  3.75166    192 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    109   2.62933  4.07203  2.95927  2.08969  4.71415  3.53463  3.84677  3.97436  2.17805  2.82549  4.41873  2.79932  4.05232  2.53645  2.16719  2.25459  2.86145  3.76301  5.81311  4.40656    193 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    110   1.17650  4.82606  4.24050  3.83461  4.98724  1.08848  4.85992  4.42183  3.81285  4.07900  4.88120  3.97861  4.34888  4.10941  3.49121  2.50205  3.18154  3.58125  6.30917  5.10145    194 g - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    111   3.90271  5.14012  5.90469  5.33230  3.41122  5.28833  5.65529  2.02087  5.19062  0.88043  2.65524  5.45552  5.42442  5.15469  5.16815  4.66249  4.12260  1.40813  5.79888  4.77647    195 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    112   2.18892  5.38966  2.64044  1.97751  4.73333  3.65659  3.60437  3.92129  2.10090  3.35469  4.43069  2.33847  4.05005  2.60616  2.77179  2.58383  3.11351  3.51057  5.82316  3.92131    196 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    113   2.81051  5.07767  4.77644  4.29954  2.03535  4.57845  2.23184  3.59557  4.18346  3.18325  4.21755  4.37554  4.93163  4.33627  4.35340  3.88728  3.48134  3.41897  4.49144  0.85916    197 y - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    114   3.22459  2.61128  5.38969  4.79509  3.58979  4.68737  5.03975  1.79213  4.61293  0.89179  2.61919  4.84389  4.96801  4.69100  4.62327  4.02095  3.66625  2.57847  5.40913  4.29402    198 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    115   4.50357  5.94639  4.67261  4.49457  2.97674  4.90740  0.35314  4.75553  4.20979  3.98991  5.25041  4.60971  5.36272  4.62490  4.36557  4.47961  4.76464  4.60938  4.62703  2.51319    199 H - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    116   2.59851  4.33805  2.68311  2.05797  4.71676  3.15802  3.59362  3.65569  2.43439  3.32473  4.42034  2.78736  4.05190  2.70193  2.69422  1.73897  3.11362  3.60918  5.81450  4.40740    200 s - - H
+          2.68619  4.42226  2.77521  2.73118  3.46355  2.40514  3.72496  3.29355  2.67742  2.69356  4.24691  2.90348  2.73741  3.18131  2.89802  2.37888  2.77521  2.98510  4.58478  3.61505
+          0.04979  3.09322  5.73865  0.35009  1.21950  0.48576  0.95510
+    117   2.54785  4.42029  2.89622  2.25922  4.34868  3.66610  3.21799  3.71995  2.27125  3.07920  3.10189  2.25867  4.05899  2.34775  2.56766  2.85682  3.11428  3.36249  5.78309  3.93739    202 n - - T
+          2.68634  4.42198  2.77524  2.73138  3.46344  2.40486  3.72467  3.29300  2.67713  2.69352  4.24714  2.90371  2.73709  3.18145  2.89825  2.37911  2.77527  2.98532  4.58501  3.61528
+          0.09842  2.40225  5.73865  1.69597  0.20263  0.48576  0.95510
+    118   2.53322  5.34393  2.95935  2.59629  3.94657  1.84501  3.63806  4.14023  2.18335  3.64044  4.39013  2.55576  3.77395  2.95784  2.71428  2.21077  3.11477  3.72355  4.68564  4.39095    213 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    119   3.55513  4.24694  5.60079  5.05662  2.60993  4.96071  5.43324  0.97900  4.91818  2.09234  3.80321  5.12225  5.23216  5.06726  4.97588  4.32549  3.79818  1.34455  5.81250  4.64107    214 i - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    120   2.50668  3.55624  4.84676  4.23404  3.24346  4.08398  4.41611  1.66920  4.02684  2.01982  2.79518  4.23489  4.44784  4.16480  3.83668  2.91482  2.83994  1.71230  4.92013  3.32611    215 i - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    121   4.62495  5.94818  4.90176  4.71687  2.80207  5.05504  0.41821  4.71670  4.43975  3.92227  5.21366  4.70109  5.45885  4.74110  4.56151  4.57303  4.86606  4.59605  4.46431  2.05738    216 H - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    122   3.04282  4.16968  3.83274  3.22981  4.12386  3.92565  4.16387  3.45658  2.89535  2.79946  3.52962  3.63885  4.33284  3.40809  0.88367  3.03173  2.91452  3.20781  5.47983  4.24517    217 r - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    123   4.66549  6.56867  0.13049  3.73947  6.20930  4.51726  5.46620  6.15252  4.80154  5.54790  6.65359  4.31602  5.22661  4.77980  5.35908  4.57977  5.04873  5.69924  7.06132  6.05090    218 D - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    124   4.11594  5.30633  6.13178  5.57769  3.73657  5.59693  5.98457  1.50133  5.46568  0.67788  3.07617  5.76705  5.63423  5.36401  5.43088  5.00606  4.33175  2.14525  5.97972  5.01356    219 L - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    125   4.55719  6.24846  4.80697  4.34215  5.94023  4.73956  5.02576  5.52333  0.17090  4.86848  5.87217  4.66859  5.24422  4.23030  3.41495  4.59394  4.77093  5.20290  6.57866  5.65826    220 K - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    126   2.73388  4.87911  3.10327  2.90832  4.07991  3.41413  4.01646  3.20246  2.89177  2.38683  3.78561  3.39051  1.51394  3.22647  3.32105  2.31617  2.81372  3.19214  5.43675  4.15025    221 p - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    127   2.30763  5.39894  2.49711  1.50775  4.74209  3.53358  3.60730  4.22742  2.31483  3.70337  3.89187  2.94609  4.05547  2.65035  3.08133  2.29509  3.12215  3.78862  5.83238  4.42137    222 e - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    128   4.24075  6.04161  4.10323  4.13804  5.66046  4.44992  5.52992  5.77835  4.64675  5.26705  6.30900  0.15130  5.17553  4.91694  4.94682  4.32646  4.70552  5.25421  6.75952  5.61338    223 N - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    129   3.55135  3.88080  5.58388  5.03211  3.05772  4.93598  5.38843  0.81084  4.88763  1.84199  3.74557  5.09695  5.20522  5.02095  4.93631  4.29650  3.79207  1.75582  5.75938  4.60163    224 i - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510 
+    130   4.26500  5.46000  6.21355  5.61602  2.31085  5.64571  5.88455  2.68862  5.47780  0.52109  2.36789  5.81754  5.61663  5.25881  5.37169  5.03996  4.45544  2.72136  5.81387  4.88779    225 L - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    131   3.14725  3.80930  5.11896  4.51210  2.75868  4.35237  4.69393  1.48763  4.30885  1.32733  3.15909  4.51494  4.68518  4.42027  4.31553  3.67228  3.37834  1.91515  5.14039  3.60311    226 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    132   2.83132  4.28838  2.02200  2.41335  4.70055  3.12743  3.31546  4.17875  2.06503  3.46693  4.09733  2.49326  4.05387  2.94892  3.07895  2.27711  2.89161  2.90947  5.80603  4.40188    227 d - - E
+          2.68620  4.42227  2.77521  2.73125  3.46356  2.40515  3.72496  3.29356  2.67743  2.69346  4.24692  2.90348  2.73741  3.18137  2.89794  2.37889  2.77521  2.98513  4.58479  3.61505
+          0.19179  2.92011  2.11536  0.31959  1.29625  0.48576  0.95510
+    133   2.77846  5.34345  2.73873  2.12504  4.68884  3.31622  3.10327  4.17503  2.07146  3.64885  4.14408  2.35495  3.55373  2.53396  2.68259  2.30312  2.80970  3.73426  5.77591  4.07717    229 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01122  4.89146  5.61380  0.61958  0.77255  0.46383  0.99121
+    134   2.76231  5.37627  2.40965  2.30431  4.72103  3.48860  3.46007  4.20680  2.15285  3.68141  4.41704  2.22463  3.54282  2.67483  2.66394  2.48608  2.48229  3.08661  5.80911  4.39830    230 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01030  4.97674  5.69908  0.61958  0.77255  0.42506  1.06054
+    135   2.88621  4.31580  2.58861  2.52891  4.00821  1.80604  3.64216  3.70404  2.55848  3.01103  3.82083  2.93142  3.28125  2.96153  3.15140  2.63196  2.92652  3.07947  5.65563  3.39061    231 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    136   2.74326  5.32913  2.62872  2.23118  4.20190  3.27586  3.01088  3.39612  2.54602  3.28443  3.99578  2.66732  4.06020  2.45230  2.82728  2.54748  2.65672  2.69485  5.77785  3.49295    232 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    137   2.61635  3.28525  4.16732  3.71739  2.98202  4.03403  4.34546  2.03775  3.50788  1.92540  3.47356  3.38535  3.11745  3.96570  3.52677  3.32696  2.46663  1.86856  4.97202  3.78516    233 v - - E
+          2.68644  4.42087  2.77438  2.73125  3.46306  2.40580  3.72561  3.29182  2.67742  2.69394  4.24637  2.90298  2.73752  3.18209  2.89809  2.37898  2.77573  2.98487  4.58490  3.61464
+          0.36530  1.19470  5.73865  2.01193  0.14356  0.48576  0.95510
+    138   2.92386  3.12674  3.30583  2.50241  4.41812  3.73989  3.57074  3.83865  1.16713  3.42239  3.64701  3.25964  4.12762  3.06518  2.74407  2.94589  3.15200  3.22587  5.64420  3.71460    253 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    139   3.61791  5.07369  5.93139  5.42030  4.01697  5.40165  5.95563  1.06228  5.32659  1.08905  3.76387  5.56598  5.56723  5.42106  5.39317  4.81179  4.11011  1.74432  6.14737  5.05160    254 i - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    140   1.74479  2.79152  4.35686  3.77898  3.55350  2.78668  4.34505  2.08763  3.66685  2.55990  3.56128  3.98833  4.38080  3.89329  3.86150  2.46831  2.34811  2.41028  5.05799  3.86488    255 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    141   4.66549  6.56867  0.13049  3.73947  6.20930  4.51726  5.46620  6.15252  4.80154  5.54790  6.65359  4.31602  5.22661  4.77980  5.35908  4.57977  5.04873  5.69924  7.06132  6.05090    256 D - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    142   4.66482  5.73614  5.86239  5.64956  0.40883  5.43325  4.33355  3.86711  5.42110  2.16428  4.36705  5.11239  5.65371  5.16689  5.27011  4.83252  4.86624  3.98432  3.74189  2.69037    257 F - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    143   3.93699  5.85566  3.02816  3.87037  6.00993  0.21285  5.44927  5.75466  4.70121  5.27717  6.21696  4.31536  4.99427  4.76567  5.12629  4.02226  4.42780  5.10478  6.99282  5.96830    258 G - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    144   2.54355  3.67295  4.73868  4.13265  2.71576  4.06852  3.76754  2.37455  3.94756  1.20416  3.31174  3.74431  4.43365  4.10500  4.00521  2.64259  3.14725  2.29206  4.93223  3.75278    259 l - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03189  5.01631  3.69859  0.61958  0.77255  0.48576  0.95510
+    145   0.77520  2.86695  4.81978  4.47036  4.95592  3.15951  5.20700  4.36343  4.38394  4.08078  4.90451  4.25075  4.38058  4.58838  4.56864  1.45304  3.34905  3.34992  6.35477  5.22001    260 a - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.07711  4.99453  2.69658  0.61958  0.77255  0.54567  0.86620
+    146   2.54977  3.79925  3.16699  2.32606  4.48674  3.31547  3.84408  3.47518  1.75582  3.12339  4.25869  2.84258  4.04145  2.96441  2.18943  2.71334  2.91887  2.95414  5.67187  4.30075    261 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.13472  4.92824  2.13029  0.61958  0.77255  0.70219  0.68419
+    147   2.64685  3.78445  3.06669  2.61534  3.32325  3.67596  3.69246  3.14713  2.01231  2.43193  3.43451  3.16113  4.06301  2.47274  3.08778  2.74475  2.84906  2.65428  5.37440  4.07606    262 k - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.29473  4.80574  1.39802  0.61958  0.77255  0.92027  0.50818
+    148   2.40579  4.15423  4.25399  3.66267  2.39272  3.57693  3.44550  2.33935  3.03827  1.86796  2.97007  3.83355  4.18573  3.73297  3.67827  3.10851  2.93289  2.21754  4.76738  2.96352    263 l - - .
+          2.68635  4.42219  2.77489  2.73146  3.46367  2.40530  3.72500  3.29419  2.67720  2.69370  4.24630  2.90362  2.73727  3.18122  2.89818  2.37860  2.77478  2.98583  4.58472  3.61420
+          0.77167  0.63015  5.24955  1.50734  0.25038  0.20147  1.70117
+    149   2.68930  5.13793  2.99383  2.28756  4.12167  3.02811  3.40047  2.83046  2.53990  2.67433  3.91490  2.66806  3.85841  2.95123  3.08518  2.54554  2.43488  3.14237  4.83794  3.11842    281 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    150   2.67960  3.59834  3.08049  2.32634  4.00400  2.85568  3.65072  3.26198  2.22635  2.80014  3.89773  3.03566  3.90780  2.84131  2.77630  2.59674  2.54121  2.94346  4.66327  3.60288    282 k - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    151   2.78407  5.36932  2.80723  2.38070  3.95652  3.28210  3.31902  3.80407  2.38757  3.23090  4.41260  2.26860  2.87333  2.94776  2.55475  2.11230  2.82314  3.31603  5.80800  4.40313    283 s - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    152   2.55066  5.37311  2.42428  2.58328  4.70981  2.65546  3.66067  3.46611  2.34139  3.39818  4.41598  2.44705  3.58966  2.48003  2.87086  2.30355  2.92043  3.58081  5.81084  3.32103    284 s - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    153   2.61131  5.36709  3.05324  2.00706  4.70125  2.53001  3.45141  4.17959  2.46541  3.54879  4.41063  3.13225  3.27183  2.67970  2.77280  2.14590  2.62504  2.97295  5.80635  3.79465    285 e - - S
+          2.68619  4.42226  2.77520  2.73124  3.46320  2.40514  3.72495  3.29355  2.67742  2.69356  4.24691  2.90348  2.73740  3.18147  2.89802  2.37888  2.77520  2.98519  4.58478  3.61504
+          0.03620  3.43177  5.73865  0.40966  1.09027  0.48576  0.95510
+    154   2.80870  4.76397  2.82688  2.35901  3.53520  3.31737  3.24083  3.53679  2.31494  2.98485  3.52265  2.69923  3.15465  2.90046  2.56489  2.40361  2.83318  3.04461  5.74293  3.76697    287 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    155   2.38638  3.55872  3.84850  3.27925  3.07902  3.89951  3.49984  3.07191  2.87600  2.13071  2.79826  2.94436  3.28103  3.24012  3.30127  2.77627  2.52689  2.66914  5.17020  2.84075    288 l - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    156   2.88266  4.79637  2.63708  2.49106  4.69372  3.27452  3.02757  4.17056  2.31920  3.54781  3.84892  2.54158  3.83133  2.71114  2.83815  2.34796  2.07167  3.53868  4.84477  3.26548    289 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    157   2.55115  5.22307  2.81541  2.42597  3.84088  2.72211  3.45978  3.70939  2.65113  3.50012  4.03956  3.00145  3.26637  2.92366  3.12986  2.10982  2.09681  2.95270  4.42058  4.32902    290 t - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    158   2.79383  4.53543  3.94528  3.00256  2.28876  3.25886  4.19260  2.53698  3.31063  2.13485  3.51266  3.25465  3.61933  3.02975  2.60672  3.04108  3.13630  2.22820  5.12884  3.03437    291 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    159   2.54133  2.27249  3.62507  3.14565  3.48798  3.47382  4.20805  2.87324  3.24770  2.61629  3.62417  3.76153  4.31084  3.45605  3.15192  3.19594  2.77273  1.44309  5.11140  3.89714    292 v - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    160   2.50560  4.02210  4.21483  3.69251  4.03927  0.87585  4.50859  3.18042  3.62456  3.12203  4.01557  3.91946  4.34666  3.89680  3.91281  2.66630  3.23503  2.52015  5.49804  3.97346    293 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    161   2.98792  5.00679  3.18026  3.47531  5.09253  3.65988  4.75357  4.53531  3.72802  4.18133  4.99276  3.79669  4.37930  3.97717  4.12874  1.60941  0.74054  3.97784  6.39182  5.11951    294 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    162   2.69840  5.26022  3.00961  2.31122  4.20998  3.68086  3.63617  3.20701  2.41779  2.58849  4.31499  2.98486  2.62271  2.99075  2.13729  2.36313  3.11573  3.42385  5.72545  3.54571    295 r - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    163   2.71301  5.29924  2.59488  2.14743  3.52695  3.04037  3.28275  4.06670  2.61594  3.34508  4.35002  2.84026  3.31113  2.97459  2.36266  2.86533  2.70674  3.41928  3.03699  3.23042    296 e - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    164   4.65993  5.73598  5.69662  5.49898  1.97465  5.32012  3.31709  4.36240  5.29326  3.66395  4.92323  4.93743  5.59573  5.06816  5.17473  4.69695  3.41633  4.25844  2.61302  0.51590    297 Y - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    165   2.46851  3.63596  4.34730  3.76113  3.49978  4.00900  4.30977  2.55613  3.41377  2.11254  1.89168  3.40620  4.37893  3.86942  2.23584  3.08926  3.14320  2.13937  5.00600  3.81292    298 m - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    166   0.54633  4.79516  4.59072  4.34047  5.33605  3.22550  5.27451  4.80651  4.37656  4.47607  5.24769  4.21379  3.02084  4.58677  4.60871  1.81435  3.40538  4.05386  6.66459  5.53199    299 A - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    167   3.08666  5.02380  4.02349  3.92167  5.10908  3.73669  5.07487  4.62556  4.04836  4.33998  5.22795  3.34786  0.41351  4.38870  4.30726  3.26072  3.60085  3.40472  6.47905  5.20179    300 P - - H
+          2.68622  4.42144  2.77523  2.73111  3.46358  2.40517  3.72498  3.29358  2.67745  2.69359  4.24694  2.90351  2.73743  3.18126  2.89786  2.37891  2.77523  2.98522  4.58481  3.61507
+          0.03484  3.47295  5.73865  0.99675  0.46057  0.48576  0.95510
+    168   3.66837  6.19086  2.84947  0.45189  5.55161  3.90523  4.43200  5.09782  3.30487  4.55035  5.42336  3.03786  4.53514  3.60153  3.37398  3.54999  3.95969  4.65772  6.64024  5.17650    305 E - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510 
+    169   2.79774  4.32598  4.68241  3.67608  3.42171  4.06471  4.38713  2.01470  3.90321  1.87174  3.44282  4.15860  4.43014  3.77035  3.25202  3.36713  2.95239  1.31877  3.77234  3.76466    306 v - - H
+          2.68603  4.42242  2.77519  2.73104  3.46342  2.40506  3.72511  3.29371  2.67728  2.69322  4.24707  2.90364  2.73756  3.18163  2.89801  2.37893  2.77519  2.98535  4.58494  3.61520
+          0.12919  2.22240  4.35495  1.23224  0.34480  0.48576  0.95510
+    170   2.91184  3.76308  4.76588  4.15799  3.39752  4.06920  3.82796  1.60071  3.96642  1.39613  3.17824  3.65225  4.43387  4.11848  4.01348  2.94594  3.14403  2.21737  4.92444  3.43929    311 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00999  5.00664  5.72898  0.61958  0.77255  0.51297  0.91308
+    171   2.62785  5.06480  3.29796  2.67561  3.73804  3.41086  3.92577  3.21358  2.32640  2.15096  3.31180  2.55443  4.11004  2.47045  2.33927  2.70318  3.11578  3.12852  5.57146  4.24107    312 l - - C
+          2.68631  4.42245  2.77511  2.73076  3.46350  2.40522  3.72547  3.29356  2.67765  2.69366  4.24573  2.90389  2.73738  3.18142  2.89826  2.37846  2.77520  2.98520  4.58530  3.61473
+          0.62427  1.87899  1.16602  1.98855  0.14722  0.46912  0.98231
+    172   2.60166  5.18307  2.62016  2.19793  3.35206  2.39740  3.57105  3.96340  2.18128  3.47543  4.23188  3.01161  3.92489  2.82990  2.86326  2.33987  2.67701  3.55746  5.63416  3.78538    327 k - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01428  4.65191  5.37425  0.61958  0.77255  0.24611  1.52250
+    173   2.37600  3.94341  2.81761  2.45806  4.08381  2.38833  3.32666  4.15213  2.47322  3.64753  4.39446  2.71786  3.74359  2.39493  2.76163  2.38666  3.00597  3.01776  5.79219  3.82026    328 a - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00998  5.00778  5.73012  0.61958  0.77255  0.47101  0.97916
+    174   2.81816  4.87774  2.88922  2.34131  3.91699  3.47934  3.84840  3.76601  2.22767  3.10881  4.41163  2.46519  2.75598  2.51039  2.43545  2.43680  2.76354  3.54179  5.80719  3.84984    329 k - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    175   2.74169  5.33416  2.58184  2.32653  3.61666  2.33545  3.50275  4.12419  2.36762  3.50261  3.56274  2.91332  3.07814  2.74477  2.96926  2.79421  2.92848  3.32496  5.78164  2.72284    330 e - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    176   2.48397  4.72191  2.72922  2.94719  3.45604  3.83733  2.73484  2.72590  3.03376  2.94128  3.81928  3.51045  4.21965  3.13222  3.31573  2.84267  3.12967  2.71705  3.94971  1.76193    331 y - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    177   2.88858  5.15756  2.48812  2.69267  3.68939  2.20273  3.90720  3.84889  2.69072  3.17648  4.22648  3.21985  3.19313  3.04303  3.16266  2.07644  2.02474  3.50391  5.64990  3.69862    332 t - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    178   2.44412  5.27089  3.18567  2.52594  4.01181  3.49400  3.20300  3.68711  2.26882  2.99802  4.32458  3.16791  2.73532  2.67304  2.47574  2.35896  2.41445  3.31659  5.73361  3.79657    333 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    179   2.27957  5.36842  3.14470  2.24142  4.70283  3.35867  3.70433  4.18054  1.84880  3.00297  4.41216  3.13478  2.50109  2.87247  2.49374  2.50485  2.88881  3.75338  5.80713  4.40386    334 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    180   2.25487  3.19836  3.67383  3.53894  3.58335  3.60706  4.24810  2.30247  3.45618  2.57768  3.58074  3.40343  4.33674  3.48890  3.71724  2.25302  2.94661  1.56396  5.07167  3.86608    335 v - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    181   3.32488  6.23611  0.30142  2.99559  5.85936  3.97225  4.81661  5.46625  4.07634  5.00781  5.98660  3.57219  4.70996  4.04099  4.76451  3.76774  4.26196  4.95940  7.04785  5.56474    336 D - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    182   2.97530  4.34655  4.92112  4.31006  3.42469  4.15298  4.48903  1.67409  4.10270  2.14170  2.44181  4.30839  4.51041  4.23558  4.11915  3.46567  2.80277  1.45020  3.28394  3.56694    337 v - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    183   4.60767  5.71652  5.61554  3.89031  2.18526  5.28181  4.15190  4.32304  5.18037  3.62888  4.88484  4.90634  5.56392  5.01906  5.10312  4.65700  4.81381  4.22147  0.60655  1.74323    338 W - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    184   1.30551  4.78823  4.65738  4.37945  5.36630  2.58206  5.28849  4.84019  4.38318  4.50739  5.27020  4.22569  4.39579  4.59600  4.61395  0.79404  2.89139  4.06528  6.68751  5.56026    339 s - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    185   2.44153  3.17932  4.87400  4.25972  2.53121  4.09082  4.42403  2.33144  4.04748  1.34403  2.92510  4.24940  4.45392  4.18053  4.05982  3.14600  3.15398  2.13810  4.92017  3.14864    340 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    186   2.22507  4.96728  4.63623  4.63233  5.66307  0.33314  5.62287  5.16416  4.86793  4.86816  5.66661  4.43512  4.57282  5.01497  4.99264  3.26151  3.63533  4.32703  6.92990  5.89905    341 G - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    187   2.93009  2.13614  4.95885  4.35253  3.48038  4.19799  4.54424  1.68794  4.14925  1.93394  3.18432  4.35359  4.55452  4.28834  4.17024  3.34008  3.23972  1.60527  5.03746  3.47367    342 v - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    188   3.21831  4.55127  5.17022  4.58630  3.70338  4.47717  4.86313  1.30610  4.40976  1.92114  2.79907  4.62299  4.81179  4.56490  4.45688  3.52794  2.67243  1.42404  5.34369  4.16408    343 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    189   2.77853  3.56970  4.91220  4.29933  2.66878  4.13468  4.46922  2.12981  4.08926  1.13811  3.14072  4.29275  4.49323  4.21981  4.10205  3.44689  2.88537  2.20246  4.95897  3.46211    344 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    190   2.08301  4.31008  4.80905  4.20025  2.66597  4.08391  3.54227  2.07553  4.00182  2.35024  3.19529  4.21899  4.44796  4.14611  4.03654  3.39206  3.15615  2.32332  2.91148  1.86433    345 y - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    191   2.65126  3.79080  3.03118  1.37895  4.54227  3.68257  3.87660  3.27048  2.56225  3.53374  4.30787  2.88399  4.07460  2.72714  3.11894  2.49943  2.86114  3.20681  5.71940  3.61825    346 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    192   2.75949  4.33120  4.86063  4.24972  2.93412  4.11800  4.44873  2.58063  4.04775  1.34098  1.86205  4.26240  4.47769  4.18564  4.07448  3.30982  2.87183  2.17494  4.95131  3.25026    347 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    193   2.13730  3.34433  4.84746  4.23449  2.67079  4.08305  4.41495  2.45417  4.02682  1.45586  2.95446  4.23448  4.44687  4.16424  3.65241  3.39295  2.78239  2.10310  4.91833  3.10946    348 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    194   2.61714  3.04119  3.51958  2.50105  3.16562  3.44068  4.02999  3.26384  2.78703  2.46125  3.90521  2.94061  4.18669  3.26384  2.94427  2.45451  1.92365  2.96026  5.36672  3.77569    349 t - - H
+          2.68592  4.42131  2.77530  2.73134  3.46364  2.40523  3.72505  3.29364  2.67751  2.69365  4.24624  2.90357  2.73750  3.18157  2.89769  2.37886  2.77510  2.98507  4.58487  3.61513
+          0.08274  2.77459  4.07273  1.24373  0.34011  0.48576  0.95510
+    195   2.74009  5.38236  2.60734  2.58658  4.30151  1.49346  3.57775  4.19577  2.06867  3.68256  4.42710  2.84258  4.06100  2.86136  2.79826  2.78642  3.12785  3.76776  5.82019  4.41533    355 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02515  5.00240  4.01100  0.61958  0.77255  0.52459  0.89600
+    196   2.87057  4.15783  2.81932  2.15097  3.67482  3.00161  3.44561  3.53712  2.01194  3.52030  4.39830  2.84675  4.04172  2.62971  2.18111  2.65254  2.90372  3.46034  5.79407  3.92999    356 k - - S
+          2.68632  4.42239  2.77496  2.73101  3.46368  2.40527  3.72508  3.29339  2.67739  2.69369  4.24616  2.90361  2.73734  3.18160  2.89815  2.37901  2.77533  2.98486  4.58491  3.61430
+          0.06990  2.74572  5.70978  1.46974  0.26135  0.43968  1.03351
+    197   2.53761  4.57755  3.85895  3.05555  3.06219  3.90225  3.89097  2.90555  3.23603  1.98376  3.43681  3.14844  2.18635  3.28921  3.56902  2.76101  2.38583  2.48063  5.16546  3.65117    363 l - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    198   2.94035  4.49377  4.16973  3.59341  3.59928  3.99457  4.28692  2.57573  3.48228  2.11382  3.59630  3.88641  1.19333  3.75706  3.46613  3.08341  3.17527  2.51467  5.10025  3.66586    364 p - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    199   2.95410  3.97958  4.76382  4.16399  1.23466  4.10162  4.38107  2.78567  3.65586  2.19089  3.46719  4.20671  3.78920  4.13156  4.03525  3.25126  3.18603  2.50296  2.73984  2.86766    365 f - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    200   2.72297  4.82530  2.62940  2.35446  3.83755  3.31971  3.71413  4.17131  2.26174  3.54363  4.14174  3.02369  2.60946  2.49179  2.66057  2.21727  2.99115  3.74587  4.55596  3.10965    366 s - - S
+          2.68620  4.42227  2.77522  2.73112  3.46340  2.40515  3.72496  3.29334  2.67743  2.69357  4.24692  2.90349  2.73742  3.18148  2.89803  2.37889  2.77522  2.98520  4.58479  3.61505
+          0.07731  2.84051  4.13492  0.30572  1.33404  0.48576  0.95510
+    201   2.63880  5.38435  2.63657  2.22720  4.72697  1.94780  3.15235  3.87964  2.57669  3.68860  4.42577  2.57921  3.16991  2.74291  2.86900  2.50219  2.85278  3.77370  5.81843  4.40865    368 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.52175  0.90012
+    202   2.40102  4.71375  2.46996  2.13243  4.71840  3.11745  3.05416  3.48265  2.25142  3.16134  4.41932  2.93828  3.25177  2.60824  2.79040  2.58260  2.90071  3.38079  5.81277  4.40438    369 e - - S
+          2.68658  4.42180  2.77453  2.73123  3.46394  2.40505  3.72421  3.29333  2.67765  2.69382  4.24730  2.90354  2.73686  3.18110  2.89829  2.37906  2.77522  2.98525  4.58428  3.61543
+          0.55463  1.48984  1.60791  1.39890  0.28351  0.52175  0.90012
+    203   2.69338  5.29005  2.51143  2.25105  4.62988  2.84270  3.49832  3.48405  2.27737  3.31427  4.33211  2.56706  3.20350  2.85310  2.67590  2.21378  2.73620  3.67787  5.72586  4.31806    375 s - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01250  4.78398  5.50633  0.61958  0.77255  0.95212  0.48763
+    204   2.65942  5.19894  2.69156  2.28179  3.77027  3.19251  3.77484  3.06173  2.43464  2.99400  3.94013  2.58274  3.44930  2.63512  2.62020  2.46578  2.71730  3.35179  5.65696  3.80565    376 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01250  4.78398  5.50633  0.61958  0.77255  0.77169  0.62033
+    205   2.38920  5.21254  2.73488  2.26876  4.51445  3.29559  3.03245  3.05648  2.42252  2.83088  3.97624  2.72691  3.66747  2.74292  2.65924  2.79642  2.87825  3.04317  5.67196  3.47007    377 e - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01186  4.83615  5.55849  0.61958  0.77255  0.33713  1.25111
+    206   2.65422  4.48489  1.88534  2.29942  4.71042  3.12833  3.84224  3.67843  2.58000  3.67468  4.41498  2.22848  4.04754  2.86157  2.64414  2.33478  2.73698  3.75923  5.80928  4.40246    378 d - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.52175  0.90012
+    207   2.52228  5.35256  2.79874  2.27245  4.68298  3.15080  3.25420  3.81263  2.42135  3.03021  2.98061  3.02733  3.41549  2.09266  2.89624  2.43800  3.03420  3.22791  5.79412  4.39217    379 q - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.52175  0.90012
+    208   2.88352  5.03264  3.01718  2.64158  3.36791  3.41419  3.67586  2.82361  2.46533  2.06980  3.25199  2.87105  3.91016  2.67457  2.54739  2.67076  3.11488  3.35644  5.54543  3.24074    380 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.52175  0.90012
+    209   2.31106  5.21929  3.20358  2.11286  3.58411  3.54755  3.12693  3.74178  2.35878  3.37262  4.27754  3.18132  3.64073  2.21825  2.83044  2.63943  3.03559  2.71879  4.50670  3.34948    381 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01003  5.00344  5.72579  0.61958  0.77255  0.46390  0.99109
+    210   2.74907  4.02445  4.23598  3.43708  3.16042  3.98772  3.66116  2.29352  2.78065  1.91975  2.65717  3.64306  4.00461  3.79624  2.62994  3.12682  2.72367  2.05105  5.03295  3.83444    382 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    211   2.79706  4.32223  4.14412  4.07508  2.44930  4.05985  3.54709  1.67401  3.90204  2.17979  2.94629  3.31750  4.42562  4.07034  3.98057  2.91878  2.88141  2.01026  4.94063  2.95520    383 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    212   2.43063  3.51667  2.84063  2.33381  3.23751  3.53757  3.64461  3.61354  2.52297  3.04234  3.80037  3.02528  3.31294  2.77439  2.36706  2.71893  3.04140  2.71650  5.64517  3.47973    384 e - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    213   2.54995  5.35768  3.14585  2.23433  4.68798  3.33616  3.38625  3.80986  2.09254  2.85705  3.68757  2.56176  4.05535  2.40160  2.38927  2.57618  3.04385  3.36418  5.79929  3.79887    385 k - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    214   2.66499  5.02053  2.80345  2.59207  4.23983  3.19081  3.94632  1.95336  2.43621  2.96229  3.77095  2.92719  4.12615  3.11304  2.86357  2.94448  2.42822  2.54184  5.53679  4.21766    386 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    215   2.79062  4.84420  3.48859  2.83007  4.02200  3.06268  4.01637  2.98055  2.36084  1.68419  3.06982  3.40535  3.56488  2.89781  2.78978  2.64270  2.97298  2.81255  5.39215  4.11258    387 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    216   2.78422  4.40067  2.87114  2.38957  4.66317  2.42774  3.11725  3.68493  2.29738  3.11118  3.80555  3.07548  3.38861  2.66839  2.52841  2.36297  2.74889  3.71883  4.85618  3.72852    388 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04975  5.01631  3.17248  0.61958  0.77255  0.48576  0.95510
+    217   2.55009  3.88585  3.08502  2.47179  4.52328  2.60499  3.86026  3.74333  2.31088  3.21633  3.94275  3.03087  2.50945  2.97834  2.41589  2.69163  2.38722  3.38360  5.70135  4.11095    389 k - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01030  4.97686  5.69921  0.61958  0.77255  0.59090  0.80705
+    218   2.71816  5.35510  2.47492  2.28903  4.69101  3.44039  3.67059  2.92462  2.15295  3.03900  4.39818  2.98975  2.40750  2.74839  2.76016  2.49540  2.85213  3.74081  5.79327  4.38792    390 k - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02103  4.97686  4.27462  0.61958  0.77255  0.59090  0.80705
+    219   2.59242  4.56547  3.37418  3.24570  3.28039  3.87349  3.78552  2.80260  2.91515  1.85640  3.67045  2.94464  3.03710  3.48913  3.31352  2.93163  2.57101  2.12270  4.60315  3.29903    391 l - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01041  4.96623  5.68858  0.61958  0.77255  0.61678  0.77584
+    220   2.76552  5.35116  2.75065  2.09233  4.26840  3.39661  3.23930  3.45666  2.13782  2.93921  3.69074  2.78256  2.85112  2.85423  2.61182  2.41762  3.01864  3.73701  5.78920  4.16743    392 e - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01041  4.96623  5.68858  0.61958  0.77255  0.61678  0.77584
+    221   2.56616  4.88573  3.26662  2.33696  2.41520  3.27403  3.41068  2.92250  2.70761  2.68623  3.97070  3.19787  3.38122  3.16656  2.79903  2.47364  2.99470  2.86843  4.82552  3.32054    393 e - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01041  4.96623  5.68858  0.61958  0.77255  0.61678  0.77584
+    222   2.62567  5.35084  2.04845  2.35215  4.39252  3.47212  3.16243  3.98892  2.45186  3.65226  3.66396  2.66846  2.63580  2.82810  3.05661  2.22708  2.99549  3.54011  5.78899  3.92777    394 d - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03667  4.96623  3.53930  0.61958  0.77255  0.61678  0.77584
+    223   2.86103  4.03193  3.18635  2.38909  3.31435  3.61153  3.49109  2.70908  2.69769  2.69388  3.88535  3.22191  3.67076  3.11276  2.73635  2.49324  3.00545  2.72730  2.94731  2.96802    395 e - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01875  4.94025  4.47244  0.61958  0.77255  0.67631  0.71028
+    224   2.62521  5.12447  2.77972  2.44738  3.31605  3.53418  3.86652  3.33309  2.47319  3.03557  4.18886  3.10134  2.42408  2.60018  2.70100  2.64509  2.92363  3.22521  3.41935  3.46519    396 p - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.05901  4.93227  2.99396  0.61958  0.77255  0.69360  0.69269
+    225   2.68343  5.20702  2.88582  2.22963  3.55567  3.45903  3.65367  3.49248  2.11994  2.97314  4.26172  2.80968  3.57686  2.44336  3.06162  2.53581  2.67303  3.18308  3.73101  3.66292    397 k - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01130  4.88456  5.60691  0.61958  0.77255  0.78866  0.60597
+    226   2.68707  4.98468  2.82158  2.38405  3.75917  3.36024  3.65392  3.18317  2.38508  2.73942  3.76303  3.22111  3.36652  3.04584  2.96704  2.31757  2.64759  2.95752  3.21600  3.40268    398 s - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.11345  4.88456  2.30573  0.61958  0.77255  0.78866  0.60597
+    227   2.79298  3.84213  2.48108  2.52210  3.99851  3.60747  3.12972  3.13545  2.48018  3.05991  4.13768  2.83211  3.54520  2.93964  2.41588  2.35619  2.76810  2.97839  5.56015  3.44494    399 s - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02807  4.78362  3.94704  0.61958  0.77255  0.95264  0.48731
+    228   2.58191  4.56682  2.77742  2.37170  4.46635  3.58143  3.77449  3.50815  2.36445  2.67587  4.22448  2.86502  2.73607  2.80387  2.79297  2.07848  2.75446  3.53442  5.63386  3.74575    400 s - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.14447  4.76826  2.07130  0.61958  0.77255  0.97412  0.47405
+    229   2.74120  5.02625  2.90214  2.38037  3.96892  2.81361  3.75340  3.09744  2.29181  2.85276  3.79351  2.85134  3.31773  2.88600  2.57247  2.48932  2.74923  2.81409  5.51153  4.15648    401 k - - .
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02950  4.63827  3.94280  0.61958  0.77255  1.12880  0.39071
+    230   2.65814  5.03703  2.72915  2.44094  4.30481  3.19996  3.74471  3.73960  2.51991  2.72378  3.12113  3.05398  2.98987  2.79382  2.49179  2.12708  2.96796  3.38544  5.51898  3.52938    402 s - - .
+          2.68724  4.42293  2.77612  2.73159  3.46162  2.40699  3.72369  3.29398  2.67731  2.69321  4.24701  2.90285  2.73662  3.18257  2.89624  2.37860  2.77511  2.98573  4.58252  3.61251
+          0.60323  0.80254  5.34581  2.99471  0.05135  0.22221  1.61320
+    231   2.51767  5.38833  2.69504  1.91983  4.73145  3.65677  3.84405  3.51135  2.26714  3.33248  4.42951  2.74739  2.83044  2.63263  2.69535  2.26534  2.89575  3.77792  5.82218  4.12814    442 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    232   2.61324  5.33087  2.55247  1.71577  3.78905  3.51981  3.85697  4.11872  2.53837  3.37618  3.68276  2.71899  3.50504  2.96215  2.76975  2.43182  2.62759  3.19721  4.83386  4.08215    443 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    233   1.85315  2.66076  4.74963  4.14369  2.72361  2.76389  4.40211  2.66580  3.95769  1.60680  3.08425  4.19191  4.43908  4.11400  4.01342  3.37949  2.94810  2.35782  4.93743  3.75833    444 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    234   2.54113  3.93957  3.31567  2.58263  3.59686  3.36801  3.93655  2.84244  1.77469  2.55244  4.12290  3.02474  4.11900  2.54032  2.70090  2.93506  2.79964  3.23719  5.55956  3.97978    445 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    235   2.66035  5.38903  1.80529  2.16718  4.22724  3.25823  3.17680  4.00903  2.28647  3.50730  4.43018  2.97613  4.05032  2.48614  2.98498  2.31241  3.11375  3.77870  5.82277  3.97909    446 d - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    236   3.21254  4.56529  5.14365  4.53738  1.97526  4.40976  4.73239  2.19759  4.34073  1.04052  3.41232  4.55986  4.72994  4.44093  4.35221  3.72900  3.00622  2.20314  5.16040  3.53582    447 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    237   2.97518  4.05135  5.35921  4.78478  3.77817  4.66169  5.06989  1.35059  4.61468  1.50253  2.60400  4.82061  4.97178  4.75525  4.65269  4.00168  3.59517  1.52175  5.50364  4.33590    448 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    238   2.63113  4.16111  2.70523  2.01221  4.32546  2.89528  3.69801  3.91463  1.97992  3.37990  4.41866  2.72468  4.05215  2.88390  2.65380  2.44936  2.78930  3.52828  5.81309  3.68713    449 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    239   2.79532  4.56741  2.59886  2.26653  4.72524  2.97326  3.84498  4.20852  1.87988  3.68761  4.42563  2.67816  4.05093  2.72680  2.26697  2.39445  3.11354  3.44147  4.06926  3.70096    450 k - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    240   2.76031  1.91137  4.93344  4.32897  3.47342  4.21043  4.55379  2.12811  4.13437  1.60981  2.11111  4.35327  4.56463  4.27495  4.16872  3.52442  2.73881  2.49904  5.05160  3.88034    451 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    241   3.00579  3.43594  4.91160  4.30236  2.88535  4.17356  4.48924  2.41412  3.62991  0.97514  3.41700  4.31537  4.52645  4.23058  4.12367  3.48482  3.23680  2.59853  2.70167  3.78558    452 l - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    242   2.51291  3.86266  2.42773  2.26878  4.71076  3.65927  3.14908  3.51790  2.32370  3.67561  4.41657  2.44903  4.05255  2.58104  2.64695  2.72413  2.48024  3.27065  5.81133  3.77060    453 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    243   2.89024  4.99098  3.22187  2.69841  3.16242  3.74556  3.43367  3.45008  2.12873  2.47972  3.65551  3.30484  3.00902  2.69329  2.47140  2.87653  2.77051  2.80352  4.74384  3.09104    454 k - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    244   2.75442  4.59220  1.48443  2.55169  4.69407  3.66624  3.85987  4.16899  2.26580  3.66358  4.41104  2.16093  4.06270  2.96232  2.94350  2.69711  3.00639  3.21953  5.80766  4.40610    455 d - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    245   2.53666  4.51809  3.31495  2.50094  3.81458  3.47863  3.66745  3.68842  2.74796  3.30408  3.76297  2.90283  1.45947  2.98944  2.97069  2.84711  3.12065  2.90248  5.56105  4.23506    456 p - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    246   2.18867  5.36299  2.90524  2.21328  4.32931  3.53924  3.49382  3.97251  2.24621  3.14962  3.99253  2.78034  3.78478  2.54072  2.85251  2.30318  2.70173  3.25844  5.80328  3.47734    457 a - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    247   2.48590  4.36945  2.67418  2.22639  4.72760  3.65776  3.84501  4.21118  1.68322  3.11616  4.42723  3.02530  4.05117  2.52411  2.40832  2.54354  2.78662  3.77464  5.82017  4.41136    458 k - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    248   3.97870  5.88109  4.77637  3.79584  5.10245  4.51923  4.26030  4.68907  2.25479  4.07008  4.99673  4.06985  4.83329  3.42182  0.45649  3.98836  4.07883  4.42272  3.45519  4.78623    459 R - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    249   2.59820  4.04607  4.60274  4.00452  3.26886  3.61184  4.36773  2.06089  3.84570  1.56372  3.45362  4.11687  2.06890  4.02734  3.95003  2.68390  3.14561  2.58630  4.40258  3.38622    460 l - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04987  5.01631  3.16967  0.61958  0.77255  0.48576  0.95510
+    250   2.79362  5.19179  3.01710  2.75300  4.64905  2.77281  4.01085  4.10036  2.79939  3.46822  4.43166  2.61914  4.12461  3.14023  3.27668  1.68833  1.53351  3.69065  5.84113  4.47617    461 t - - T
+          2.68631  4.42192  2.77519  2.73130  3.46353  2.40482  3.72508  3.29367  2.67738  2.69360  4.24703  2.90360  2.73753  3.18148  2.89804  2.37867  2.77518  2.98532  4.58490  3.61498
+          0.12278  2.37863  3.77824  1.17468  0.36950  0.42506  1.06054
+    251   1.47902  3.78300  4.72209  4.11644  2.74562  3.65840  4.38345  2.02614  3.93274  2.07959  3.21794  4.17061  3.49702  4.09137  3.99270  2.98272  3.05871  2.38788  4.48487  3.74373    467 a - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01009  4.99737  5.71972  0.61958  0.77255  0.53813  0.87669
+    252   2.38222  4.71734  2.84513  2.05232  4.42547  3.25385  3.43556  4.19285  2.14440  3.09056  3.51596  2.80436  3.18490  2.67888  2.63294  2.69832  2.67125  3.58577  5.80764  4.40015    468 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01009  4.99737  5.71972  0.61958  0.77255  0.45436  1.00747
+    253   2.65797  4.06542  2.63237  1.57032  4.71890  3.65831  3.45654  4.20087  2.52289  3.68238  4.00276  3.00654  3.59507  2.12286  2.86428  2.58695  3.11362  3.45316  5.81563  3.91003    469 e - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    254   1.93383  3.77543  4.87213  4.26567  3.27005  3.35948  4.48352  1.60295  4.06924  1.71770  3.29328  4.28554  4.50523  4.21524  4.10410  3.45599  3.20183  2.00553  4.99383  3.81574    470 i - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    255   2.91099  3.35807  4.39311  3.80506  3.12662  3.41984  4.32058  2.74098  2.62412  1.35983  2.89439  3.70896  4.38574  3.55146  3.43970  3.02120  3.14303  2.30767  4.99433  3.18557    471 l - - H
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    256   2.62697  4.23577  2.94369  2.01671  4.73311  3.52212  3.12192  4.21804  1.98366  3.41966  4.43054  2.33684  4.05005  2.29561  2.80226  2.65814  2.90658  3.41449  5.82302  4.41298    472 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  5.01631  5.73865  0.61958  0.77255  0.48576  0.95510
+    257   2.67425  5.24257  2.69003  2.64384  4.09422  3.68496  1.59772  3.97575  2.52719  3.06621  3.97630  3.17995  4.07682  2.88982  2.86815  2.31165  2.78826  3.60139  5.71188  4.10399    473 h - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.18941  5.01631  1.79622  0.61958  0.77255  0.48576  0.95510
+    258   2.81850  5.23743  2.76502  2.35780  4.54654  3.39495  3.79640  3.57339  2.36240  3.35446  4.28834  3.08690  1.61434  2.83455  2.79066  2.56844  3.04975  3.37601  5.69198  4.30446    474 p - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01183  4.83873  5.56107  0.61958  0.77255  0.86853  0.54398
+    259   3.22678  4.58175  4.94227  4.40609  1.73776  4.31983  4.20406  3.01156  4.21650  2.23279  3.33965  4.33985  4.66520  3.80636  4.24184  3.63704  3.45535  2.61441  1.69956  1.91736    475 w - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01183  4.83873  5.56107  0.61958  0.77255  0.30436  1.33787
+    260   2.99670  4.36610  4.95290  4.33956  1.72799  3.71830  4.50360  1.92619  4.12878  1.69258  2.79907  4.33234  4.52551  4.25179  4.13733  3.48573  3.22794  1.98896  4.25850  3.81122    476 l - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00667  5.01308        *  0.61958  0.77255  0.00000        *
+//
diff --git a/test/jalview/io/test_fn3_hmm.txt b/test/jalview/io/test_fn3_hmm.txt
new file mode 100644 (file)
index 0000000..0dcfa22
--- /dev/null
@@ -0,0 +1,285 @@
+HMMER3/f [3.1b1 | May 2013]
+NAME  fn3
+ACC   PF00041.13
+DESC  Fibronectin type III domain
+LENG  86
+ALPH  amino
+RF    no
+MM    no
+CONS  yes
+CS    yes
+MAP   yes
+DATE  Fri Jun 20 08:22:31 2014
+NSEQ  106
+EFFN  11.415833
+CKSUM 3564431818
+GA    8.00 7.20
+TC    8.00 7.20
+NC    7.90 7.90
+STATS LOCAL MSV       -9.4043  0.71847
+STATS LOCAL VITERBI   -9.7737  0.71847
+STATS LOCAL FORWARD   -3.8341  0.71847
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   2.70330  4.91262  3.03272  2.64079  3.60307  2.84344  3.74204  3.07942  2.79841  2.65364  4.14864  2.95826  2.87120  3.02176  2.96125  2.44783  2.59757  2.57680  4.02726  3.21526
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.00000        *
+      1   3.16986  5.21447  4.52134  3.29953  4.34285  4.18764  4.30886  3.35801  3.70246  2.11675  4.32057  4.32984  0.76706  3.91880  4.22437  3.23552  3.21670  2.88223  5.80355  3.93889      1 p - - -
+          2.68629  4.42236  2.77530  2.73088  3.46365  2.40512  3.72505  3.29365  2.67737  2.69316  4.24701  2.90358  2.73734  3.18157  2.89812  2.37898  2.77517  2.98515  4.58488  3.61514
+          0.09796  2.38361  6.81068  0.10064  2.34607  0.48576  0.95510
+      2   2.70230  5.97353  2.24744  2.62947  5.31433  2.60356  4.43584  4.79731  3.17221  2.95090  5.01531  3.26630  2.09873  3.30219  3.34190  1.45782  3.14099  3.57507  6.40877  4.25623      3 s - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+      3   1.38116  5.98285  3.50784  2.54546  5.32790  3.48945  4.43311  4.81385  2.38773  3.98773  5.02352  3.27895  1.92260  2.69012  2.96119  2.64228  3.29228  3.29618  6.41555  4.20553      4 a - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+      4   3.32856  5.10403  4.47046  4.60386  4.23079  4.75438  5.09647  2.69918  4.46632  2.97102  4.23502  4.77984  0.63388  4.68581  3.76781  4.05413  3.46306  2.04533  5.75329  4.56372      5 P - - -
+          2.68616  4.42236  2.77530  2.73134  3.46365  2.40523  3.72505  3.29295  2.67751  2.69303  4.24634  2.90357  2.73739  3.18157  2.89783  2.37897  2.77530  2.98529  4.58488  3.61514
+          0.09682  2.39494  6.81068  0.10162  2.33687  0.48576  0.95510
+      5   2.95325  4.65976  3.57762  2.20709  3.14816  2.51487  3.41109  4.78902  2.65862  3.19599  4.41042  3.45032  3.44719  2.43205  2.26492  2.25400  2.23196  3.66828  4.80003  4.52485      7 e - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01246  6.08833  4.59386  0.61958  0.77255  0.48576  0.95510
+      6   2.74215  5.97618  2.19482  2.69150  4.58171  2.33553  3.83525  3.28222  2.95080  3.32698  5.01691  1.45822  3.52462  2.79670  2.90942  3.13467  3.27956  4.36668  6.40902  3.92307      8 n - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00341  6.07928  6.80162  0.61958  0.77255  0.44282  1.02784
+      7   3.32507  4.98102  3.78072  3.31043  2.85257  4.76439  5.09585  2.50332  4.69760  1.03851  3.36125  4.91001  2.73206  4.83820  4.72389  4.07376  3.83146  1.59790  5.60385  4.42704      9 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.03752  6.08833  3.36505  0.61958  0.77255  0.48576  0.95510
+      8   3.15997  4.90658  3.35204  2.72775  4.53493  3.60960  2.65074  3.69535  2.11078  4.01384  4.99896  3.14668  4.61695  2.40643  2.34723  1.92358  2.03982  3.05153  6.39127  4.98082     10 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00349  6.05430  6.77664  0.61958  0.77255  0.35749  1.20207
+      9   1.76295  3.98252  5.55061  4.93551  2.13202  3.39992  5.09294  2.14638  4.23898  2.23988  3.42109  4.92079  4.39252  3.70640  3.99349  3.50811  3.63432  1.47830  4.51148  4.41177     11 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     10   3.01387  4.98892  2.91217  2.42744  5.22342  4.00576  3.74074  2.67275  2.47618  2.92529  3.89570  3.36720  4.15809  3.26810  2.80854  1.81572  2.02040  2.77133  4.92415  4.31555     12 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     11   2.41247  5.98374  2.24093  2.04842  3.41543  2.59695  4.10033  4.81544  3.05501  4.28918  5.02429  2.22829  2.90635  3.12939  3.01921  2.37278  3.01194  3.02522  6.41619  3.66635     13 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.06784  6.08833  2.75947  0.61958  0.77255  0.48576  0.95510
+     12   2.77725  4.36386  3.23435  2.92496  4.75140  4.31852  4.53101  1.91389  3.01135  2.51491  3.47932  2.97934  3.54432  2.88257  2.68923  3.07794  2.71169  1.80880  6.06849  4.75973     14 v - - E
+          2.68623  4.42259  2.77533  2.73059  3.46323  2.40500  3.72529  3.29333  2.67757  2.69369  4.24724  2.90364  2.73744  3.18108  2.89835  2.37891  2.77531  2.98493  4.58511  3.61510
+          0.22113  1.62346  6.74643  0.44471  1.02446  0.29166  1.37446
+     13   3.17575  5.97994  3.10322  2.84738  5.32369  2.00173  4.43389  4.80873  3.01150  3.75019  4.42663  2.23751  4.64014  2.74467  2.85546  1.99984  1.67133  4.36987  5.08444  3.58488     18 t - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     14   2.14203  5.98483  2.53686  2.20884  5.33077  2.76253  3.61799  4.81737  2.91636  3.96256  5.02525  2.79307  2.44932  3.35978  3.34773  1.76758  2.51815  4.12754  4.53404  4.35768     19 s - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02274  6.08833  3.90154  0.61958  0.77255  0.48576  0.95510
+     15   3.45984  5.96297  2.32904  2.98671  5.30486  3.14893  3.59992  3.68067  2.95954  4.26690  5.00447  2.01875  4.62814  3.51950  2.89162  1.97303  1.47565  3.87160  6.39755  3.59993     20 t - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00344  6.06904  6.79138  0.61958  0.77255  0.40302  1.10352
+     16   2.82603  5.98256  2.96292  2.53617  4.39559  3.14388  4.09532  4.81336  2.59005  4.28779  5.02326  3.12547  4.63955  2.76620  3.03618  1.28432  2.14874  3.55065  4.82032  3.29405     21 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     17   2.29842  4.96481  5.56794  4.95172  2.45211  3.33868  4.31545  1.97312  4.73378  1.34355  2.88087  4.92903  5.12608  4.86259  4.73754  4.07438  3.55674  1.71344  5.58685  3.78328     22 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     18   2.99930  4.68496  3.44656  2.53427  3.92510  4.04338  3.13178  3.10095  3.07007  2.68343  3.58599  3.17010  4.15335  2.63450  2.71950  2.30083  2.03779  2.23518  4.92400  3.84991     23 t - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     19   3.61302  4.50726  5.99163  5.39935  2.74200  5.23506  5.61087  1.85210  5.20622  1.10188  3.56291  5.40353  5.56305  5.33364  5.22134  4.56441  3.85751  1.20867  6.05610  4.88933     24 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     20   2.90508  5.98486  3.37356  2.37027  5.33083  3.46854  3.40789  4.81743  2.65230  3.22177  4.17825  2.67373  4.63906  2.52648  2.39431  1.50547  2.16764  4.37598  5.01440  5.00552     25 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     21   5.54218  6.63564  6.83891  6.61797  2.57168  6.35073  5.30532  3.96643  6.37377  3.18917  5.26281  6.07009  4.35269  6.11992  6.21105  5.74680  5.75143  4.86346  0.24436  3.66807     26 W - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     22   3.10862  5.98423  2.61761  2.10221  4.46995  3.93009  3.84182  3.79843  2.19229  3.09373  4.47555  2.66452  4.06864  2.59255  2.99987  1.99073  2.05618  3.67318  6.41655  4.47364     27 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     23   2.05280  5.87614  3.77610  2.63103  5.17655  3.25143  3.55897  3.09279  2.68152  3.35866  4.92882  3.43937  1.44938  3.29932  2.98336  2.85751  2.78420  3.02863  4.43359  4.47040     28 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     24   2.65644  5.88726  3.37601  2.96202  5.19190  3.53629  4.46143  4.20046  2.87295  2.91429  4.93884  3.27084  1.07653  3.39095  3.69926  2.07705  3.29723  2.92337  6.34501  4.95985     29 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.32165  6.08833  1.29911  0.61958  0.77255  0.48576  0.95510
+     25   2.44244  5.77880  2.64467  2.21733  3.20572  3.66340  3.27861  4.60939  2.17717  2.95495  4.81953  3.17778  2.62084  2.96028  2.64039  2.55818  2.51134  3.52175  6.21164  4.20060     30 k - - S
+          2.68557  4.42278  2.77404  2.73101  3.46370  2.40555  3.72548  3.29364  2.67779  2.69337  4.24743  2.90378  2.73741  3.18051  2.89835  2.37928  2.77557  2.98526  4.58530  3.61392
+          1.12909  0.74203  1.60680  0.24883  1.51281  1.67198  0.20810
+     26   2.76497  5.64634  2.06362  2.44254  4.06108  3.91520  3.28362  3.73992  2.46695  3.95074  4.68755  2.93859  2.87257  2.71813  3.08100  2.16767  2.28242  3.00778  6.08028  4.00221     33 d - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00580  5.54941  6.27176  0.61958  0.77255  1.23854  0.34222
+     27   2.94904  4.81418  2.88265  2.99332  4.83563  1.49306  3.87927  3.68299  2.59086  2.53757  4.07313  2.89409  2.92833  3.04624  2.88166  2.82744  3.22994  3.21444  4.18838  4.04981     34 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00508  5.68074  6.40309  0.61958  0.77255  0.20085  1.70396
+     28   2.96588  5.95917  2.45759  2.65943  5.30490  1.91234  3.11781  3.44164  2.78003  4.01788  4.99965  2.12379  3.26764  2.84040  2.87160  2.26272  3.15721  3.84740  4.86821  3.64128     35 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00351  6.05095  6.77330  0.61958  0.77255  0.34864  1.22298
+     29   2.45969  5.96445  2.88574  2.61716  5.30131  1.53630  4.43818  3.46883  2.98393  3.60366  4.33332  3.25719  4.28257  3.08417  2.40821  2.08539  3.20111  2.81105  6.40207  4.25093     36 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     30   2.71563  5.98438  2.50720  1.96228  5.33013  3.47246  3.38617  3.68065  2.34086  4.03521  4.36775  3.08029  1.87041  2.90329  3.33287  2.70645  2.77558  2.97286  6.41666  4.17777     37 p - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     31   3.04837  4.96747  2.67316  4.92527  2.42064  4.14655  5.09097  1.34551  4.71334  2.18068  3.34829  4.91585  3.31178  4.15082  4.72663  3.69906  3.53551  1.88881  3.93067  3.04034     38 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     32   2.89418  4.58676  2.12720  2.65970  3.99748  4.30700  4.50689  3.12934  2.75241  2.32504  4.34805  3.25317  4.69765  2.93544  2.97945  2.48570  1.85268  2.60501  5.05387  4.40931     39 t - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     33   3.05045  5.96458  3.15002  2.79713  4.16491  1.56242  3.20986  4.07540  2.34002  3.77648  3.66616  2.65073  4.64351  3.21500  2.62101  2.34442  2.98761  3.25677  5.04578  3.36446     40 g - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     34   4.72855  5.99332  6.32397  5.91516  1.75259  5.71064  3.47111  3.64093  3.68669  3.44300  5.13564  5.60513  6.03397  5.64902  5.63703  5.05114  4.95149  3.46344  3.97019  0.49348     41 Y - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     35   3.03913  5.98101  2.74983  1.95825  3.75604  3.98121  3.78677  3.48894  2.41418  2.89991  5.02189  2.66693  4.63989  2.65222  2.20113  2.26435  2.64729  3.16844  6.41420  3.93691     42 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     36   3.75576  5.90373  6.92143  6.48083  5.27028  6.48043  7.33031  1.16190  6.46559  1.72148  4.18143  6.65320  6.63807  6.70678  6.63399  5.94811  5.00240  0.82398  7.51298  6.31097     43 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.04904  6.08833  3.08806  0.61958  0.77255  0.48576  0.95510
+     37   2.63429  4.71789  2.89387  2.04081  4.17861  4.22097  3.38514  2.92734  2.36124  3.26230  4.97143  3.69265  4.61418  2.27063  2.38238  2.70982  2.11937  3.37005  6.36711  3.73375     44 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00353  6.04282  6.76517  0.61958  0.77255  0.32899  1.27173
+     38   3.00800  2.48193  5.53105  4.91728  2.98458  4.75707  4.15268  2.83469  3.12355  2.32451  4.08737  4.91198  5.12099  4.84273  3.46182  3.58557  3.26283  2.28912  2.64554  1.29971     45 y - - E
+          2.68641  4.42053  2.77543  2.73091  3.46377  2.40536  3.72420  3.29377  2.67764  2.69378  4.24582  2.90336  2.73763  3.18113  2.89660  2.37910  2.77543  2.98542  4.58500  3.61526
+          0.12278  2.16768  6.81068  0.54422  0.86820  0.48576  0.95510
+     39   2.52553  4.02469  3.60093  2.65311  4.18239  3.63052  4.17989  3.44209  2.14970  3.12319  4.96260  3.43770  4.02454  2.12722  2.15391  2.32250  3.25888  3.40611  2.73453  3.57446     49 q - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02932  6.08833  3.62591  0.61958  0.77255  0.48576  0.95510
+     40   2.85303  5.96779  2.74660  1.91867  5.31393  3.60453  3.59476  4.33679  2.36399  3.57280  3.62613  2.83996  2.06170  2.51716  3.24767  2.43993  2.61505  3.39964  6.39984  4.98824     50 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00347  6.06248  6.78482  0.61958  0.77255  0.67944  0.70705
+     41   2.55267  3.11480  2.72137  2.31006  5.21613  3.67111  4.08491  3.18721  2.11932  2.73126  3.73119  3.72342  3.44703  2.78931  3.31632  2.60923  2.50487  2.33623  6.34948  4.95631     51 k - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.09789  6.06248  2.39773  0.61958  0.77255  0.38130  1.14877
+     42   3.41114  5.92195  2.00739  2.51445  4.35946  1.85149  4.04885  4.75310  3.02073  3.41727  4.96259  1.88803  4.57836  2.81891  2.77402  2.53317  2.79169  3.60394  6.35459  4.48731     52 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00370  5.99676  6.71911  0.61958  0.77255  0.25112  1.50474
+     43   2.89692  5.98568  2.39354  2.04021  5.33202  2.12548  3.27810  4.81889  2.36649  3.39071  4.58505  2.82477  4.63888  2.99231  3.02264  2.04514  2.45319  3.82791  6.41761  5.00590     53 e - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     44   3.10206  5.95088  3.50928  2.19657  4.70794  1.83640  4.44201  3.85177  2.81849  3.20653  3.64542  2.17673  2.82486  2.50236  3.67274  2.64718  2.71954  3.18909  6.39210  3.73228     54 g - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.08059  6.08833  2.58819  0.61958  0.77255  0.48576  0.95510
+     45   2.83017  5.93388  2.31048  1.94273  5.28007  2.46456  3.60606  4.35357  2.35448  2.95362  4.97424  3.06816  3.41033  2.69285  2.84649  2.21743  2.98206  3.67978  4.23187  4.95426     55 e - - C
+          2.68733  4.40831  2.77609  2.73043  3.46444  2.40393  3.72592  3.29278  2.67833  2.69426  4.24827  2.90407  2.73626  3.18024  2.89744  2.37952  2.77650  2.98614  4.58019  3.61570
+          1.45631  0.90375  1.01651  1.51529  0.24813  0.96821  0.47765
+     46   2.32839  5.42660  2.93163  2.28220  4.02543  3.04571  3.03894  3.22247  2.82753  3.21315  3.89864  3.49093  2.50859  3.14260  2.89921  2.69284  3.05772  2.38519  4.38264  3.20345     66 e - - G
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00571  5.56406  6.28641  0.61958  0.77255  0.18459  1.78051
+     47   2.69465  3.91083  2.42967  2.34662  4.43247  3.13708  3.62175  3.49809  2.56727  2.84127  4.03266  3.52527  3.00745  3.22895  3.52756  2.46523  2.69768  3.11906  2.19019  4.92515     67 w - - C
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00353  6.04443  6.76678  0.61958  0.77255  0.33269  1.26228
+     48   2.67627  5.86490  3.17099  3.22595  3.40616  4.27494  3.15476  3.07365  2.21494  2.78239  4.39426  2.30764  3.56160  2.19351  2.71433  2.94392  2.62330  2.55032  5.16850  4.37026     68 q - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     49   3.05871  5.98132  3.36643  1.71285  5.32569  3.90513  2.27648  4.25125  2.92072  4.28630  4.28595  2.90579  3.33969  2.79371  2.63337  2.42582  2.46361  2.81009  3.46671  3.72048     69 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     50   2.88323  4.65127  3.40086  2.73607  2.41972  3.62669  3.91044  2.52424  2.75640  2.37424  3.94274  3.64921  4.76561  2.38668  2.64750  3.03028  3.09193  2.27100  6.08057  3.03402     70 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     51   3.36533  5.95840  2.65995  2.86095  3.44584  4.25167  3.55888  2.90987  2.78397  3.33346  3.90493  2.03375  3.68901  2.80089  2.78508  2.11531  1.97302  3.15541  6.39763  4.99330     71 t - - E
+          2.68571  4.42246  2.77540  2.73144  3.46375  2.40497  3.72515  3.29375  2.67742  2.69376  4.24711  2.90367  2.73710  3.18135  2.89822  2.37876  2.77540  2.98457  4.58498  3.61524
+          0.06628  2.76409  6.81068  0.97562  0.47314  0.48576  0.95510
+     52   2.38926  5.49703  3.09615  2.80044  4.68202  3.76562  4.62096  2.19958  3.33274  2.03099  4.11871  2.97731  4.26404  3.83080  2.89542  3.19964  2.84193  1.56133  6.03936  4.75239     75 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     53   2.79501  4.92737  2.35659  2.60299  4.06511  2.98090  3.88301  4.80087  2.44593  3.57653  5.01701  3.37711  1.76863  3.53250  3.23955  1.94419  2.68524  2.95506  6.41016  5.00121     76 p - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     54   2.44542  5.98316  3.18675  2.55065  5.32835  2.12386  4.43300  4.38419  2.38413  2.93654  5.02378  2.50193  2.49139  3.27226  2.05133  2.36069  3.70337  4.12664  4.32391  4.48343     77 r - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     55   2.77179  5.98329  2.50848  2.76644  5.32854  3.30269  3.08416  4.38434  3.16759  4.28865  5.02390  2.27915  2.67265  2.61285  3.32102  2.18277  1.82444  2.83013  6.41587  4.35727     78 t - - T
+          2.68621  4.42251  2.77546  2.73149  3.46380  2.40468  3.72521  3.29380  2.67767  2.69252  4.24716  2.90344  2.73766  3.18134  2.89827  2.37913  2.77442  2.98545  4.58503  3.61529
+          0.07130  2.69245  6.81068  1.11635  0.39671  0.48576  0.95510
+     56   2.32530  5.97446  3.57954  1.89562  5.31575  4.24796  3.32554  3.73278  2.42253  2.98562  5.01611  3.71687  3.10116  2.71107  2.91871  2.60336  1.70360  3.15915  6.40941  5.00074     83 t - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.35248  6.08833  1.22151  0.61958  0.77255  0.48576  0.95510
+     57   2.95924  5.72336  2.75932  2.63159  3.96190  3.29462  3.22449  3.40062  2.77057  3.18108  3.56769  2.46117  2.98702  3.05715  2.72729  2.56520  1.96589  3.52719  6.16591  2.96938     84 t - - S
+          2.68622  4.42162  2.77539  2.73088  3.46349  2.40510  3.72514  3.29311  2.67761  2.69358  4.24710  2.90367  2.73759  3.18166  2.89753  2.37894  2.77488  2.98538  4.58497  3.61523
+          0.23969  1.55321  6.46298  0.15973  1.91309  0.51157  0.91517
+     58   2.78411  5.86726  3.65151  2.46190  3.55121  3.32277  3.71415  3.82816  2.87545  3.69015  4.27003  2.90512  3.60994  2.68731  2.37548  1.72361  1.95655  3.42914  6.30822  3.85760     87 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00384  5.96109  6.68344  0.61958  0.77255  0.21363  1.64843
+     59   2.13080  3.38910  5.56698  4.95075  2.41578  4.20194  3.39215  2.83299  4.73282  2.14660  3.19234  4.92810  5.12527  4.86169  4.18461  4.07348  3.03808  1.63705  4.66089  1.78369     88 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     60   3.12543  5.93769  2.99354  2.53954  5.26303  4.25659  3.21054  2.85212  2.62935  2.82513  3.45830  2.90110  4.19559  2.80624  3.10357  2.88568  1.50190  2.67316  6.38237  3.93622     89 t - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     61   3.61965  4.99402  3.63828  4.95783  2.26826  4.79135  5.12555  1.86647  4.74679  1.34194  3.74460  4.94944  5.15281  3.10559  4.75989  3.74420  3.85186  1.42486  5.61987  4.44474     90 l - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     62   3.10387  5.98366  3.06368  2.31445  4.05906  3.57903  3.48488  4.81531  2.43543  4.01680  3.91148  2.67498  2.99920  2.70828  2.56621  2.14984  1.90367  3.06274  4.55677  4.37671     91 t - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     63   3.34220  5.98744  1.86090  2.69096  5.33359  1.40608  3.63608  4.82043  2.48624  4.29318  4.45099  1.96888  4.06897  3.19339  3.48838  2.73868  3.70514  4.37867  6.41942  4.25681     92 g - - S
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     64   5.18530  6.36522  4.58586  6.57578  3.53131  6.59442  6.84537  2.81242  6.44067  0.21363  3.54046  6.78308  6.53953  6.19263  6.31583  5.99910  5.37457  3.39834  6.73440  5.83217     93 L - - -
+          2.68590  4.42227  2.77521  2.73125  3.46356  2.40515  3.72496  3.29356  2.67743  2.69357  4.24692  2.90349  2.73741  3.18148  2.89803  2.37889  2.77521  2.98520  4.58479  3.61505
+          0.02033  3.96193  6.81068  0.31431  1.31041  0.48576  0.95510
+     65   2.93361  5.98253  3.16620  2.07447  5.32745  3.84017  3.84639  3.52003  2.07989  2.71701  4.56317  3.05465  3.94228  2.39023  2.13660  2.81003  2.42767  2.98359  6.41531  3.87097     95 e - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     66   2.17452  5.85112  3.79178  2.44872  5.14174  4.27993  4.47388  4.59086  3.04069  4.13287  4.42378  3.36057  0.82761  3.31072  3.71538  3.13243  3.15654  3.97958  4.90439  4.38214     96 p - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     67   2.72531  5.97666  2.50761  2.79752  4.22378  1.29966  2.70734  4.80294  2.85170  4.02964  5.01805  2.59981  4.64085  3.32835  3.25617  2.51345  3.59137  3.91820  4.88800  2.97800     97 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     68   2.39925  4.86641  3.79312  2.74568  5.13568  4.27988  3.97435  3.95098  2.69562  3.65359  3.00813  3.38952  4.67180  3.12070  2.33490  2.43668  1.27713  2.90106  6.31421  4.93977     98 t - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     69   2.87821  5.98261  2.71299  2.05681  3.93787  3.36966  3.57296  3.81023  2.25993  3.03102  3.49917  2.39917  3.09415  2.62154  2.82818  2.67359  2.51409  3.67730  4.58228  5.00448     99 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     70   6.32206  7.09639  6.95855  7.01624  2.70399  6.62558  5.12529  5.84365  6.77161  4.03604  6.32463  4.32154  6.86163  6.30239  6.48747  6.05185  6.49899  5.81871  5.18730  0.14189    100 Y - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     71   3.06725  5.97020  3.56838  1.93769  4.23056  3.77167  3.39655  3.53252  2.56448  3.45405  4.47893  2.47898  4.64226  2.55695  2.74362  2.36648  2.01401  2.66399  6.40629  3.70776    101 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     72   3.19486  4.19171  5.58508  4.96942  1.44027  4.15574  5.11433  1.81297  4.75161  2.09873  3.37140  4.94615  5.14143  4.88008  4.75485  4.09123  3.83769  1.47173  5.60267  3.09551    102 f - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     73   3.18039  4.06436  3.15201  2.27681  5.32468  3.77041  3.95744  3.70705  2.23538  4.28548  4.11883  2.88564  4.63997  2.58030  1.70576  2.27707  2.39981  3.62914  4.03739  3.61343    103 r - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     74   3.76685  5.84337  6.79391  6.31497  3.84743  6.27452  6.95358  1.59565  6.25134  2.11498  4.30213  6.44619  6.46746  6.44080  6.36566  5.70153  4.90672  0.53161  7.20703  6.03175    104 V - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     75   2.31005  4.88319  3.40675  2.63903  3.58848  4.26911  3.49342  3.09105  2.39543  3.00463  4.93879  3.41670  4.66153  1.98639  2.22144  3.11070  2.61129  2.78609  6.34491  2.92043    105 q - - E
+          2.68621  4.42228  2.77522  2.73126  3.46357  2.40516  3.72497  3.29357  2.67744  2.69312  4.24693  2.90350  2.73743  3.18149  2.89804  2.37890  2.77522  2.98521  4.58480  3.61506
+          0.03738  3.58894  4.70319  0.25135  1.50394  0.48576  0.95510
+     76   0.79499  5.17226  4.80437  3.93376  4.33120  3.17569  4.96596  3.30029  4.15773  2.86829  4.32533  4.52823  5.01384  4.41886  4.42465  2.28661  2.19420  2.76335  5.81537  4.60940    107 a - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00340  6.08033  6.80268  0.61958  0.77255  0.44741  1.01966
+     77   2.84306  4.15407  4.98296  3.19564  3.23517  4.66606  3.67524  2.49603  3.23224  2.21212  3.84796  4.62630  5.03633  2.88555  2.43211  3.49088  3.22704  1.33993  5.67363  2.88123    108 v - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     78   3.27061  4.75060  2.81965  3.10410  5.31934  3.95942  3.99367  3.88107  2.62205  4.02823  5.01830  1.35628  3.08534  3.32913  3.08546  1.88067  2.21938  4.02145  6.41122  3.76470    109 n - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00992  6.08833  4.87890  0.61958  0.77255  0.48576  0.95510
+     79   2.39836  4.69624  2.57939  2.56364  4.72011  1.55094  3.74815  4.26504  2.61409  4.28517  5.02018  2.82673  4.26340  2.69971  2.87382  2.73983  2.53993  3.07568  6.41202  5.00074    110 g - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00340  6.08180  6.80415  0.61958  0.77255  0.45398  1.00812
+     80   2.22211  4.94595  2.69424  2.44928  4.84552  2.32005  3.06335  2.95704  2.33976  3.55821  4.09648  2.87488  4.09930  2.85656  2.97877  3.08279  3.07714  2.39346  6.40553  4.01548    111 a - - T
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.38398  6.08833  1.15015  0.61958  0.77255  0.48576  0.95510
+     81   2.96920  5.43248  3.46409  2.76236  3.93019  1.02513  4.29951  4.07917  3.10833  3.39330  4.50784  3.40559  4.48149  3.45547  3.56956  2.50552  2.39680  3.76237  5.94228  3.01765    112 g - - E
+          2.68652  4.42259  2.77488  2.73144  3.46170  2.40466  3.72529  3.29388  2.67703  2.69373  4.24724  2.90335  2.73774  3.18162  2.89801  2.37895  2.77529  2.98552  4.58511  3.61537
+          0.29928  1.35852  6.43163  0.48724  0.95274  1.77816  0.18506
+     82   2.84273  4.18992  3.05053  2.12883  3.36284  2.75189  4.25559  3.03507  2.66396  2.65563  4.59024  2.63081  3.84786  2.76844  3.19058  2.84597  2.82776  2.89016  3.06821  3.41272    117 e - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00494  5.70928  6.43163  0.61958  0.77255  1.56406  0.23482
+     83   3.37920  5.61493  3.74277  3.20384  4.92800  1.01625  3.96683  4.35082  2.94708  2.91738  4.72998  3.71516  3.70329  3.52945  3.00683  1.61777  3.61882  4.00263  6.13360  4.80162    118 g - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00481  5.73459  6.45693  0.61958  0.77255  0.30535  1.33510
+     84   2.58463  5.93784  3.04102  2.09605  4.57465  2.51630  3.24109  4.26208  2.60545  3.44607  3.62705  3.20484  1.89678  2.68661  2.74662  2.97880  3.02092  3.23569  6.37074  4.50367    119 p - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00361  6.02233  6.74467  0.61958  0.77255  0.28862  1.38348
+     85   2.48488  5.72055  3.87501  1.97538  3.04853  3.48010  4.51877  3.51898  2.88839  2.73568  4.42660  3.64380  2.08811  3.48814  2.70856  2.40769  2.92982  4.05679  2.77386  3.43366    120 e - - B
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00338  6.08833  6.81068  0.61958  0.77255  0.48576  0.95510
+     86   3.03720  5.94099  3.75455  2.96917  5.26587  2.91682  3.66571  4.11840  2.98472  4.23738  4.98891  3.74380  4.66031  3.40955  3.12788  0.72443  2.46104  4.32115  6.38683  4.99111    121 s - - E
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00227  6.08723        *  0.61958  0.77255  0.00000        *
+//
index 95af77a..f0fbfc4 100644 (file)
@@ -52,6 +52,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLocus;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.PDBEntry;
@@ -65,7 +66,6 @@ import jalview.datamodel.features.FeatureMatcher;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
@@ -92,6 +92,8 @@ import jalview.util.matcher.Condition;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
+import junit.extensions.PA;
+
 @Test(singleThreaded = true)
 public class Jalview2xmlTests extends Jalview2xmlBase
 {
@@ -159,7 +161,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
             DataSourceType.FILE);
     assertNotNull(af, "Didn't read input file " + inFile);
     af.loadJalviewDataFile(inAnnot, DataSourceType.FILE, null, null);
-    AlignViewport viewport = af.getViewport();
+    AlignViewportI viewport = af.getViewport();
     assertSame(viewport.getGlobalColourScheme().getClass(),
             TCoffeeColourScheme.class, "Didn't set T-coffee colourscheme");
     assertNotNull(
@@ -827,7 +829,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
 
-    AlignViewport av = af.getViewport();
+    AlignViewportI av = af.getViewport();
     AlignmentI al = av.getAlignment();
 
     /*
@@ -1073,6 +1075,59 @@ public class Jalview2xmlTests extends Jalview2xmlBase
   }
 
   /**
+   * Load an HMM profile to an alignment, and confirm it is correctly restored
+   * when reloaded from project
+   * 
+   * @throws IOException
+   */
+  @Test(groups = { "Functional" })
+  public void testStoreAndRecoverHmmProfile() throws IOException
+  {
+    Desktop.getInstance().closeAll_actionPerformed(null);
+    AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.fa", DataSourceType.FILE);
+  
+    AlignViewportI av = af.getViewport();
+    AlignmentI al = av.getAlignment();
+
+    /*
+     * mimic drag and drop of hmm file on to alignment
+     */
+    AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
+            "examples/uniref50.hmm", DataSourceType.FILE);
+    al.insertSequenceAt(0,
+            af2.getViewport().getAlignment().getSequenceAt(0));
+
+    /*
+     * check it loaded in
+     */
+    SequenceI hmmSeq = al.getSequenceAt(0);
+    assertTrue(hmmSeq.hasHMMProfile());
+    HiddenMarkovModel hmm = hmmSeq.getHMM();
+    assertSame(hmm.getConsensusSequence(), hmmSeq);
+
+    /*
+     * save project, close windows, reload project, verify
+     */
+    File tfile = File.createTempFile("testStoreAndRecoverHmmProfile",
+            ".jvp");
+    tfile.deleteOnExit();
+    new Jalview2XML(false).saveState(tfile);
+    Desktop.getInstance().closeAll_actionPerformed(null);
+    af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(),
+            DataSourceType.FILE);
+    Assert.assertNotNull(af, "Failed to reload project");
+
+    hmmSeq = al.getSequenceAt(0);
+    assertTrue(hmmSeq.hasHMMProfile());
+    assertSame(hmm.getConsensusSequence(), hmmSeq);
+    Mapping mapToHmmConsensus = (Mapping) PA.getValue(hmm,
+            "mapToHmmConsensus");
+    assertNotNull(mapToHmmConsensus);
+    assertSame(mapToHmmConsensus.getTo(), hmmSeq.getDatasetSequence());
+  }
+
+  /**
    * pre 2.11 - jalview 2.10 erroneously created new dataset entries for each
    * view (JAL-3171) this test ensures we can import and merge those views
    */
index 1687516..e44dbe0 100644 (file)
@@ -22,6 +22,7 @@ package jalview.renderer;
 
 import static org.testng.AssertJUnit.assertEquals;
 
+import jalview.api.AlignViewportI;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -33,7 +34,6 @@ import jalview.gui.JvOptionPane;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-
 import java.awt.Color;
 import java.util.ArrayList;
 
@@ -56,7 +56,7 @@ public class OverviewResColourFinderTest
   {
     SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new OverviewResColourFinder();
 
     // gaps are grey, residues white
@@ -80,7 +80,7 @@ public class OverviewResColourFinderTest
     SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
                                                             // gap
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new OverviewResColourFinder();
     av.setGlobalColourScheme(new ZappoColourScheme());
 
@@ -126,7 +126,7 @@ public class OverviewResColourFinderTest
     SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
                                                             // gap
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new OverviewResColourFinder();
 
     Color[] newColours = new Color[24];
@@ -179,7 +179,7 @@ public class OverviewResColourFinderTest
     SequenceGroup[] groups = new SequenceGroup[1];
     groups[0] = sg;
     
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new OverviewResColourFinder();
     
     // G in group specified as magenta in Zappo
@@ -230,8 +230,6 @@ public class OverviewResColourFinderTest
   {
     SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
                                                             // gap
-    AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
 
     // non-legacy colouring
     ResidueColourFinder rcf = new OverviewResColourFinder();
@@ -269,9 +267,7 @@ public class OverviewResColourFinderTest
 
     // gaps gap colour
     c = rcf.getBoxColour(shader, seq, 3);
-    assertEquals(
-            jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP,
-            c);
+    assertEquals(OverviewResColourFinder.OVERVIEW_DEFAULT_GAP, c);
 
     // non legacy colouring with colour scheme
     rcf = new OverviewResColourFinder(false, Color.blue, Color.red);
index 81fb2c0..da50e8f 100644 (file)
@@ -22,6 +22,7 @@ package jalview.renderer;
 
 import static org.testng.AssertJUnit.assertEquals;
 
+import jalview.api.AlignViewportI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Sequence;
@@ -30,7 +31,6 @@ import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-
 import java.awt.Color;
 
 import org.testng.annotations.BeforeClass;
@@ -51,7 +51,7 @@ public class ResidueColourFinderTest
   {
     SequenceI seq = new Sequence("name", "MATVLGSPRAPAFF"); // FER1_MAIZE...
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new ResidueColourFinder();
     av.setGlobalColourScheme(new ZappoColourScheme());
 
@@ -86,7 +86,7 @@ public class ResidueColourFinderTest
   {
     SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF");
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new ResidueColourFinder();
 
     assertEquals(Color.white,
@@ -109,7 +109,7 @@ public class ResidueColourFinderTest
     SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a
                                                             // gap
     AlignmentI al = new Alignment(new SequenceI[] { seq });
-    final AlignViewport av = new AlignViewport(al);
+    final AlignViewportI av = new AlignViewport(al);
     ResidueColourFinder rcf = new ResidueColourFinder();
 
     Color[] newColours = new Color[24];
index 0af67cd..e78fc5a 100644 (file)
@@ -6,10 +6,10 @@ import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 import jalview.renderer.ScaleRenderer.ScaleMark;
+import jalview.viewmodel.AlignmentViewport;
 
 import java.util.List;
 
@@ -23,7 +23,7 @@ public class ScaleRendererTest
     String data = ">Seq/20-45\nABCDEFGHIJKLMNOPQRSTUVWXYS\n";
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(data,
             DataSourceType.PASTE);
-    AlignViewport av = af.getViewport();
+    AlignmentViewport av = af.getViewport();
 
     /*
      * scale has minor ticks at 5, 15, 25, major at 10 and 20
index 22294a6..fd90999 100644 (file)
@@ -17,7 +17,7 @@ import jalview.api.FeatureColourI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
+import jalview.api.AlignViewportI;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 import jalview.schemes.FeatureColour;
@@ -43,7 +43,7 @@ import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
  */
 public class FeatureColourFinderTest
 {
-  private AlignViewport av;
+  private AlignViewportI av;
 
   private SequenceI seq;
 
index d35ca76..af7036f 100644 (file)
@@ -85,8 +85,6 @@ public class ClustalxColourSchemeTest
 
     // TODO more test cases; check if help documentation matches implementation
   }
-
-  // @formatter:on
   
   /**
    * Test for colour calculation when the consensus percentage ignores gapped
diff --git a/test/jalview/schemes/HmmerGlobalBackgroundTest.java b/test/jalview/schemes/HmmerGlobalBackgroundTest.java
new file mode 100644 (file)
index 0000000..1cdee91
--- /dev/null
@@ -0,0 +1,90 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.HMMFile;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.testng.annotations.Test;
+
+public class HmmerGlobalBackgroundTest {
+
+  @Test(groups = "Functional")
+  public void testFindColour() throws MalformedURLException, IOException
+  {
+    HMMFile file = new HMMFile("test/jalview/io/test_PKinase_hmm.txt",
+            DataSourceType.FILE);
+
+    SequenceI hmmSeq = file.getSeqsAsArray()[0];
+    AlignmentI al = new Alignment(new SequenceI[] { hmmSeq });
+    ColourSchemeI scheme = new HmmerGlobalBackground(al);
+
+    /*
+     * 'A' in column 1, node 2, match emission 2.77204
+     * e-2.77204 = 0.0625 
+     * background frequency is 0.0826
+     * ratio is 0.757, log is negative, colour is Orange
+     */
+    Color actual = scheme.findColour('A', 1, null, null, 0);
+    assertEquals(actual, Color.ORANGE);
+
+    // gap is white
+    actual = scheme.findColour('-', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+    actual = scheme.findColour(' ', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+    actual = scheme.findColour('.', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+
+    /*
+     * 'Y' in column 4, node 5, match emission 4.41426
+     * e-4.41426 = 0.0121 
+     * background frequency is 0.0292
+     * ratio is 0.414, log is negative, colour is Orange
+     */
+    actual = scheme.findColour('Y', 4, null, null, 0);
+    assertEquals(actual, Color.ORANGE);
+
+    /*
+     * 'M' in column 109, no matching node, colour is reddish
+     */
+    actual = scheme.findColour('M', 109, null, null, 0);
+    assertEquals(actual, new Color(230, 0, 0));
+
+    /*
+     * 'I' in column 6, node 7, match emission 1.33015
+     * e-1.33015 = 0.2644
+     * background frequency is 0.0593
+     * ratio is 4.459, log is 1.495
+     * colour is graduated 1.495/4.52 or 84/255 of the way from
+     * white(255, 255, 255) to blue(0, 0, 255)
+     */
+    actual = scheme.findColour('I', 6, null, null, 0);
+    assertEquals(actual, new Color(171, 171, 255));
+
+    /*
+     * 'V' in column 14, node 15, match emission 0.44769
+     * e-0.44769 = 0.6391
+     * background frequency is 0.0686
+     * ratio is 9.316, log is 2.232
+     * colour is graduated 2.232/4.52 or 126/255 of the way from
+     * white(255, 255, 255) to blue(0, 0, 255)
+     */
+    actual = scheme.findColour('V', 14, null, null, 0);
+    assertEquals(actual, new Color(129, 129, 255));
+
+    /*
+     * invalid symbol is White
+     */
+    actual = scheme.findColour('X', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+  }
+
+}
diff --git a/test/jalview/schemes/HmmerLocalBackgroundTest.java b/test/jalview/schemes/HmmerLocalBackgroundTest.java
new file mode 100644 (file)
index 0000000..5f2bb8f
--- /dev/null
@@ -0,0 +1,77 @@
+package jalview.schemes;
+
+import static org.testng.Assert.assertEquals;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.HMMFile;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import org.testng.annotations.Test;
+
+public class HmmerLocalBackgroundTest {
+
+  @Test(groups = "Functional")
+  public void testFindColour() throws MalformedURLException, IOException
+  {
+    HMMFile file = new HMMFile("test/jalview/io/test_PKinase_hmm.txt",
+            DataSourceType.FILE);
+
+    /*
+     * alignment with 20 residues and background frequencies:
+     * A/a, S 3/20 = 0.15
+     * M, K 4/20 = 0.2
+     * V 2/20 = 0.1
+     * Q, R, L 1/20 = 0.05
+     * log(totalCount) = log(20) = 2.996
+     */
+    SequenceI seq1 = new Sequence("seq1", "AAMMMKKKVV");
+    SequenceI seq2 = new Sequence("seq2", "aAM-QKRSSSL");
+    SequenceI hmmSeq = file.getSeqsAsArray()[0];
+    AnnotatedCollectionI ac = new Alignment(
+            new SequenceI[]
+            { hmmSeq, seq1, seq2 });
+    ColourSchemeI scheme = new HmmerLocalBackground(ac);
+
+    /*
+     * 'A' in column 1, node 2, match emission 2.77204
+     * e-2.77204 = 0.0625 
+     * background frequency is 0.15
+     * ratio is < 1, log is negative, colour is Orange
+     */
+    Color actual = scheme.findColour('A', 1, null, null, 0);
+    assertEquals(actual, Color.ORANGE);
+
+    // gap is white
+    actual = scheme.findColour('-', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+    actual = scheme.findColour(' ', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+    actual = scheme.findColour('.', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+
+    /*
+     * 'L' in column 3, node 4, match emission 1.98342
+     * e-1.98342 = 0.1376 
+     * background frequency is 0.05
+     * ratio is 2.752, log is 1.012
+     * colour is graduated 1.012/2.996 or 86/255 of the way from
+     * white(255, 255, 255) to blue(0, 0, 255)
+     */
+    actual = scheme.findColour('L', 3, null, null, 0);
+    assertEquals(actual, new Color(169, 169, 255));
+
+    /*
+     * invalid symbol is White
+     */
+    actual = scheme.findColour('X', 2, null, null, 0);
+    assertEquals(actual, Color.WHITE);
+  }
+
+}
index 8a584f6..4117b23 100644 (file)
@@ -8,9 +8,9 @@ import org.testng.annotations.Test;
 
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
+import jalview.viewmodel.AlignmentViewport;
 
 public class PIDColourSchemeTest
 {
@@ -83,7 +83,7 @@ public class PIDColourSchemeTest
      */
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqs,
             DataSourceType.PASTE);
-    AlignViewport viewport = af.getViewport();
+    AlignmentViewport viewport = af.getViewport();
     viewport.setIgnoreGapsConsensus(false, af.alignPanel);
     do
     {
diff --git a/test/jalview/util/Binned.csv b/test/jalview/util/Binned.csv
new file mode 100644 (file)
index 0000000..f140646
--- /dev/null
@@ -0,0 +1,4 @@
+1.8, 4.53
+3.4, 2.65
+0, 5.4
+6.4, 10.8
\ No newline at end of file
diff --git a/test/jalview/util/FileUtilsTest.java b/test/jalview/util/FileUtilsTest.java
new file mode 100644 (file)
index 0000000..909d0c8
--- /dev/null
@@ -0,0 +1,73 @@
+package jalview.util;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class FileUtilsTest
+{
+  @Test(groups = "Functional")
+  public void testFindMatchingPaths() throws IOException
+  {
+    String expect1 = Paths.get("..", "jalview", "examples", "plantfdx.fa")
+            .toString();
+    String expect2 = Paths.get("../jalview/examples/plantfdx.features")
+            .toString();
+    String expect3 = Paths
+            .get("../jalview/examples/testdata/plantfdx.features")
+            .toString();
+
+    List<String> matches = FileUtils
+            .findMatchingPaths(Paths.get(".."),
+                    ".*[\\\\/]plant.*\\.f.*");
+    System.out.println(matches);
+    assertTrue(matches.contains(expect1));
+    assertTrue(matches.contains(expect2));
+    assertTrue(matches.contains(expect3));
+  }
+
+  @Test(groups = "External")
+  public void testWindowsPath() throws IOException
+  {
+    if (System.getProperty("os.name").startsWith("Windows"))
+    {
+      /*
+       * should pass provided Eclipse is installed
+       */
+      List<String> matches = FileUtils.findMatches("C:\\",
+              "Program Files*/eclips*/eclips?.exe");
+      assertFalse(matches.isEmpty());
+
+      /*
+       * should pass provided Chimera is installed
+       */
+      matches = FileUtils.findMatches("C:\\",
+              "Program Files*/Chimera*/bin/{chimera,chimera.exe}");
+      assertFalse(matches.isEmpty());
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testFindMatches() throws IOException
+  {
+    String expect1 = Paths.get("..", "jalview", "examples", "plantfdx.fa")
+            .toString();
+    String expect2 = Paths.get("../jalview/examples/plantfdx.features")
+            .toString();
+    String expect3 = Paths
+            .get("../jalview/examples/testdata/plantfdx.features")
+            .toString();
+  
+    List<String> matches = FileUtils
+            .findMatches("..", "jalview/ex*/plant*.f*");
+    System.out.println(matches);
+    assertTrue(matches.contains(expect1));
+    assertTrue(matches.contains(expect2));
+    assertFalse(matches.contains(expect3));
+  }
+}
diff --git a/test/jalview/util/HMMProbabilityDistributionAnalyserTest.java b/test/jalview/util/HMMProbabilityDistributionAnalyserTest.java
new file mode 100644 (file)
index 0000000..4dbf05e
--- /dev/null
@@ -0,0 +1,119 @@
+package jalview.util;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import jalview.datamodel.HMMNode;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.testng.annotations.Test;
+
+import junit.extensions.PA;
+
+public class HMMProbabilityDistributionAnalyserTest {
+
+  HMMProbabilityDistributionAnalyser analyser = new HMMProbabilityDistributionAnalyser();
+
+  @Test
+  public void testMoveToFile() throws IOException
+  {
+
+    BufferedReader br = new BufferedReader(new FileReader(
+            "test/jalview/util/test_Fams_for_probability_analysis"));
+    analyser.moveLocationBy(1, br);
+
+    String line = br.readLine();
+    assertEquals(line, "# STOCKHOLM 1.0");
+    line = br.readLine();
+    assertEquals(line, "seq1 ATW");
+    line = br.readLine();
+    assertEquals(line, "seq2 ATI");
+
+  }
+
+  @Test
+  public void testCountValidResidues()
+  {
+    analyser.sequences = new Vector<>();
+    analyser.hmm = new HiddenMarkovModel();
+    analyser.hmm.setProperty("LENG", "8");
+
+    List<HMMNode> nodes = new ArrayList<>();
+    nodes.add(new HMMNode());
+    for (int i = 1; i < 9; i++)
+    {
+      HMMNode node = new HMMNode();
+      node.setResidueNumber(i - 1);
+      nodes.add(node);
+
+    }
+    PA.setValue(analyser.hmm, "nodes", nodes);
+
+    SequenceI[] sequence = new Sequence[] {
+        new Sequence("seq1", "ATGWWSCF"), new Sequence("seq2", "GGMKI"),
+        new Sequence("seq3", "--.ATccGc") };
+    analyser.sequences.add(sequence[0]);
+    analyser.sequences.add(sequence[1]);
+    analyser.sequences.add(sequence[2]);
+
+    int count = analyser.countValidResidues();
+    assertEquals(count, 16);
+  }
+
+  @Test(priority = 0)
+  public void testReadBinned() throws IOException
+  {
+    analyser.readBinned("test/jalview/util/");
+    Map<String, Double> map = analyser.binned;
+    assertEquals(map.get("1.8"), 4.53);
+    assertEquals(map.get("3.4"), 2.65);
+    assertEquals(map.get("6.4"), 10.8);
+    assertEquals(map.get("0"), 5.4);
+  }
+
+  @Test
+  public void testReadRaw() throws IOException
+  {
+    analyser.readRaw("test/jalview/util/");
+    List<ArrayList<Double>> list = analyser.raw;
+
+    assertEquals(list.get(0).get(0), 1.43);
+    assertNull(list.get(0).get(2));
+    assertEquals(list.get(1).get(1), 1.2);
+    assertEquals(list.get(2).get(0), 5.6);
+    assertEquals(list.get(2).get(2), 6.8);
+
+  }
+
+  @Test(priority = 1)
+  public void testProcessData() throws IOException
+  {
+    analyser.keepRaw = true;
+    BufferedReader brFam = new BufferedReader(new FileReader(
+            "test/jalview/util/test_Fams_for_probability_analysis"));
+    BufferedReader brHMM = new BufferedReader(new FileReader(
+            "test/jalview/util/test_HMMs_for_probability_analysis"));
+    analyser.readStockholm(brFam);
+    analyser.readHMM(brHMM);
+    analyser.processData(6);
+    Map<String, Double> map = analyser.binned;
+    List<ArrayList<Double>> list = analyser.raw;
+    assertEquals(map.get("1.8"), 4.863, 0.001d);
+    assertEquals(map.get("3.4"), 2.65);
+    assertEquals(map.get("0"), 5.4);
+    assertEquals(map.get("6.4"), 10.8);
+    assertEquals(map.get("1.4"), 0.166667, 0.00001d);
+    assertEquals(map.get("4.4"), 0.5);
+
+  }
+}
index 86dcc39..493545a 100644 (file)
@@ -601,60 +601,6 @@ public class MapListTest
     assertEquals("[ [11, 16] ] 1:3 to [ [72, 53] ]", ml.toString());
   }
 
-  @Test(groups = "Functional")
-  public void testAddRange()
-  {
-    int[] range = { 1, 5 };
-    List<int[]> ranges = new ArrayList<>();
-
-    // add to empty list:
-    MapList.addRange(range, ranges);
-    assertEquals(1, ranges.size());
-    assertSame(range, ranges.get(0));
-
-    // extend contiguous (same position):
-    MapList.addRange(new int[] { 5, 10 }, ranges);
-    assertEquals(1, ranges.size());
-    assertEquals(1, ranges.get(0)[0]);
-    assertEquals(10, ranges.get(0)[1]);
-
-    // extend contiguous (next position):
-    MapList.addRange(new int[] { 11, 15 }, ranges);
-    assertEquals(1, ranges.size());
-    assertEquals(1, ranges.get(0)[0]);
-    assertEquals(15, ranges.get(0)[1]);
-
-    // change direction: range is not merged:
-    MapList.addRange(new int[] { 16, 10 }, ranges);
-    assertEquals(2, ranges.size());
-    assertEquals(16, ranges.get(1)[0]);
-    assertEquals(10, ranges.get(1)[1]);
-
-    // extend reverse contiguous (same position):
-    MapList.addRange(new int[] { 10, 8 }, ranges);
-    assertEquals(2, ranges.size());
-    assertEquals(16, ranges.get(1)[0]);
-    assertEquals(8, ranges.get(1)[1]);
-
-    // extend reverse contiguous (next position):
-    MapList.addRange(new int[] { 7, 6 }, ranges);
-    assertEquals(2, ranges.size());
-    assertEquals(16, ranges.get(1)[0]);
-    assertEquals(6, ranges.get(1)[1]);
-
-    // change direction: range is not merged:
-    MapList.addRange(new int[] { 6, 9 }, ranges);
-    assertEquals(3, ranges.size());
-    assertEquals(6, ranges.get(2)[0]);
-    assertEquals(9, ranges.get(2)[1]);
-
-    // not contiguous: not merged
-    MapList.addRange(new int[] { 11, 12 }, ranges);
-    assertEquals(4, ranges.size());
-    assertEquals(11, ranges.get(3)[0]);
-    assertEquals(12, ranges.get(3)[1]);
-  }
-
   /**
    * Check state after construction
    */
index 097ccd4..af82ac6 100644 (file)
@@ -1284,4 +1284,58 @@ public class MappingUtilsTest
     assertEquals(1, ranges.size());
     assertEquals(9, ranges.get(0)[1]);
   }
+
+  @Test(groups = "Functional")
+  public void testAddRange()
+  {
+    int[] range = { 1, 5 };
+    List<int[]> ranges = new ArrayList<>();
+  
+    // add to empty list:
+    MappingUtils.addRange(range, ranges);
+    assertEquals(1, ranges.size());
+    assertSame(range, ranges.get(0));
+  
+    // extend contiguous (same position):
+    MappingUtils.addRange(new int[] { 5, 10 }, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(1, ranges.get(0)[0]);
+    assertEquals(10, ranges.get(0)[1]);
+  
+    // extend contiguous (next position):
+    MappingUtils.addRange(new int[] { 11, 15 }, ranges);
+    assertEquals(1, ranges.size());
+    assertEquals(1, ranges.get(0)[0]);
+    assertEquals(15, ranges.get(0)[1]);
+  
+    // change direction: range is not merged:
+    MappingUtils.addRange(new int[] { 16, 10 }, ranges);
+    assertEquals(2, ranges.size());
+    assertEquals(16, ranges.get(1)[0]);
+    assertEquals(10, ranges.get(1)[1]);
+  
+    // extend reverse contiguous (same position):
+    MappingUtils.addRange(new int[] { 10, 8 }, ranges);
+    assertEquals(2, ranges.size());
+    assertEquals(16, ranges.get(1)[0]);
+    assertEquals(8, ranges.get(1)[1]);
+  
+    // extend reverse contiguous (next position):
+    MappingUtils.addRange(new int[] { 7, 6 }, ranges);
+    assertEquals(2, ranges.size());
+    assertEquals(16, ranges.get(1)[0]);
+    assertEquals(6, ranges.get(1)[1]);
+  
+    // change direction: range is not merged:
+    MappingUtils.addRange(new int[] { 6, 9 }, ranges);
+    assertEquals(3, ranges.size());
+    assertEquals(6, ranges.get(2)[0]);
+    assertEquals(9, ranges.get(2)[1]);
+  
+    // not contiguous: not merged
+    MappingUtils.addRange(new int[] { 11, 12 }, ranges);
+    assertEquals(4, ranges.size());
+    assertEquals(11, ranges.get(3)[0]);
+    assertEquals(12, ranges.get(3)[1]);
+  }
 }
diff --git a/test/jalview/util/Raw.csv b/test/jalview/util/Raw.csv
new file mode 100644 (file)
index 0000000..83d3452
--- /dev/null
@@ -0,0 +1,4 @@
+Seq1, Seq2, Seq3
+1.43, 2.34, 5.6,
+EMPTY, 1.2, 0.05,
+EMPTY, 5.4, 6.8,
\ No newline at end of file
index 37506c0..ebb5a31 100644 (file)
@@ -87,19 +87,6 @@ public class StringUtilsTest
   }
 
   @Test(groups = { "Functional" })
-  public void testGetLastToken()
-  {
-    assertNull(StringUtils.getLastToken(null, null));
-    assertNull(StringUtils.getLastToken(null, "/"));
-    assertEquals("a", StringUtils.getLastToken("a", null));
-
-    assertEquals("abc", StringUtils.getLastToken("abc", "/"));
-    assertEquals("c", StringUtils.getLastToken("abc", "b"));
-    assertEquals("file1.dat", StringUtils.getLastToken(
-            "file://localhost:8080/data/examples/file1.dat", "/"));
-  }
-
-  @Test(groups = { "Functional" })
   public void testSeparatorListToArray()
   {
     String[] result = StringUtils.separatorListToArray(
diff --git a/test/jalview/util/test_Fams_for_probability_analysis b/test/jalview/util/test_Fams_for_probability_analysis
new file mode 100644 (file)
index 0000000..74fbab0
--- /dev/null
@@ -0,0 +1,13 @@
+# STOCKHOLM 1.0
+seq1 AW
+seq2 GW
+seq3 AW
+//
+# STOCKHOLM 1.0
+seq1 ATW
+seq2 ATI
+//
+# STOCKHOLM 1.0
+seq1 R-WW
+seq2 RAWW
+//
\ No newline at end of file
diff --git a/test/jalview/util/test_hmms_for_probability_analysis b/test/jalview/util/test_hmms_for_probability_analysis
new file mode 100644 (file)
index 0000000..b70d42b
--- /dev/null
@@ -0,0 +1,99 @@
+HMMER3/f [3.1b2 | February 2015]
+NAME  test1
+LENG  4
+ALPH  amino
+RF    no
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Fri Jul 21 06:35:06 2017
+NSEQ  3
+EFFN  3.000000
+CKSUM 657102310
+STATS LOCAL MSV       -5.0223  0.82341
+STATS LOCAL VITERBI   -4.9569  0.82341
+STATS LOCAL FORWARD   -2.0282  0.82341
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   1.94296  5.20658  4.78882  4.52987  4.66525  2.54188  5.19553  2.25221  4.08549  3.87133  5.00250  4.55734  4.73106  4.65220  2.77287  3.67799  1.53923  3.75384  1.48526  4.84023
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01083  4.92694  5.64929  0.61958  0.77255  0.00000        *
+      1   0.67027  4.79120  4.60974  4.51892  5.43734  1.28080  5.43621  4.90028  4.64310  4.61059  5.39837  4.28688  4.41468  4.80804  4.79047  3.08135  3.44468  4.10506  6.74908  5.67939      1 A - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01083  4.92694  5.64929  0.61958  0.77255  0.48576  0.95510
+      2   5.43405  6.34487  5.85697  5.84679  4.39288  5.10370  5.65594  5.70664  5.69821  4.87848  6.25251  5.89664  5.70261  6.00722  5.60902  5.64576  5.80049  5.59366  0.08910  4.36301      2 W - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01083  4.92694  5.64929  0.61958  0.77255  0.48576  0.95510
+      3   3.42384  5.23617  4.84601  4.77568  5.39247  4.01365  5.64153  4.72950  4.75585  4.52264  5.55782  4.69647  4.81267  5.08969  4.87301  3.64217  0.20934  4.25217  6.65833  5.63018      3 T - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01083  4.92694  5.64929  0.61958  0.77255  0.48576  0.95510
+      4   3.53954  5.09963  4.71395  4.06038  4.20429  4.44020  4.65482  0.90152  3.16536  2.96072  4.13056  4.31689  4.83725  3.95143  1.46549  3.86829  3.78084  2.85654  5.74911  4.54685      4 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00730  4.92341        *  0.61958  0.77255  0.00000        *
+//
+HMMER3/f [3.1b2 | February 2015]
+NAME  test2
+LENG  3
+ALPH  amino
+RF    no
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Fri Jul 21 06:36:50 2017
+NSEQ  2
+EFFN  2.000000
+CKSUM 777554360
+STATS LOCAL MSV       -5.2452  0.95763
+STATS LOCAL VITERBI   -5.2886  0.95763
+STATS LOCAL FORWARD   -1.5134  0.95763
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   1.33364  4.79082  4.44132  4.24796  3.91456  3.75718  4.85762  2.23342  4.16821  3.09137  4.29744  4.25088  4.41741  4.46803  4.31080  3.33397  1.39376  3.21010  2.54819  4.14914
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01467  4.62483  5.34718  0.61958  0.77255  0.00000        *
+      1   0.32372  4.76536  4.42980  4.32857  5.00499  3.55951  5.22620  4.27004  4.37081  4.10495  5.08789  4.22499  4.36948  4.63911  4.51684  3.12947  3.46009  3.76842  6.33337  5.25783      1 A - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01467  4.62483  5.34718  0.61958  0.77255  0.48576  0.95510
+      2   3.04414  4.87155  4.35068  4.21532  4.89213  3.66881  5.13994  4.14202  4.17893  3.96810  5.00600  4.23490  4.44590  4.53729  4.35178  3.25814  0.35496  3.73038  6.23308  5.12388      2 T - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01467  4.62483  5.34718  0.61958  0.77255  0.48576  0.95510
+      3   3.41901  4.77187  4.98694  4.49106  3.10447  4.49364  4.52024  1.21391  4.22709  2.30875  3.57865  4.53952  4.83367  4.43564  4.31127  3.88439  3.66452  2.61326  1.44329  3.34125      3 i - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  4.62006        *  0.61958  0.77255  0.00000        *
+//
+HMMER3/f [3.1b2 | February 2015]
+NAME  test3
+LENG  4
+ALPH  amino
+RF    no
+MM    no
+CONS  yes
+CS    no
+MAP   yes
+DATE  Fri Jul 21 06:37:01 2017
+NSEQ  2
+EFFN  2.000000
+CKSUM 986955970
+STATS LOCAL MSV       -5.4578  0.80004
+STATS LOCAL VITERBI   -5.2499  0.80004
+STATS LOCAL FORWARD   -2.1856  0.80004
+HMM          A        C        D        E        F        G        H        I        K        L        M        N        P        Q        R        S        T        V        W        Y   
+            m->m     m->i     m->d     i->m     i->i     d->m     d->d
+  COMPO   2.16700  5.33023  4.57707  4.32329  4.15728  4.03215  4.83242  4.49728  3.73978  4.00181  5.18156  4.45520  4.63709  4.41734  1.53081  3.84281  4.10073  4.20172  0.82417  4.15750
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01467  4.62483  5.34718  0.61958  0.77255  0.00000        *
+      1   4.09153  5.75008  4.67229  4.09411  5.31638  4.34678  4.67762  4.97541  2.93879  4.35023  5.37643  4.37234  4.85576  3.90366  0.27042  4.17197  4.33362  4.67489  6.11461  5.14175      1 R - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.39762  4.62483  1.14482  0.61958  0.77255  0.48576  0.95510
+      2   0.58385  4.42717  3.89187  3.72118  4.47383  3.23815  4.69159  3.65968  3.74862  3.52210  4.52478  3.76053  4.01438  4.05655  3.96007  2.78076  3.08518  3.24526  5.86063  4.71068      2 A - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.02145  4.24866  4.97100  0.61958  0.77255  0.27360  1.42978
+      3   4.82318  5.87391  5.36844  5.28961  3.81117  4.70308  5.10523  4.98084  5.06729  4.21822  5.56037  5.33222  5.28501  5.40387  5.04111  5.02415  5.17266  4.88017  0.16601  3.78547      3 W - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.01467  4.62483  5.34718  0.61958  0.77255  0.48576  0.95510
+      4   4.82318  5.87391  5.36844  5.28961  3.81117  4.70308  5.10523  4.98084  5.06729  4.21822  5.56037  5.33222  5.28501  5.40387  5.04111  5.02415  5.17266  4.88017  0.16601  3.78547      4 W - - -
+          2.68618  4.42225  2.77519  2.73123  3.46354  2.40513  3.72494  3.29354  2.67741  2.69355  4.24690  2.90347  2.73739  3.18146  2.89801  2.37887  2.77519  2.98518  4.58477  3.61503
+          0.00990  4.62006        *  0.61958  0.77255  0.00000        *
+//
\ No newline at end of file
index 9cc4fc2..f0fcdba 100644 (file)
@@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcManagerI2;
 import jalview.api.AlignCalcWorkerI;
 import jalview.api.FeatureRenderer;
 import jalview.datamodel.Alignment;
@@ -63,7 +64,7 @@ public class AlignCalcManagerTest
   @Test(groups = "Functional")
   public void testRemoveWorkerForAnnotation()
   {
-    AlignCalcManagerI acm = alignFrame.getViewport().getCalcManager();
+    AlignCalcManagerI2 acm = alignFrame.getViewport().getCalcManager();
     final AlignmentAnnotation ann1 = new AlignmentAnnotation("Ann1",
             "desc", new Annotation[] {});
     final AlignmentAnnotation ann2 = new AlignmentAnnotation("Ann2",
@@ -96,8 +97,7 @@ public class AlignCalcManagerTest
       }
     }
 
-    List<AlignCalcWorkerI> workers = acm
-            .getRegisteredWorkersOfClass(worker1.getClass());
+    List<AlignCalcWorkerI> workers = acm.getWorkersOfClass(worker1.getClass());
     assertEquals(2, workers.size());
     assertTrue(workers.contains(worker1));
     assertTrue(workers.contains(worker2));
@@ -108,10 +108,8 @@ public class AlignCalcManagerTest
      * 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));
+    assertTrue(acm.getWorkersOfClass(worker1.getClass()).contains(worker1));
+    assertTrue(acm.getWorkersOfClass(worker1.getClass()).contains(worker2));
     assertFalse(acm.isDisabled(worker1));
     assertFalse(acm.isDisabled(worker2));
 
@@ -120,10 +118,8 @@ public class AlignCalcManagerTest
      * - should delete worker1 but not worker2
      */
     acm.removeWorkerForAnnotation(ann1);
-    assertEquals(1, acm.getRegisteredWorkersOfClass(worker1.getClass())
-            .size());
-    assertTrue(acm.getRegisteredWorkersOfClass(worker1.getClass())
-            .contains(worker2));
+    assertEquals(1, acm.getWorkersOfClass(worker1.getClass()).size());
+    assertTrue(acm.getWorkersOfClass(worker1.getClass()).contains(worker2));
     assertFalse(acm.isDisabled(worker1));
     assertFalse(acm.isDisabled(worker2));
   }
diff --git a/test/jalview/ws/ebi/HmmerJSONProcessTest.java b/test/jalview/ws/ebi/HmmerJSONProcessTest.java
new file mode 100644 (file)
index 0000000..bf68906
--- /dev/null
@@ -0,0 +1,122 @@
+package jalview.ws.ebi;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileParse;
+import jalview.io.FormatAdapter;
+
+import java.io.File;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class HmmerJSONProcessTest {
+  public static File alignmentFragFile = new File(
+          "examples/testdata/hmmer3/alignment_frag.fa.gz");
+
+  private AlignmentI getSearchResultFragmentAlignment() throws Exception
+  {
+    AlignmentI alf = new FormatAdapter().readFile(
+            alignmentFragFile.getAbsolutePath(), DataSourceType.FILE,
+            FileFormat.Fasta);
+
+    return alf;
+  }
+
+  public static File alignmentResultFile = new File(
+          "examples/testdata/hmmer3/alignment_res.fa.gz");
+
+  private AlignmentI getSearchResultAlignment() throws Exception
+  {
+    AlignmentI alf = new FormatAdapter().readFile(
+            alignmentResultFile.getAbsolutePath(), DataSourceType.FILE,
+            FileFormat.Fasta);
+
+    return alf;
+  }
+
+  public static String hitTestFile = "examples/testdata/hmmer3/hit_fragment.json.gz",
+          hmmerResultFile = "examples/testdata/hmmer3/hmmeresult.json.gz";
+
+
+  @Test(groups = { "Functional" })
+  public void parseHitTest() throws Exception
+  {
+
+    Assert.assertTrue(new File(hitTestFile).exists(),
+            "Can't find test data.\n"
+            + hitTestFile);
+    JSONParser jp = new JSONParser();
+    // read JSON in same way - via fileparse
+    Object hitfragment = jp.parse(new FileParse(hitTestFile,
+            DataSourceType.FILE).getReader());
+    Assert.assertTrue((hitfragment instanceof JSONObject),
+            "Didn't find a JSON object map in " + hitTestFile);
+    AlignmentI searchResult = getSearchResultFragmentAlignment();
+
+    Assert.assertTrue(searchResult != null && searchResult.getHeight() > 0,
+            "Didn't read search result alignment from " + alignmentFragFile);
+
+    HmmerJSONProcessor hjsp = new HmmerJSONProcessor(searchResult);
+    hjsp.addHit((JSONObject) hitfragment, 1);
+    // check that
+    // scores, posterior probabilities and stuff exist.
+  }
+
+  @Test(groups = { "Functional" })
+  public void parseJsonResultTest() throws Exception
+  {
+
+    Assert.assertTrue(new File(hmmerResultFile).exists(),
+            "Can't find test data.\n" + hmmerResultFile);
+
+    AlignmentI searchResult = getSearchResultAlignment();
+
+    Assert.assertTrue(searchResult != null && searchResult.getHeight() > 0,
+            "Didn't read search result alignment from " + alignmentFragFile);
+
+    HmmerJSONProcessor hjsp = new HmmerJSONProcessor(searchResult);
+    hjsp.parseFrom(new FileParse(hmmerResultFile, DataSourceType.FILE));
+    AlignmentAnnotation[] aa = searchResult.getSequenceAt(5)
+            .getAnnotation();
+    Assert.assertNotNull(aa);
+    Assert.assertEquals(aa.length, 3,
+            "didn't get expected set of annotation.\n");
+    // DPTSERWFHGHLSGKEAEKLLTeKGKHGSFLVRESQSHPGDFVLSVRTgddkgesndgKSKVTHVMIR-CQELKYDVGGGERFDSLTDLVEHYKKNPmvet
+    // LGTVLQLKQP
+    // 5789*****************9799***********************999998888888********.99**************************9999
+    // 899999*999
+    // AlignmentAnnotation
+    // 101 == 8
+    String seq = "tLGT";
+    SequenceI s5 = searchResult.getSequenceAt(5);
+    Assert.assertEquals(
+            s5.getSubSequence(s5.findIndex(225), s5.findIndex(229))
+                    .getSequenceAsString(),
+            seq);
+    int pos = s5.findIndex(226);
+    for (AlignmentAnnotation an : aa)
+    {
+      if (an.label.startsWith("Posterior"))
+      {
+        Assert.assertEquals(an.annotations[pos].value, 8f);
+
+      }
+    }
+    ;
+    // check that
+    // scores, posterior probabilities and stuff exist.
+  }
+  // Groovy test
+  // def al = Jalview.getAlignFrames()[0].getViewport().getAlignment()
+  // def jproc = new jalview.ws.ebi.HmmerJSONProcessor(al)
+  // jproc.parseFrom(new
+  // jalview.io.FileParse("examples/testdata/hmmer3/hmmeresult.json.gz","File"))
+  // jproc.updateView(Jalview.getAlignFrames()[0].getViewport())
+
+}
index 80b48c3..ec9d2be 100644 (file)
@@ -24,10 +24,13 @@ import jalview.bin.Cache;
 import jalview.gui.JvOptionPane;
 import jalview.gui.WsJobParameters;
 import jalview.util.MessageManager;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jabaws.JalviewJabawsTestUtils;
 import jalview.ws.jws2.JabaPreset;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
 
 import java.awt.BorderLayout;
 import java.awt.event.WindowAdapter;
@@ -58,12 +61,12 @@ public class Jws2ParamView
   /**
    * which services to test
    */
-  public static List<String> serviceTests = new ArrayList<String>();
+  public static List<String> serviceTests = new ArrayList<>();
 
   /**
    * which presets to test for services
    */
-  public static List<String> presetTests = new ArrayList<String>();
+  public static List<String> presetTests = new ArrayList<>();
   static
   {
     serviceTests.add("AAConWS".toLowerCase());
@@ -88,10 +91,12 @@ public class Jws2ParamView
   public void testJws2Gui()
   {
     Iterator<String> presetEnum = presetTests.iterator();
-    for (Jws2Instance service : disc.getServices())
+    for (ServiceWithParameters _service : disc.getServices())
     {
+      // This will fail for non-jabaws services
+      Jws2Instance service = (Jws2Instance) _service;
       if (serviceTests.size() == 0
-              || serviceTests.contains(service.serviceType.toLowerCase()))
+              || serviceTests.contains(service.getName().toLowerCase()))
       {
         List<Preset> prl = null;
         Preset pr = null;
@@ -127,11 +132,12 @@ public class Jws2ParamView
             }
             pr = en.next();
           }
-          WsJobParameters pgui = new WsJobParameters(service,
-                  new JabaPreset(service, pr));
-          JFrame jf = new JFrame(MessageManager.formatMessage(
-                  "label.ws_parameters_for",
-                  new String[] { service.getActionText() }));
+          WsJobParameters pgui = new WsJobParameters((ParamDatastoreI) null,
+                  service, new JabaPreset(service, pr),
+                  (List<ArgumentI>) null);
+          JFrame jf = new JFrame(MessageManager
+                  .formatMessage("label.ws_parameters_for", new String[]
+                  { service.getActionText() }));
           jf.setSize(700, 800);
           JPanel cont = new JPanel(new BorderLayout());
           pgui.validate();
diff --git a/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java b/test/jalview/ws/jabaws/AAConAnnotAndSettingsIO.java
new file mode 100644 (file)
index 0000000..5428acd
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the 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.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.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.jws2.SeqAnnotationServiceCalcWorker;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * All methods in this class are set to the Network group because setUpBeforeClass will fail
+ * if there is no network.
+ */
+@Test(singleThreaded = true)
+public class AAConAnnotAndSettingsIO
+{
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpJvOptionPane()
+  {
+    JvOptionPane.setInteractiveMode(false);
+    JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
+  }
+
+  public static String testseqs = "examples/uniref50.fa";
+
+  public static Jws2Discoverer disc;
+
+  public static List<ServiceWithParameters[]> aacon;
+
+  jalview.ws.jws2.SeqAnnotationServiceCalcWorker aaconClient;
+
+  public static jalview.gui.AlignFrame af = null;
+
+  @BeforeClass(alwaysRun = true)
+  public static void setUpBeforeClass() throws Exception
+  {
+    Cache.loadProperties("test/jalview/io/testProps.jvprops");
+    Cache.initLogger();
+    disc = JalviewJabawsTestUtils.getJabawsDiscoverer();
+
+    while (disc.isRunning())
+    {
+      // don't get services until discoverer has finished
+      Thread.sleep(100);
+    }
+
+
+    aacon = new ArrayList<>();
+    for (ServiceWithParameters svc : disc.getServices())
+    {
+      if (svc.getNameURI().toLowerCase().contains("aacon"))
+      {
+        aacon.add(new ServiceWithParameters[] { svc });
+      }
+    }
+
+    for (ServiceWithParameters svc : SlivkaWSDiscoverer.getInstance()
+            .getServices())
+    {
+      if (svc.getNameURI().toLowerCase().contains("aacon"))
+      {
+        aacon.add(new ServiceWithParameters[] { svc });
+      }
+    }
+    assertTrue("Couldn't discover any AACon services to use to test.",
+            aacon.size() > 0);
+  }
+
+  @AfterClass(alwaysRun = true)
+  public static void tearDownAfterClass() throws Exception
+  {
+    if (af != null)
+    {
+      af.setVisible(false);
+      af.dispose();
+      af = null;
+    }
+  }
+
+  @DataProvider(name = "aacons")
+  public Object[][] getAaconArray()
+  {
+
+    Object[][] rtn = new Object[aacon.size()][1];
+    int i = 0;
+    for (ServiceWithParameters[] aa : aacon)
+    {
+      rtn[i++] = aa;
+    }
+    return rtn;
+  }
+  /**
+   * Run AACon on an alignment with defaults and verify Just Shenkin annotation
+   * appears
+   */
+  @Test(groups = { "External", "Network" }, dataProvider = "aacons")
+  public void testAAConAnnotAndRecovery(ServiceWithParameters service)
+  {
+    jalview.io.FileLoader fl = new jalview.io.FileLoader(false);
+    AlignFrame _af = fl.LoadFileWaitTillLoaded(testseqs,
+            jalview.io.DataSourceType.FILE);
+    assertNotNull("Couldn't load test data ('" + testseqs + "')", _af);
+    af = _af;
+    try
+    {
+    testAAConClient(_af, service);
+    } finally
+    {
+      af = null;
+      _af.setVisible(false);
+      _af.dispose();
+      _af = null;
+
+    }
+  }
+
+  /**
+   * triggers the given aacon worker on the alignment, waits for 5s and gives up
+   * or verifies SHENKIN annotation is produced.
+   * 
+   * @param af
+   *          - test data in an alignment frame
+   * @param aacon
+   *          - the service to test
+   */
+  static void testAAConClient(AlignFrame af, ServiceWithParameters aacon)
+  {
+    SeqAnnotationServiceCalcWorker aaconClient = new SeqAnnotationServiceCalcWorker(
+            aacon, af, null,
+            null);
+    long current = System.currentTimeMillis(), limit = 15;
+    af.getViewport().getCalcManager().startWorker(aaconClient);
+    do
+    {
+      try
+      {
+        Thread.sleep(50);
+      } catch (InterruptedException x)
+      {
+      }
+      ;
+      assertTrue(
+              "Waited " + limit + "s for " + aacon.getHostURL()
+                      + " - giving up.",
+              (System.currentTimeMillis() - current) < limit * 1000);
+    } while (af.getViewport().getCalcManager().isWorking());
+    AlignmentI orig_alig = af.getViewport().getAlignment();
+    boolean foundShenkin = false;
+    Iterable<AlignmentAnnotation> _aa=orig_alig
+            .findAnnotation(aacon.getAlignAnalysisUI().getCalcId());
+    assertTrue("No annotation from service",
+            _aa != null && _aa.iterator().hasNext());
+
+    for (AlignmentAnnotation aa : _aa)
+    {
+      assertTrue("AACon annotation not marked as autocalculated!",
+              aa.autoCalculated);
+      if ("shenkin".equals(aa.label.toLowerCase()))
+      {
+        foundShenkin = true;
+        break;
+      }
+    }
+    assertTrue("Failed to locate 'SHENKIN' annotation row.", foundShenkin);
+  }
+}
index e8b6c2b..372dcb2 100644 (file)
@@ -32,9 +32,10 @@ import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
 import jalview.io.FormatAdapter;
 import jalview.io.StockholmFileTest;
-import jalview.ws.jws2.AADisorderClient;
+import jalview.ws.api.ServiceWithParameters;
 import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.jws2.SeqAnnotationServiceCalcWorker;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -63,9 +64,9 @@ public class DisorderAnnotExportImport
 
   public static Jws2Discoverer disc;
 
-  public static List<Jws2Instance> iupreds;
+  public static List<ServiceWithParameters> iupreds;
 
-  jalview.ws.jws2.AADisorderClient disorderClient;
+  jalview.ws.jws2.SeqAnnotationServiceCalcWorker disorderClient;
 
   public static jalview.gui.AlignFrame af = null;
 
@@ -81,11 +82,16 @@ public class DisorderAnnotExportImport
       // don't get services until discoverer has finished
       Thread.sleep(100);
     }
-
-    iupreds = new ArrayList<Jws2Instance>();
-    for (Jws2Instance svc : disc.getServices())
+    SlivkaWSDiscoverer disc2 = SlivkaWSDiscoverer.getInstance();
+    disc2.startDiscoverer();
+    while (disc2.isRunning())
+    {
+      Thread.sleep(100);
+    }
+    iupreds = new ArrayList<>();
+    for (ServiceWithParameters svc : disc2.getServices())
     {
-      if (svc.getServiceTypeURI().toLowerCase().contains("iupredws"))
+      if (svc.getNameURI().toLowerCase().contains("iupred"))
       {
         iupreds.add(svc);
       }
@@ -114,7 +120,8 @@ public class DisorderAnnotExportImport
   @Test(groups = { "External", "Network" })
   public void testDisorderAnnotExport()
   {
-    disorderClient = new AADisorderClient(iupreds.get(0), af, null, null);
+    disorderClient = new SeqAnnotationServiceCalcWorker(iupreds.get(0), af, null,
+            null);
     af.getViewport().getCalcManager().startWorker(disorderClient);
     do
     {
@@ -129,7 +136,7 @@ public class DisorderAnnotExportImport
     AlignmentI orig_alig = af.getViewport().getAlignment();
     // NOTE: Consensus annotation row cannot be exported and reimported
     // faithfully - so we remove them
-    List<AlignmentAnnotation> toremove = new ArrayList<AlignmentAnnotation>();
+    List<AlignmentAnnotation> toremove = new ArrayList<>();
     for (AlignmentAnnotation aa : orig_alig.getAlignmentAnnotation())
     {
       if (aa.autoCalculated)
index 889c003..292a48a 100644 (file)
@@ -33,8 +33,10 @@ import jalview.io.FileFormat;
 import jalview.io.FormatAdapter;
 import jalview.io.StockholmFileTest;
 import jalview.project.Jalview2XML;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.JabaParamStore;
 import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.RNAalifoldClient;
+import jalview.ws.jws2.SeqAnnotationServiceCalcWorker;
 import jalview.ws.jws2.SequenceAnnotationWSClient;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.params.AutoCalcSetting;
@@ -78,7 +80,7 @@ public class RNAStructExportImport
 
   public static Jws2Instance rnaalifoldws;
 
-  jalview.ws.jws2.RNAalifoldClient alifoldClient;
+  SeqAnnotationServiceCalcWorker alifoldClient;
 
   public static jalview.gui.AlignFrame af = null;
 
@@ -95,12 +97,12 @@ public class RNAStructExportImport
       Thread.sleep(100);
     }
 
-    for (Jws2Instance svc : disc.getServices())
+    for (ServiceWithParameters svc : disc.getServices())
     {
 
-      if (svc.getServiceTypeURI().toLowerCase().contains("rnaalifoldws"))
+      if (svc.getNameURI().toLowerCase().contains("rnaalifoldws"))
       {
-        rnaalifoldws = svc;
+        rnaalifoldws = (Jws2Instance) svc;
       }
     }
 
@@ -154,7 +156,8 @@ public class RNAStructExportImport
   public void testRNAAliFoldValidStructure()
   {
 
-    alifoldClient = new RNAalifoldClient(rnaalifoldws, af, null, null);
+    alifoldClient = new SeqAnnotationServiceCalcWorker(rnaalifoldws, af, null,
+            null);
 
     af.getViewport().getCalcManager().startWorker(alifoldClient);
 
@@ -187,7 +190,8 @@ public class RNAStructExportImport
   public void testRNAStructExport()
   {
 
-    alifoldClient = new RNAalifoldClient(rnaalifoldws, af, null, null);
+    alifoldClient = new SeqAnnotationServiceCalcWorker(rnaalifoldws, af, null,
+            null);
 
     af.getViewport().getCalcManager().startWorker(alifoldClient);
 
@@ -204,7 +208,7 @@ public class RNAStructExportImport
     AlignmentI orig_alig = af.getViewport().getAlignment();
     // JBPNote: this assert fails (2.10.2) because the 'Reference Positions'
     // annotation is mistakenly recognised as an RNA annotation row when read in
-    // as an annotation file.
+    // as an annotation file. bug is JAL-3122
     verifyAnnotationFileIO("Testing RNAalifold Annotation IO", orig_alig);
 
   }
@@ -280,7 +284,8 @@ public class RNAStructExportImport
         opts.add(rg);
       }
     }
-    alifoldClient = new RNAalifoldClient(rnaalifoldws, af, null, opts);
+    alifoldClient = new SeqAnnotationServiceCalcWorker(rnaalifoldws, af, null,
+            JabaParamStore.getJwsArgsfromJaba(opts));
 
     af.getViewport().getCalcManager().startWorker(alifoldClient);
 
index c0aa2ee..ab245c9 100644 (file)
@@ -26,6 +26,8 @@ import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.bin.Cache;
 import jalview.gui.JvOptionPane;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.api.UIinfo;
 import jalview.ws.jabaws.JalviewJabawsTestUtils;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 
@@ -61,7 +63,7 @@ public class ParameterUtilsTest
    * To limit tests to specify services, add them to this list; leave list empty
    * to test all
    */
-  private static List<String> serviceTests = new ArrayList<String>();
+  private static List<String> serviceTests = new ArrayList<>();
 
   private static Jws2Discoverer disc = null;
 
@@ -77,10 +79,11 @@ public class ParameterUtilsTest
   @Test(groups = { "Network" })
   public void testWriteParameterSet() throws WrongParameterException
   {
-    for (Jws2Instance service : disc.getServices())
+    for (ServiceWithParameters _service : disc.getServices())
     {
-      if (isForTesting(service))
+      if (isForTesting(_service))
       {
+        Jws2Instance service = (Jws2Instance) _service;
 
         List<Preset> prl = null;
         PresetManager prman = service.getPresets();
@@ -128,19 +131,20 @@ public class ParameterUtilsTest
    * @param service
    * @return
    */
-  public boolean isForTesting(Jws2Instance service)
+  public boolean isForTesting(UIinfo service)
   {
     return serviceTests.size() == 0
-            || serviceTests.contains(service.serviceType.toLowerCase());
+            || serviceTests.contains(service.getName().toLowerCase());
   }
 
   @Test(groups = { "Network" })
   public void testCopyOption()
   {
-    for (Jws2Instance service : disc.getServices())
+    for (ServiceWithParameters _service : disc.getServices())
     {
-      if (isForTesting(service))
+      if (isForTesting(_service))
       {
+        Jws2Instance service = (Jws2Instance) _service;
         List<Option<?>> options = service.getRunnerConfig().getOptions();
         for (Option<?> o : options)
         {
@@ -161,10 +165,11 @@ public class ParameterUtilsTest
   @Test(groups = { "Network" })
   public void testCopyParameter()
   {
-    for (Jws2Instance service : disc.getServices())
+    for (ServiceWithParameters _service : disc.getServices())
     {
-      if (isForTesting(service))
+      if (isForTesting(_service))
       {
+        Jws2Instance service = (Jws2Instance) _service;
         List<Parameter> parameters = service.getRunnerConfig()
                 .getParameters();
         for (Parameter o : parameters)
index 709f2c5..261c059 100644 (file)
@@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertTrue;
 
 import jalview.gui.AlignFrame;
 import jalview.gui.JvOptionPane;
+import jalview.ws.rest.clientdefs.ShmrRestClient;
 
 import java.util.Map;
 
@@ -52,13 +53,13 @@ public class ShmmrRSBSService
     assertTrue(
             "Test Rsd Exchange using using default Shmmr service failed.",
             testRsdExchange("Test using default Shmmr service",
-                    RestClient.makeShmmrRestClient().service));
+                    ShmrRestClient.makeShmmrRestClient().service));
   }
 
   @Test(groups = { "Functional" })
   public void testShmmrServiceDataprep() throws Exception
   {
-    RestClient _rc = RestClient.makeShmmrRestClient();
+    RestClient _rc = ShmrRestClient.makeShmmrRestClient();
     assertNotNull(_rc);
     AlignFrame alf = new jalview.io.FileLoader(false)
             .LoadFileWaitTillLoaded("examples/testdata/smad.fa",
@@ -127,6 +128,12 @@ public class ShmmrRSBSService
       if (!service.equals(newService))
       {
         System.err.println("Failed for service (" + desc + ").");
+        if (fromservicetostring.equals(newService.toString()))
+        {
+          System.err.println(
+                  "Description strings are equivalent: fault during RestServiceDescription.equals()");
+          return false;
+        }
         System.err.println("Original service and parsed service differ.");
         System.err.println("Original: " + fromservicetostring);
         System.err.println("Parsed  : " + newService.toString());
index 360a700..2cbfeb9 100755 (executable)
@@ -40,7 +40,7 @@
                <param name="file2" value="${file2}" />
        </antcall>
        <echo message=" "/>
-       <echo message="Missing message labels in Messages.properties compare to ${file2}"/>
+       <echo message="Missing message labels in Messages.properties compared to ${file2}"/>
        <antcall target="compareProperties">
                <param name="file2" value="resources/lang/Messages.properties"/>
                <param name="file1" value="${file2}" />
diff --git a/utils/jalviewjs/libjs/slivka-client-site.zip b/utils/jalviewjs/libjs/slivka-client-site.zip
new file mode 100644 (file)
index 0000000..a22dade
Binary files /dev/null and b/utils/jalviewjs/libjs/slivka-client-site.zip differ