LISTSERV mailing list manager LISTSERV 16.5

Help for HPS-SVN Archives


HPS-SVN Archives

HPS-SVN Archives


HPS-SVN@LISTSERV.SLAC.STANFORD.EDU


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Proportional Font

LISTSERV Archives

LISTSERV Archives

HPS-SVN Home

HPS-SVN Home

HPS-SVN  March 2015

HPS-SVN March 2015

Subject:

r2555 - in /java/branches/prod: ./ analysis/src/main/java/org/hps/analysis/ecal/ analysis/src/main/java/org/hps/analysis/trigger/ analysis/src/main/java/org/hps/analysis/trigger/event/ analysis/src/main/java/org/hps/analysis/trigger/util/ conditions/src/main/java/org/hps/conditions/api/ conditions/src/main/java/org/hps/conditions/database/ conditions/src/main/java/org/hps/conditions/deprecated/ conditions/src/main/java/org/hps/conditions/ecal/ conditions/src/main/java/org/hps/conditions/svt/ conditions/src/test/java/org/hps/conditions/ detector-data/detectors/HPS-ECalCommissioning-v2/ ecal-readout-sim/src/main/java/org/hps/readout/ecal/ ecal-readout-sim/src/main/java/org/hps/readout/ecal/daqconfig/ ecal-readout-sim/src/main/java/org/hps/readout/ecal/triggerbank/ ecal-recon/src/main/java/org/hps/recon/ecal/ ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/ ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/ evio/ evio/src/main/java/org/hps/evio/ evio/src/test/java/org/hps/evio/ monitoring-app/ monitoring-app/src/main/java/org/hps/monitoring/application/ monitoring-app/src/main/java/org/hps/monitoring/application/model/ monitoring-app/src/main/java/org/hps/monitoring/application/util/ monitoring-app/src/main/resources/org/hps/monitoring/config/ monitoring-app/src/main/scripts/ monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/ monitoring-drivers/src/main/java/org/hps/monitoring/drivers/trackrecon/ monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/ monitoring-util/src/main/java/org/hps/monitoring/plotting/ monitoring-util/src/main/java/org/hps/monitoring/subsys/ monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/ monitoring-util/src/main/java/org/hps/monitoring/subsys/et/ monitoring-util/src/main/java/org/hps/monitoring/trigger/ record-util/src/main/java/org/hps/record/ record-util/src/main/java/org/hps/record/composite/ record-util/src/main/java/org/hps/record/epics/ record-util/src/main/java/org/hps/record/et/ record-util/src/main/java/org/hps/record/evio/ record-util/src/main/java/org/hps/record/scalars/ record-util/src/test/java/org/ steering-files/src/main/resources/org/hps/steering/monitoring/ steering-files/src/main/resources/org/hps/steering/readout/ steering-files/src/main/resources/org/hps/steering/users/celentan/ steering-files/src/main/resources/org/hps/steering/users/holly/ steering-files/src/main/resources/org/hps/steering/users/mgraham/ tracking/src/main/java/org/hps/readout/svt/ users/src/main/java/org/hps/users/celentan/ users/src/main/java/org/hps/users/phansson/

From:

[log in to unmask]

Reply-To:

Notification of commits to the hps svn repository <[log in to unmask]>

Date:

Wed, 25 Mar 2015 21:44:16 -0000

Content-Type:

text/plain

Parts/Attachments:

Parts/Attachments

text/plain (13501 lines)

Author: [log in to unmask]
Date: Wed Mar 25 14:43:27 2015
New Revision: 2555

Log:
Merge in r2364 through r2554 to prod branch.

Added:
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerPlotsModule.java
      - copied unchanged from r2554, java/trunk/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerPlotsModule.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/DaqMapHandler.java
      - copied unchanged from r2554, java/trunk/conditions/src/main/java/org/hps/conditions/svt/DaqMapHandler.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtConditionsLoader.java
      - copied unchanged from r2554, java/trunk/conditions/src/main/java/org/hps/conditions/svt/SvtConditionsLoader.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtConditionsReader.java
      - copied unchanged from r2554, java/trunk/conditions/src/main/java/org/hps/conditions/svt/SvtConditionsReader.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/
      - copied from r2554, java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/daqconfig/
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/
      - copied from r2554, java/trunk/ecal-recon/src/main/java/org/hps/recon/ecal/triggerbank/
    java/branches/prod/evio/src/main/java/org/hps/evio/BasicPhysicsEventBuilder.java
      - copied unchanged from r2554, java/trunk/evio/src/main/java/org/hps/evio/BasicPhysicsEventBuilder.java
    java/branches/prod/evio/src/test/java/org/hps/evio/EpicsScalarDataTest.java
      - copied unchanged from r2554, java/trunk/evio/src/test/java/org/hps/evio/EpicsScalarDataTest.java
    java/branches/prod/evio/src/test/java/org/hps/evio/ScalarsTest.java
      - copied unchanged from r2554, java/trunk/evio/src/test/java/org/hps/evio/ScalarsTest.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/AIDAServer.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/EventTagFilter.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EventTagFilter.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/MonitoringApplicationEventBuilder.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/MonitoringApplicationEventBuilder.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/PhysicsSyncEventStation.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/PhysicsSyncEventStation.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/PreStartEtStation.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/PreStartEtStation.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/RunnableEtStation.java
      - copied unchanged from r2554, java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/RunnableEtStation.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SamplesPlots.java
      - copied unchanged from r2554, java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SamplesPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtHitPlots.java
      - copied unchanged from r2554, java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtHitPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalLedSequenceMonitor.java
      - copied unchanged from r2554, java/trunk/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalLedSequenceMonitor.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/PlotterRegistry.java
      - copied unchanged from r2554, java/trunk/monitoring-util/src/main/java/org/hps/monitoring/plotting/PlotterRegistry.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/ValueProvider.java
      - copied unchanged from r2554, java/trunk/monitoring-util/src/main/java/org/hps/monitoring/plotting/ValueProvider.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsListener.java
      - copied unchanged from r2554, java/trunk/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsListener.java
    java/branches/prod/record-util/src/main/java/org/hps/record/epics/
      - copied from r2554, java/trunk/record-util/src/main/java/org/hps/record/epics/
    java/branches/prod/record-util/src/main/java/org/hps/record/et/EtStationThread.java
      - copied unchanged from r2554, java/trunk/record-util/src/main/java/org/hps/record/et/EtStationThread.java
    java/branches/prod/record-util/src/main/java/org/hps/record/et/PreStartProcessor.java
      - copied unchanged from r2554, java/trunk/record-util/src/main/java/org/hps/record/et/PreStartProcessor.java
    java/branches/prod/record-util/src/main/java/org/hps/record/et/SyncEventProcessor.java
      - copied unchanged from r2554, java/trunk/record-util/src/main/java/org/hps/record/et/SyncEventProcessor.java
    java/branches/prod/record-util/src/main/java/org/hps/record/scalars/
      - copied from r2554, java/trunk/record-util/src/main/java/org/hps/record/scalars/
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/EcalLedSequenceMonitor.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/monitoring/EcalLedSequenceMonitor.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/readout/CommRun2014TightPairs.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/readout/CommRun2014TightPairs.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/readout/EngineeringRun2014PrescaledTriggers.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/readout/EngineeringRun2014PrescaledTriggers.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/holly/ECalSimReadout.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/users/holly/ECalSimReadout.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/holly/QuickEcalReadout.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/users/holly/QuickEcalReadout.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/mgraham/NoTimeNoTriggerReadout.lcsim
      - copied unchanged from r2554, java/trunk/steering-files/src/main/resources/org/hps/steering/users/mgraham/NoTimeNoTriggerReadout.lcsim
Removed:
    java/branches/prod/conditions/src/main/java/org/hps/conditions/deprecated/
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TriggerModule.java
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/daqconfig/
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/triggerbank/
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/RunPanel.java
    java/branches/prod/record-util/src/test/java/org/
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/readout/CommRun2014LoosePairs.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/celentan/LedAnalysis.lcsim
    java/branches/prod/users/src/main/java/org/hps/users/celentan/LedAnalysis.java
Modified:
    java/branches/prod/   (props changed)
    java/branches/prod/analysis/src/main/java/org/hps/analysis/ecal/EcalHitPlots.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java
    java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/api/AbstractConditionsObjectCollection.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObject.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObjectCollection.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/database/ConditionsObjectConverter.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableMetaData.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableRegistry.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalBadChannel.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalCalibration.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalChannel.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalGain.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLed.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLedCalibration.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalTimeShift.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtChannel.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtDaqMapping.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/CalibrationHandler.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtChannel.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDaqMapping.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDetectorSetup.java
    java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/TestRunSvtChannel.java
    java/branches/prod/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java
    java/branches/prod/detector-data/detectors/HPS-ECalCommissioning-v2/detector.properties
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCPrimaryTriggerDriver.java
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/SinglesTriggerDriver.java
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TestRunTriggerDriver.java
    java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TriggerDriver.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalPedestalCalculator.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverter.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverterDriver.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java
    java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java
    java/branches/prod/evio/pom.xml
    java/branches/prod/evio/src/main/java/org/hps/evio/LCSimEngRunEventBuilder.java
    java/branches/prod/evio/src/main/java/org/hps/evio/LCSimTestRunEventBuilder.java
    java/branches/prod/evio/src/main/java/org/hps/evio/SVTHitWriter.java
    java/branches/prod/evio/src/main/java/org/hps/evio/TestRunSvtEvioReader.java
    java/branches/prod/evio/src/main/java/org/hps/evio/TestRunTriggeredReconToLcio.java
    java/branches/prod/evio/src/main/java/org/hps/evio/TriggerConfigEvioReader.java
    java/branches/prod/evio/src/main/java/org/hps/evio/TriggerDataWriter.java
    java/branches/prod/monitoring-app/   (props changed)
    java/branches/prod/monitoring-app/pom.xml
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java
    java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java
    java/branches/prod/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop
    java/branches/prod/monitoring-app/src/main/scripts/evio_file_producer.sh
    java/branches/prod/monitoring-app/src/main/scripts/start_et_ring.sh
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SensorOccupancyPlotsDriver.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtTimingInPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/trackrecon/TrackTimePlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalClusterPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalHitPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringPlots.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringUtilities.java
    java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalPedestalViewer.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/MonitoringPlotFactory.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartBuilder.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartUpdater.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/StatusCode.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatistics.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalPedestalMonitor.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalStripChartTestDriver.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/et/EtSystemStripCharts.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/ClusterTablePanel.java
    java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/TableTextModel.java
    java/branches/prod/record-util/src/main/java/org/hps/record/RecordProcessingException.java
    java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoop.java
    java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoopConfiguration.java
    java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventConstants.java
    java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventUtilities.java
    java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioFileProducer.java
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/ECalLedCommissioning.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/EcalMonitoringFinal.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/TriggerDiagnosticsMonitoring.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/celentan/LedAnalysisFromEvio.lcsim
    java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/mgraham/AlignmentMonitorTest.lcsim
    java/branches/prod/tracking/src/main/java/org/hps/readout/svt/SimpleSvtReadout.java
    java/branches/prod/users/src/main/java/org/hps/users/celentan/DummyDriverRaw.java
    java/branches/prod/users/src/main/java/org/hps/users/phansson/ROOTFlatTupleDriver.java

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/ecal/EcalHitPlots.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/ecal/EcalHitPlots.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/ecal/EcalHitPlots.java	Wed Mar 25 14:43:27 2015
@@ -4,11 +4,13 @@
 import hep.aida.IHistogram2D;
 import hep.aida.IPlotter;
 import hep.aida.IPlotterFactory;
+
 import java.util.List;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.SSPData;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+
 import org.hps.recon.ecal.ECalUtils;
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.SSPData;
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/TriggerDiagnosticDriver.java	Wed Mar 25 14:43:27 2015
@@ -1,10 +1,14 @@
 package org.hps.analysis.trigger;
+
+import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
 
 import java.awt.Point;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -18,28 +22,32 @@
 import org.hps.analysis.trigger.event.TriggerEfficiencyModule;
 import org.hps.analysis.trigger.event.TriggerMatchEvent;
 import org.hps.analysis.trigger.event.TriggerMatchStatus;
+import org.hps.analysis.trigger.event.TriggerPlotsModule;
 import org.hps.analysis.trigger.util.OutputLogger;
 import org.hps.analysis.trigger.util.Pair;
 import org.hps.analysis.trigger.util.PairTrigger;
 import org.hps.analysis.trigger.util.SinglesTrigger;
 import org.hps.analysis.trigger.util.Trigger;
 import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
-import org.hps.readout.ecal.TriggerModule;
-import org.hps.readout.ecal.daqconfig.ConfigurationManager;
-import org.hps.readout.ecal.daqconfig.DAQConfig;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.SSPCluster;
-import org.hps.readout.ecal.triggerbank.SSPData;
-import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
-import org.hps.readout.ecal.triggerbank.SSPPairTrigger;
-import org.hps.readout.ecal.triggerbank.SSPSinglesTrigger;
-import org.hps.readout.ecal.triggerbank.SSPTrigger;
-import org.hps.readout.ecal.triggerbank.TIData;
+import org.hps.recon.ecal.daqconfig.ConfigurationManager;
+import org.hps.recon.ecal.daqconfig.DAQConfig;
+import org.hps.recon.ecal.daqconfig.PairTriggerConfig;
+import org.hps.recon.ecal.daqconfig.SinglesTriggerConfig;
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
+import org.hps.recon.ecal.triggerbank.SSPData;
+import org.hps.recon.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.recon.ecal.triggerbank.SSPPairTrigger;
+import org.hps.recon.ecal.triggerbank.SSPSinglesTrigger;
+import org.hps.recon.ecal.triggerbank.SSPTrigger;
+import org.hps.recon.ecal.triggerbank.TIData;
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;
 import org.lcsim.util.Driver;
+import org.lcsim.util.aida.AIDA;
 
 public class TriggerDiagnosticDriver extends Driver {
 	// Store the LCIO collection names for the needed objects.
@@ -62,6 +70,10 @@
 	private int activeTrigger = -1;
 	private TriggerModule[] singlesTrigger = new TriggerModule[2];
 	private TriggerModule[] pairsTrigger = new TriggerModule[2];
+	private boolean[][] singlesCutsEnabled = new boolean[2][3];
+	private boolean[][] pairCutsEnabled = new boolean[2][7];
+	private boolean[] singlesTriggerEnabled = new boolean[2];
+	private boolean[] pairTriggerEnabled = new boolean[2];
 	
 	// Verification settings.
 	private int nsa = 100;
@@ -69,13 +81,14 @@
 	private int windowWidth = 200;
 	private int hitAcceptance = 1;
 	private int noiseThreshold = 50;
+	private double energyAcceptance = 0.003;
 	private long localWindowStart = 0;
 	private boolean readDAQConfig = false;
-	private double energyAcceptance = 0.03;
 	private int localWindowThreshold = 10 * 1000;
 	private boolean performClusterVerification = true;
 	private boolean performSinglesTriggerVerification = true;
 	private boolean performPairTriggerVerification = true;
+	private boolean enforceTimeCompliance = false;
 	
 	// Efficiency tracking variables.
 	private ClusterMatchStatus clusterRunStats = new ClusterMatchStatus();
@@ -103,7 +116,8 @@
     private boolean printSinglesTriggerInternalFail = true;
     private boolean printPairTriggerEfficiencyFail = true;
     private boolean printPairTriggerInternalFail = true;
-    
+    private int     printResultsEveryNEvents = 100000;
+
     // Cut index arrays for trigger verification.
 	private static final int ENERGY_MIN   = TriggerDiagnosticUtil.SINGLES_ENERGY_MIN;
 	private static final int ENERGY_MAX   = TriggerDiagnosticUtil.SINGLES_ENERGY_MAX;
@@ -113,12 +127,101 @@
 	private static final int ENERGY_SLOPE = TriggerDiagnosticUtil.PAIR_ENERGY_SLOPE;
 	private static final int COPLANARITY  = TriggerDiagnosticUtil.PAIR_COPLANARITY;
     
+	// Track the total run time.
+	private long startTime = -1;
+	private long endTime = -1;
+	
+	// Cut names for logging.
+	private static final String[][] cutNames = {
+			{ "E_min", "E_max", "hit count", "null" },
+			{ "E_sum", "E_diff", "E_slope", "coplanar" }
+	};
+	
+	// Temporary AIDA Plots
+	private TriggerPlotsModule globalTriggerPlots = new TriggerPlotsModule(0, 0);
+	private static final int RECON   = 0;
+	private static final int SSP     = 1;
+	private static final int ALL     = 0;
+	private static final int MATCHED = 1;
+	private static final int FAILED  = 2;
+	private AIDA aida = AIDA.defaultInstance();
+	private IHistogram1D[][] clusterHitPlot = {
+			{
+				aida.histogram1D("cluster/Recon Cluster Hit Count (All)",     9, 0.5, 9.5),
+				aida.histogram1D("cluster/Recon Cluster Hit Count (Matched)", 9, 0.5, 9.5),
+				aida.histogram1D("cluster/Recon Cluster Hit Count (Failed)",  9, 0.5, 9.5)
+			},
+			{
+				aida.histogram1D("cluster/SSP Cluster Hit Count (All)",     9, 0.5, 9.5),
+				aida.histogram1D("cluster/SSP Cluster Hit Count (Matched)", 9, 0.5, 9.5),
+				aida.histogram1D("cluster/SSP Cluster Hit Count (Failed)",  9, 0.5, 9.5)
+			}
+	};
+	private IHistogram1D[][] clusterEnergyPlot = {
+			{
+				aida.histogram1D("cluster/Recon Cluster Energy (All)",     300, 0.0, 3.0),
+				aida.histogram1D("cluster/Recon Cluster Energy (Matched)", 300, 0.0, 3.0),
+				aida.histogram1D("cluster/Recon Cluster Energy (Failed)",  300, 0.0, 3.0)
+			},
+			{
+				aida.histogram1D("cluster/SSP Cluster Energy (All)",     300, 0.0, 3.0),
+				aida.histogram1D("cluster/SSP Cluster Energy (Matched)", 300, 0.0, 3.0),
+				aida.histogram1D("cluster/SSP Cluster Energy (Failed)",  300, 0.0, 3.0)
+			}
+	};
+	private IHistogram1D[][] clusterTimePlot = {
+			{
+				aida.histogram1D("cluster/Recon Cluster Time (All)",     115, 0, 460),
+				aida.histogram1D("cluster/Recon Cluster Time (Matched)", 115, 0, 460),
+				aida.histogram1D("cluster/Recon Cluster Time (Failed)",  115, 0, 460)
+			},
+			{
+				aida.histogram1D("cluster/SSP Cluster Time (All)",     115, 0, 460),
+				aida.histogram1D("cluster/SSP Cluster Time (Matched)", 115, 0, 460),
+				aida.histogram1D("cluster/SSP Cluster Time (Failed)",  115, 0, 460)
+			}
+	};
+	private IHistogram2D[][] clusterPositionPlot = {
+			{
+				aida.histogram2D("cluster/Recon Cluster Position (All)",     47, -23.5, 23.5, 11, -5.5, 5.5),
+				aida.histogram2D("cluster/Recon Cluster Position (Matched)", 47, -23.5, 23.5, 11, -5.5, 5.5),
+				aida.histogram2D("cluster/Recon Cluster Position (Failed)",  47, -23.5, 23.5, 11, -5.5, 5.5)
+			},
+			{
+				aida.histogram2D("cluster/SSP Cluster Position (All)",     47, -23.5, 23.5, 11, -5.5, 5.5),
+				aida.histogram2D("cluster/SSP Cluster Position (Matched)", 47, -23.5, 23.5, 11, -5.5, 5.5),
+				aida.histogram2D("cluster/SSP Cluster Position (Failed)",  47, -23.5, 23.5, 11, -5.5, 5.5)
+			}
+	};
+	private IHistogram2D[] energyhitDiffPlot = {
+		aida.histogram2D("cluster/Recon-SSP Energy-Hit Difference (All)",     21, -0.010, 0.010, 6, -3, 3),
+		aida.histogram2D("cluster/Recon-SSP Energy-Hit Difference (Matched)", 21, -0.010, 0.010, 6, -3, 3),
+		aida.histogram2D("cluster/Recon-SSP Energy-Hit Difference (Failed)",  21, -0.010, 0.010, 6, -3, 3)
+	};
+	
 	/**
 	 * Define the trigger modules. This should be replaced by parsing
 	 * the DAQ configuration at some point.
 	 */
 	@Override
 	public void startOfData() {
+		// By default, all triggers and cuts are enabled.
+		for(int i = 0; i < 2; i++) {
+			// Enable the triggers.
+			pairTriggerEnabled[i] = true;
+			singlesTriggerEnabled[i] = true;
+			
+			// Enable the singles cuts.
+			for(int j = 0; j < singlesCutsEnabled.length; j++) {
+				singlesCutsEnabled[i][j] = true;
+			}
+			
+			// Enable the pair cuts.
+			for(int j = 0; j < pairCutsEnabled.length; j++) {
+				pairCutsEnabled[i][j] = true;
+			}
+		}
+		
 		// If the DAQ configuration should be read, attach a listener
 		// to track when it updates.
 		if(readDAQConfig) {
@@ -127,6 +230,10 @@
 				public void actionPerformed(ActionEvent e) {
 					// Get the DAQ configuration.
 					DAQConfig daq = ConfigurationManager.getInstance();
+					
+					// Update the plotting energy slope values.
+					globalTriggerPlots.setEnergySlopeParamF(0, daq.getSSPConfig().getPair1Config().getEnergySlopeCutConfig().getParameterF());
+					globalTriggerPlots.setEnergySlopeParamF(1, daq.getSSPConfig().getPair2Config().getEnergySlopeCutConfig().getParameterF());
 					
 					// Load the DAQ settings from the configuration manager.
 					singlesTrigger[0].loadDAQConfiguration(daq.getSSPConfig().getSingles1Config());
@@ -137,6 +244,33 @@
 					nsb = daq.getFADCConfig().getNSB();
 					windowWidth = daq.getFADCConfig().getWindowWidth();
 					
+					// Get the trigger configurations from the DAQ.
+					SinglesTriggerConfig[] singles = { daq.getSSPConfig().getSingles1Config(),
+							daq.getSSPConfig().getSingles2Config() };
+					PairTriggerConfig[] pairs = { daq.getSSPConfig().getPair1Config(),
+							daq.getSSPConfig().getPair2Config() };
+					
+					// Update the enabled/disabled statuses.
+					for(int i = 0; i < 2; i++) {
+						// Set the trigger enabled status.
+						pairTriggerEnabled[i] = pairs[i].isEnabled();
+						singlesTriggerEnabled[i] = singles[i].isEnabled();
+						
+						// Set the singles cut statuses.
+						singlesCutsEnabled[i][ENERGY_MIN] = singles[i].getEnergyMinCutConfig().isEnabled();
+						singlesCutsEnabled[i][ENERGY_MAX] = singles[i].getEnergyMaxCutConfig().isEnabled();
+						singlesCutsEnabled[i][HIT_COUNT] = singles[i].getHitCountCutConfig().isEnabled();
+						
+						// Set the pair cut statuses.
+						pairCutsEnabled[i][ENERGY_MIN] = pairs[i].getEnergyMinCutConfig().isEnabled();
+						pairCutsEnabled[i][ENERGY_MAX] = pairs[i].getEnergyMaxCutConfig().isEnabled();
+						pairCutsEnabled[i][HIT_COUNT] = pairs[i].getHitCountCutConfig().isEnabled();
+						pairCutsEnabled[i][3 + ENERGY_SUM] = pairs[i].getEnergySumCutConfig().isEnabled();
+						pairCutsEnabled[i][3 + ENERGY_DIFF] = pairs[i].getEnergyDifferenceCutConfig().isEnabled();
+						pairCutsEnabled[i][3 + ENERGY_SLOPE] = pairs[i].getEnergySlopeCutConfig().isEnabled();
+						pairCutsEnabled[i][3 + COPLANARITY] = pairs[i].getCoplanarityCutConfig().isEnabled();
+					}
+					
 					// Print a DAQ configuration settings header.
 					System.out.println();
 					System.out.println();
@@ -154,51 +288,6 @@
 		System.out.println("======================================================================");
 		System.out.println("=== Cluster/Trigger Verification Settings ============================");
 		System.out.println("======================================================================");
-		
-		// Set the FADC settings.
-		nsa = 100;
-		nsb = 20;
-		windowWidth = 400;
-		
-		/*
-		// Define the first singles trigger.
-		singlesTrigger[0] = new TriggerModule();
-		singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
-		singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 8.191);
-		singlesTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
-		
-		// Define the second singles trigger.
-		singlesTrigger[1] = new TriggerModule();
-		singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
-		singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 0.050);
-		singlesTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
-		
-		// Define the first pairs trigger.
-		pairsTrigger[0] = new TriggerModule();
-		pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.020);
-		pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 0.055);
-		pairsTrigger[0].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 1);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.010);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 2.000);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 1.200);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.400);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.0055);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 40);
-		pairsTrigger[0].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 16);
-		
-		// Define the second pairs trigger.
-		pairsTrigger[1] = new TriggerModule();
-		pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW, 0.010);
-		pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH, 1.800);
-		pairsTrigger[1].setCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW, 2);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW, 0.020);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH, 2.000);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH, 1.200);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW, 0.400);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F, 0.0055);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_COPLANARITY_HIGH, 40);
-		pairsTrigger[1].setCutValue(TriggerModule.PAIR_TIME_COINCIDENCE, 16);
-		*/
 		
 		// Define the first singles trigger.
 		singlesTrigger[0] = new TriggerModule();
@@ -255,6 +344,10 @@
 	 */
 	@Override
 	public void endOfData() {
+		PrintResults();
+	}
+	
+	public void PrintResults() {
 		// Print the cluster/trigger verification header.
 		System.out.println();
 		System.out.println();
@@ -263,17 +356,48 @@
 		System.out.println("======================================================================");
 		
 		// Print the general event failure rate.
-		System.out.println("Event Failure Rate:");
-		System.out.printf("\tNoise Events          :: %d / %d (%7.3f%%)%n",
+		int headSpaces = getPrintSpaces(totalEvents, triggerRunStats[0].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfTypeSeen(1),
+				triggerRunStats[1].getEventsOfTypeSeen(0), triggerRunStats[1].getEventsOfTypeSeen(1));
+		System.out.println("General Event Statistics:");
+		System.out.printf("\tEvent Start Time      :: %.3f s%n", (startTime / Math.pow(10, 9)));
+		System.out.printf("\tEvent End Time        :: %.3f%n", (endTime / Math.pow(10, 9)));
+		System.out.printf("\tEvent Run Time        :: %.3f%n", ((endTime - startTime) / Math.pow(10, 9)));
+		System.out.printf("\tNoise Events          :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
 				noiseEvents, totalEvents, (100.0 * noiseEvents / totalEvents));
-		System.out.printf("\tCluster Events Failed :: %d / %d (%7.3f%%)%n",
+		System.out.printf("\tCluster Events Failed :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
 				failedClusterEvents, totalEvents, (100.0 * failedClusterEvents / totalEvents));
-		System.out.printf("\tSingles Events Failed :: %d / %d (%7.3f%%)%n",
+		System.out.printf("\tSingles Events Failed :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
 				failedSinglesEvents, totalEvents, (100.0 * failedSinglesEvents / totalEvents));
-		System.out.printf("\tPair Events Failed    :: %d / %d (%7.3f%%)%n",
+		System.out.printf("\tPair Events Failed    :: %" + headSpaces + "d / %" + headSpaces + "d (%7.3f%%)%n",
 				failedPairEvents, totalEvents, (100.0 * failedPairEvents / totalEvents));
 		
+		// Print out how many events were triggered by a type along
+		// with how many were verified.
+		System.out.println();
+		System.out.println("Event Triggering Type Verification:");
+		System.out.printf("\tSingles Trigger 1     :: %" + headSpaces + "d / %" + headSpaces + "d",
+				triggerRunStats[0].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfType(0));
+		if(triggerRunStats[0].getEventsOfType(0) != 0) {
+			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[0].getEventsOfTypeSeen(0) / triggerRunStats[0].getEventsOfType(0)));
+		} else { System.out.println(); }
+		System.out.printf("\tSingles Trigger 2     :: %" + headSpaces + "d / %" + headSpaces + "d",
+				triggerRunStats[0].getEventsOfTypeSeen(1), triggerRunStats[0].getEventsOfType(1));
+		if(triggerRunStats[0].getEventsOfType(0) != 0) {
+			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[0].getEventsOfTypeSeen(1) / triggerRunStats[0].getEventsOfType(1)));
+		} else { System.out.println(); }
+		System.out.printf("\tPair Trigger 1        :: %" + headSpaces + "d / %" + headSpaces + "d",
+				triggerRunStats[1].getEventsOfTypeSeen(0), triggerRunStats[0].getEventsOfType(0));
+		if(triggerRunStats[1].getEventsOfType(0) != 0) {
+			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[1].getEventsOfTypeSeen(0) / triggerRunStats[1].getEventsOfType(0)));
+		} else { System.out.println(); }
+		System.out.printf("\tPair Trigger 2        :: %" + headSpaces + "d / %" + headSpaces + "d",
+				triggerRunStats[1].getEventsOfTypeSeen(1), triggerRunStats[0].getEventsOfType(1));
+		if(triggerRunStats[1].getEventsOfType(0) != 0) {
+			System.out.printf(" (%7.3f%%)%n", (100.0 * triggerRunStats[1].getEventsOfTypeSeen(1) / triggerRunStats[1].getEventsOfType(1)));
+		} else { System.out.println(); }
+		
 		// Print the cluster verification data.
+		System.out.println();
 		System.out.println("Cluster Verification:");
 		System.out.printf("\tRecon Clusters        :: %d%n", clusterRunStats.getReconClusterCount());
 		System.out.printf("\tSSP Clusters          :: %d%n", clusterRunStats.getSSPClusterCount());
@@ -282,7 +406,7 @@
 		System.out.printf("\tFailed (Energy)       :: %d%n", clusterRunStats.getEnergyFailures());
 		System.out.printf("\tFailed (Hit Count)    :: %d%n", clusterRunStats.getHitCountFailures());
 		if(clusterRunStats.getReconClusterCount() == 0) { System.out.printf("\tCluster Efficiency    :: N/A%n"); }
-		else { System.out.printf("\tCluster Efficiency :: %7.3f%%%n", 100.0 * clusterRunStats.getMatches() / clusterRunStats.getReconClusterCount()); }
+		else { System.out.printf("\tCluster Efficiency    :: %7.3f%%%n", 100.0 * clusterRunStats.getMatches() / clusterRunStats.getReconClusterCount()); }
 		
 		// Print the trigger verification data.
 		for(int triggerType = 0; triggerType < 2; triggerType++) {
@@ -310,61 +434,67 @@
 			else { System.out.printf("(%7.3f%%)%n" , (100.0 * triggerRunStats[triggerType].getMatchedReconTriggers() / triggerRunStats[triggerType].getReconTriggerCount())); }
 			
 			// Print the individual cut performances.
-			int halfSSPTriggers = triggerRunStats[triggerType].getSSPSimTriggerCount() / 2;
 			if(triggerType == 0) {
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+				int sspTriggerCount = triggerRunStats[0].getTotalSSPTriggers(triggerNum);
+				System.out.println();
+				System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
+				if(sspTriggerCount == 0) {
+					System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[0].getUnmatchedTriggers(triggerNum));
+						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount);
+						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount);
+						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount);
+					} else {
+						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[0].getUnmatchedTriggers(triggerNum));
+						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount,
+								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN) / sspTriggerCount));
+						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount,
+								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX) / sspTriggerCount));
+						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount,
+								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT) / sspTriggerCount));
+					}
+				}
+			} else {
+				for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+					int sspTriggerCount = triggerRunStats[1].getTotalSSPTriggers(triggerNum);
 					System.out.println();
 					System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
-					if(triggerRunStats[0].getSSPSimTriggerCount() == 0) {
-						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), halfSSPTriggers);
-						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), halfSSPTriggers);
-						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), halfSSPTriggers);
+					if(sspTriggerCount == 0) {
+						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[1].getUnmatchedTriggers(triggerNum));
+						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount);
+						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount);
+						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount);
+						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d%n",
+								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), sspTriggerCount);
 					} else {
-						System.out.printf("\t\tCluster Energy Lower Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN), halfSSPTriggers,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MIN) / halfSSPTriggers));
-						System.out.printf("\t\tCluster Energy Upper Bound :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX), halfSSPTriggers,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, ENERGY_MAX) / halfSSPTriggers));
-						System.out.printf("\t\tCluster Hit Count          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT), halfSSPTriggers,
-								(100.0 * triggerRunStats[0].getCutFailures(triggerNum, HIT_COUNT) / halfSSPTriggers));
+						System.out.printf("\t\tUmatched Triggers          :: %" + spaces + "d%n", triggerRunStats[1].getUnmatchedTriggers(triggerNum));
+						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount,
+								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM) / sspTriggerCount));
+						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount,
+								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF) / sspTriggerCount));
+						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount,
+								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE) / sspTriggerCount));
+						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
+								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), sspTriggerCount,
+								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY) / sspTriggerCount));
 					}
 				}
-			} else {
-				for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
-					System.out.println();
-					System.out.printf("\tTrigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
-					if(triggerRunStats[1].getSSPSimTriggerCount() == 0) {
-						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), halfSSPTriggers);
-						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), halfSSPTriggers);
-						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), halfSSPTriggers);
-						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d%n",
-								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), halfSSPTriggers);
-					} else {
-						System.out.printf("\t\tPair Energy Sum            :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM), halfSSPTriggers,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SUM) / halfSSPTriggers));
-						System.out.printf("\t\tPair Energy Difference     :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF), halfSSPTriggers,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_DIFF) / halfSSPTriggers));
-						System.out.printf("\t\tPair Energy Slope          :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE), halfSSPTriggers,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, ENERGY_SLOPE) / halfSSPTriggers));
-						System.out.printf("\t\tPair Coplanarity           :: %" + spaces + "d / %" + spaces + "d (%7.3f%%)%n",
-								triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY), halfSSPTriggers,
-								(100.0 * triggerRunStats[1].getCutFailures(triggerNum, COPLANARITY) / halfSSPTriggers));
-					}
-				}
-			}
-		}
-		
+			}
+		}
+		
+		System.out.println();
 		this.efficiencyRunStats.printModule();
 	}
 	
@@ -374,7 +504,7 @@
 	@Override
 	public void process(EventHeader event) {
 		// ==========================================================
-		// ==== Initialize the Event ================================
+		// ==== Event Pre-Initialization ============================
 		// ==========================================================
         
 		// If DAQ settings are to be used, check if they are initialized
@@ -385,14 +515,12 @@
 			}
 		}
 		
-        // Print the verification header.
-		OutputLogger.printNewLine(2);
-		OutputLogger.println("======================================================================");
-		OutputLogger.println("==== Cluster/Trigger Verification ====================================");
-		OutputLogger.println("======================================================================");
-		
 		// Increment the total event count.
 		totalEvents++;
+		
+		if(totalEvents%printResultsEveryNEvents == 0){
+			PrintResults();
+		}
 		
 		// Reset the output buffer and print flags.
 		clusterFail = false;
@@ -400,12 +528,61 @@
 		singlesEfficiencyFail = false;
 		pairInternalFail = false;
 		pairEfficiencyFail = false;
+		OutputLogger.clearLog();
+		
+		// Track the times.
+		if(startTime == -1) { startTime = event.getTimeStamp(); }
+		else { endTime = event.getTimeStamp(); }
+		
+		
+		
+		// ==========================================================
+		// ==== Output GTP Information ==============================
+		// ==========================================================
+		
+        // Print the verification header.
+		OutputLogger.printNewLine(2);
+		OutputLogger.println("======================================================================");
+		OutputLogger.println("==== FADC/GTP Readout ================================================");
+		OutputLogger.println("======================================================================");
+		
+		OutputLogger.println("FADC Hits:");
+		for(CalorimeterHit hit : event.get(CalorimeterHit.class, "EcalCalHits")) {
+			int ix = hit.getIdentifierFieldValue("ix");
+			int iy = hit.getIdentifierFieldValue("iy");
+			OutputLogger.printf("\tHit at (%3d, %3d) with %7.3f GeV at time %3.0f ns%n", ix, iy, hit.getCorrectedEnergy(), hit.getTime());
+		}
+		OutputLogger.printNewLine(2);
+		OutputLogger.println("GTP Clusters:");
+		for(Cluster cluster : event.get(Cluster.class, clusterCollectionName)) {
+			OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(cluster));
+			for(CalorimeterHit hit : cluster.getCalorimeterHits()) {
+				int ix = hit.getIdentifierFieldValue("ix");
+				int iy = hit.getIdentifierFieldValue("iy");
+				OutputLogger.printf("\t\t> (%3d, %3d) :: %7.3f GeV%n", ix, iy, hit.getCorrectedEnergy());
+			}
+		}
+		
+		
+		
+		// ==========================================================
+		// ==== Initialize the Event ================================
+		// ==========================================================
+		
+        // Print the verification header.
+		OutputLogger.printNewLine(2);
+		OutputLogger.println("======================================================================");
+		OutputLogger.println("==== Cluster/Trigger Verification ====================================");
+		OutputLogger.println("======================================================================");
 		
 		
 		
 		// ==========================================================
 		// ==== Obtain SSP and TI Banks =============================
 		// ==========================================================
+		
+		// Output the event number and information.
+		OutputLogger.printf("Event Number %d (%d)%n", totalEvents, event.getEventNumber());
 		
 		// Get the SSP clusters.
 		if(event.hasCollection(GenericObject.class, bankCollectionName)) {
@@ -441,6 +618,9 @@
 					} else if(tiBank.isCalibTrigger()) {
 						OutputLogger.println("Trigger type :: Cosmic");
 						activeTrigger = TriggerDiagnosticUtil.TRIGGER_COSMIC;
+					} else {
+						System.err.println("TriggerDiagnosticDriver: Skipping event; no TI trigger source found.");
+						return;
 					}
 				}
 			}
@@ -454,6 +634,12 @@
 					OutputLogger.printf("%d SSP clusters found.%n", sspClusters.size());
 				}
 			}
+		}
+		
+		// Make sure that both an SSP bank and a TI bank were found.
+		if(tiBank == null || sspBank == null) {
+			System.err.println("TriggerDiagnosticDriver :: SEVERE WARNING :: TI bank or SSP bank missing from event!");
+			return;
 		}
 		
 		
@@ -523,7 +709,6 @@
 					reconClusters.add(reconCluster);
 					OutputLogger.println(" [  verifiable  ]");
 				} else { OutputLogger.println(" [ unverifiable ]"); }
-				
 			}
 			
 			// Output the number of verifiable clusters found.
@@ -576,10 +761,10 @@
 				(pairInternalFail && printPairTriggerInternalFail) ||
 				(pairEfficiencyFail && printPairTriggerEfficiencyFail)) {
 			OutputLogger.printLog();
-		}
-		
-		
-		
+		}	
+		
+		
+				
 		// ==========================================================
 		// ==== Process Local Tracked Variables =====================
 		// ==========================================================
@@ -604,6 +789,10 @@
 			localWindowStart = Calendar.getInstance().getTimeInMillis();
 		}
 	}
+
+	public void setPrintResultsEveryNEvents(int N) {
+		printResultsEveryNEvents = N;
+	}
 	
 	public void setPrintOnClusterFailure(boolean state) {
 		printClusterFail = state;
@@ -653,8 +842,16 @@
 		energyAcceptance = window;
 	}
 	
+	public void setEnforceStrictTimeCompliance(boolean state) {
+		enforceTimeCompliance = state;
+	}
+	
 	public void setReadDAQConfig(boolean state) {
 		readDAQConfig = state;
+	}
+	
+	public void setLocalWindowThresholdMilliseconds(int localWindowThreshold) {
+	    this.localWindowThreshold = localWindowThreshold;
 	}
 	
 	/**
@@ -679,15 +876,164 @@
 		OutputLogger.println("=== Cluster Verification =============================================");
 		OutputLogger.println("======================================================================");
 		
+		
+		
+		// ==========================================================
+		// ==== Perform Cluster Matching ============================
+		// ==========================================================
+		
 		// Track the number of cluster pairs that were matched and that
 		// failed by failure type.
 		ClusterMatchEvent event = new ClusterMatchEvent();
 		
-		
-		
-		// ==========================================================
-		// ==== Produce the Cluster Position Mappings ===============
-		// ==========================================================
+		if(enforceTimeCompliance) {
+			event = matchClustersTimeCompliant(reconClusters, sspClusters, energyAcceptance, hitAcceptance);
+		} else {
+			event = matchClusters(reconClusters, sspClusters, energyAcceptance, hitAcceptance);
+		}
+		
+		// Add the event results to the global results.
+		clusterRunStats.addEvent(event, reconClusters, sspClusters);
+		clusterLocalStats.addEvent(event, reconClusters, sspClusters);
+		
+		
+		
+		// ==========================================================
+		// ==== Output Event Summary ================================
+		// ==========================================================
+		
+		// Print the valid reconstructed clusters and populate their
+		// distribution graphs.
+		OutputLogger.println();
+		OutputLogger.println("Verified Reconstructed Clusters:");
+		if(!reconClusters.isEmpty()) {
+			for(Cluster reconCluster : reconClusters) {
+				OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(reconCluster));
+			}
+		} else { OutputLogger.println("\tNone"); }
+		
+		// Print the SSP clusters and populate their distribution graphs.
+		OutputLogger.println("SSP Clusters:");
+		if(!sspClusters.isEmpty()) {
+			for(SSPCluster sspCluster : sspClusters) {
+				OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(sspCluster));
+			}
+		} else { OutputLogger.println("\tNone"); }
+		
+		// Print the matched clusters.
+		OutputLogger.println("Matched Clusters:");
+		if(event.getMatchedPairs().size() != 0) {
+			// Iterate over the matched pairs.
+			for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+				// If the pair is a match, print it out.
+				if(pair.isMatch()) {
+					OutputLogger.printf("\t%s --> %s%n",
+							TriggerDiagnosticUtil.clusterToString(pair.getReconstructedCluster()),
+							TriggerDiagnosticUtil.clusterToString(pair.getSSPCluster()));
+				}
+			}
+		}
+		 else { OutputLogger.println("\tNone"); }
+		
+		// Print event statistics.
+		OutputLogger.println();
+		OutputLogger.println("Event Statistics:");
+		OutputLogger.printf("\tRecon Clusters     :: %d%n", reconClusters.size());
+		OutputLogger.printf("\tClusters Matched   :: %d%n", event.getMatches());
+		OutputLogger.printf("\tFailed (Position)  :: %d%n", event.getPositionFailures());
+		OutputLogger.printf("\tFailed (Time)      :: %d%n", event.getTimeFailures());
+		OutputLogger.printf("\tFailed (Energy)    :: %d%n", event.getEnergyFailures());
+		OutputLogger.printf("\tFailed (Hit Count) :: %d%n", event.getHitCountFailures());
+		OutputLogger.printf("\tCluster Efficiency :: %3.0f%%%n", 100.0 * event.getMatches() / reconClusters.size());
+		
+		// Note whether there was a cluster match failure.
+		if(event.isFailState() || event.getMatches() - reconClusters.size() != 0) {
+			clusterFail = true;
+		}
+		
+		
+		
+		// TEMP :: Populate the cluster diagnostic plots.
+		
+		// Populate the ALL cluster plots.
+		for(Cluster cluster : reconClusters) {
+			clusterHitPlot[RECON][ALL].fill(cluster.getCalorimeterHits().size());
+			clusterEnergyPlot[RECON][ALL].fill(cluster.getEnergy());
+			clusterTimePlot[RECON][ALL].fill(cluster.getCalorimeterHits().get(0).getTime());
+			Point position = TriggerDiagnosticUtil.getClusterPosition(cluster);
+			clusterPositionPlot[RECON][ALL].fill(position.x, position.y);
+		}
+		for(SSPCluster cluster : sspClusters) {
+			clusterHitPlot[SSP][ALL].fill(cluster.getHitCount());
+			clusterEnergyPlot[SSP][ALL].fill(cluster.getEnergy());
+			clusterTimePlot[SSP][ALL].fill(cluster.getTime());
+			clusterPositionPlot[SSP][ALL].fill(cluster.getXIndex(), cluster.getYIndex());
+		}
+		
+		// Populate the matched and failed plots.
+		for(ClusterMatchedPair pair : event.getMatchedPairs()) {
+			 if(pair.getFirstElement() != null && pair.getSecondElement() != null) {
+				double energyDiff = pair.getSecondElement().getEnergy() - pair.getFirstElement().getEnergy();
+				int hitDiff = pair.getSecondElement().getHitCount() - pair.getFirstElement().getCalorimeterHits().size();
+				energyhitDiffPlot[ALL].fill(energyDiff, hitDiff);
+			 }
+			
+			if(pair.isMatch()) {
+				if(pair.getFirstElement() != null) {
+					clusterHitPlot[RECON][MATCHED].fill(pair.getFirstElement().getCalorimeterHits().size());
+					clusterEnergyPlot[RECON][MATCHED].fill(pair.getFirstElement().getEnergy());
+					clusterTimePlot[RECON][MATCHED].fill(pair.getFirstElement().getCalorimeterHits().get(0).getTime());
+					Point position = TriggerDiagnosticUtil.getClusterPosition(pair.getFirstElement());
+					clusterPositionPlot[RECON][MATCHED].fill(position.x, position.y);
+				} if(pair.getSecondElement() != null) {
+					clusterHitPlot[SSP][MATCHED].fill(pair.getSecondElement().getHitCount());
+					clusterEnergyPlot[SSP][MATCHED].fill(pair.getSecondElement().getEnergy());
+					clusterTimePlot[SSP][MATCHED].fill(pair.getSecondElement().getTime());
+					clusterPositionPlot[SSP][MATCHED].fill(pair.getSecondElement().getXIndex(), pair.getSecondElement().getYIndex());
+				} if(pair.getFirstElement() != null && pair.getSecondElement() != null) {
+					double energyDiff = pair.getSecondElement().getEnergy() - pair.getFirstElement().getEnergy();
+					int hitDiff = pair.getSecondElement().getHitCount() - pair.getFirstElement().getCalorimeterHits().size();
+					energyhitDiffPlot[MATCHED].fill(energyDiff, hitDiff);
+				}
+			} else {
+				if(pair.getFirstElement() != null) {
+					clusterHitPlot[RECON][FAILED].fill(pair.getFirstElement().getCalorimeterHits().size());
+					clusterEnergyPlot[RECON][FAILED].fill(pair.getFirstElement().getEnergy());
+					clusterTimePlot[RECON][FAILED].fill(pair.getFirstElement().getCalorimeterHits().get(0).getTime());
+					Point position = TriggerDiagnosticUtil.getClusterPosition(pair.getFirstElement());
+					clusterPositionPlot[RECON][FAILED].fill(position.x, position.y);
+				} if(pair.getSecondElement() != null) {
+					clusterHitPlot[SSP][FAILED].fill(pair.getSecondElement().getHitCount());
+					clusterEnergyPlot[SSP][FAILED].fill(pair.getSecondElement().getEnergy());
+					clusterTimePlot[SSP][FAILED].fill(pair.getSecondElement().getTime());
+					clusterPositionPlot[SSP][FAILED].fill(pair.getSecondElement().getXIndex(), pair.getSecondElement().getYIndex());
+				} if(pair.getFirstElement() != null && pair.getSecondElement() != null) {
+					double energyDiff = pair.getSecondElement().getEnergy() - pair.getFirstElement().getEnergy();
+					int hitDiff = pair.getSecondElement().getHitCount() - pair.getFirstElement().getCalorimeterHits().size();
+					energyhitDiffPlot[FAILED].fill(energyDiff, hitDiff);
+				}
+			}
+		}
+	}
+	
+	/**
+     * Performs cluster matching between a collection of reconstructed
+	 * clusters and a collection of SSP clusters with an algorithm that
+	 * ignores the times reported for each cluster.
+	 * @param reconClusters - A collection of reconstructed clusters.
+	 * @param sspClusters - A collection of SSP clusters.
+	 * @param energyWindow - The window of allowed deviation between
+	 * the reconstructed cluster and SSP cluster energies.
+	 * @param hitWindow - The window of allowed deviation between
+	 * the reconstructed cluster and SSP cluster hit counts.
+	 * @return Returns the cluster matching results stored inside a
+	 * <code>clusterMatchEvent</code> object.
+	 */
+	private static final ClusterMatchEvent matchClusters(Collection<Cluster> reconClusters,
+			Collection<SSPCluster> sspClusters, double energyWindow, int hitWindow) {
+		// Track the number of cluster pairs that were matched and that
+		// failed by failure type.
+		ClusterMatchEvent event = new ClusterMatchEvent();
 		
 		// Create maps to link cluster position to the list of clusters
 		// that were found at that location.
@@ -726,12 +1072,6 @@
 			// Add the cluster to the list.
 			sspList.add(sspCluster);
 		}
-		
-		
-		
-		// ==========================================================
-		// ==== Perform Cluster Matching ============================
-		// ==========================================================
 		
 		// For each reconstructed cluster, attempt to match the clusters
 		// with SSP clusters at the same position.
@@ -749,17 +1089,11 @@
 			// reason of position. The remainder of the loop may be
 			// skipped, since there is nothing to check.
 			if(sspList == null || sspList.isEmpty()) {
-				clusterFail = true;
 				for(Cluster cluster : reconList) {
 					event.pairFailPosition(cluster, null);
 				}
 				continue positionLoop;
 			}
-			
-			// If there are more reconstructed clusters than there are
-			// SSP clusters, than a number equal to the difference must
-			// fail by means of positions.
-			if(sspList.size() < reconList.size()) { clusterFail = true; }
 			
 			// Get all possible permutations of SSP clusters.
 			List<List<Pair<Cluster, SSPCluster>>> permutations = getPermutations(reconList, sspList);
@@ -794,20 +1128,31 @@
 					// If either cluster in the pair is null, there
 					// are not enough clusters to perform this match.
 					if(pair.getFirstElement() == null || pair.getSecondElement() == null) {
+						// Log the result.
 						OutputLogger.printf(" [ %18s ]%n", "failure: unpaired");
-						perm.pairFailPosition(pair.getFirstElement(), pair.getSecondElement());
+						
+						// An unpaired SSP cluster does not necessarily
+						// represent a problem. Often, this just means
+						// that the SSP cluster's matching reconstructed
+						// cluster is outside the verification window.
+						if(pair.getSecondElement() == null) {
+							perm.pairFailPosition(pair.getFirstElement(), pair.getSecondElement());
+						}
+						
+						// Skip the rest of the checks.
 						continue pairLoop;
 					}
 					
 					// Check if the reconstructed cluster has an energy
 					// within the allotted threshold of the SSP cluster.
-					if(pair.getSecondElement().getEnergy() >= pair.getFirstElement().getEnergy() * (1 - energyAcceptance) &&
-							pair.getSecondElement().getEnergy() <= pair.getFirstElement().getEnergy() * (1 + energyAcceptance)) {
+					if(pair.getSecondElement().getEnergy() >= pair.getFirstElement().getEnergy() - energyWindow &&
+							pair.getSecondElement().getEnergy() <= pair.getFirstElement().getEnergy() + energyWindow) {
+						
 						// Check that the hit count of the reconstructed
 						// is within the allotted threshold of the SSP
 						// cluster.
-						if(pair.getSecondElement().getHitCount() >= pair.getFirstElement().getCalorimeterHits().size() - hitAcceptance &&
-								pair.getSecondElement().getHitCount() <= pair.getFirstElement().getCalorimeterHits().size() + hitAcceptance) {
+						if(pair.getSecondElement().getHitCount() >= pair.getFirstElement().getCalorimeterHits().size() - hitWindow &&
+								pair.getSecondElement().getHitCount() <= pair.getFirstElement().getCalorimeterHits().size() + hitWindow) {
 							// Designate the pair as a match.
 							perm.pairMatch(pair.getFirstElement(), pair.getSecondElement());
 							OutputLogger.printf(" [ %18s ]%n", "success: matched");
@@ -844,69 +1189,113 @@
 			event.addEvent(bestPerm);
 		} // End Crystal Position Loop
 		
-		// Add the event results to the global results.
-		clusterRunStats.addEvent(event, reconClusters, sspClusters);
-		clusterLocalStats.addEvent(event, reconClusters, sspClusters);
-		
-		
-		
-		// ==========================================================
-		// ==== Output Event Summary ================================
-		// ==========================================================
-		
-		// Print the valid reconstructed clusters and populate their
-		// distribution graphs.
-		OutputLogger.println();
-		OutputLogger.println("Verified Reconstructed Clusters:");
-		if(!reconClusters.isEmpty()) {
-			for(Cluster reconCluster : reconClusters) {
-				OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(reconCluster));
-			}
-		} else { OutputLogger.println("\tNone"); }
-		
-		// Print the SSP clusters and populate their distribution graphs.
-		OutputLogger.println("SSP Clusters:");
-		if(!sspClusters.isEmpty()) {
+		// Return the cluster match summary.
+		return event;
+	}
+	
+	/**
+	 * Performs cluster matching between a collection of reconstructed
+	 * clusters and a collection of SSP clusters using the strictly
+	 * time-compliant algorithm.
+	 * @param reconClusters - A collection of reconstructed clusters.
+	 * @param sspClusters - A collection of SSP clusters.
+	 * @param energyWindow - The window of allowed deviation between
+	 * the reconstructed cluster and SSP cluster energies.
+	 * @param hitWindow - The window of allowed deviation between
+	 * the reconstructed cluster and SSP cluster hit counts.
+	 * @return Returns the cluster matching results stored inside a
+	 * <code>clusterMatchEvent</code> object.
+	 */
+	private static final ClusterMatchEvent matchClustersTimeCompliant(Collection<Cluster> reconClusters,
+			Collection<SSPCluster> sspClusters, double energyWindow, int hitWindow) {
+		// Track the number of cluster pairs that were matched and that
+		// failed by failure type.
+		ClusterMatchEvent event = new ClusterMatchEvent();
+		
+		// Store the clusters which have been successfully paired.
+		Set<SSPCluster> sspMatched = new HashSet<SSPCluster>(sspClusters.size());
+		
+		// Find reconstructed/SSP cluster matched pairs.
+		reconLoop:
+		for(Cluster reconCluster : reconClusters) {
+			// Track whether a position-matched cluster was found.
+			boolean matchedPosition = false;
+			
+			// VERBOSE :: Output the cluster being matched.
+			OutputLogger.printf("Considering %s%n", TriggerDiagnosticUtil.clusterToString(reconCluster));
+			
+			// Search through the SSP clusters for a matching cluster.
+			sspLoop:
 			for(SSPCluster sspCluster : sspClusters) {
-				OutputLogger.printf("\t%s%n", TriggerDiagnosticUtil.clusterToString(sspCluster));
-			}
-		} else { OutputLogger.println("\tNone"); }
-		
-		// Print the matched clusters.
-		OutputLogger.println("Matched Clusters:");
-		if(event.getMatchedPairs().size() != 0) {
-			// Iterate over the matched pairs.
-			for(ClusterMatchedPair pair : event.getMatchedPairs()) {
-				// If the pair is a match, print it out.
-				if(pair.isMatch()) {
-					OutputLogger.printf("\t%s --> %s%n",
-							TriggerDiagnosticUtil.clusterToString(pair.getReconstructedCluster()),
-							TriggerDiagnosticUtil.clusterToString(pair.getSSPCluster()));
-				}
-			}
-		}
-		 else { OutputLogger.println("\tNone"); }
-		
-		// Get the number of position failures.
-		int failPosition = event.getPositionFailures();
-		if(sspClusters == null || sspClusters.isEmpty()) {
-			failPosition = (reconClusters == null ? 0 : reconClusters.size());
-		}
-		
-		// Print event statistics.
-		OutputLogger.println();
-		OutputLogger.println("Event Statistics:");
-		OutputLogger.printf("\tRecon Clusters     :: %d%n", reconClusters.size());
-		OutputLogger.printf("\tClusters Matched   :: %d%n", event.getMatches());
-		OutputLogger.printf("\tFailed (Position)  :: %d%n", failPosition);
-		OutputLogger.printf("\tFailed (Energy)    :: %d%n", event.getEnergyFailures());
-		OutputLogger.printf("\tFailed (Hit Count) :: %d%n", event.getHitCountFailures());
-		OutputLogger.printf("\tCluster Efficiency :: %3.0f%%%n", 100.0 * event.getMatches() / reconClusters.size());
-		
-		// Note whether there was a cluster match failure.
-		if(event.getMatches() - reconClusters.size() != 0) {
-			clusterFail = true;
-		}
+				// VERBOSE :: Output the SSP cluster being considered.
+				OutputLogger.printf("\t%s ", TriggerDiagnosticUtil.clusterToString(sspCluster));
+				
+				// If this cluster has been paired, skip it.
+				if(sspMatched.contains(sspCluster)) {
+					OutputLogger.printf("[ %7s; %9s ]%n", "fail", "matched");
+					continue sspLoop;
+				}
+				
+				// Matched clusters must have the same position.
+				if(TriggerDiagnosticUtil.getXIndex(reconCluster) != sspCluster.getXIndex()
+						|| TriggerDiagnosticUtil.getYIndex(reconCluster) != sspCluster.getYIndex()) {
+					OutputLogger.printf("[ %7s; %9s ]%n", "fail", "position");
+					continue sspLoop;
+				}
+				
+				// Note that a cluster was found at this position.
+				matchedPosition = true;
+				
+				// Matched clusters must have the same time-stamp.
+				if(reconCluster.getCalorimeterHits().get(0).getTime() != sspCluster.getTime()) {
+					OutputLogger.printf("[ %7s; %9s ]%n", "fail", "time");
+					continue sspLoop;
+				}
+				
+				// Clusters that pass all of the above checks are the
+				// same cluster.
+				sspMatched.add(sspCluster);
+				
+				// Check that the clusters are sufficiently close in
+				// energy to one another.
+				if(sspCluster.getEnergy() >= reconCluster.getEnergy() - energyWindow
+						&& sspCluster.getEnergy() <= reconCluster.getEnergy() + energyWindow) {
+					// If a cluster matches in energy, check that it
+					// is also sufficiently close in hit count.
+					if(sspCluster.getHitCount() >= reconCluster.getCalorimeterHits().size() - hitWindow &&
+							sspCluster.getHitCount() <= reconCluster.getCalorimeterHits().size() + hitWindow) {
+						// The cluster is a match.
+						event.pairMatch(reconCluster, sspCluster);
+						OutputLogger.printf("[ %7s; %9s ]%n", "success", "matched");
+						continue reconLoop;
+					} else {
+						event.pairFailHitCount(reconCluster, sspCluster);
+						OutputLogger.printf("[ %7s; %9s ]%n", "fail", "hit count");
+						continue reconLoop;
+					} // End hit count check.
+				} else {
+					event.pairFailEnergy(reconCluster, sspCluster);
+					OutputLogger.printf("[ %7s; %9s ]%n", "fail", "energy");
+					continue reconLoop;
+				} // End energy check.
+			}// End SSP loop.
+			
+			// If the reconstructed cluster has not been matched, check
+			// if a cluster was found at the same position. If not, then
+			// the cluster fails by reason of position.
+			if(!matchedPosition) {
+				event.pairFailPosition(reconCluster, null);
+			}
+			
+			// Otherwise, the cluster had a potential matched, but the
+			// time-stamps were off. The cluster fails by reason of time.
+			else {
+				event.pairFailTime(reconCluster, null);
+			}
+		} // End recon loop.
+		
+		// Return the populated match event.
+		return event;
 	}
 	
 	/**
@@ -1002,9 +1391,9 @@
 		OutputLogger.println("SSP Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 			for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
-				OutputLogger.printf("\tTrigger %d :: %s :: %s%n",
+				OutputLogger.printf("\tTrigger %d :: %s :: %3.0f :: %s%n",
 						(triggerNum + 1), triggerPositionString(simTrigger),
-						simTrigger.toString());
+						getTriggerTime(simTrigger), simTrigger.toString());
 			}
 		}
 		if(sspTriggerList.get(0).size() + sspTriggerList.get(1).size() == 0) {
@@ -1015,9 +1404,9 @@
 		OutputLogger.println("Reconstructed Cluster " + (isSingles ? "Singles" : "Pair") + " Triggers");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 			for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) {
-				OutputLogger.printf("\tTrigger %d :: %s :: %s%n",
+				OutputLogger.printf("\tTrigger %d :: %s :: %3.0f :: %s%n",
 						(triggerNum + 1), triggerPositionString(simTrigger),
-						simTrigger.toString());
+						getTriggerTime(simTrigger), simTrigger.toString());
 			}
 		}
 		if(reconTriggerList.get(0).size() + reconTriggerList.get(1).size() == 0) {
@@ -1053,42 +1442,85 @@
 		
 		// Iterate over the triggers.
 		OutputLogger.println();
-		OutputLogger.println("SSP Reported Trigger --> SSP Cluster Trigger Match Status");
+		OutputLogger.println("Matching SSP Reported Triggers to SSP Simulated Triggers:");
 		for(SSPNumberedTrigger sspTrigger : sspTriggers) {
 			// Get the trigger information.
 			int triggerNum = sspTrigger.isFirstTrigger() ? 0 : 1;
-			boolean matchedTrigger = false;
+			OutputLogger.printf("\t%s%n", sspTrigger.toString());
 			
 			// Iterate over the SSP cluster simulated triggers and
 			// look for a trigger that matches.
 			matchLoop:
 			for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
-				// If the current SSP trigger has already been
-				// matched, skip it.
-				if(sspTriggerSet.contains(sspTrigger)) { continue matchLoop; }
-				
-				// Otherwise, check whether the reconstructed SSP
-				// cluster trigger matches the SSP trigger.
-				if(compareTriggers(sspTrigger, simTrigger)) {
-					matchedTrigger = true;
-					sspTriggerSet.add(sspTrigger);
-					simTriggerSet.add(simTrigger);
-					event.matchedSSPPair(simTrigger, sspTrigger);
-					break matchLoop;
-				}
-				
-				OutputLogger.printf("\t%s :: Matched: %5b%n", sspTrigger.toString(), matchedTrigger);
+				// VERBOSE :: Output the trigger being considered for
+				//            matching.
+				OutputLogger.printf("\t\tTrigger %d :: %s :: %3.0f :: %s ",
+						(triggerNum + 1), triggerPositionString(simTrigger),
+						getTriggerTime(simTrigger), simTrigger.toString());
+				
+				// If the current SSP trigger has already been matched,
+				// skip it.
+				if(simTriggerSet.contains(simTrigger)) {
+					OutputLogger.printf("[ %-15s ]%n", "failed; matched");
+					continue matchLoop;
+				}
+				
+				// Check that the triggers have the same time. Triggers
+				// generated from SSP bank clusters should always align
+				// in time.
+				if(sspTrigger.getTime() != getTriggerTime(simTrigger)) {
+					OutputLogger.printf("[ %-15s ]%n", "failed; time");
+					continue matchLoop;
+				}
+				
+				// Check whether the trigger cuts match.
+				boolean[] matchedCuts = triggerCutMatch(simTrigger, sspTrigger);
+				for(int i = 0; i < matchedCuts.length; i++) {
+					if(!matchedCuts[i]) {
+						int typeIndex = isSingles ? 0 : 1;
+						OutputLogger.printf("[ %-15s ]%n", String.format("failed; %s", cutNames[typeIndex][i]));
+						continue matchLoop;
+					}
+				}
+				
+				// If all the cuts match, along with the time and the
+				// trigger number, than these triggers are a match.
+				sspTriggerSet.add(sspTrigger);
+				simTriggerSet.add(simTrigger);
+				event.matchedSSPPair(simTrigger, sspTrigger);
+				OutputLogger.printf("[ %-15s ]%n", "success");
+				break matchLoop;
+			}
+		}
+		
+		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+			for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
+				globalTriggerPlots.sawTrigger(simTrigger);
+				if(simTriggerSet.contains(simTrigger)) {
+					globalTriggerPlots.matchedTrigger(simTrigger);
+				} else {
+					globalTriggerPlots.failedTrigger(simTrigger);
+				}
 			}
 		}
 		
 		// Iterate over the unmatched simulated triggers again and the
 		// unmatched SSP reported trigger that most closely matches it.
-		simLoop:
+		OutputLogger.println();
+		OutputLogger.println("Matching Failed SSP Reported Triggers to Remaining SSP Simulated Triggers:");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+			simLoop:
 			for(Trigger<?> simTrigger : sspTriggerList.get(triggerNum)) {
+				OutputLogger.printf("\tTrigger %d :: %s :: %3.0f :: %s%n",
+						(triggerNum + 1), triggerPositionString(simTrigger),
+						getTriggerTime(simTrigger), simTrigger.toString());
+				
 				// Check whether this trigger has already been matched
 				// or not. If it has been matched, skip it.
-				if(simTriggerSet.contains(simTrigger)) { continue simLoop; }
+				if(simTriggerSet.contains(simTrigger)) {
+					OutputLogger.println("\t\tSkipping; already matched successfully");
+					continue simLoop;
+				}
 				
 				// Get the trigger time for the simulated trigger.
 				double simTime = getTriggerTime(simTrigger);
@@ -1099,18 +1531,27 @@
 				boolean[] matchedCut = null;
 				SSPNumberedTrigger bestMatch = null;
 				
+				// Store the readout for the best match.
+				String bestMatchText = null;
+				
 				// Iterate over the reported triggers to find a match.
 				reportedLoop:
 				for(SSPNumberedTrigger sspTrigger : sspTriggers) {
+					OutputLogger.printf("\t\t%s ", sspTrigger.toString());
+					
 					// If the two triggers have different times, this
 					// trigger should be skipped.
 					if(sspTrigger.getTime() != simTime) {
+						OutputLogger.printf("[ %-15s ]%n", "failed; time");
 						continue reportedLoop;
 					}
 					
 					// If this reported trigger has been matched then
 					// it should be skipped.
-					if(sspTriggerSet.contains(sspTrigger)) { continue reportedLoop; }
+					if(sspTriggerSet.contains(sspTrigger)) {
+						OutputLogger.printf("[ %-15s ]%n", "failed; matched");
+						continue reportedLoop;
+					}
 					
 					// Check each of the cuts.
 					boolean[] tempMatchedCut = triggerCutMatch(simTrigger, sspTrigger);
@@ -1119,6 +1560,7 @@
 					// than the previous best match.
 					int tempNumMatched = 0;
 					for(boolean passed : tempMatchedCut) { if(passed) { tempNumMatched++; } }
+					OutputLogger.printf("[ %-15s ]%n", String.format("maybe; %d failed", tempNumMatched));
 					
 					// If the number of matched cuts exceeds the old
 					// best result, this becomes the new best result.
@@ -1126,18 +1568,27 @@
 						numMatched = tempNumMatched;
 						matchedCut = tempMatchedCut;
 						bestMatch = sspTrigger;
+						bestMatchText = String.format("%s%n", sspTrigger.toString());
 					}
 				}
 				
 				// If there was no match found, it means that there were
 				// no triggers that were both unmatched and at the same
 				// time as this simulated trigger.
-				
 				if(bestMatch == null) {
 					if(isSingles) { singlesInternalFail = true; }
 					else { pairInternalFail = true; }
+					event.matchedSSPPair(simTrigger, bestMatch, matchedCut);
+					OutputLogger.printf("\t\tTrigger %d :: %s :: %3.0f :: %s",
+							(triggerNum + 1), triggerPositionString(simTrigger),
+							getTriggerTime(simTrigger), simTrigger.toString());
+					OutputLogger.println(" --> No Valid Match Found");
 				} else {
 					event.matchedSSPPair(simTrigger, bestMatch, matchedCut);
+					OutputLogger.printf("\t\tTrigger %d :: %s :: %3.0f :: %s",
+							(triggerNum + 1), triggerPositionString(simTrigger),
+							getTriggerTime(simTrigger), simTrigger.toString());
+					OutputLogger.println(" --> " + bestMatchText);
 				}
 			}
 		}
@@ -1156,12 +1607,31 @@
 		OutputLogger.println("Recon Cluster Trigger --> SSP Reported Trigger Match Status");
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 			for(Trigger<?> simTrigger : reconTriggerList.get(triggerNum)) {
+				// If the trigger number and type align with the event
+				// trigger type, mark that it was seen.
+				if(triggerNum == 1) {
+					if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 && isSingles) {
+						event.setSawEventType(true);
+					} else if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_PAIR_1 && !isSingles) {
+						event.setSawEventType(true);
+					}
+				} else {
+					if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 && isSingles) {
+						event.setSawEventType(true);
+					} else if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_PAIR_2 && !isSingles) {
+						event.setSawEventType(true);
+					}
+				}
 				
 				OutputLogger.printf("\tTrigger %d :: %s :: %s%n", (triggerNum + 1),
 						triggerPositionString(simTrigger), simTrigger.toString());
 				
+				// TEMP :: Populate the recon ALL pairs plots.
+				globalTriggerPlots.sawTrigger(simTrigger);
+				
 				// Iterate over the SSP reported triggers and compare
 				// them to the reconstructed cluster simulated trigger.
+				boolean matched = false;
 				matchLoop:
 				for(SSPNumberedTrigger sspTrigger : sspTriggers) {
 					OutputLogger.printf("\t\t\t%s", sspTrigger.toString());
@@ -1182,10 +1652,6 @@
 					}
 					
 					// Test each cut.
-					String[][] cutNames = {
-							{ "E_min", "E_max", "hit count", "null" },
-							{ "E_sum", "E_diff", "E_slope", "coplanar" }
-					};
 					int typeIndex = isSingles ? 0 : 1;
 					boolean[] matchedCuts = triggerCutMatch(simTrigger, sspTrigger);
 					for(int cutIndex = 0; cutIndex < matchedCuts.length; cutIndex++) {
@@ -1200,8 +1666,12 @@
 					sspTriggerSet.add(sspTrigger);
 					event.matchedReconPair(simTrigger, sspTrigger);
 					OutputLogger.print(" [ success         ]%n");
+					globalTriggerPlots.matchedTrigger(simTrigger);
+					matched = true;
 					break matchLoop;
 				}
+				
+				if(!matched) { globalTriggerPlots.failedTrigger(simTrigger); }
 			}
 		}
 		
@@ -1213,14 +1683,19 @@
 		
 		// Get the number of SSP and reconstructed cluster simulated
 		// triggers.
-		
 		int sspSimTriggers = sspTriggerList.get(0).size() + sspTriggerList.get(1).size();
 		int reconSimTriggers = reconTriggerList.get(0).size() + reconTriggerList.get(1).size();
-		int halfSimTriggers = sspSimTriggers / 2;
+		int[] sspTriggerCount = { sspTriggerList.get(0).size(), sspTriggerList.get(1).size() };
 		
 		// Print event statistics.
 		OutputLogger.println();
 		OutputLogger.println("Event Statistics:");
+		OutputLogger.printf("\tSaw Triggering Event Type  :: ");
+		if(activeTrigger == TriggerDiagnosticUtil.TRIGGER_COSMIC || activeTrigger == TriggerDiagnosticUtil.TRIGGER_PULSER) {
+			OutputLogger.println("Unsupported for Cosmic/Pulser");
+		} else {
+			OutputLogger.println("" + event.sawEventType());
+		}
 		OutputLogger.printf("\tSSP Cluster Sim Triggers   :: %d%n", sspSimTriggers);
 		OutputLogger.printf("\tRecon Cluster Sim Triggers :: %d%n", reconSimTriggers);
 		OutputLogger.printf("\tSSP Reported Triggers      :: %d%n", sspTriggers.size());
@@ -1245,23 +1720,26 @@
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				OutputLogger.printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
 				if(sspSimTriggers == 0) {
-					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MIN), halfSimTriggers);
-					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MAX), halfSimTriggers);
-					OutputLogger.printf("\tCluster Hit Count          :: %d / %d%n", event.getCutFailures(triggerNum, HIT_COUNT), halfSimTriggers);
+					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tCluster Hit Count          :: %d / %d%n", event.getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount[triggerNum]);
 				} else {
 					OutputLogger.printf("\tCluster Energy Lower Bound :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_MIN), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_MIN) / halfSimTriggers));
+							event.getCutFailures(triggerNum, ENERGY_MIN), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, ENERGY_MIN) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tCluster Energy Upper Bound :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_MAX), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_MAX) / halfSimTriggers));
+							event.getCutFailures(triggerNum, ENERGY_MAX), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, ENERGY_MAX) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tCluster Hit Count          :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, HIT_COUNT), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, HIT_COUNT) / halfSimTriggers));
+							event.getCutFailures(triggerNum, HIT_COUNT), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, HIT_COUNT) / sspTriggerCount[triggerNum]));
 				}
 				OutputLogger.printf("\tExcess Reported Triggers   :: %d%n", sspReportedExtras / 2);
 			}
 			
 			// Update the global trigger tracking variables.
-			triggerRunStats[0].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
-			triggerLocalStats[0].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+			triggerRunStats[0].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
+			triggerLocalStats[0].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
 			efficiencyRunStats.addSinglesTriggers(activeTrigger, reconTriggerList);
 			efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
 			efficiencyRunStats.addEvent(activeTrigger, event);
@@ -1270,27 +1748,31 @@
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				OutputLogger.println();
 				OutputLogger.printf("Trigger %d Individual Cut Failure Rate:%n", (triggerNum + 1));
-				if(sspSimTriggers == 0) {
-					OutputLogger.printf("\tPair Energy Sum            :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SUM), halfSimTriggers);
-					OutputLogger.printf("\tPair Energy Difference     :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_DIFF), halfSimTriggers);
-					OutputLogger.printf("\tPair Energy Slope          :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SLOPE), halfSimTriggers);
-					OutputLogger.printf("\tPair Coplanarity           :: %d / %d%n", event.getCutFailures(triggerNum, COPLANARITY), halfSimTriggers);
+				if(sspTriggerCount[triggerNum] == 0) {
+					OutputLogger.printf("\tPair Energy Sum            :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Energy Difference     :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Energy Slope          :: %d / %d%n", event.getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount[triggerNum]);
+					OutputLogger.printf("\tPair Coplanarity           :: %d / %d%n", event.getCutFailures(triggerNum, COPLANARITY), sspTriggerCount[triggerNum]);
 				} else {
 					OutputLogger.printf("\tPair Energy Sum            :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_SUM), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_SUM) / halfSimTriggers));
+							event.getCutFailures(triggerNum, ENERGY_SUM), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, ENERGY_SUM) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Energy Difference     :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_DIFF), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_DIFF) / halfSimTriggers));
+							event.getCutFailures(triggerNum, ENERGY_DIFF), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, ENERGY_DIFF) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Energy Slope          :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, ENERGY_SLOPE), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, ENERGY_SLOPE) / halfSimTriggers));
+							event.getCutFailures(triggerNum, ENERGY_SLOPE), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, ENERGY_SLOPE) / sspTriggerCount[triggerNum]));
 					OutputLogger.printf("\tPair Coplanarity           :: %d / %d (%3.0f%%)%n",
-							event.getCutFailures(triggerNum, COPLANARITY), halfSimTriggers, (100.0 * event.getCutFailures(triggerNum, COPLANARITY) / halfSimTriggers));
+							event.getCutFailures(triggerNum, COPLANARITY), sspTriggerCount[triggerNum],
+							(100.0 * event.getCutFailures(triggerNum, COPLANARITY) / sspTriggerCount[triggerNum]));
 				}
 				OutputLogger.printf("\tExcess Reported Triggers   :: %d%n", sspReportedExtras / 2);
 			}
 			
 			// Update the global trigger tracking variables.
-			triggerRunStats[1].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
-			triggerLocalStats[1].addEvent(event, reconTriggerList, sspTriggerList, sspTriggers);
+			triggerRunStats[1].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
+			triggerLocalStats[1].addEvent(activeTrigger, event, reconTriggerList, sspTriggerList, sspTriggers);
 			efficiencyRunStats.addPairTriggers(activeTrigger, reconTriggerList);
 			efficiencyLocalStats.addSinglesTriggers(activeTrigger, reconTriggerList);
 			efficiencyRunStats.addEvent(activeTrigger, event);
@@ -1298,9 +1780,12 @@
 		}
 		
 		// Note whether the was a trigger match failure.
-		if((event.getMatchedReconTriggers() - reconSimTriggers != 0) || (event.getMatchedSSPTriggers() - sspSimTriggers != 0)) {
+		if(event.getMatchedReconTriggers() - reconSimTriggers != 0) {
 			if(isSingles) { singlesEfficiencyFail = true; }
 			else { pairEfficiencyFail = true; }
+		} if(event.getMatchedSSPTriggers() - sspSimTriggers != 0) {
+			if(isSingles) { singlesInternalFail = true; }
+			else { pairInternalFail = true; }
 		}
 	}
 	
@@ -1312,6 +1797,7 @@
 		// Run the SSP clusters through the singles trigger to determine
 		// whether they pass it or not.
 		for(SSPCluster cluster : sspClusters) {
+			triggerLoop:
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				// For a cluster to have formed it is assumed to have passed
 				// the cluster seed energy cuts. This can not be verified
@@ -1332,7 +1818,19 @@
 				trigger.setStateClusterEnergyHigh(passClusterHigh);
 				trigger.setStateHitCount(passHitCount);
 				
-				// Store the trigger.
+				// A trigger will only be reported by the SSP if it
+				// passes all of the enabled cuts for that trigger.
+				// Check whether this trigger meets these conditions.
+				if(singlesCutsEnabled[triggerNum][ENERGY_MIN] && !trigger.getStateClusterEnergyLow()) {
+					continue triggerLoop;
+				} if(singlesCutsEnabled[triggerNum][ENERGY_MAX] && !trigger.getStateClusterEnergyHigh()) {
+					continue triggerLoop;
+				} if(singlesCutsEnabled[triggerNum][HIT_COUNT] && !trigger.getStateHitCount()) {
+					continue triggerLoop;
+				}
+				
+				// If all the necessary checks passed, store the new
+				// trigger for verification.
 				sspSinglesTriggers.get(triggerNum).add(trigger);
 			}
 		}
@@ -1341,6 +1839,7 @@
 		// to determine whether they pass it or not.
 		for(Cluster cluster : reconClusters) {
 			// Simulate each of the cluster singles triggers.
+			triggerLoop:
 			for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 				// For a cluster to have formed it is assumed to have passed
 				// the cluster seed energy cuts. This can not be verified
@@ -1360,6 +1859,17 @@
 				trigger.setStateClusterEnergyLow(passClusterLow);
 				trigger.setStateClusterEnergyHigh(passClusterHigh);
 				trigger.setStateHitCount(passHitCount);
+				
+				// A trigger will only be reported by the SSP if it
+				// passes all of the enabled cuts for that trigger.
+				// Check whether this trigger meets these conditions.
+				if(singlesCutsEnabled[triggerNum][ENERGY_MIN] && !trigger.getStateClusterEnergyLow()) {
+					continue triggerLoop;
+				} if(singlesCutsEnabled[triggerNum][ENERGY_MAX] && !trigger.getStateClusterEnergyHigh()) {
+					continue triggerLoop;
+				} if(singlesCutsEnabled[triggerNum][HIT_COUNT] && !trigger.getStateHitCount()) {
+					continue triggerLoop;
+				}
 				
 				// Store the trigger.
 				reconSinglesTriggers.get(triggerNum).add(trigger);
@@ -1417,13 +1927,13 @@
 		// Simulate the pair triggers and record the results.
 		for(Cluster[] reconPair : reconPairs) {
 			// Simulate each of the cluster pair triggers.
-			reconTriggerLoop:
+			pairTriggerLoop:
 			for(int triggerIndex = 0; triggerIndex < 2; triggerIndex++) {
 				// Check that the pair passes the time coincidence cut.
 				// If it does not, it is not a valid pair and should be
 				// destroyed.
 				if(!pairsTrigger[triggerIndex].pairTimeCoincidenceCut(reconPair)) {
-					continue reconTriggerLoop;
+					continue pairTriggerLoop;
 				}
 				
 				// For a cluster to have formed it is assumed to have passed
@@ -1460,6 +1970,25 @@
 				trigger.setStateCoplanarity(passPairCoplanarity);
 				trigger.setStateTimeCoincidence(passTimeCoincidence);
 				
+				// A trigger will only be reported by the SSP if it
+				// passes all of the enabled cuts for that trigger.
+				// Check whether this trigger meets these conditions.
+				if(pairCutsEnabled[triggerIndex][ENERGY_MIN] && !trigger.getStateClusterEnergyLow()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][ENERGY_MAX] && !trigger.getStateClusterEnergyHigh()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][HIT_COUNT] && !trigger.getStateHitCount()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_SUM] && !trigger.getStateEnergySum()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_DIFF] && !trigger.getStateEnergyDifference()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_SLOPE] && !trigger.getStateEnergySlope()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + COPLANARITY] && !trigger.getStateCoplanarity()) {
+					continue pairTriggerLoop;
+				}
+				
 				// Add the trigger to the list.
 				reconPairsTriggers.get(triggerIndex).add(trigger);
 			}
@@ -1509,6 +2038,25 @@
 				trigger.setStateCoplanarity(passPairCoplanarity);
 				trigger.setStateTimeCoincidence(passTimeCoincidence);
 				
+				// A trigger will only be reported by the SSP if it
+				// passes all of the enabled cuts for that trigger.
+				// Check whether this trigger meets these conditions.
+				if(pairCutsEnabled[triggerIndex][ENERGY_MIN] && !trigger.getStateClusterEnergyLow()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][ENERGY_MAX] && !trigger.getStateClusterEnergyHigh()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][HIT_COUNT] && !trigger.getStateHitCount()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_SUM] && !trigger.getStateEnergySum()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_DIFF] && !trigger.getStateEnergyDifference()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + ENERGY_SLOPE] && !trigger.getStateEnergySlope()) {
+					continue pairTriggerLoop;
+				} if(pairCutsEnabled[triggerIndex][3 + COPLANARITY] && !trigger.getStateCoplanarity()) {
+					continue pairTriggerLoop;
+				}
+				
 				// Add the trigger to the list.
 				sspPairsTriggers.get(triggerIndex).add(trigger);
 			}
@@ -1524,8 +2072,9 @@
 	private void logSettings() {
 		// Output general settings.
 		System.out.println("Cluster Verification Settings");
-		System.out.printf("\tEnergy Threshold       :: %1.2f%%%n", energyAcceptance);
-		System.out.printf("\tHit Threshold          :: %1d%n", hitAcceptance);
+		System.out.printf("\tHit Threshold          :: %1d hit(s)%n", hitAcceptance);
+		System.out.printf("\tEnergy Threshold       :: %5.3f GeV%n",  energyAcceptance);
+		System.out.println();
 		
 		// Output window settings.
 		System.out.println("FADC Timing Window Settings");
@@ -1544,28 +2093,45 @@
 			System.out.println("\tCluster verification will not be performed!");
 			performClusterVerification = false;
 		}
+		System.out.println();
 		
 		// Output the singles trigger settings.
 		for(int i = 0; i < 2; i++) {
-			System.out.printf("Singles Trigger %d Settings%n", (i + 1));
-			System.out.printf("\tCluster Energy Low     :: %.3f GeV%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW));
-			System.out.printf("\tCluster Energy High    :: %.3f GeV%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH));
-			System.out.printf("\tCluster Hit Count      :: %.0f hits%n", singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW));
+			// Print the settings.
+			System.out.printf("Singles Trigger %d Settings%23s[%5b]%n", (i + 1), "", singlesTriggerEnabled[i]);
+			System.out.printf("\tCluster Energy Low     :: %.3f GeV      [%5b]%n",
+					singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW), singlesCutsEnabled[i][0]);
+			System.out.printf("\tCluster Energy High    :: %.3f GeV      [%5b]%n",
+					singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH), singlesCutsEnabled[i][1]);
+			System.out.printf("\tCluster Hit Count      :: %.0f hit(s)       [%5b]%n",
+					singlesTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW), singlesCutsEnabled[i][2]);
+			System.out.println();
 		}
 		
 		// Output the pair trigger settings.
 		for(int i = 0; i < 2; i++) {
-			System.out.printf("Pairs Trigger %d Settings%n", (i + 1));
-			System.out.printf("\tCluster Energy Low     :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW));
-			System.out.printf("\tCluster Energy High    :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH));
-			System.out.printf("\tCluster Hit Count      :: %.0f hits%n", pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW));
-			System.out.printf("\tPair Energy Sum Low    :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW));
-			System.out.printf("\tPair Energy Sum Low    :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH));
-			System.out.printf("\tPair Energy Difference :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH));
-			System.out.printf("\tPair Energy Slope      :: %.3f GeV%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW));
-			System.out.printf("\tPair Energy Slope F    :: %.3f GeV / mm%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F));
-			System.out.printf("\tPair Coplanarity       :: %.0f Degrees%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_COPLANARITY_HIGH));
-			System.out.printf("\tPair Time Coincidence  :: %.0f ns%n", pairsTrigger[i].getCutValue(TriggerModule.PAIR_TIME_COINCIDENCE));
+			System.out.printf("Pairs Trigger %d Settings%25s[%5b]%n", (i + 1), "", pairTriggerEnabled[i]);
+			System.out.printf("\tCluster Energy Low     :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_LOW), pairCutsEnabled[i][0]);
+			System.out.printf("\tCluster Energy High    :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_TOTAL_ENERGY_HIGH), pairCutsEnabled[i][1]);
+			System.out.printf("\tCluster Hit Count      :: %.0f hit(s)       [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.CLUSTER_HIT_COUNT_LOW), pairCutsEnabled[i][2]);
+			System.out.printf("\tPair Energy Sum Low    :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_LOW), pairCutsEnabled[i][3]);
+			System.out.printf("\tPair Energy Sum High   :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SUM_HIGH), pairCutsEnabled[i][3]);
+			System.out.printf("\tPair Energy Difference :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_DIFFERENCE_HIGH), pairCutsEnabled[i][4]);
+			System.out.printf("\tPair Energy Slope      :: %.3f GeV      [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_LOW), pairCutsEnabled[i][5]);
+			System.out.printf("\tPair Energy Slope F    :: %.4f GeV / mm%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_ENERGY_SLOPE_F));
+			System.out.printf("\tPair Coplanarity       :: %3.0f Degrees    [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_COPLANARITY_HIGH), pairCutsEnabled[i][6]);
+			System.out.printf("\tPair Time Coincidence  :: %2.0f ns          [%5b]%n",
+					pairsTrigger[i].getCutValue(TriggerModule.PAIR_TIME_COINCIDENCE), true);
+			System.out.println();
 		}
 	}
 	
@@ -1578,122 +2144,6 @@
 	 */
 	private final boolean isVerifiable(Cluster reconCluster) {
 		return TriggerDiagnosticUtil.isVerifiable(reconCluster, nsa, nsb, windowWidth);
-	}
-	
-	/**
-	 * Compares an SSP trigger with a simulated trigger. Note that only
-	 * certain class combinations are supported. Triggers of the type
-	 * <code>SSPSinglesTrigger</code> may be compared with triggers of
-	 * the type <code>SinglesTrigger<SSPCluster></code> and triggers of
-	 * the type <code>SSPPairTrigger</code> may be compared to either
-	 * <code>PairTrigger<SSPCluster[]></code> triggers objects.
-	 * @param bankTrigger - The SSP bank trigger.
-	 * @param simTrigger - The simulated trigger.
-	 * @return Returns <code>true</code> if the triggers are valid
-	 * matches and <code>false</code> if they are not.
-	 * @throws IllegalArgumentException Occurs if the trigger types
-	 * are not of a supported type.
-	 */
-	@SuppressWarnings("unchecked")
-	private static final boolean compareTriggers(SSPNumberedTrigger bankTrigger, Trigger<?> simTrigger) throws IllegalArgumentException {
-		// Get the classes of the arguments. This is used to check the
-		// generic type of the Trigger<?> object, and means that the
-		// "unchecked" warnings can be safely ignored.
-		Object source = simTrigger.getTriggerSource();
-		
-		// If the combination of classes is supported, pass the triggers
-		// to the appropriate handler.
-		if(bankTrigger instanceof SSPSinglesTrigger && simTrigger instanceof SinglesTrigger && source instanceof SSPCluster) {
-			return compareSSPSinglesTriggers((SSPSinglesTrigger) bankTrigger, (SinglesTrigger<SSPCluster>) simTrigger);
-		} else if(bankTrigger instanceof SSPPairTrigger && simTrigger instanceof PairTrigger && source instanceof SSPCluster[]) {
-			return compareSSPPairTriggers((SSPPairTrigger) bankTrigger, (PairTrigger<SSPCluster[]>) simTrigger);
-		}
-		
-		// Otherwise, the trigger combination is not supported. Produce
-		// and exception.
-		throw new IllegalArgumentException(String.format("Trigger type \"%s\" can not be compared to trigger type \"%s\" with source type \"%s\".",
-				bankTrigger.getClass().getSimpleName(), simTrigger.getClass().getSimpleName(), source.getClass().getSimpleName()));
-	}
-	
-	/**
-	 * Compares a trigger from the SSP bank to a trigger simulated on
-	 * an SSP cluster.
-	 * @param bankTrigger - The trigger from the SSP bank.
-	 * @param simTrigger - The trigger from the simulation.
-	 * @return Returns <code>true</code> if the triggers match and
-	 * <code>false</code> if they do not.
-	 */
-	private static final boolean compareSSPSinglesTriggers(SSPSinglesTrigger bankTrigger, SinglesTrigger<SSPCluster> simTrigger) {
-		// The bank trigger and simulated trigger must have the same
-		// time. This is equivalent to the time of the triggering cluster.
-		if(bankTrigger.getTime() != simTrigger.getTriggerSource().getTime()) {
-			return false;
-		}
-		
-		// If the time stamp is the same, check that the trigger flags
-		// are all the same. Start with cluster energy low.
-		if(bankTrigger.passCutEnergyMin() != simTrigger.getStateClusterEnergyLow()) {
-			return false;
-		}
-		
-		// Check cluster energy high.
-		if(bankTrigger.passCutEnergyMax() != simTrigger.getStateClusterEnergyHigh()) {
-			return false;
-		}
-		
-		// Check cluster hit count.
-		if(bankTrigger.passCutHitCount() != simTrigger.getStateHitCount()) {
-			return false;
-		}
-		
-		// If all of the tests are successful, the triggers match.
-		return true;
-	}
-	
-	/**
-	 * Compares a trigger from the SSP bank to a trigger simulated on
-	 * an SSP cluster.
-	 * @param bankTrigger - The trigger from the SSP bank.
-	 * @param simTrigger - The trigger from the simulation.
-	 * @return Returns <code>true</code> if the triggers match and
-	 * <code>false</code> if they do not.
-	 */
-	private static final boolean compareSSPPairTriggers(SSPPairTrigger bankTrigger, PairTrigger<SSPCluster[]> simTrigger) {
-		// Get the time of the bottom cluster in the pair.
-		int simTime = 0;
-		if(simTrigger.getTriggerSource()[0].getYIndex() < 0) {
-			simTime = simTrigger.getTriggerSource()[0].getTime();
-		} else {
-			simTime = simTrigger.getTriggerSource()[1].getTime();
-		}
-		
-		// The bank trigger and simulated trigger must have the same
-		// time. This is equivalent to the time of the triggering cluster.
-		if(bankTrigger.getTime() != simTime) { return false; }
-		
-		// If the time stamp is the same, check that the trigger flags
-		// are all the same. Start with energy sum.
-		if(bankTrigger.passCutEnergySum() != simTrigger.getStateEnergySum()) {
-			return false;
-		}
-		
-		// Check pair energy difference.
-		if(bankTrigger.passCutEnergyDifference() != simTrigger.getStateEnergyDifference()) {
-			return false;
-		}
-		
-		// Check pair energy slope.
-		if(bankTrigger.passCutEnergySlope() != simTrigger.getStateEnergySlope()) {
-			return false;
-		}
-		
-		// Check pair coplanarity.
-		if(bankTrigger.passCutCoplanarity() != simTrigger.getStateCoplanarity()) {
-			return false;
-		}
-		
-		// If all of the tests are successful, the triggers match.
-		return true;
 	}
 	
 	/**

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchEvent.java	Wed Mar 25 14:43:27 2015
@@ -3,7 +3,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
 import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
 import org.lcsim.event.Cluster;
 
@@ -21,6 +21,7 @@
 	private int failPosition = 0;
 	private int failEnergy = 0;
 	private int failHitCount = 0;
+	private int failTime = 0;
 	
 	// Store all of the pairs.
 	private List<ClusterMatchedPair> pairList = new ArrayList<ClusterMatchedPair>();
@@ -46,6 +47,7 @@
 			if(cmp.isPositionFailState()) { failPosition++; }
 			if(cmp.isEnergyFailState()) { failEnergy++; }
 			if(cmp.isHitCountFailState()) { failHitCount++; }
+			if(cmp.isTimeFailState()) { failTime++; }
 		}
 	}
 	
@@ -100,6 +102,26 @@
 	}
 	
 	/**
+	 * Gets the number of cluster pairs stored in this event that are
+	 * marked with time fail states.
+	 * @return Returns the number of instances of this state as an
+	 * <code>int</code> primitive.
+	 */
+	public int getTimeFailures() {
+		return failTime;
+	}
+	
+	/**
+	 * Indicates whether at least one cluster pair in the event created
+	 * a fail state.
+	 * @return Returns <code>true</code> if not all clusters matched and
+	 * <code>false</code> otherwise.
+	 */
+	public boolean isFailState() {
+		return (failEnergy > 0) || (failHitCount > 0) || (failTime > 0) || (failPosition > 0);
+	}
+	
+	/**
 	 * Adds a reconstructed/SSP cluster pair and marks it as having an
 	 * energy fail state.
 	 * @param reconCluster - The reconstructed cluster.
@@ -134,6 +156,17 @@
 	
 	/**
 	 * Adds a reconstructed/SSP cluster pair and marks it as having a
+	 * time fail state.
+	 * @param reconCluster - The reconstructed cluster.
+	 * @param sspCluster - The SSP cluster.
+	 */
+	public void pairFailTime(Cluster reconCluster, SSPCluster sspCluster) {
+		failTime++;
+		pairList.add(new ClusterMatchedPair(reconCluster, sspCluster, TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_TIME));
+	}
+	
+	/**
+	 * Adds a reconstructed/SSP cluster pair and marks it as having a
 	 * match state.
 	 * @param reconCluster - The reconstructed cluster.
 	 * @param sspCluster - The SSP cluster.

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchStatus.java	Wed Mar 25 14:43:27 2015
@@ -1,12 +1,8 @@
 package org.hps.analysis.trigger.event;
 
-import java.awt.Point;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
-import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
-import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
 import org.lcsim.event.Cluster;
 
 /**
@@ -16,27 +12,6 @@
  * @author Kyle McCarty
  */
 public class ClusterMatchStatus extends ClusterStatModule {
-	// Plot binning values.
-	private static final int TIME_BIN = 4;
-	private static final double ENERGY_BIN = 0.01;
-	private static final int TIME_BIN_HALF = TIME_BIN / 2;
-	private static final double ENERGY_BIN_HALF = ENERGY_BIN / 2;
-	
-	// Track plotting values for reconstructed and SSP clusters.
-	private Map<Integer, Integer> sspHitCountBins = new HashMap<Integer, Integer>();
-	private Map<Integer, Integer> reconHitCountBins = new HashMap<Integer, Integer>();
-	private Map<Point, Integer> sspPositionBins = new HashMap<Point, Integer>();
-	private Map<Point, Integer> reconPositionBins = new HashMap<Point, Integer>();
-	private Map<Integer, Integer> sspEnergyBins = new HashMap<Integer, Integer>();
-	private Map<Integer, Integer> reconEnergyBins = new HashMap<Integer, Integer>();
-	
-	// Track plotting values for cluster matching results.
-	private Map<Point, Integer> failPositionBins = new HashMap<Point, Integer>();
-	private Map<Point, Integer> allHenergyBins = new HashMap<Point, Integer>();
-	private Map<Point, Integer> failHenergyBins = new HashMap<Point, Integer>();
-	private Map<Integer, Integer> allTimeBins = new HashMap<Integer, Integer>();
-	private Map<Integer, Integer> failTimeBins = new HashMap<Integer, Integer>();
-	
     public void addEvent(ClusterMatchEvent event, List<Cluster> reconClusters, List<SSPCluster> sspClusters) {
     	// Update the number of reconstructed and SSP clusters
 		// that have been seen so far.
@@ -57,91 +32,6 @@
 		if(sspClusters == null || sspClusters.isEmpty()) {
 			failPosition += (reconClusters == null ? 0 : reconClusters.size());
 		}
-    	
-    	// Update the plotting information for reconstructed clusters.
-		for(Cluster cluster : reconClusters) {
-			// Update the hit count bin data.
-			Integer hitCountCount = reconHitCountBins.get(cluster.getCalorimeterHits().size());
-			if(hitCountCount == null) { reconHitCountBins.put(cluster.getCalorimeterHits().size(), 1); }
-			else { reconHitCountBins.put(cluster.getCalorimeterHits().size(), hitCountCount + 1); }
-			
-			// Update the position bin data.
-			Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(cluster);
-			Integer positionCount = reconPositionBins.get(clusterPosition);
-			if(positionCount == null) { reconPositionBins.put(clusterPosition, 1); }
-			else { reconPositionBins.put(clusterPosition, positionCount + 1); }
-			
-			// Update the energy bin data.
-			int energyBin = (int) Math.floor(cluster.getEnergy() / ENERGY_BIN);
-			Integer energyCount = reconEnergyBins.get(energyBin);
-			if(energyCount == null) { reconEnergyBins.put(energyBin, 1); }
-			else { reconEnergyBins.put(energyBin, energyCount + 1); }
-		}
-		
-    	// Update the plotting information for SSP clusters.
-		for(SSPCluster cluster : sspClusters) {
-			// Update the hit count bin data.
-			Integer hitCountCount = sspHitCountBins.get(cluster.getHitCount());
-			if(hitCountCount == null) { sspHitCountBins.put(cluster.getHitCount(), 1); }
-			else { sspHitCountBins.put(cluster.getHitCount(), hitCountCount + 1); }
-			
-			// Update the position bin data.
-			Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(cluster);
-			Integer positionCount = sspPositionBins.get(clusterPosition);
-			if(positionCount == null) { sspPositionBins.put(clusterPosition, 1); }
-			else { sspPositionBins.put(clusterPosition, positionCount + 1); }
-			
-			// Update the energy bin data.
-			int energyBin = (int) Math.floor(cluster.getEnergy() / ENERGY_BIN);
-			Integer energyCount = sspEnergyBins.get(energyBin);
-			if(energyCount == null) { sspEnergyBins.put(energyBin, 1); }
-			else { sspEnergyBins.put(energyBin, energyCount + 1); }
-		}
-		
-		// Update the plotting information for SSP/reconstructed cluster
-		// pairs.
-		pairLoop:
-		for(ClusterMatchedPair pair : event.getMatchedPairs()) {
-			// If one of the pairs is null, then it is unmatched cluster
-			// and may be skipped.
-			if(pair.getReconstructedCluster() == null || pair.getSSPCluster() == null) {
-				continue pairLoop;
-			}
-			
-			// Populate the bins for the "all" plots.
-			// Update the match time plots.
-			int timeBin = (int) Math.floor(TriggerDiagnosticUtil.getClusterTime(pair.getReconstructedCluster()) / TIME_BIN);
-			Integer timeCount = allTimeBins.get(timeBin);
-			if(timeCount == null) { allTimeBins.put(timeBin, 1); }
-			else { allTimeBins.put(timeBin, timeCount + 1); }
-			
-			// Update the energy/hit difference plots.
-			int hitBin = getHitCountDifference(pair.getSSPCluster(), pair.getReconstructedCluster());
-			int energyBin = (int) Math.floor(getEnergyPercentDifference(pair.getSSPCluster(), pair.getReconstructedCluster()) / ENERGY_BIN);
-			Point henergyBin = new Point(hitBin, energyBin);
-			Integer henergyCount = allHenergyBins.get(henergyBin);
-			if(henergyCount == null) { allHenergyBins.put(henergyBin, 1); }
-			else { allHenergyBins.put(henergyBin, henergyCount + 1); }
-			
-			// Populate the bins for the "fail" plots.
-			if(!pair.isMatch()) {
-				// Update the failed cluster position bins.
-				Point clusterPosition = TriggerDiagnosticUtil.getClusterPosition(pair.getReconstructedCluster());
-				Integer positionCount = failPositionBins.get(clusterPosition);
-				if(positionCount == null) { failPositionBins.put(clusterPosition, 1); }
-				else { failPositionBins.put(clusterPosition, positionCount + 1); }
-				
-				// Update the failed match time plots.
-				timeCount = failTimeBins.get(timeBin);
-				if(timeCount == null) { failTimeBins.put(timeBin, 1); }
-				else { failTimeBins.put(timeBin, timeCount + 1); }
-				
-				// Update the failed energy/hit difference plots.
-				henergyCount = failHenergyBins.get(henergyBin);
-				if(henergyCount == null) { failHenergyBins.put(henergyBin, 1); }
-				else { failHenergyBins.put(henergyBin, henergyCount + 1); }
-			}
-		}
     }
     
 	/**
@@ -150,21 +40,7 @@
 	 */
     @Override
 	public void clear() {
-		// Clear statistical data.
 		super.clear();
-		
-		// Clear plot collections.
-		sspHitCountBins.clear();
-		reconHitCountBins.clear();
-		sspPositionBins.clear();
-		reconPositionBins.clear();
-		sspEnergyBins.clear();
-		reconEnergyBins.clear();
-		failPositionBins.clear();
-		allHenergyBins.clear();
-		failHenergyBins.clear();
-		allTimeBins.clear();
-		failTimeBins.clear();
 	}
     
     /**
@@ -175,26 +51,4 @@
     public ClusterStatModule cloneStatModule() {
     	return new ClusterStatModule(this);
     }
-	
-	/**
-	 * Solves the equation <code>|E_ssp / E_recon|</code>.
-	 * @param sspCluster - The SSP cluster.
-	 * @param reconCluster - The reconstructed cluster.
-	 * @return Returns the solution to the equation as a <code>double
-	 * </code> primitive.
-	 */
-	private static final double getEnergyPercentDifference(SSPCluster sspCluster, Cluster reconCluster) {
-		return Math.abs((sspCluster.getEnergy() / reconCluster.getEnergy()));
-	}
-    
-	/**
-	 * Gets the difference in hit count between an SSP cluster and a
-	 * reconstructed cluster.
-	 * @param sspCluster - The SSP cluster.
-	 * @param reconCluster - The reconstructed cluster.
-	 * @return Returns the difference as an <code>int</code> primitive.
-	 */
-	private static final int getHitCountDifference(SSPCluster sspCluster, Cluster reconCluster) {
-		return sspCluster.getHitCount() - TriggerDiagnosticUtil.getHitCount(reconCluster);
-	}
 }

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/ClusterMatchedPair.java	Wed Mar 25 14:43:27 2015
@@ -2,7 +2,7 @@
 
 import org.hps.analysis.trigger.util.Pair;
 import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
-import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
 import org.lcsim.event.Cluster;
 
 /**
@@ -97,13 +97,23 @@
 	}
 	
 	/**
-	 * Indicates whether the recon/SSP pair failed to match due to a
-	 * the cluster positions not aligning.
+	 * Indicates whether the recon/SSP pair failed to match due to the
+	 * cluster positions not aligning.
 	 * @return Returns <code>true</code> if the pair match state is a
 	 * position fail state and <code>false</code> otherwise.
 	 */
 	public boolean isPositionFailState() {
 		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_POSITION);
+	}
+	
+	/**
+	 * Indicates whether the recon/SSP pair failed to match due to the
+	 * cluster time-stamps not aligning.
+	 * @return Returns <code>true</code> if the pair match state is a
+	 * time fail state and <code>false</code> otherwise.
+	 */
+	public boolean isTimeFailState() {
+		return (state == TriggerDiagnosticUtil.CLUSTER_STATE_FAIL_TIME);
 	}
 	
 	/**

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerEfficiencyModule.java	Wed Mar 25 14:43:27 2015
@@ -6,7 +6,7 @@
 import org.hps.analysis.trigger.util.Pair;
 import org.hps.analysis.trigger.util.PairTrigger;
 import org.hps.analysis.trigger.util.SinglesTrigger;
-import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.recon.ecal.triggerbank.SSPNumberedTrigger;
 import org.hps.analysis.trigger.util.Trigger;
 import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
 

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchEvent.java	Wed Mar 25 14:43:27 2015
@@ -5,7 +5,7 @@
 
 import org.hps.analysis.trigger.util.Pair;
 import org.hps.analysis.trigger.util.Trigger;
-import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.recon.ecal.triggerbank.SSPNumberedTrigger;
 
 /**
  * Tracks trigger pairs that were matched within an event. This can also
@@ -19,10 +19,14 @@
 	private int[] sspInternalMatched = new int[2];
 	private int[] reconTriggersMatched = new int[2];
 	private int[][] triggerComp = new int[4][2];
+	private int[] unmatchedTriggers = new int[2];
 	
 	// Track the matched trigger pairs.
 	private List<TriggerMatchedPair> sspPairList = new ArrayList<TriggerMatchedPair>();
 	private List<Pair<Trigger<?>, SSPNumberedTrigger>> reconPairList = new ArrayList<Pair<Trigger<?>, SSPNumberedTrigger>>();
+	
+	// Track whether the event triggering type was seen.
+	private boolean sawEventType = false;
 	
 	/**
 	 * Gets the number of times a cut of the given cut ID failed when
@@ -34,7 +38,7 @@
 	 */
 	public int getCutFailures(int triggerNumber, int cutID) {
 		// Validate the arguments.
-		if(triggerNumber !=0 && triggerNumber != 1) {
+		if(triggerNumber != 0 && triggerNumber != 1) {
 			throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
 		} if(cutID < 0 || cutID > 3) {
 			throw new IndexOutOfBoundsException(String.format("Cut ID \"%d\" is not valid.", cutID));
@@ -45,12 +49,29 @@
 	}
 	
 	/**
+	 * Gets the number of triggers for this trigger for which there
+	 * were no matches.
+	 * @param triggerNum - The trigger for which to get the value.
+	 * @return Returns the number of triggers that failed to match as
+	 * an <code>int</code>.
+	 */
+	public int getUnmatchedTriggers(int triggerNum) {
+		// Validate the arguments.
+		if(triggerNum != 0 && triggerNum != 1) {
+			throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+		}
+		
+		// Return the requested cut value.
+		return unmatchedTriggers[triggerNum];
+	}
+	
+	/**
 	 * Gets the number of reconstructed cluster triggers that were
 	 * matched successfully.
 	 * @return Returns the value as an <code>int</code> primitive.
 	 */
 	public int getMatchedReconTriggers() {
-		return reconPairList.size();
+		return reconTriggersMatched[0] + reconTriggersMatched[1];
 	}
 	
 	/**
@@ -61,7 +82,7 @@
 	 */
 	public int getMatchedReconTriggers(int triggerNumber) {
 		// Validate the arguments.
-		if(triggerNumber !=0 && triggerNumber != 1) {
+		if(triggerNumber != 0 && triggerNumber != 1) {
 			throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
 		}
 		
@@ -75,7 +96,7 @@
 	 * @return Returns the value as an <code>int</code> primitive.
 	 */
 	public int getMatchedSSPTriggers() {
-		return sspPairList.size();
+		return sspInternalMatched[0] + sspInternalMatched[1];
 	}
 	
 	/**
@@ -86,7 +107,7 @@
 	 */
 	public int getMatchedSSPTriggers(int triggerNumber) {
 		// Validate the arguments.
-		if(triggerNumber !=0 && triggerNumber != 1) {
+		if(triggerNumber != 0 && triggerNumber != 1) {
 			throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
 		}
 		
@@ -122,12 +143,8 @@
 	 * @param sspTrigger - The SSP bank trigger.
 	 */
 	public void matchedSSPPair(Trigger<?> simTrigger, SSPNumberedTrigger sspTrigger) {
-		// A null SSP trigger means that no match was found. This is
-		// treated as a failure due to time, which is not tracked.
-		if(sspTrigger != null) {
-			sspInternalMatched[sspTrigger.isFirstTrigger() ? 0 : 1]++;
-			sspPairList.add(new TriggerMatchedPair(simTrigger, sspTrigger, new boolean[] { true, true, true, true }));
-		}
+		sspInternalMatched[sspTrigger.isFirstTrigger() ? 0 : 1]++;
+		sspPairList.add(new TriggerMatchedPair(simTrigger, sspTrigger, new boolean[] { true, true, true, true }));
 	}
 	
 	/**
@@ -139,28 +156,31 @@
 	 * which did not.
 	 */
 	public void matchedSSPPair(Trigger<?> simTrigger, SSPNumberedTrigger sspTrigger, boolean[] cutsMatched) {
-		// Store the full cut array.
-		boolean[] cutArray = cutsMatched;
-		
-		// If the array is size 3, it is the a singles trigger. Update
-		// it to an array of size 4 for compatibility.
-		if(cutsMatched.length == 3) {
-			boolean[] tempArray = { true, true, true, true };
-			for(int cutIndex = 0; cutIndex < cutsMatched.length; cutIndex++) {
-				tempArray[cutIndex] = cutsMatched[cutIndex];
-			}
-			cutArray = tempArray;
+		// The cut values must be stored in an array of size four, but
+		// singles triggers use arrays of size 3. If the array is not
+		// of the appropriate size, resize it.
+		boolean[] cutArray;
+		if(cutsMatched == null) {
+			cutArray = new boolean[] { false, false, false, false };
+		} else if(cutsMatched.length == 4) {
+			cutArray = cutsMatched;
+		} else {
+			cutArray = new boolean[] { cutsMatched[0], cutsMatched[1], cutsMatched[2], true };
 		}
 		
 		// Add the trigger pair to the list.
 		TriggerMatchedPair triggerPair = new TriggerMatchedPair(simTrigger, sspTrigger, cutArray);
 		sspPairList.add(triggerPair);
 		
+		// If the argument cut array was null, then this trigger was
+		// not actually matched. Track this.
+		int triggerNum = triggerPair.isFirstTrigger() ? 0 : 1;
+		if(cutsMatched == null) { unmatchedTriggers[triggerNum]++; }
+		
 		// Track which cuts have failed.
 		boolean isMatched = true;
-		int triggerNum = triggerPair.isFirstTrigger() ? 0 : 1;
-		for(int cutIndex = 0; cutIndex < cutsMatched.length; cutIndex++) {
-			if(!cutsMatched[cutIndex]) {
+		for(int cutIndex = 0; cutIndex < cutArray.length; cutIndex++) {
+			if(!cutArray[cutIndex]) {
 				triggerComp[cutIndex][triggerNum]++;
 				isMatched = false;
 			}
@@ -169,4 +189,24 @@
 		// If all the cuts are true, then the trigger pair is a match.
 		if(isMatched) { sspInternalMatched[triggerNum]++; }
 	}
+	
+	/**
+	 * Indicates whether an event of the type that caused the event
+	 * readout was seen.
+	 * @return Returns <code>true</code> if an event was seen and
+	 * <code>false</code> otherwise.
+	 */
+	public boolean sawEventType() {
+		return sawEventType;
+	}
+	
+	/**
+	 * Sets whether a simulated trigger of the type that caused the
+	 * event readout was seen.
+	 * @param state - <code>true</code> indicates that the trigger type
+	 * was seen and <code>false</code> that it was not.
+	 */
+	public void setSawEventType(boolean state) {
+		sawEventType = state;
+	}
 }

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchStatus.java	Wed Mar 25 14:43:27 2015
@@ -3,7 +3,8 @@
 import java.util.List;
 
 import org.hps.analysis.trigger.util.Trigger;
-import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.analysis.trigger.util.TriggerDiagnosticUtil;
+import org.hps.recon.ecal.triggerbank.SSPNumberedTrigger;
 
 /**
  * Tracks the trigger diagnostic statistics for trigger matching.
@@ -11,6 +12,10 @@
  * @author Kyle McCarty <[log in to unmask]>
  */
 public class TriggerMatchStatus extends TriggerStatModule {
+	// Track the number of triggers seen.
+	private int[] sspTriggersSeen = new int[2];
+	private int[] reconTriggersSeen = new int[2];
+	
 	/**
 	 * Adds the statistical data stored in a trigger comparison event
 	 * into this status tracking module.
@@ -19,8 +24,15 @@
 	 * @param sspSimTriggers - A list of simulated SSP cluster triggers.
 	 * @param sspBankTriggers - A list of SSP bank triggers.
 	 */
-	public void addEvent(TriggerMatchEvent event, List<List<? extends Trigger<?>>> reconTriggers,
+	public void addEvent(int eventType, TriggerMatchEvent event, List<List<? extends Trigger<?>>> reconTriggers,
 			List<List<? extends Trigger<?>>> sspSimTriggers, List<? extends SSPNumberedTrigger> sspBankTriggers) {
+		// Increment the event type count.
+		if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
+			triggerTypesSeen[0]++;
+		} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_2) {
+			triggerTypesSeen[1]++;
+		}
+		
 		// Check if there are more bank triggers than there are
 		// simulated SSP triggers.
 		int sspTriggerDiff = sspBankTriggers.size() - sspSimTriggers.size();
@@ -34,8 +46,16 @@
 		this.reconTriggers += reconTriggers.get(0).size() + reconTriggers.get(1).size();
 		reportedTriggers += sspBankTriggers.size();
 		
+		// Fill the specific trigger counters.
+		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+			sspTriggersSeen[triggerNum] += sspSimTriggers.get(triggerNum).size();
+			reconTriggersSeen[triggerNum] += reconTriggers.get(triggerNum).size();
+		}
+		
 		// Increment the count for each cut failure type.
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
+			unmatchedTriggers[triggerNum] += event.getUnmatchedTriggers(triggerNum);
+			
 			for(int cutIndex = 0; cutIndex < 4; cutIndex++) {
 				triggerComp[cutIndex][triggerNum] += event.getCutFailures(triggerNum, cutIndex);
 			}
@@ -45,6 +65,16 @@
 		for(int triggerNum = 0; triggerNum < 2; triggerNum++) {
 			sspInternalMatched[triggerNum] += event.getMatchedSSPTriggers(triggerNum);
 			reconTriggersMatched[triggerNum] += event.getMatchedReconTriggers(triggerNum);
+		}
+		
+		// Check if a trigger of the right time was found.
+		// Get the trigger number and type.
+		if(event.sawEventType()) {
+			if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_1 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_1) {
+				triggerTypesFound[0]++;
+			} else if(eventType == TriggerDiagnosticUtil.TRIGGER_SINGLES_2 || eventType == TriggerDiagnosticUtil.TRIGGER_PAIR_2) {
+				triggerTypesFound[1]++;
+			}
 		}
 	}
 	
@@ -62,4 +92,52 @@
 	public TriggerStatModule cloneStatModule() {
     	return new TriggerStatModule(this);
     }
+	
+	/**
+	 * Gets the number of reconstructed triggers seen for a specific
+	 * trigger number.
+	 * @param triggerNum - The trigger number.
+	 * @return Returns the total number of reconstructed triggers seen
+	 * by the indicated trigger number. 
+	 */
+	public int getTotalReconTriggers(int triggerNum) {
+		return getSSPTriggerCount(false, triggerNum);
+	}
+	
+	/**
+	 * Gets the number of SSP bank triggers seen for a specific trigger
+	 * number.
+	 * @param triggerNum - The trigger number.
+	 * @return Returns the total number of SSP bank triggers seen by
+	 * the indicated trigger number. 
+	 */
+	public int getTotalSSPTriggers(int triggerNum) {
+		return getSSPTriggerCount(true, triggerNum);
+	}
+	
+	/**
+	 * Gets the total number of triggers seen for a specific trigger
+	 * source type and number.
+	 * @param isSSP - Whether the trigger source is SSP bank clusters.
+	 * @param triggerNum - The trigger number.
+	 * @return Returns the trigger count.
+	 */
+	private final int getSSPTriggerCount(boolean isSSP, int triggerNum) {
+		// Make sure the trigger number is valid.
+		validateTriggerNumber(triggerNum);
+		
+		// Return the triggers.
+		if(isSSP) { return sspTriggersSeen[triggerNum]; }
+		else { return reconTriggersSeen[triggerNum]; }
+	}
+	
+	/**
+	 * Produces an exception if the trigger number argument is invalid.
+	 * @param triggerNum - The trigger number to validate.
+	 */
+	private static final void validateTriggerNumber(int triggerNum) {
+		if(triggerNum < 0 || triggerNum > 2) {
+			throw new IndexOutOfBoundsException(String.format("Trigger number \"%d\" is invalid", triggerNum));
+		}
+	}
 }

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerMatchedPair.java	Wed Mar 25 14:43:27 2015
@@ -4,9 +4,9 @@
 import org.hps.analysis.trigger.util.PairTrigger;
 import org.hps.analysis.trigger.util.SinglesTrigger;
 import org.hps.analysis.trigger.util.Trigger;
-import org.hps.readout.ecal.triggerbank.SSPNumberedTrigger;
-import org.hps.readout.ecal.triggerbank.SSPPairTrigger;
-import org.hps.readout.ecal.triggerbank.SSPSinglesTrigger;
+import org.hps.recon.ecal.triggerbank.SSPNumberedTrigger;
+import org.hps.recon.ecal.triggerbank.SSPPairTrigger;
+import org.hps.recon.ecal.triggerbank.SSPSinglesTrigger;
 
 /**
  * Stores a pair of one simulated trigger and one SSP bank trigger that
@@ -80,7 +80,11 @@
 	 * object.
 	 */
 	public Class<?> getSimulatedTriggerType() {
-		return getFirstElement().getTriggerSource().getClass();
+		if(getFirstElement() != null) {
+			return getFirstElement().getTriggerSource().getClass();
+		} else {
+			return null;
+		}
 	}
 	
 	/**
@@ -99,7 +103,11 @@
 	 * first trigger and <code>false</code> otherwise.
 	 */
 	public boolean isFirstTrigger() {
-		return getSecondElement().isFirstTrigger();
+		if(getSecondElement() != null) {
+			return getSecondElement().isFirstTrigger();
+		} else {
+			return getFirstElement().getTriggerNumber() == 0 ? true : false;
+		}
 	}
 	
 	/**
@@ -108,7 +116,7 @@
 	 * triggers and <code>false</code> otherwise.
 	 */
 	public boolean isPairTrigger() {
-		if(getFirstElement() instanceof PairTrigger && getSecondElement() instanceof SSPPairTrigger) {
+		if(getFirstElement() instanceof PairTrigger || getSecondElement() instanceof SSPPairTrigger) {
 			return true;
 		} else {
 			return false;
@@ -122,7 +130,7 @@
 	 * second trigger and <code>false</code> otherwise.
 	 */
 	public boolean isSecondTrigger() {
-		return getSecondElement().isSecondTrigger();
+		return !isFirstTrigger();
 	}
 	
 	/**
@@ -131,7 +139,7 @@
 	 * triggers and <code>false</code> otherwise.
 	 */
 	public boolean isSinglesTrigger() {
-		if(getFirstElement() instanceof SinglesTrigger && getSecondElement() instanceof SSPSinglesTrigger) {
+		if(getFirstElement() instanceof SinglesTrigger || getSecondElement() instanceof SSPSinglesTrigger) {
 			return true;
 		} else {
 			return false;

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/event/TriggerStatModule.java	Wed Mar 25 14:43:27 2015
@@ -15,7 +15,9 @@
 	protected int[] sspInternalMatched = new int[2];
 	protected int[] reconTriggersMatched = new int[2];
 	protected int[][] triggerComp = new int[4][2];
-	
+	protected int[] unmatchedTriggers = new int[2];
+	protected int[] triggerTypesSeen = new int[2];
+	protected int[] triggerTypesFound = new int[2];
 	
 	/**
 	 * Instantiates a <code>TriggerStatModule</code> with no statistics
@@ -40,6 +42,13 @@
 		for(int i = 0; i < reconTriggersMatched.length; i++) {
 			reconTriggersMatched[i] = base.reconTriggersMatched[i];
 		}
+		for(int i = 0; i < triggerTypesSeen.length; i++) {
+			triggerTypesSeen[i] = base.triggerTypesSeen[i];
+			triggerTypesFound[i] = base.triggerTypesFound[i];
+		}
+		for(int i = 0; i < unmatchedTriggers.length; i++) {
+			unmatchedTriggers[i] = base.unmatchedTriggers[i];
+		}
 		for(int i = 0; i < triggerComp.length; i++) {
 			for(int j = 0; j < triggerComp[i].length; j++) {
 				triggerComp[i][j] = base.triggerComp[i][j];
@@ -82,6 +91,40 @@
 	}
 	
 	/**
+	 * Gets the number of events that were readout due to a trigger
+	 * of the indicated type.
+	 * @param triggerType - The type of trigger.
+	 * @return Returns the number of events readout because of the
+	 * trigger type as an <code>int</code>.
+	 */
+	public int getEventsOfType(int triggerNum) {
+		// Make sure that the trigger type is defined.
+		if(triggerNum < 0 || triggerNum > 1) {
+			throw new IndexOutOfBoundsException(String.format("Trigger number \"%d\" is not valid.", triggerNum));
+		}
+		
+		// Return the number of events that were trigger by this type.
+		return triggerTypesSeen[triggerNum];
+	}
+	
+	/**
+	 * Gets the number of events that were readout due to a trigger
+	 * of the indicated type where a reconstructed cluster simulated
+	 * trigger of that type existed.
+	 * @param triggerType - The type of trigger.
+	 * @return Returns the number of events as an <code>int</code>.
+	 */
+	public int getEventsOfTypeSeen(int triggerNum) {
+		// Make sure that the trigger type is defined.
+		if(triggerNum < 0 || triggerNum > 1) {
+			throw new IndexOutOfBoundsException(String.format("Trigger number \"%d\" is not valid.", triggerNum));
+		}
+		
+		// Return the number of events that were trigger by this type.
+		return triggerTypesFound[triggerNum];
+	}
+	
+	/**
 	 * Gets the number of SSP bank triggers that were reported in excess
 	 * of the number of simulated SSP triggers seen.
 	 * @return Returns the value as an <code>int</code> primitive.
@@ -163,4 +206,21 @@
 	public int getSSPBankTriggerCount() {
 		return reportedTriggers;
 	}
+	
+	/**
+	 * Gets the number of triggers for this trigger for which there
+	 * were no matches.
+	 * @param triggerNum - The trigger for which to get the value.
+	 * @return Returns the number of triggers that failed to match as
+	 * an <code>int</code>.
+	 */
+	public int getUnmatchedTriggers(int triggerNum) {
+		// Validate the arguments.
+		if(triggerNum != 0 && triggerNum != 1) {
+			throw new IndexOutOfBoundsException("Trigger number must be 0 or 1.");
+		}
+		
+		// Return the requested cut value.
+		return unmatchedTriggers[triggerNum];
+	}
 }

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/PairTrigger.java	Wed Mar 25 14:43:27 2015
@@ -1,6 +1,6 @@
 package org.hps.analysis.trigger.util;
 
-import org.hps.readout.ecal.TriggerModule;
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 
 public class PairTrigger<E> extends SinglesTrigger<E> {
 	// Define the supported trigger cuts.
@@ -65,7 +65,7 @@
 	 * <code>false</code> otherwise.
 	 */
 	public boolean getStateEnergyDifference() {
-		return getCutState(PAIR_ENERGY_SUM_HIGH);
+		return getCutState(PAIR_ENERGY_DIFFERENCE_HIGH);
 	}
 	
 	/**

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/SinglesTrigger.java	Wed Mar 25 14:43:27 2015
@@ -1,6 +1,6 @@
 package org.hps.analysis.trigger.util;
 
-import org.hps.readout.ecal.TriggerModule;
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 
 public class SinglesTrigger<E> extends Trigger<E> {
 	// Define the supported trigger cuts.

Modified: java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java
 =============================================================================
--- java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java	(original)
+++ java/branches/prod/analysis/src/main/java/org/hps/analysis/trigger/util/TriggerDiagnosticUtil.java	Wed Mar 25 14:43:27 2015
@@ -2,7 +2,7 @@
 
 import java.awt.Point;
 
-import org.hps.readout.ecal.triggerbank.SSPCluster;
+import org.hps.recon.ecal.triggerbank.SSPCluster;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 
@@ -19,7 +19,8 @@
 	public static final byte CLUSTER_STATE_FAIL_POSITION  = 1;
 	public static final byte CLUSTER_STATE_FAIL_ENERGY    = 2;
 	public static final byte CLUSTER_STATE_FAIL_HIT_COUNT = 3;
-	public static final byte CLUSTER_STATE_FAIL_UNKNOWN   = 4;
+	public static final byte CLUSTER_STATE_FAIL_TIME      = 4;
+	public static final byte CLUSTER_STATE_FAIL_UNKNOWN   = 5;
 	
 	// Trigger match cut IDs.
 	public static final int SINGLES_ENERGY_MIN = 0;

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/api/AbstractConditionsObjectCollection.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/api/AbstractConditionsObjectCollection.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/api/AbstractConditionsObjectCollection.java	Wed Mar 25 14:43:27 2015
@@ -8,6 +8,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 
+import org.hps.conditions.api.ConditionsObject.DefaultConditionsObjectComparator;
 import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.conditions.database.TableMetaData;
 
@@ -201,7 +202,37 @@
      * @param comparator The comparator to use for the sort.
      * @return A sorted list of the objects.
      */
+    @SuppressWarnings("unchecked")
     public AbstractConditionsObjectCollection<ObjectType> sorted(Comparator<ObjectType> comparator) {
-        throw new UnsupportedOperationException("This method is not implemented.");
+        List<ObjectType> objects = new ArrayList<ObjectType>(this);
+        Collections.sort(objects, comparator);
+        AbstractConditionsObjectCollection<ObjectType> collection = null;
+        try {
+            collection = (AbstractConditionsObjectCollection<ObjectType>) getClass().newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+        collection.addAll(objects);
+        return collection;
+    }
+    
+    public void sort() {
+        AbstractConditionsObjectCollection<ObjectType> sortedCollection = sorted();
+        this.clear();
+        this.addAll(sortedCollection);
+    }
+    
+    public AbstractConditionsObjectCollection<ObjectType> sorted() {
+        List<ObjectType> objects = new ArrayList<ObjectType>(this);
+        Collections.sort(objects, new DefaultConditionsObjectComparator());
+        AbstractConditionsObjectCollection<ObjectType> collection = null;
+        try {
+            // FIXME: This is kind of ugly.
+            collection = (AbstractConditionsObjectCollection<ObjectType>) getClass().newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+        collection.addAll(objects);
+        return collection;
     }
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObject.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObject.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObject.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.api;
+
+import java.util.Comparator;
 
 /**
  * This is an ORM interface for accessing conditions database information by
@@ -63,4 +65,16 @@
      * @return True if record is new.
      */
     public boolean isNew();
+    
+    static class DefaultConditionsObjectComparator implements Comparator<ConditionsObject> {
+        public int compare(ConditionsObject o1, ConditionsObject o2) {
+            if (o1.getRowId() < o2.getRowId()) {
+                return -1;
+            } else if (o1.getRowId() > o2.getRowId()) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }        
+    }
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObjectCollection.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObjectCollection.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/api/ConditionsObjectCollection.java	Wed Mar 25 14:43:27 2015
@@ -68,4 +68,8 @@
      * @return A sorted list of the objects.
      */
     public AbstractConditionsObjectCollection<ObjectType> sorted(Comparator<ObjectType> comparator);
+    
+    public void sort();
+    
+    public AbstractConditionsObjectCollection<ObjectType> sorted();
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/database/ConditionsObjectConverter.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/database/ConditionsObjectConverter.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/database/ConditionsObjectConverter.java	Wed Mar 25 14:43:27 2015
@@ -76,6 +76,11 @@
         
         // Get the TableMetaData from the table name.
         TableMetaData tableMetaData = databaseConditionsManager.findTableMetaData(name);    
+        
+        // Throw an exception if the table name does not map to a known type.
+        if (tableMetaData == null) {
+            throw new RuntimeException(new ConditionsObjectException("No table information found for name: " + name));
+        }
         
         // Get the ConditionsRecordCollection with the run number assignments.
         ConditionsRecordCollection conditionsRecords = databaseConditionsManager.findConditionsRecords(name);

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	Wed Mar 25 14:43:27 2015
@@ -12,8 +12,10 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -62,7 +64,7 @@
 public final class DatabaseConditionsManager extends ConditionsManagerImplementation {
 
     // Initialize logger.
-    private static Logger logger = LogUtil.create(DatabaseConditionsManager.class.getName(), new DefaultLogFormatter(), Level.INFO);
+    private static Logger logger = LogUtil.create(DatabaseConditionsManager.class.getName(), new DefaultLogFormatter(), Level.FINE);
 
     // Global registry of conditions converters.
     private ConverterRegistry converters = ConverterRegistry.create();
@@ -131,6 +133,33 @@
             registerConditionsConverter(converter);
         }
         addConditionsListener(svtSetup);
+    }    
+       
+    /**
+     * Get the static instance of this class.
+     * @return The static instance of the manager.
+     */
+    public synchronized static DatabaseConditionsManager getInstance() {
+
+        logger.finer("getting conditions manager instance");
+        
+        // Is there no manager installed yet?
+        if (!ConditionsManager.isSetup() || !(ConditionsManager.defaultInstance() instanceof DatabaseConditionsManager)) {
+            logger.finer("creating new instance");
+            // Create a new instance if necessary, which will install it globally as the default.
+            new DatabaseConditionsManager();
+        }
+
+        // Get the instance back from the default conditions system and check that the type is correct now.
+        ConditionsManager manager = ConditionsManager.defaultInstance();
+        if (!(manager instanceof DatabaseConditionsManager)) {
+            logger.severe("default conditions manager has wrong type");
+            throw new RuntimeException("Default conditions manager has the wrong type: " + ConditionsManager.defaultInstance().getClass().getName());
+        }
+        
+        logger.finer("returning conditions manager instance");
+
+        return (DatabaseConditionsManager) manager;
     }
     
     /**
@@ -145,35 +174,10 @@
     }
     
     /**
-     * Get the static instance of this class.
-     * @return The static instance of the manager.
-     */
-    public static DatabaseConditionsManager getInstance() {
-
-        logger.fine("setting up new conditions manager instance");
-        
-        // Is there no manager installed yet?
-        if (!ConditionsManager.isSetup()) {
-            // Create a new instance if necessary.
-            new DatabaseConditionsManager();
-        }
-
-        // Get the instance back from the default conditions system and check that the type is correct.
-        ConditionsManager manager = ConditionsManager.defaultInstance();
-        if (!(manager instanceof DatabaseConditionsManager)) {
-            throw new RuntimeException("The default ConditionsManager has the wrong type.");
-        }
-        
-        logger.fine("instance initialized succesfully");
-
-        return (DatabaseConditionsManager) manager;
-    }
-    
-    /**
      * Open the database connection.
      * @return True if a connection was opened; false if using an existing connection.
      */
-    public boolean openConnection() {
+    public synchronized boolean openConnection() {
         boolean openedConnection = false;
         if (!isConnected) {
             // Do the connection parameters need to be figured out automatically?
@@ -207,7 +211,7 @@
     /**
      * Close the database connection.
      */
-    public void closeConnection() {
+    public synchronized void closeConnection() {
         logger.fine("closing connection");
         if (connection != null) {
             try {
@@ -228,7 +232,7 @@
      * based on the flag.  Otherwise, it should be left open.
      * @param connectionOpened True to close the connection; false to leave it open.
      */
-    public void closeConnection(boolean connectionOpened) {
+    public synchronized void closeConnection(boolean connectionOpened) {
         if (connectionOpened) {
             closeConnection();
         }
@@ -265,7 +269,7 @@
      * needs to be updated.
      */
     @Override
-    public void setDetector(String detectorName, int runNumber) throws ConditionsNotFoundException {
+    public synchronized void setDetector(String detectorName, int runNumber) throws ConditionsNotFoundException {
 
         logger.finest("setDetector " + detectorName + " with run number " + runNumber);
         
@@ -367,7 +371,7 @@
      * @param tableName The name of the table.
      * @return The next collection ID.
      */
-    public int getNextCollectionID(String tableName) {
+    public synchronized int getNextCollectionID(String tableName) {
         boolean openedConnection = openConnection();
         ResultSet resultSet = selectQuery("SELECT MAX(collection_id)+1 FROM " + tableName);
         int collectionId = 1;
@@ -533,7 +537,7 @@
      * This method can be called to "freeze" the conditions system so that
      * any subsequent updates to run number or detector name will be ignored.
      */
-    public void freeze() {
+    public synchronized void freeze() {
         if (getDetector() != null && getRun() != -1) {
             isFrozen = true;
             logger.config("conditions system is frozen");
@@ -545,7 +549,7 @@
     /**
      * Un-freeze the conditions system so that updates will be received again.
      */
-    public void unfreeze() {
+    public synchronized void unfreeze() {
         isFrozen = false;
         logger.info("conditions system unfrozen");
     }
@@ -701,6 +705,39 @@
     public boolean isInitialized() {
         return isInitialized;
     }
+    
+    /**
+     * Get the set of unique conditions tags from the conditions table.
+     * @return The list of unique conditions tags.
+     */
+    public Set<String> getTags() {
+        logger.fine("getting list of available conditions tags");
+        boolean openedConnection = openConnection();
+        Set<String> tags = new LinkedHashSet<String>();
+        ResultSet rs = selectQuery("select distinct(tag) from conditions where tag is not null order by tag");
+        try {
+            while (rs.next()) {
+                tags.add(rs.getString(1));
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+        try {
+            rs.close();
+        } catch (SQLException e) {
+            logger.log(Level.WARNING, "error closing ResultSet", e);
+        }
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("found unique conditions tags ...");
+        for (String tag : tags) {
+            buffer.append(tag + " ");
+        }
+        buffer.setLength(buffer.length() - 1);
+        buffer.append('\n');
+        logger.fine(buffer.toString());        
+        closeConnection(openedConnection);
+        return tags;
+    }
 
     /*
      *******************************
@@ -713,7 +750,7 @@
      * configuration and loading of conditions onto the Detector.
      */
     private void initialize(String detectorName, int runNumber) throws ConditionsNotFoundException {
-        
+                
         logger.config("initializing with detector " + detectorName + " and run " + runNumber);
         
         // Is not configured yet?

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableMetaData.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableMetaData.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableMetaData.java	Wed Mar 25 14:43:27 2015
@@ -1,12 +1,15 @@
 package org.hps.conditions.database;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
 import org.hps.conditions.api.ConditionsObject;
+import org.hps.conditions.api.ConditionsObjectCollection;
 
 /**
  * <p>
@@ -30,6 +33,7 @@
     protected Class<? extends ConditionsObject> objectClass;
     protected Class<? extends AbstractConditionsObjectCollection<?>> collectionClass;
     protected Set<String> fieldNames = new LinkedHashSet<String>();
+    protected Map<String, Class<?>> fieldTypes;
 
     /**
      * The fully qualified constructor.
@@ -37,19 +41,53 @@
      * @param objectClass The type of object for the data mapping.
      * @param collectionClass The type of collection for the data mapping.
      */
-    public TableMetaData(String key, String tableName, Class<? extends ConditionsObject> objectClass, Class<? extends AbstractConditionsObjectCollection<?>> collectionClass) {
+    /*
+    public TableMetaData(
+            String key, 
+            String tableName, 
+            Class<? extends ConditionsObject> objectClass, 
+            Class<? extends AbstractConditionsObjectCollection<?>> collectionClass,
+            Map<String, Class<?>> fieldTypes) {
+       
         this.key = key;
         this.tableName = tableName;
         this.objectClass = objectClass;
         this.collectionClass = collectionClass;
+        this.fieldTypes = fieldTypes;
     }
+    */
     
-    public TableMetaData(String key, String tableName, Class<? extends ConditionsObject> objectClass, Class<? extends AbstractConditionsObjectCollection<?>> collectionClass, Set<String> fieldNames) {
+    public TableMetaData(
+            String key, 
+            String tableName, 
+            Class<? extends ConditionsObject> objectClass, 
+            Class<? extends AbstractConditionsObjectCollection<?>> collectionClass, 
+            Set<String> fieldNames,
+            Map<String, Class<?>> fieldTypes) {
+        if (key == null) {
+            throw new IllegalArgumentException("key is null");
+        }
+        if (tableName == null) {
+            throw new IllegalArgumentException("tableName is null");
+        }
+        if (objectClass == null) {
+            throw new IllegalArgumentException("objectClass is null");
+        }
+        if (fieldNames == null) {
+            throw new IllegalArgumentException("fieldNames is null");
+        }
+        if (collectionClass == null) {
+            throw new IllegalArgumentException("collectionClass is null");
+        }
+        if (fieldTypes == null) {
+            throw new IllegalArgumentException("fieldTypes is null");
+        }
         this.key = key;
         this.tableName = tableName;
         this.objectClass = objectClass;
         this.collectionClass = collectionClass;
         this.fieldNames = fieldNames;
+        this.fieldTypes = fieldTypes;
     }
     
     /**
@@ -77,15 +115,11 @@
     }
 
     /**
-     * Add a field.
-     * @param name The name of the field.
+     * Get the type of the field called <code>fieldName</code>.
+     * @return The type of the field.
      */
-    void addField(String name) {
-        fieldNames.add(name);
-    }
-    
-    void addFields(List<String> names) {
-        fieldNames.addAll(names);
+    public Class<?> getFieldType(String fieldName) {
+        return fieldTypes.get(fieldName);
     }
 
     /**
@@ -106,15 +140,11 @@
     }
     
     static public List<TableMetaData> findByObjectType(List<TableMetaData> tableMetaDataList, Class<? extends ConditionsObject> objectType) {
-        System.out.println("findByObjectType - " + objectType.getCanonicalName());
         List<TableMetaData> list = new ArrayList<TableMetaData>();
         for (TableMetaData tableMetaData : tableMetaDataList) {
-            System.out.println("comparing to " + tableMetaData.getObjectClass().getCanonicalName());
             if (tableMetaData.getObjectClass().equals(objectType)) {
-                System.out.println("found match");
+
                 list.add(tableMetaData);
-            } else {
-                System.out.println("does not match");
             }
         }
         return list;

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableRegistry.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableRegistry.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/database/TableRegistry.java	Wed Mar 25 14:43:27 2015
@@ -1,8 +1,11 @@
 package org.hps.conditions.database;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -42,13 +45,32 @@
     static TableRegistry create() {
         TableRegistry registry = new TableRegistry();
         for (Class<? extends ConditionsObject> objectType : ConditionsObjectUtilities.findConditionsObjectTypes()) {
+            
+            // Get the collection type.
             Class<? extends AbstractConditionsObjectCollection<?>> collectionType = 
                     ConditionsObjectUtilities.getCollectionType(objectType);
+            
+            // Get the list of field names.
             Set<String> fieldNames = ConditionsObjectUtilities.getFieldNames(objectType);            
-            for (String name : ConditionsObjectUtilities.getTableNames(objectType)) {    
-                
+            
+            // Create map of fields to their types.
+            Map<String, Class<?>> fieldTypes = new HashMap<String, Class<?>>();
+            for (Method method : objectType.getMethods()) {
+                if (!method.getReturnType().equals(Void.TYPE)) {
+                    for (Annotation annotation : method.getAnnotations()) {
+                        if (annotation.annotationType().equals(Field.class)) {                            
+                            Field field = (Field) annotation;
+                            for (String fieldName : field.names()) {
+                                fieldTypes.put(fieldName, method.getReturnType());
+                            }
+                        }
+                    }
+                }
+            }
+                        
+            for (String name : ConditionsObjectUtilities.getTableNames(objectType)) {                    
                 // Create a meta data mapping for each table name in the class description.
-                TableMetaData data = new TableMetaData(name, name, objectType, collectionType, fieldNames);
+                TableMetaData data = new TableMetaData(name, name, objectType, collectionType, fieldNames, fieldTypes);
                 registry.put(name, data);                               
                 registry.objectTypeMap.add(objectType, data);
                 registry.collectionTypeMap.add(collectionType, data);                  

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalBadChannel.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalBadChannel.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalBadChannel.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.ecal;
+
+import java.util.Comparator;
 
 import org.hps.conditions.api.AbstractConditionsObject;
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -16,14 +18,30 @@
 public final class EcalBadChannel extends AbstractConditionsObject {
 
     public static class EcalBadChannelCollection extends AbstractConditionsObjectCollection<EcalBadChannel> {
+        
+        public AbstractConditionsObjectCollection<EcalBadChannel> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+                
+        class ChannelIdComparator implements Comparator<EcalBadChannel> {
+            public int compare(EcalBadChannel o1, EcalBadChannel o2) {
+                if (o1.getChannelId() < o2.getChannelId()) {
+                    return -1;
+                } else if (o1.getChannelId() > o2.getChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        }        
     }
-
+    
     /**
-     * Get the channel ID of the bad channel.
-     * @return The channel ID of the bad channel.
+     * Get the ECAL channel ID.
+     * @return The ECAL channel ID.
      */
     @Field(names = {"ecal_channel_id"})
     public int getChannelId() {
-        return getFieldValue("ecal_channel_id");
+        return getFieldValue("ecal_channel_id");    
     }
-}
+}

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalCalibration.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalCalibration.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalCalibration.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.ecal;
+
+import java.util.Comparator;
 
 import org.hps.conditions.api.AbstractConditionsObject;
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -21,8 +23,24 @@
 public final class EcalCalibration extends AbstractConditionsObject {
 
     public static class EcalCalibrationCollection extends AbstractConditionsObjectCollection<EcalCalibration> {
+        
+        public AbstractConditionsObjectCollection<EcalCalibration> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+                
+        class ChannelIdComparator implements Comparator<EcalCalibration> {
+            public int compare(EcalCalibration o1, EcalCalibration o2) {
+                if (o1.getChannelId() < o2.getChannelId()) {
+                    return -1;
+                } else if (o1.getChannelId() > o2.getChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        }
     }
-    
+               
     public EcalCalibration() {
     }
     
@@ -33,12 +51,12 @@
     }
 
     /**
-     * Get the channel ID.
-     * @return The channel ID.
+     * Get the ECAL channel ID.
+     * @return The ECAL channel ID.
      */
     @Field(names = {"ecal_channel_id"})
     public int getChannelId() {
-        return getFieldValue("ecal_channel_id");
+        return getFieldValue("ecal_channel_id");    
     }
 
     /**

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalChannel.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalChannel.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalChannel.java	Wed Mar 25 14:43:27 2015
@@ -1,10 +1,7 @@
 package org.hps.conditions.ecal;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import org.hps.conditions.api.AbstractConditionsObject;
@@ -137,20 +134,6 @@
         }
     }
     
-    private static final class ChannelIdComparator implements Comparator<EcalChannel> {
-        
-        public int compare(EcalChannel c1, EcalChannel c2) {
-            if (c1.getChannelId() < c2.getChannelId()) {
-                return -1;
-            } else if (c1.getChannelId() > c2.getChannelId()) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-        
-    }
-
     DaqId createDaqId() {
         return new DaqId(new int[] { getCrate(), getSlot(), getChannel() });
     }
@@ -254,16 +237,22 @@
          */
         public EcalChannel findDaq(long id) {
             return daqMap.get(id);
-        }
-        
-        /**
-         * Get a list of channels sorted by channel ID.
-         * @return A list of channels sorted by channel ID.
-         */
-        public List<EcalChannel> sortedByChannelId() {
-            List<EcalChannel> channelList = new ArrayList<EcalChannel>(this);
-            Collections.sort(channelList, new ChannelIdComparator());
-            return channelList;
+        }        
+                   
+        public AbstractConditionsObjectCollection<EcalChannel> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+            
+        class ChannelIdComparator implements Comparator<EcalChannel> {        
+            public int compare(EcalChannel c1, EcalChannel c2) {
+                if (c1.getChannelId() < c2.getChannelId()) {
+                    return -1;
+                } else if (c1.getChannelId() > c2.getChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }            
         }
     }
 

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalGain.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalGain.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalGain.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.ecal;
+
+import java.util.Comparator;
 
 import org.hps.conditions.api.AbstractConditionsObject;
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -17,8 +19,26 @@
 public final class EcalGain extends AbstractConditionsObject {
 
     public static class EcalGainCollection extends AbstractConditionsObjectCollection<EcalGain> {
+        
+        public AbstractConditionsObjectCollection<EcalGain> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+                
+        class ChannelIdComparator implements Comparator<EcalGain> {
+            public int compare(EcalGain o1, EcalGain o2) {
+                if (o1.getChannelId() < o2.getChannelId()) {
+                    return -1;
+                } else if (o1.getChannelId() > o2.getChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+            
+        }
     }
-
+    
+    
     /**
      * Get the gain value in units of MeV/ADC count.
      * @return The gain value.

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLed.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLed.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLed.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.ecal;
+
+import java.util.Comparator;
 
 import org.hps.conditions.api.AbstractConditionsObject;
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -6,6 +8,7 @@
 import org.hps.conditions.database.Field;
 import org.hps.conditions.database.MultipleCollectionsAction;
 import org.hps.conditions.database.Table;
+import org.hps.conditions.ecal.EcalGain.EcalGainCollection.ChannelIdComparator;
 
 /**
  * A conditions class for representing the setup of the LED system in the ECAL
@@ -20,6 +23,22 @@
      * Generic collection class for these objects.
      */
     public static class EcalLedCollection extends AbstractConditionsObjectCollection<EcalLed> {
+        public AbstractConditionsObjectCollection<EcalLed> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+                
+        class ChannelIdComparator implements Comparator<EcalLed> {
+            public int compare(EcalLed o1, EcalLed o2) {
+                if (o1.getEcalChannelId() < o2.getEcalChannelId()) {
+                    return -1;
+                } else if (o1.getEcalChannelId() > o2.getEcalChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+            
+        }
     }
 
     /**

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLedCalibration.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLedCalibration.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalLedCalibration.java	Wed Mar 25 14:43:27 2015
@@ -15,6 +15,9 @@
      * Generic collection class for these objects.
      */
     public static class EcalLedCalibrationCollection extends AbstractConditionsObjectCollection<EcalLedCalibration> {
+    }
+    
+    public EcalLedCalibration() {        
     }
     
     public EcalLedCalibration(int channelId, double mean, double rms) {

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalTimeShift.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalTimeShift.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/ecal/EcalTimeShift.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,6 @@
 package org.hps.conditions.ecal;
+
+import java.util.Comparator;
 
 import org.hps.conditions.api.AbstractConditionsObject;
 import org.hps.conditions.api.AbstractConditionsObjectCollection;
@@ -6,6 +8,7 @@
 import org.hps.conditions.database.Field;
 import org.hps.conditions.database.MultipleCollectionsAction;
 import org.hps.conditions.database.Table;
+import org.hps.conditions.ecal.EcalCalibration.EcalCalibrationCollection.ChannelIdComparator;
 
 /**
  * This class represents a time shift calibration value for an ECAL channel.
@@ -19,6 +22,21 @@
      * A collection of {@link EcalTimeShift} objects.
      */
     public static class EcalTimeShiftCollection extends AbstractConditionsObjectCollection<EcalTimeShift> {
+        public AbstractConditionsObjectCollection<EcalTimeShift> sorted() {
+            return sorted(new ChannelIdComparator());
+        }
+                
+        class ChannelIdComparator implements Comparator<EcalTimeShift> {
+            public int compare(EcalTimeShift o1, EcalTimeShift o2) {
+                if (o1.getChannelId() < o2.getChannelId()) {
+                    return -1;
+                } else if (o1.getChannelId() > o2.getChannelId()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        }
     }
 
     /**

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtChannel.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtChannel.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtChannel.java	Wed Mar 25 14:43:27 2015
@@ -24,10 +24,10 @@
         Map<Integer, T> channelMap = new HashMap<Integer, T>();
 
         /**
-         * Add a channel of type extending {@link AbstractSvtChannel} to the
-         * channel map
+         *  Add a channel of type extending {@link AbstractSvtChannel} to the
+         *  channel map
          * 
-         * @param A channel of a type extending {@link AbstractSvtChannel}
+         *  @param A channel of a type extending {@link AbstractSvtChannel}
          */
         public boolean add(T channel) {
 
@@ -42,29 +42,29 @@
         }
 
         /**
-         * Find a channel of type extending {@link AbstractSvtChannel} using the
-         * channel ID
+         *  Find a channel of type extending {@link AbstractSvtChannel} using the
+         *  channel ID
          * 
-         * @param channelID
-         * @return An SVT channel of type extending {@link AbstractSvtChannel}
+         *  @param channelID
+         *  @return An SVT channel of type extending {@link AbstractSvtChannel}
          */
         public T findChannel(int channelID) {
             return channelMap.get(channelID);
         }
 
         /**
-         * Find the collection of channels of type extending
-         * {@link AbstractSvtChannel} that match a DAQ pair.
+         *  Find the collection of channels of type extending
+         *  {@link AbstractSvtChannel} that match a DAQ pair.
          * 
-         * @param pair The DAQ pair.
-         * @return The channels matching the DAQ pair or null if not found.
+         *  @param pair The DAQ pair.
+         *  @return The channels matching the DAQ pair or null if not found.
          */
         public abstract Collection<T> find(Pair<Integer, Integer> pair);
 
         /**
-         * Convert this object to a human readable string.
+         *  Convert this object to a human readable string.
          * 
-         * @return This object converted to a string.
+         *  @return This object converted to a string.
          */
         public String toString() {
             StringBuffer buff = new StringBuffer();
@@ -76,9 +76,9 @@
     }
 
     /**
-     * Get the channel ID.
+     *  Get the channel ID.
      * 
-     * @return The channel ID.
+     *  @return The SVT channel ID.
      */
     @Field(names = {"channel_id"})
     public int getChannelID() {
@@ -86,12 +86,30 @@
     }
 
     /**
-     * Get the channel number. This is different from the ID.
+     *  Get the channel number (0-639). This is different from the ID.
      * 
-     * @return The channel number.
+     *  @return The channel number.
      */
     @Field(names = {"channel"})
     public int getChannel() {
         return getFieldValue("channel");
     }
+    
+    /**
+     *  Set the channel ID.
+     * 
+     *  @param channelID : The SVT channel ID
+     */
+    public void setChannelID(int channelID) { 
+        this.setFieldValue("channel_id", channelID);
+    }
+    
+    /**
+     *  Set the channel number (0-639). This is different from the ID.
+     * 
+     *  @param channel : The channel number
+     */
+    public void setChannel(int channel) { 
+        this.setFieldValue("channel", channel);
+    }
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtDaqMapping.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtDaqMapping.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/AbstractSvtDaqMapping.java	Wed Mar 25 14:43:27 2015
@@ -14,8 +14,6 @@
  */
 public abstract class AbstractSvtDaqMapping extends AbstractConditionsObject {
 
-    public static abstract class AbstractSvtDaqMappingCollection<T extends AbstractSvtDaqMapping> extends AbstractConditionsObjectCollection<T> {
-
         /**
          * Flag values for top or bottom half.
          */
@@ -27,6 +25,9 @@
          */
         public static final String AXIAL = "A";
         public static final String STEREO = "S";
+
+        public static abstract class AbstractSvtDaqMappingCollection<T extends AbstractSvtDaqMapping> extends AbstractConditionsObjectCollection<T> {
+
 
         /**
          * Get a DAQ pair for the given {@link HpsSiSensor}
@@ -48,18 +49,68 @@
 
     }
 
+    /**
+     *  Get the SVT half (TOP or BOTTOM) that the sensor belongs to.
+     *  
+     *  @return SVT half (TOP or BOTTOM)
+     */
     @Field(names = {"svt_half"})
     public String getSvtHalf() {
         return getFieldValue("svt_half");
     }
 
+    /**
+     *  Get the SVT sensor layer number (1-10 for test run and 1-12 for
+     *  engineering run).
+     *  
+     *  @return SVT sensor layer number
+     */
     @Field(names = {"layer"})
     public int getLayerNumber() {
         return getFieldValue("layer");
     }
 
+    
+    /**
+     *  Get the orientation of an SVT sensor (AXIAL or STEREO).
+     * 
+     *  @param orientation : Orientation of an SVT sensor (AXIAL or STEREO) 
+     */
     @Field(names = {"orientation"})
     public String getOrientation() {
         return getFieldValue("orientation");
     }
+    
+    /**
+     *  Set the SVT half (TOP or BOTTOM) that the sensor belongs to.
+     *  
+     *   @param svtHalf : SVT half (TOP or BOTTOM)
+     */
+    public void setSvtHalf(String svtHalf) { 
+        if (!svtHalf.equals(AbstractSvtDaqMapping.TOP_HALF) && !svtHalf.equals(AbstractSvtDaqMapping.BOTTOM_HALF)) 
+            throw new RuntimeException("[ " + this.getClass().getSimpleName() + " ]: Invalid value of SVT half.");
+        this.setFieldValue("svt_half", svtHalf);
+        
+    }
+    
+    /**
+     *  Set the SVT sensor layer number (1-10 for test run and 1-12 for
+     *  engineering run).
+     *  
+     *  @param layer : SVT sensor layer number
+     */
+    public void setLayerNumber(int layer) { 
+        this.setFieldValue("layer", layer);
+    }
+    
+    /**
+     *  Set the orientation of an SVT sensor (AXIAL or STEREO).
+     * 
+     *  @param orientation : Orientation of an SVT sensor (AXIAL or STEREO) 
+     */
+    public void setOrientation(String orientation) { 
+        if (!orientation.equals(AbstractSvtDaqMapping.AXIAL) && !orientation.equals(AbstractSvtDaqMapping.STEREO))
+            throw new RuntimeException("[ " + this.getClass().getSimpleName() + " ]: Invalid orientation of sensor.");
+        this.setFieldValue("orientation", orientation);
+    }
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/CalibrationHandler.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/CalibrationHandler.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/CalibrationHandler.java	Wed Mar 25 14:43:27 2015
@@ -1,8 +1,14 @@
 package org.hps.conditions.svt;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import org.xml.sax.helpers.DefaultHandler;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
+
+import org.lcsim.util.log.DefaultLogFormatter;
+import org.lcsim.util.log.LogUtil;
 
 import org.hps.conditions.svt.SvtChannel.SvtChannelCollection;
 import org.hps.conditions.svt.SvtCalibration.SvtCalibrationCollection;
@@ -14,6 +20,11 @@
  *  @author Omar Moreno <[log in to unmask]>
  */
 class CalibrationHandler extends DefaultHandler {
+    
+    
+    // Initialize the logger
+    private static Logger logger = LogUtil.create(SvtConditionsLoader.class.getSimpleName(), 
+            new DefaultLogFormatter(), Level.INFO);
 
     // List of SVT channels
     private SvtChannelCollection svtChannels;
@@ -39,12 +50,17 @@
     // Noise sample ID (0-5)
     int noiseSampleID = 0; 
     
+    // Flag denoting whether the calibrations of a given channel should be
+    // loaded into the conditions DB.  If a channel is found to be missing
+    // baseline or noise values, is will be marked invalid.
+    boolean isValidChannel = false;
+    
     /**
      *  Default Constructor
      */
     public CalibrationHandler() {
-        svtChannels = DatabaseConditionsManager.getInstance()
-                .getSvtConditions().getChannelMap();
+       svtChannels = (SvtChannelCollection) DatabaseConditionsManager.getInstance()
+               .getCachedConditions(SvtChannelCollection.class, "svt_channels").getCachedData();
     }
 
     /**
@@ -63,15 +79,15 @@
         switch (qName) {
             case "Feb":
                 febID = Integer.parseInt(attributes.getValue("id"));
-                System.out.println("FEB ID: " + febID);
                 break;
             case "Hybrid":
                 hybridID = Integer.parseInt(attributes.getValue("id"));
-                System.out.println("Hybrid ID: " + hybridID);
+                logger.info("Processing calibrations for FEB " + febID + " Hybrid " + hybridID);
                 break;
             case "channel":
                 channel = Integer.parseInt(attributes.getValue("id"));
                 calibration = new SvtCalibration(svtChannels.findChannelID(febID, hybridID, channel));
+                isValidChannel = false;
                 break;
             case "baseline":
                 baselineSampleID = Integer.parseInt(attributes.getValue("id"));
@@ -96,13 +112,16 @@
         
         switch (qName) { 
             case "channel":
+                if (!isValidChannel) break;
                 calibrations.add(calibration);
                 break;
             case "baseline":
-                calibration.setPedestal(baselineSampleID, Double.parseDouble(content)); 
+                calibration.setPedestal(baselineSampleID, Double.parseDouble(content));
+                isValidChannel = true;
                 break;
             case "noise": 
                 calibration.setNoise(baselineSampleID, Double.parseDouble(content)); 
+                isValidChannel = true;
                 break;
         }
     }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtChannel.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtChannel.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtChannel.java	Wed Mar 25 14:43:27 2015
@@ -20,12 +20,38 @@
 @Converter(multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED)
 public final class SvtChannel extends AbstractSvtChannel {
 
+    /**
+     * 
+     */
+    public SvtChannel() { 
+    }
+    
+    /**
+     *  Constructor 
+     *
+     *  @param channelID : The SVT channel ID
+     *  @param febID : The Front End Board (FEB) ID (0-9)
+     *  @param febHybridID : The hybrid ID (0-3)
+     *  @param channel : The channel number (0-639)
+     */
+    public SvtChannel(int channelID, int febID, int febHybridID, int channel) { 
+        if (!this.isValidFeb(febID) 
+                || !this.isValidFebHybridID(febHybridID) 
+                || !this.isValidPhysicalChannel(channel)) { 
+            throw new RuntimeException("Invalid FEB ID, FEB hybrid ID or physical channel number is being used.");
+        }
+        this.setChannelID(channelID);
+        this.setFebID(febID);
+        this.setFebHybridID(febHybridID);
+        this.setChannel(channel);
+    }
+    
     public static class SvtChannelCollection extends AbstractSvtChannel.AbstractSvtChannelCollection<SvtChannel> {
         /**
-         * Find channels that match a DAQ pair (FEB ID, FEB Hybrid ID).
+         *  Find channels that match a DAQ pair (FEB ID, FEB Hybrid ID).
          * 
-         * @param pair : The DAQ pair consiting of a FEB ID and FEB Hybrid ID.
-         * @return The channels matching the DAQ pair or null if ?not found.
+         *  @param pair : The DAQ pair consiting of a FEB ID and FEB Hybrid ID.
+         *  @return The channels matching the DAQ pair or null if ?not found.
          */
         @Override
         public Collection<SvtChannel> find(Pair<Integer, Integer> pair) {
@@ -41,13 +67,13 @@
         }
 
         /**
-         * Get the SVT channel ID associated with a given FEB ID/Hybrid ID/physical channel.
+         *  Get the SVT channel ID associated with a given FEB ID/Hybrid ID/physical channel.
          *
-         * @param febID : The FEB ID
-         * @param febHybridID : The FEB hybrid ID
-         * @param channel : The physical channel number
-         * @return The SVT channel ID
-         * @throws {@link RuntimeException} if the channel ID can't be found
+         *  @param febID : The FEB ID
+         *  @param febHybridID : The FEB hybrid ID
+         *  @param channel : The physical channel number
+         *  @return The SVT channel ID
+         *  @throws {@link RuntimeException} if the channel ID can't be found
          */
         public int findChannelID(int febID, int febHybridID, int channel) {
             for (SvtChannel svtChannel : this) {
@@ -61,9 +87,9 @@
     }
 
     /**
-     * Get the FEB ID associated with this SVT channel ID.
+     *  Get the FEB ID associated with this SVT channel ID.
      * 
-     * @return The FEB ID.
+     *  @return The FEB ID.
      */
     @Field(names = { "feb_id" })
     public int getFebID() {
@@ -71,9 +97,9 @@
     }
 
     /**
-     * Get the FEB hybrid ID associated with this SVT channel ID.
+     *  Get the FEB hybrid ID associated with this SVT channel ID.
      * 
-     * @return The FEB hybrid ID.
+     *  @return The FEB hybrid ID.
      */
     @Field(names = { "feb_hybrid_id" })
     public int getFebHybridID() {
@@ -81,8 +107,58 @@
     }
 
     /**
-     * Implementation of equals.
-     * @return True if the object equals this one; false if not.
+     *  Set the FEB ID associated with this SVT channel ID.
+     * 
+     *  @param febID : The FEB ID
+     */
+    public void setFebID(int febID) { 
+        this.setFieldValue("feb_id", febID);
+    }
+    
+    /**
+     *  Set the FEB hybrid ID associated with this SVT channel ID.
+     * 
+     *  @param febHybridID : The FEB hybrid ID
+     */
+    public void setFebHybridID(int febHybridID) {
+        this.setFieldValue("feb_hybrid_id", febHybridID);
+    }
+    
+    /**
+     *  Checks if a FEB ID is valid
+     * 
+     *  @param febID : The Front End Board (FEB) ID
+     *  @return True if the FEB ID lies within the range 0-9, false otherwise
+     */
+    public boolean isValidFeb(int febID) { 
+        return (febID >= 0 && febID <= 9) ? true : false; 
+    }
+    
+    /**
+     *  Checks if a Front End Board hybrid ID is valid
+     *  
+     *  @param febHybridID : The hybrid ID 
+     *  @return True if the hybrid ID lies within the range 0-3, false otherwise
+     */
+    public boolean isValidFebHybridID(int febHybridID) { 
+        return (febHybridID >= 0 && febHybridID <= 3) ? true : false; 
+    }
+    
+    /**
+     *  Checks if a physical channel number is valid
+     *  
+     *  @param channel : The physical channel number
+     *  @return True if the channel number lies within the range 0-639, false 
+     *          otherwise
+     */
+    public boolean isValidPhysicalChannel(int channel) { 
+        return (channel >= 0 && channel <= 639) ? true : false; 
+    }
+    
+    /**
+     *  Implementation of equals.
+     *  
+     *  @return True if the object equals this one; false if not.
      */
     public boolean equals(Object o) {
         if (o == null)

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDaqMapping.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDaqMapping.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDaqMapping.java	Wed Mar 25 14:43:27 2015
@@ -14,9 +14,32 @@
  * @author Omar Moreno <[log in to unmask]>
  */
 @Table(names = {"svt_daq_map"})
-@Converter(multipleCollectionsAction = MultipleCollectionsAction.ERROR)
+@Converter(multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED)
 public class SvtDaqMapping extends AbstractSvtDaqMapping {
+    
+    /**
+     *  Constants describing the side of a sensor
+     */
+    public static final String ELECTRON = "ELECTRON";
+    public static final String POSITRON = "POSITRON";
 
+    /**
+     *  Default Constructor 
+     */
+    public SvtDaqMapping() { 
+    }
+   
+    /**
+     *  Constructor 
+     *
+     *  @param febID : The Front End Board (FEB) ID (0-9)
+     *  @param febHybridID : The FEB hybrid ID (0-3)
+     */
+    public SvtDaqMapping(int febID, int febHybridID) { 
+        this.setFebID(febID);
+        this.setFebHybridID(febHybridID);
+    }
+    
     public static class SvtDaqMappingCollection extends AbstractSvtDaqMappingCollection<SvtDaqMapping> {
 
         /**
@@ -100,18 +123,62 @@
         }
     }
 
+    /**
+     *  Get the Front End Board (FEB) ID.
+     *
+     *  @return The FEB ID
+     */
     @Field(names = {"feb_id"})
     public int getFebID() {
         return getFieldValue("feb_id");
     }
 
+    /**
+     *  Get the Front End Board (FEB) hybrid ID.
+     *  
+     *  @param The FEB hybrid ID
+     */
     @Field(names = {"feb_hybrid_id"})
     public int getFebHybridID() {
         return getFieldValue("feb_hybrid_id");
     }
 
+    /**
+     *  Get the side of the sensor (ELECTRON or POSITRON).
+     *  
+     *  @param sensor side (ELECTRON or POSITRON)
+     */
     @Field(names = {"side"})
     public String getSide() {
         return getFieldValue("side");
     }
+    
+    /**
+     *  Set the Front End Board (FEB) ID.
+     *  
+     *  @param febID : FEB ID
+     */
+    public void setFebID(int febID) { 
+        this.setFieldValue("feb_id", febID);
+    }
+    
+    /**
+     *  Set the Front End Board (FEB) hybrid ID.
+     *  
+     *  @param febHybridID : FEB hybrid ID
+     */
+    public void setFebHybridID(int febHybridID) { 
+        this.setFieldValue("feb_hybrid_id", febHybridID);
+    }
+    
+    /**
+     *  Set the side of the sensor (ELECTRON or POSITRON).
+     *  
+     *  @param side : sensor side (ELECTRON or POSITRON)
+     */
+    public void setSide(String side) {
+        if (!side.equals(SvtDaqMapping.ELECTRON) && !side.equals(SvtDaqMapping.POSITRON)) 
+            throw new RuntimeException("[ " + this.getClass().getSimpleName() + " ]: Invalid value for sensor side.");
+        this.setFieldValue("side", side);
+    }
 }

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDetectorSetup.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDetectorSetup.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/SvtDetectorSetup.java	Wed Mar 25 14:43:27 2015
@@ -112,9 +112,9 @@
 
             // Set the orientation of the sensor
             String orientation = daqMap.getOrientation(daqPair);
-            if (orientation != null && orientation.contentEquals(SvtDaqMappingCollection.AXIAL)) {
+            if (orientation != null && orientation.contentEquals(SvtDaqMapping.AXIAL)) {
                 sensor.setAxial(true);
-            } else if (orientation != null && orientation.contains(SvtDaqMappingCollection.STEREO)) {
+            } else if (orientation != null && orientation.contains(SvtDaqMapping.STEREO)) {
                 sensor.setStereo(true);
             }
 
@@ -194,9 +194,9 @@
 
             // Set the orientation of the sensor
             String orientation = daqMap.getOrientation(daqPair);
-            if (orientation != null && orientation.contentEquals(TestRunSvtDaqMappingCollection.AXIAL)) {
+            if (orientation != null && orientation.contentEquals(TestRunSvtDaqMapping.AXIAL)) {
                 sensor.setAxial(true);
-            } else if (orientation != null && orientation.contains(TestRunSvtDaqMappingCollection.STEREO)) {
+            } else if (orientation != null && orientation.contains(TestRunSvtDaqMapping.STEREO)) {
                 sensor.setStereo(true);
             }
 

Modified: java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/TestRunSvtChannel.java
 =============================================================================
--- java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/TestRunSvtChannel.java	(original)
+++ java/branches/prod/conditions/src/main/java/org/hps/conditions/svt/TestRunSvtChannel.java	Wed Mar 25 14:43:27 2015
@@ -11,7 +11,7 @@
 import org.hps.util.Pair;
 
 @Table(names = {"test_run_svt_channels"})
-@Converter(multipleCollectionsAction = MultipleCollectionsAction.ERROR)
+@Converter(multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED)
 public final class TestRunSvtChannel extends AbstractSvtChannel {
 
     public static class TestRunSvtChannelCollection extends AbstractSvtChannel.AbstractSvtChannelCollection<TestRunSvtChannel> {

Modified: java/branches/prod/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java
 =============================================================================
--- java/branches/prod/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java	(original)
+++ java/branches/prod/conditions/src/test/java/org/hps/conditions/EngRunConditionsTest.java	Wed Mar 25 14:43:27 2015
@@ -109,7 +109,7 @@
             
             ecalConditions = conditionsManager.getCachedConditions(EcalConditions.class, "ecal_conditions").getCachedData();
             Set<EcalChannelConstants> channelConstants = new LinkedHashSet<EcalChannelConstants>();
-            for (EcalChannel channel : ecalConditions.getChannelCollection().sortedByChannelId()) {
+            for (EcalChannel channel : ecalConditions.getChannelCollection().sorted()) {
                 channelConstants.add(ecalConditions.getChannelConstants(channel));
             }
             assertEquals("Wrong number of channel constants.", nChannels, channelConstants.size());

Modified: java/branches/prod/detector-data/detectors/HPS-ECalCommissioning-v2/detector.properties
 =============================================================================
--- java/branches/prod/detector-data/detectors/HPS-ECalCommissioning-v2/detector.properties	(original)
+++ java/branches/prod/detector-data/detectors/HPS-ECalCommissioning-v2/detector.properties	Wed Mar 25 14:43:27 2015
@@ -1 +1 @@
-name: HPS-ECalCommissioning-v3
+name: HPS-ECalCommissioning-v2

Modified: java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java
 =============================================================================
--- java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java	(original)
+++ java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCEcalReadoutDriver.java	Wed Mar 25 14:43:27 2015
@@ -92,9 +92,16 @@
     private double fixedGain = -1;
     private boolean constantTriggerWindow = true;
     private boolean addNoise = false;
-    private double pePerMeV = 2.0; //photoelectrons per MeV, used to calculate noise
+   
+    // 32.8 p.e./MeV = New detector in 2014
+    // 2 p.e./MeV = Test Run detector
+    private double pePerMeV = 32.8; //photoelectrons per MeV, used to calculate noise
+    
     //switch between test run and 2014 definitions of gain constants
-    private boolean use2014Gain = true;
+    // true = ONLY simulation studies in 2014
+    // false = Test Run data/simulations and 2014+ Detector's real data 
+    private boolean use2014Gain = false;
+    
     //switch between three pulse shape functions
     private PulseShape pulseShape = PulseShape.ThreePole;
 
@@ -448,9 +455,11 @@
                 //add preamp noise and photoelectron Poisson noise in quadrature
                 double noise;
                 if (use2014Gain) {
-                    noise = Math.sqrt(Math.pow(channelData.getCalibration().getNoise() * channelData.getGain().getGain() * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod, 2) + hit.getRawEnergy() / (ECalUtils.lightYield * ECalUtils.quantumEff * ECalUtils.surfRatio));
+                    noise = Math.sqrt(Math.pow(channelData.getCalibration().getNoise() * channelData.getGain().getGain() * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod, 2) 
+                    		+ hit.getRawEnergy() / (ECalUtils.lightYield * ECalUtils.quantumEff * ECalUtils.surfRatio));
                 } else {
-                    noise = Math.sqrt(Math.pow(channelData.getCalibration().getNoise() * channelData.getGain().getGain() * ECalUtils.MeV, 2) + hit.getRawEnergy() * ECalUtils.MeV / pePerMeV);
+                    noise = Math.sqrt(Math.pow(channelData.getCalibration().getNoise() * channelData.getGain().getGain() * ECalUtils.MeV, 2) 
+                    		+ hit.getRawEnergy() * ECalUtils.MeV / pePerMeV);
                 }
                 energyAmplitude += RandomGaussian.getGaussian(0, noise);
             }

Modified: java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCPrimaryTriggerDriver.java
 =============================================================================
--- java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCPrimaryTriggerDriver.java	(original)
+++ java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/FADCPrimaryTriggerDriver.java	Wed Mar 25 14:43:27 2015
@@ -9,6 +9,7 @@
 import java.util.Queue;
 
 import org.hps.recon.ecal.ECalUtils;
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.util.aida.AIDA;
@@ -703,4 +704,14 @@
         topClusterQueue.remove();
         botClusterQueue.remove();
     }
+    
+    /**
+     * Sets all cut values for the trigger using a string argument with
+     * the format "clusterMin clusterMax hitMin sumMin sumMax diffMax
+     * slopeMin slopeF coplanarMax timeDiffMax".
+     * @param cuts - The cut string.
+     */
+    public void setCuts(String cuts) {
+    	triggerModule.setCutValues(false, cuts);
+    }
 }

Modified: java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/SinglesTriggerDriver.java
 =============================================================================
--- java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/SinglesTriggerDriver.java	(original)
+++ java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/SinglesTriggerDriver.java	Wed Mar 25 14:43:27 2015
@@ -5,6 +5,7 @@
 
 import java.util.List;
 
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 import org.lcsim.util.aida.AIDA;
@@ -21,8 +22,7 @@
  */
 public class SinglesTriggerDriver extends TriggerDriver {
     // Cut Values
-    private TriggerModule triggerModule = new TriggerModule(2.0, 0.125,
-    		6.600, 0.200, 6.600, 0.000, 13.200, 6.600, 0.0, 360, 0.0055);
+    private TriggerModule triggerModule = new TriggerModule();
     
     // LCIO Collection Names
     private String clusterCollectionName = "EcalClusters";
@@ -69,6 +69,9 @@
      */
     @Override
     protected boolean triggerDecision(EventHeader event) {
+    	// Track whether triggering cluster was seen.
+    	boolean passTrigger = false;
+    	
         // Check that there is a cluster object collection.
         if(event.hasCollection(Cluster.class, clusterCollectionName)) {
             // Get the list of hits.
@@ -92,6 +95,9 @@
                     continue triggerLoop;
                 }
                 
+                // A trigger was seen. Note it.
+                passTrigger = true;
+                
                 // Get the x and y indices.
                 int ix = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
                 int iy = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
@@ -105,9 +111,8 @@
             }
         }
         
-        // If there were either no passing hits or not hits at all,
-        // then there is also no trigger.
-        return false;
+        // Return whether a triggering cluster was seen.
+        return passTrigger;
     }
     
     /**
@@ -162,4 +167,13 @@
     public void setClusterCollectionName(String clusterCollectionName) {
         this.clusterCollectionName = clusterCollectionName;
     }
+    
+    /**
+     * Sets all cut values for the trigger using a string argument with
+     * the format "Emin Emax Nmin".
+     * @param cuts - The cut string.
+     */
+    public void setCuts(String cuts) {
+    	triggerModule.setCutValues(true, cuts);
+    }
 }

Modified: java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TestRunTriggerDriver.java
 =============================================================================
--- java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TestRunTriggerDriver.java	(original)
+++ java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TestRunTriggerDriver.java	Wed Mar 25 14:43:27 2015
@@ -2,7 +2,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
 

Modified: java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TriggerDriver.java
 =============================================================================
--- java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TriggerDriver.java	(original)
+++ java/branches/prod/ecal-readout-sim/src/main/java/org/hps/readout/ecal/TriggerDriver.java	Wed Mar 25 14:43:27 2015
@@ -9,8 +9,8 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
-
+
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.lcsim.event.EventHeader;
 import org.lcsim.lcio.LCIOWriter;
 

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalPedestalCalculator.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalPedestalCalculator.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalPedestalCalculator.java	Wed Mar 25 14:43:27 2015
@@ -7,6 +7,8 @@
 import java.io.IOException;
 import java.sql.SQLException;
 import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 import org.hps.conditions.api.ConditionsObjectException;
 import org.hps.conditions.api.ConditionsRecord;
@@ -90,22 +92,31 @@
         userInput=cc.readLine("Enter filename prefix, or just press RETURN ...");
         if (userInput==null || userInput.length()==0 || userInput=="") {
             String home=System.getenv().get("HOME");
-            outputFilePrefix = home+"/EcalPedestalCalculator_"+runNumber+"_";
+            outputFilePrefix = home+"/EcalPedestals/EcalPedestalCalculator_"+runNumber+"_";
         } else {
             outputFilePrefix = userInput;
         }
+        
+        String date = new SimpleDateFormat("yyyy-MM-dd-hh-mm").format(new Date());
+        outputFilePrefix += date+"_";
 
         if (writeFileForDAQ) writeFileForDAQ(outputFilePrefix);
         if (writeFileForDB)  writeFileForDB(outputFilePrefix);
         
-        System.err.println("\n\n***************************************************************\n");
+        System.out.println("\n\n***************************************************************\n");
         userInput=cc.readLine(String.format("Enter 'YES' to write conditions database for run range [%s,%s] ...",runNumber,runNumberMax));
         System.out.println("***********"+userInput+"********");
+        boolean uploadToDB=false;
         if (userInput!=null && userInput.equals("YES")) {
             userInput=cc.readLine("Really?");
             if (userInput!=null && userInput.equals("YES")) {
-                uploadToDB();
-            }
+                uploadToDB=true;
+            }
+        }
+        if (uploadToDB) {
+            uploadToDB();
+        } else {
+            System.out.println("!!!!!!!!!!!!!!!!!!!!!!! Not Writing Database !!!!!!!!!!!!!!!!!!!!!!!!!!");
         }
     }
 

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverter.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverter.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverter.java	Wed Mar 25 14:43:27 2015
@@ -1,6 +1,7 @@
 package org.hps.recon.ecal;
 
-import java.awt.List;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.util.ArrayList;
 import java.util.Map;
 
@@ -8,6 +9,8 @@
 import org.hps.conditions.ecal.EcalChannel;
 import org.hps.conditions.ecal.EcalChannelConstants;
 import org.hps.conditions.ecal.EcalConditions;
+import org.hps.recon.ecal.daqconfig.ConfigurationManager;
+import org.hps.recon.ecal.daqconfig.FADCConfig;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;
@@ -22,10 +25,8 @@
  * objects with energy information.
  *
  * @author Sho Uemura <[log in to unmask]>
- * @author Jeremy McCormick <[log in to unmask]>
  * @author Andrea Celentano <[log in to unmask]>
  * @author Nathan Baltzell <[log in to unmask]>
- *
  *
  * baltzell:  New in 2015:  (default behavior is still unchanged)
  *
@@ -36,9 +37,6 @@
  * 
  * Pedestal subtracting clipped pulses more correctly for all Modes.
  * 
- * Changed threshold cut for Mode-1 to >= instead of > to emulate SSP instead of
- * FADC firmware for trigger diagnostics.
- *
  * Implemented finding multiple peaks for Mode-1.
  * 
  * Implemented conversion of Mode-1 to Mode-7 with high-resolution timing.
@@ -53,6 +51,8 @@
     private boolean constantGain = false;
     private double gain;
     private boolean use2014Gain = true;
+    private boolean useDAQConfig = false;
+    private FADCConfig config = null;
 
     /*
      * The time for one FADC sample (units = ns).
@@ -66,7 +66,7 @@
      * 
      * The default value of 12 is what we used for most of the 2014 run.
      */
-    private double leadingEdgeThreshold=12;
+    private double leadingEdgeThreshold = 12;
     
     /*
      * Integration range after (NSA) and before (NSB) threshold crossing.  Units=ns,
@@ -75,8 +75,8 @@
      * 
      * The default values of 20/100 are what we had during the entire 2014 run.
      */
-    private int NSB=20;
-    private int NSA=100;
+    private int NSB = 20;
+    private int NSA = 100;
   
     /*
      * The number of samples in the FADC readout window.  Needed in order to
@@ -87,48 +87,89 @@
      * the old behavior which assumed integration range was constant.
      * 
      */
-    private int windowSamples=-1;
+    private int windowSamples = -1;
     
     /*
      * The maximum number of peaks to be searched for.
      */
-    private int nPeak=3;
+    private int nPeak = 3;
    
     /*
      * Convert Mode-1 into Mode-7, else Mode-3.
      */
-    private boolean mode7=false;
+    private boolean mode7 = false;
 
 
     private EcalConditions ecalConditions = null;
 
     public EcalRawConverter() {
-    }
-
+    	// Track changes in the DAQ configuration.
+    	ConfigurationManager.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				// If the DAQ configuration should be used, load the
+				// relevant settings into the driver.
+				if(useDAQConfig) {
+					// Get the FADC configuration.
+					config = ConfigurationManager.getInstance().getFADCConfig();
+					
+					// Load the settings.
+					NSB = config.getNSB();
+					NSA = config.getNSA();
+					windowSamples = config.getWindowWidth() / 4;
+					
+					// Get the number of peaks.
+					if(config.getMode() == 1) {
+						nPeak = Integer.MAX_VALUE;
+					} else {
+						nPeak = config.getMaxPulses();
+					}
+					
+					// Print the FADC configuration.
+					System.out.println();
+					System.out.println();
+					System.out.printf("NSA            :: %d ns%n", NSA);
+					System.out.printf("NSB            :: %d ns%n", NSB);
+					System.out.printf("Window Samples :: %d clock-cycles%n", windowSamples);
+					System.out.printf("Max Peaks      :: %d peaks%n", nPeak);
+					System.out.println("======================================================================");
+					System.out.println("=== FADC Pulse-Processing Settings ===================================");
+					System.out.println("======================================================================");
+					config.printConfig();
+				}
+			}
+    	});
+    }
+  
     public void setLeadingEdgeThreshold(double thresh) {
         leadingEdgeThreshold=thresh;
     }
+    
     public void setNSA(int nsa) {
         if (NSA%nsPerSample !=0 || NSA<0) {
             throw new RuntimeException("NSA must be multiples of 4ns and non-negative.");
         }
         NSA=nsa;
     }
+    
     public void setNSB(int nsb) {
         if (NSB%nsPerSample !=0 || NSB<0) {
             throw new RuntimeException("NSB must be multiples of 4ns and non-negative.");
         }
         NSB=nsb;
     }
+    
     public void setWindowSamples(int windowSamples) {
         this.windowSamples=windowSamples;
     }
+    
     public void setNPeak(int nPeak) {
         if (nPeak<1 || nPeak>3) {
             throw new RuntimeException("Npeak must be 1, 2, or 3.");
         }
         this.nPeak=nPeak;
     }
+    
     public void setMode7(boolean mode7)
     {
         this.mode7=mode7;
@@ -150,13 +191,24 @@
     public void setUseTimeWalkCorrection(boolean useTimeWalkCorrection) {
         this.useTimeWalkCorrection=useTimeWalkCorrection;
     }
+    
+    public void setUseDAQConfig(boolean state) {
+    	useDAQConfig = state;
+    }
 
     /*
      * This should probably be deprecated.  It just integrates the entire window.
      */
     public int sumADC(RawTrackerHit hit) {
         EcalChannelConstants channelData = findChannel(hit.getCellID());
-        double pedestal = channelData.getCalibration().getPedestal();
+        double pedestal;
+        if(useDAQConfig) {
+    		//EcalChannel channel = ecalConditions.getChannelCollection().findGeometric(hit.getCellID());
+    		pedestal = config.getPedestal(hit.getCellID());
+        } else {
+        	pedestal = channelData.getCalibration().getPedestal();
+        }
+        
         int sum = 0;
         short samples[] = hit.getADCValues();
         for (int isample = 0; isample < samples.length; ++isample) {
@@ -182,11 +234,13 @@
      * Choose whether to use static pedestal from database or running pedestal from mode-7.
      */
     public double getSingleSamplePedestal(EventHeader event,long cellID) {
+    	if(useDAQConfig) {
+    		//EcalChannel channel = ecalConditions.getChannelCollection().findGeometric(cellID);
+    		return config.getPedestal(cellID);
+    	}
         if (useRunningPedestal && event!=null) {
             if (event.hasItem("EcalRunningPedestals")) {
-                Map<EcalChannel, Double> runningPedMap=
-                        (Map<EcalChannel, Double>)
-                        event.get("EcalRunningPedestals");
+                Map<EcalChannel, Double> runningPedMap = (Map<EcalChannel, Double>) event.get("EcalRunningPedestals");
                 EcalChannel chan = ecalConditions.getChannelCollection().findGeometric(cellID);
                 if (!runningPedMap.containsKey(chan)){
                     System.err.println("************** Missing Pedestal");
@@ -228,7 +282,7 @@
    
     
     /*
-     * Emulate the FADC250 firmware emulation Mode-1 waveform to a Mode-3/7 pulse,
+     * Emulate the FADC250 firmware in conversion of Mode-1 waveform to a Mode-3/7 pulse,
      * given a time for threshold crossing.
      */
     public double[] convertWaveformToPulse(RawTrackerHit hit,int thresholdCrossing,boolean mode7) {
@@ -245,12 +299,17 @@
             lastSample  = thresholdCrossing + NSA/nsPerSample - 1;
         }
         
-        // mode-7 min and max:
+        // mode-7's minimum/pedestal (average of first 4 samples):
         double minADC=0;
+        for (int jj=0; jj<4; jj++) minADC += samples[jj];
+        // does the firmware's conversion of min to int occur before or after time calculation?  undocumented.
+        minADC=(int)(minADC/4); 
+        
+        // mode-7's max pulse height:
         double maxADC=0;
         int sampleMaxADC=0;
         
-        // pulse integral:
+        // mode-3/7's pulse integral:
         short sumADC = 0;
         
         for (int jj=firstSample; jj<=lastSample; jj++) {
@@ -261,11 +320,8 @@
             // integrate pulse:
             sumADC += samples[jj];
            
-            // compute "minimum" at beginning of window:
-            if (jj<4) minADC+=samples[jj];
-          
             // find pulse maximum:
-            if (jj>firstSample && jj<samples.length-5) {
+            if (jj>firstSample && jj<samples.length-5) { // The "5" here is a firmware constant.
                 if (samples[jj+1]<samples[jj]) {
                     sampleMaxADC=jj;
                     maxADC=samples[jj];
@@ -273,15 +329,13 @@
             }
         }
        
-        // minADC is the average of first four samples:
-        minADC/=4;
-      
         // pulse time with 4ns resolution:
         double pulseTime=thresholdCrossing*nsPerSample;
         
         // calculate Mode-7 high-resolution time:
         if (mode7) {
             if (thresholdCrossing < 4) {
+                // special case where firmware sets max to zero and time to 4ns time.
                 maxADC=0;
             }
             else if (maxADC>0) {
@@ -293,10 +347,12 @@
                 double a1 = maxADC;
                 double slope = (a1-a0)/(t1-t0);
                 double halfMax = (maxADC+minADC)/2;
+                // this is not rigorously firmware-correct, need to find halfMax-crossing.
                 double tmpTime = t1 - (a1 - halfMax) / slope;
                 if (slope>0 && tmpTime>0) {
                     pulseTime = tmpTime;
                 }
+                // else another special firmware case
             }
         }
         
@@ -317,55 +373,64 @@
      * TODO: Generate GenericObject (and corresponding LCRelation) to store min and max
      * to fully emulate mode-7.  This is less important for now.
      *
-     * NOTE: March 7, 2015. Threshold crossing requirement currently emulates the current
-     * SSP firmware (>=) instead of FADC firmware (>) to aid trigger studies.  Firmware will
-     * be changed to make them identical.  But for now this code prefers SSP over FADC.
-     */
-    public ArrayList <CalorimeterHit> HitDtoA(EventHeader event,RawTrackerHit hit) {
-     
+     */
+    public ArrayList <CalorimeterHit> HitDtoA(EventHeader event, RawTrackerHit hit) {
         final long cellID = hit.getCellID();
         final short samples[] = hit.getADCValues();
-        if (samples.length==0) return null;
+        if(samples.length == 0) return null;
         
         // threshold is pedestal plus threshold configuration parameter:
-        final int absoluteThreshold = (int)(getSingleSamplePedestal(event,cellID)+leadingEdgeThreshold);
-       
+        final int absoluteThreshold;
+        if(useDAQConfig) {
+        	//EcalChannel channel = ecalConditions.getChannelCollection().findGeometric(hit.getCellID());
+        	//int leadingEdgeThreshold = ConfigurationManager.getInstance().getFADCConfig().getThreshold(channel.getChannelId());
+        	int leadingEdgeThreshold = config.getThreshold(cellID);
+        	absoluteThreshold = (int) (getSingleSamplePedestal(event, cellID) + leadingEdgeThreshold);
+        } else {
+        	absoluteThreshold = (int) (getSingleSamplePedestal(event, cellID) + leadingEdgeThreshold);
+        }
+        
         ArrayList <Integer> thresholdCrossings = new ArrayList<Integer>();
         
         // special case, first sample is above threshold:
-        if (samples[0] >= absoluteThreshold) { // SSP/FADC firmware discrepancy.
+        if (samples[0] > absoluteThreshold) {
             thresholdCrossings.add(0);
         } 
-
+        
         // search for threshold crossings:
-        for (int ii = 1; ii < samples.length; ++ii) {
-            if ( samples[ii]   >=  absoluteThreshold &&
-                 samples[ii-1] <   absoluteThreshold) // SSP/FADC firmware discrepancy.
-            {
+        for(int ii = 1; ii < samples.length; ++ii) {
+            if ( samples[ii]   >  absoluteThreshold && 
+                 samples[ii-1] <= absoluteThreshold) {
+                
                 // found one:
                 thresholdCrossings.add(ii);
 
                 // search for next threshold crossing begins at end of this pulse:
-                ii += NSA/nsPerSample-1; 
+                if(useDAQConfig && ConfigurationManager.getInstance().getFADCConfig().getMode() == 1) {
+                    // special case, emulating SSP:
+                	ii += 8;
+                } else {
+                    // "normal" case, emulating FADC250:
+                	ii += NSA/nsPerSample - 1;
+                }
 
                 // firmware limit on # of peaks:
                 if (thresholdCrossings.size() >= nPeak) break;
             }
         }
-
+        
         // make hits
-        ArrayList <CalorimeterHit> newHits=new ArrayList<CalorimeterHit>();
-        for (int thresholdCrossing : thresholdCrossings) {
-           
+        ArrayList <CalorimeterHit> newHits = new ArrayList<CalorimeterHit>();
+        for(int thresholdCrossing : thresholdCrossings) {
             // do pulse integral:
-            final double[] data = convertWaveformToPulse(hit,thresholdCrossing,mode7);
+            final double[] data = convertWaveformToPulse(hit, thresholdCrossing, mode7);
             double time = data[0];
             double sum = data[1];
             final double min = data[2]; // TODO: stick min and max in a GenericObject with an 
             final double max = data[3]; // LCRelation to finish mode-7 emulation
             
             // do pedestal subtraction:
-            sum -= getPulsePedestal(event,cellID,samples.length,thresholdCrossing);
+            sum -= getPulsePedestal(event, cellID, samples.length, thresholdCrossing);
           
             // do gain scaling:
             double energy = adcToEnergy(sum, cellID);
@@ -421,7 +486,7 @@
         // Get the channel data.
         EcalChannelConstants channelData = findChannel(id);
         int amplitude;
-        double pedestal = getPulsePedestal(null,id,windowSamples,(int)hit.getTime()/nsPerSample);
+        double pedestal = getPulsePedestal(null, id, windowSamples, (int) hit.getTime() / nsPerSample);
         if (constantGain) {
             amplitude = (int) Math.round((hit.getRawEnergy() / ECalUtils.MeV) / gain + pedestal);
         } else {
@@ -438,15 +503,18 @@
 
         // Get the channel data.
         EcalChannelConstants channelData = findChannel(cellID);
-
-        if (use2014Gain) {
+        
+        if(useDAQConfig) {
+        	//float gain = ConfigurationManager.getInstance().getFADCConfig().getGain(ecalConditions.getChannelCollection().findGeometric(cellID));
+        	return config.getGain(cellID) * adcSum * ECalUtils.MeV;
+        }  else if(use2014Gain) {
             if (constantGain) {
                 return adcSum * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod;
             } else {
                 return channelData.getGain().getGain() * adcSum * ECalUtils.gainFactor * ECalUtils.ecalReadoutPeriod; // should not be used for the moment (2014/02)
             }
         } else {
-            if (constantGain) {
+            if(constantGain) {
                 return gain * adcSum * ECalUtils.MeV;
             } else {
                 return channelData.getGain().getGain() * adcSum * ECalUtils.MeV; //gain is defined as MeV/integrated ADC

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverterDriver.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverterDriver.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/EcalRawConverterDriver.java	Wed Mar 25 14:43:27 2015
@@ -6,6 +6,7 @@
 import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.conditions.ecal.EcalChannelConstants;
 import org.hps.conditions.ecal.EcalConditions;
+import org.hps.recon.ecal.daqconfig.ConfigurationManager;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;
@@ -17,10 +18,6 @@
 import org.lcsim.util.Driver;
 
 /**
- *
- * @version $Id: HPSEcalRawConverterDriver.java,v 1.2 2012/05/03 00:17:54
- * phansson Exp $
- * baltzell
  * 
  * 
  * baltzell New in 2015:  (default behavior is unchanged)
@@ -52,6 +49,7 @@
     private boolean runBackwards = false;
     private boolean useTimestamps = false;
     private boolean useTruthTime = false;
+    private boolean useDAQConfig = false;
 
     private boolean emulateFirmware = false;
     
@@ -59,77 +57,243 @@
         converter = new EcalRawConverter();
     }
 
+    /**
+     * Set to <code>true</code> to use "2014" gain formula:<br/>
+     * <pre>channelGain * adcSum * gainFactor * readoutPeriod</pre>
+     * <p>
+     * This formula is deprecated and should generally not be used. 
+     * 
+     * @param use2014Gain True to use 2014 gain formulation.
+     */
     public void setUse2014Gain(boolean use2014Gain) {
         converter.setUse2014Gain(use2014Gain);
     }
 
+    /**
+     * Set to <code>true</code> to apply time walk correction from {@link EcalTimeWalk#correctTimeWalk(double, double)}.
+     * <p>
+     * This is only applicable to Mode-3 data.
+     * 
+     * @param useTimeWalkCorrection True to apply time walk correction.
+     */
     public void setUseTimeWalkCorrection(boolean useTimeWalkCorrection) {
         converter.setUseTimeWalkCorrection(useTimeWalkCorrection);
     }
+    
+    /**
+     * Set to <code>true</code> to use a running pedestal calibration from mode 7 data.
+     * <p>
+     * The running pedestal values are retrieved from the event collection "EcalRunningPedestals"
+     * which is a <code>Map</code> between {@link org.hps.conditions.ecal.EcalChannel} objects
+     * are their average pedestal.
+     * 
+     * @param useRunningPedestal True to use a running pedestal value.
+     */
     public void setUseRunningPedestal(boolean useRunningPedestal) {
         converter.setUseRunningPedestal(useRunningPedestal);
     }
 
+    /**
+     * Set to <code>true</code> to generate a {@link org.lcsim.event.CalorimeterHit} 
+     * collection which is a conversion from energy to raw signals.
+     * 
+     * @param runBackwards True to run the procedure backwards.
+     */
     public void setRunBackwards(boolean runBackwards) {
         this.runBackwards = runBackwards;
     }
 
+    /**
+     * Set to <code>true</code> to drop hits that are mapped to a hard-coded 
+     * bad FADC configuration from the Test Run.
+     * 
+     * @param dropBadFADC True to drop hits mapped to a bad FADC.
+     */
     public void setDropBadFADC(boolean dropBadFADC) {
         this.dropBadFADC = dropBadFADC;
     }
 
+    /**
+     * Set a minimum energy threshold in GeV for created {@link org.lcsim.event.CalorimeterHit}
+     * objects to be written into the output collection.
+     * @param threshold The minimum energy threshold in GeV.
+     */
     public void setThreshold(double threshold) {
         this.threshold = threshold;
     }
 
+    /**
+     * Set to <code>true</code> to use Mode-7 emulation in calculations.
+     * False is Mode-3.
+     * 
+     * @param mode7 True to use Mode-7 emulation in calculations.
+     */
     public void setEmulateMode7(boolean mode7) {
         converter.setMode7(mode7);
     }
+    
+    /**
+     * Set to <code>true</code> to emulate firmware conversion of Mode-1 to Mode-3/7 data.
+     * 
+     * @param emulateFirmware True to use firmware emulation.
+     */
     public void setEmulateFirmware(boolean emulateFirmware) {
         this.emulateFirmware = emulateFirmware;
     }
+    
+    /**
+     * Set the leading-edge threshold in ADC counts, relative to pedestal, for pulse-finding 
+     * and time determination.
+     * <p>
+     * Used to convert Mode-1 readout into Mode-3 or Mode-7 data that is usable by clustering.
+     * 
+     * @param threshold The leading edge threshold in ADC counts.
+     */
     public void setLeadingEdgeThreshold(double threshold) {
         converter.setLeadingEdgeThreshold(threshold);
     }
+    
+    /**
+     * Set the number of samples in the FADC readout window.
+     * <p>
+     * This is needed in order to properly pedestal-correct clipped pulses for mode-3 and mode-7.  
+     * It is ignored for mode-1 input, since this data already includes the number of samples.
+     * <p>
+     * A non-positive number disables pulse-clipped pedestals and reverts to the old behavior which 
+     * assumed that the integration range was constant.
+     * 
+     * @param windowSamples The number of samples in the FADC readout window.
+     */
     public void setWindowSamples(int windowSamples) {
         converter.setWindowSamples(windowSamples);
     }
+    
+    /**
+     * Set the integration range in nanoseconds after the threshold crossing. 
+     * <p>
+     * These numbers must be multiples of 4 nanoseconds.
+     * <p>
+     * This value is used for pulse integration in Mode-1, and pedestal subtraction in all modes.
+     * 
+     * @param nsa The number of nanoseconds after the threshold crossing.
+     * @see #setNsb(int)
+     */
     public void setNsa(int nsa) {
         converter.setNSA(nsa);
     }
+    
+    /**
+     * Set the integration range in nanoseconds before the threshold crossing.
+     * <p>
+     * These numbers must be multiples of 4 nanoseconds.
+     * <p>
+     * This value is used for pulse integration in Mode-1, and pedestal subtraction in all modes.
+     * 
+     * @param nsb The number of nanoseconds after the threshold crossing.
+     * @see #setNsa(int)
+     */
     public void setNsb(int nsb) {
         converter.setNSB(nsb);
     }
+    
+    /**
+     * Set the maximum number of peaks to search for in the signal, 
+     * which must be between 1 and 3, inclusive.
+     * @param nPeak The maximum number of peaks to search for in the signal.
+     */
     public void setNPeak(int nPeak) {
         converter.setNPeak(nPeak);
     }
     
+    /**
+     * Set a constant gain factor in the converter for all channels.
+     * @param gain The constant gain value.
+     */
     public void setGain(double gain) {
         converter.setGain(gain);
     }
 
+    /**
+     * Set the {@link org.lcsim.event.CalorimeterHit} collection name,
+     * which is used as input in "normal" mode and output when running
+     * "backwards".
+     * 
+     * @param ecalCollectionName The <code>CalorimeterHit</code> collection name.
+     * @see #runBackwards
+     */
     public void setEcalCollectionName(String ecalCollectionName) {
         this.ecalCollectionName = ecalCollectionName;
     }
 
+    /**
+     * Set the raw collection name which is used as output in "normal" mode
+     * and input when running "backwards".
+     * <p>
+     * Depending on the Driver configuration, this could be a collection
+     * of {@link org.lcsim.event.RawTrackerHit} objects for Mode-1
+     * or {@link org.lcsim.event.RawCalorimeterHit} objects for Mode-3
+     * or Mode-7.
+     * 
+     * @param rawCollectionName The raw collection name.
+     */
     public void setRawCollectionName(String rawCollectionName) {
         this.rawCollectionName = rawCollectionName;
     }
 
+    /**
+     * Set to <code>true</code> to ignore data from channels that
+     * are flagged as "bad" in the conditions system.
+     * @param apply True to ignore bad channels.
+     */
     public void setApplyBadCrystalMap(boolean apply) {
         this.applyBadCrystalMap = apply;
     }
 
+    /**
+     * Set to <code>true</code> to turn on debug output.
+     * @param debug True to turn on debug output.
+     */
     public void setDebug(boolean debug) {
         this.debug = debug;
     }
 
+    /**
+     * Set to <code>true</code> to use timestamp information from the ECal or trigger.
+     * @param useTimestamps True to use timestamp information.
+     */
+    // FIXME: What does this actually do?  What calculations does it affect?  
     public void setUseTimestamps(boolean useTimestamps) {
         this.useTimestamps = useTimestamps;
     }
 
+    /**
+     * Set to <code>true</code> to use MC truth information.
+     * @param useTruthTime True to use MC truth information.
+     */
+    // FIXME: What does this actually do?  What calculations does it affect?  
     public void setUseTruthTime(boolean useTruthTime) {
         this.useTruthTime = useTruthTime;
+    }
+    
+    /**
+     * Sets whether the driver should use the DAQ configuration from
+     * EvIO file for its parameters. If activated, the converter will
+     * obtain gains, thresholds, pedestals, the window size, and the
+     * pulse integration window from the EvIO file. This will replace
+     * and overwrite any manually defined settings.<br/>
+     * <br/>
+     * Note that if this setting is active, the driver will not output
+     * any data until a DAQ configuration has been read from the data
+     * stream.
+     * @param state - <code>true</code> indicates that the configuration
+     * should be read from the DAQ data in an EvIO file. Setting this
+     * to <code>false</code> will cause the driver to use its regular
+     * manually-defined settings and pull gains and pedestals from the
+     * conditions database.
+     */
+    public void setUseDAQConfig(boolean state) {
+    	useDAQConfig = state;
+    	converter.setUseDAQConfig(state);
     }
 
     @Override
@@ -185,6 +349,12 @@
 
     @Override
     public void process(EventHeader event) {
+    	// Do not process the event if the DAQ configuration should be
+    	// used for value, but is not initialized.
+    	if(useDAQConfig && !ConfigurationManager.isInitialized()) {
+    		return;
+    	}
+    	
         final int SYSTEM_TRIGGER = 0;
         final int SYSTEM_TRACKER = 1;
         final int SYSTEM_ECAL = 2;

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/ClusterDriver.java	Wed Mar 25 14:43:27 2015
@@ -249,7 +249,7 @@
                 }
             }
         } else {
-            getLogger().severe("The input hit collection " + this.inputHitCollectionName + " is missing from the event.");
+            getLogger().info("The input hit collection " + this.inputHitCollectionName + " is missing from the event.");
             if (this.raiseErrorNoHitCollection) {
                 throw new RuntimeException("The expected input hit collection is missing from the event.");
             }

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterDriver.java	Wed Mar 25 14:43:27 2015
@@ -1,4 +1,11 @@
 package org.hps.recon.ecal.cluster;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import org.hps.recon.ecal.daqconfig.ConfigurationManager;
+import org.hps.recon.ecal.daqconfig.GTPConfig;
+import org.lcsim.event.EventHeader;
 
 /**
  * Class <code>GTPOnlineClusterDriver</code> allows parameters for the
@@ -7,16 +14,47 @@
  * @author Kyle McCarty <[log in to unmask]>
  */
 public class GTPOnlineClusterDriver extends ClusterDriver {
-    // Store the clustering algorithm.
     private final GTPOnlineClusterer gtp;
+    private boolean useDAQConfig = false;
     
     /**
      * Instantiates a new clustering algorithm using the readout
      * variant of the GTP clustering algorithm.
      */
     public GTPOnlineClusterDriver() {
+    	// Instantiate the clusterer.
         clusterer = ClustererFactory.create("GTPOnlineClusterer");
         gtp = (GTPOnlineClusterer) clusterer;
+        
+        // Track the DAQ configuration status.
+        ConfigurationManager.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				// If DAQ configuration settings should be used, then
+				// update the clusterer.
+				if(useDAQConfig) {
+					// Get the GTP settings.
+					GTPConfig config = ConfigurationManager.getInstance().getGTPConfig();
+					
+					// Send the DAQ configuration settings to the clusterer.
+					gtp.setSeedLowThreshold(config.getSeedEnergyCutConfig().getLowerBound());
+					gtp.setWindowAfter(config.getTimeWindowAfter());
+					gtp.setWindowBefore(config.getTimeWindowBefore());
+					
+					// Print the updated settings.
+					logSettings();
+				}
+			}
+        });
+    }
+    
+    @Override
+    public void process(EventHeader event) {
+    	// Only process an event if either the DAQ configuration is not
+    	// in use or if it has been initialized.
+    	if((useDAQConfig && ConfigurationManager.isInitialized()) || !useDAQConfig) {
+    		super.process(event);
+    	}
     }
     
     /**
@@ -25,19 +63,7 @@
     @Override
     public void startOfData() {
     	// VERBOSE :: Output the driver settings.
-    	if(gtp.isVerbose()) {
-			// Print the cluster driver header.
-			System.out.println();
-			System.out.println();
-			System.out.println("======================================================================");
-			System.out.println("=== GTP Readout Clusterer Settings ===================================");
-			System.out.println("======================================================================");
-			
-			// Output the driver settings.
-			System.out.printf("Seed Energy Threshold :: %.3f GeV%n", gtp.getSeedLowThreshold());
-			System.out.printf("Time Window (Before)  :: %.0f ns%n", gtp.getWindowBefore());
-			System.out.printf("Time Window (After)   :: %.0f ns%n", gtp.getWindowAfter());
-    	}
+    	if(gtp.isVerbose()) { logSettings(); }
     }
     
     /**
@@ -80,4 +106,31 @@
     public void setVerbose(boolean verbose) {
         gtp.setVerbose(verbose);
     }
+    
+    /**
+     * Sets whether GTP settings should be drawn from the EvIO data
+     * DAQ configuration or read from the steering file.
+     * @param state - <code>true</code> means that DAQ configuration
+     * will be used and <code>false</code> that it will not.
+     */
+    public void setUseDAQConfig(boolean state) {
+    	useDAQConfig = state;
+    }
+    
+    /**
+     * Outputs the current GTP settings to the terminal.
+     */
+    private void logSettings() {
+		// Print the cluster driver header.
+		System.out.println();
+		System.out.println();
+		System.out.println("======================================================================");
+		System.out.println("=== GTP Readout Clusterer Settings ===================================");
+		System.out.println("======================================================================");
+		
+		// Output the driver settings.
+		System.out.printf("Seed Energy Threshold :: %.3f GeV%n", gtp.getSeedLowThreshold());
+		System.out.printf("Time Window (Before)  :: %.0f ns%n", gtp.getWindowBefore());
+		System.out.printf("Time Window (After)   :: %.0f ns%n", gtp.getWindowAfter());
+    }
 }

Modified: java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java
 =============================================================================
--- java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java	(original)
+++ java/branches/prod/ecal-recon/src/main/java/org/hps/recon/ecal/cluster/GTPOnlineClusterer.java	Wed Mar 25 14:43:27 2015
@@ -158,30 +158,37 @@
                 // Iterate over the other hits and if the are within
                 // the clustering spatiotemporal window, compare their
                 // energies.
+                hitLoop:
                 for(CalorimeterHit hit : hitList) {
-                    // Do not perform the comparison if the hit is the
-                    // current potential seed.
-                    if(hit != seed) {
-                        // Check if the hit is within the spatiotemporal
-                        // clustering window.
-                        if(withinTimeVerificationWindow(seed, hit) && withinSpatialWindow(seed, hit)) {
-                            // Check if the hit invalidates the potential
-                            // seed.
-                            if(isValidSeed(seed, hit)) {
-                                // Make sure that the hit is also within
-                                // the hit add window; this may not be
-                                // the same as the verification window
-                                // if the asymmetric window is active.
-                                if(withinTimeClusteringWindow(seed, hit)) {
-                                    protoCluster.addHit(hit);
-                                }
+                	// Negative energy hits are never valid. Skip them.
+                	if(hit.getCorrectedEnergy() < 0) {
+                		continue hitLoop;
+                	}
+                	
+                	// Do not compare the potential seed hit to itself.
+                	if(hit == seed) {
+                		continue hitLoop;
+                	}
+                	
+                    // Check if the hit is within the spatiotemporal
+                    // clustering window.
+                    if(withinTimeVerificationWindow(seed, hit) && withinSpatialWindow(seed, hit)) {
+                        // Check if the hit invalidates the potential
+                        // seed.
+                        if(isValidSeed(seed, hit)) {
+                            // Make sure that the hit is also within
+                            // the hit add window; this may not be
+                            // the same as the verification window
+                            // if the asymmetric window is active.
+                            if(withinTimeClusteringWindow(seed, hit)) {
+                                protoCluster.addHit(hit);
                             }
-                            
-                            // If it is not, then skip the rest of the
-                            // loop; the potential seed is not really
-                            // a seed.
-                            else { continue seedLoop; }
                         }
+                        
+                        // If it is not, then skip the rest of the
+                        // loop; the potential seed is not really
+                        // a seed.
+                        else { continue seedLoop; }
                     }
                 }
                 
@@ -308,20 +315,37 @@
      * <code>false</code> otherwise.
      */
     private boolean withinSpatialWindow(CalorimeterHit seed, CalorimeterHit hit) {
-        // Get the x-indices of each hit.
-        int six = seed.getIdentifierFieldValue("ix");
-        int hix = hit.getIdentifierFieldValue("ix");
-        
-        // Check that the x indices are either the same or within a
-        // range of one of one another.
-        if((six == hix) || (six + 1 == hix) || (six - 1 == hix)) {
-            // Get the y-indices of each hit.
-            int siy = seed.getIdentifierFieldValue("iy");
-            int hiy = hit.getIdentifierFieldValue("iy");
+        // Get the y-indices of each hit.
+        int siy = seed.getIdentifierFieldValue("iy");
+        int hiy = hit.getIdentifierFieldValue("iy");
+        
+        // Ensure that the y-indices are either the same or are within
+        // one of one another.
+        if((siy == hiy) || (siy + 1 == hiy) || (siy - 1 == hiy)) {
+            // Get the x-indices of each hit.
+            int six = seed.getIdentifierFieldValue("ix");
+            int hix = hit.getIdentifierFieldValue("ix");
             
-            // Ensure that the y-indices are either the same or are
-            // within one of one another.
-            return (siy == hiy) || (siy + 1 == hiy) || (siy - 1 == hiy);
+            // If the x-indices are the same or within one of each other
+            // then the crystals are within the spatial window of one
+            // another.
+            if((six == hix) || (six + 1 == hix) || (six - 1 == hix)) {
+                return true;
+            }
+            
+            // Otherwise, check for the special case where ix = 1 is
+            // considered to be adjacent to ix = -1 rather than the
+            // expected ix = 0. (ix = 0 does not exist.)
+            else {
+            	// ix = -1 is adjacent to ix = 1 and vice versa.
+                if((six == -1 && hix == 1) || (six == 1 && hix == -1)) {
+                	return true;
+                }
+                
+                // Any other combination that reaches this point is not
+                // a valid combination.
+                else { return false; }
+            }
         }
         
         // If the x-index comparison fails, return false.

Modified: java/branches/prod/evio/pom.xml
 =============================================================================
--- java/branches/prod/evio/pom.xml	(original)
+++ java/branches/prod/evio/pom.xml	Wed Mar 25 14:43:27 2015
@@ -20,6 +20,10 @@
             <groupId>org.hps</groupId>
             <artifactId>hps-tracking</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
+            <artifactId>hps-record-util</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
@@ -29,6 +33,8 @@
                 <configuration>
                     <excludes>
                         <exclude>org/hps/evio/LCSimEngRunEventBuilderTest.java</exclude>
+                        <exclude>org/hps/evio/SvtEvioReaderTest.java</exclude>
+                        <exclude>org/hps/evio/TestRunSvtEvioReaderTest.java</exclude>
                     </excludes>
                     <trimStackTrace>true</trimStackTrace>
                 </configuration>

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/LCSimEngRunEventBuilder.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/LCSimEngRunEventBuilder.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/LCSimEngRunEventBuilder.java	Wed Mar 25 14:43:27 2015
@@ -5,39 +5,47 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.jlab.coda.jevio.BaseStructure;
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.SSPData;
+import org.hps.recon.ecal.triggerbank.TIData;
+import org.hps.record.epics.EpicsEvioProcessor;
+import org.hps.record.epics.EpicsScalarData;
+import org.hps.record.evio.EvioEventUtilities;
+import org.hps.record.scalars.ScalarData;
+import org.hps.record.scalars.ScalarsEvioProcessor;
 import org.jlab.coda.jevio.EvioEvent;
-
 import org.lcsim.event.EventHeader;
 
-import org.hps.readout.ecal.daqconfig.EvioDAQParser;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.SSPData;
-import org.hps.readout.ecal.triggerbank.TIData;
-import org.hps.record.evio.EvioEventUtilities;
-
-
 /**
- * Build LCSim events from EVIO data.
+ * This is the {@link org.hps.record.LCSimEventBuilder} implementation for the Engineering Run and the Commissioning Run.
+ * <p>
+ * It has several modifications from the Test Run builder including different values for certain bank tags.
+ * <p>
+ * Additionally, this builder will write DAQ config information, EPICS control data, and scalar bank data into the output LCSim events if these banks are present in the EVIO data.
  *
  * @author Sho Uemura <[log in to unmask]>
  * @author Jeremy McCormick <[log in to unmask]>
  */
 public class LCSimEngRunEventBuilder extends LCSimTestRunEventBuilder {
-    
+
     TriggerConfigEvioReader triggerConfigReader = null;
-    
+
+    EpicsEvioProcessor epicsProcessor = new EpicsEvioProcessor();
+    EpicsScalarData epicsData;
+
+    ScalarsEvioProcessor scalarProcessor = new ScalarsEvioProcessor();
+    ScalarData scalarData;
+
     public LCSimEngRunEventBuilder() {
         ecalReader.setTopBankTag(0x25);
         ecalReader.setBotBankTag(0x27);
-        svtReader = new SvtEvioReader(); 
-        sspCrateBankTag = 0x2E; //A.C. modification after Sergey's confirmation
+        svtReader = new SvtEvioReader();
+        sspCrateBankTag = 0x2E; // A.C. modification after Sergey's confirmation
         sspBankTag = 0xe10c;
         intBanks = new ArrayList<IntBankDefinition>();
-        intBanks.add(new IntBankDefinition(SSPData.class, new int[]{sspCrateBankTag, sspBankTag}));
-        intBanks.add(new IntBankDefinition(TIData.class, new int[]{sspCrateBankTag, 0xe10a}));
+        intBanks.add(new IntBankDefinition(SSPData.class, new int[] { sspCrateBankTag, sspBankTag }));
+        intBanks.add(new IntBankDefinition(TIData.class, new int[] { sspCrateBankTag, 0xe10a }));
         // ecalReader = new ECalEvioReader(0x25, 0x27);
-        
         triggerConfigReader = new TriggerConfigEvioReader();
     }
 
@@ -53,6 +61,37 @@
     }
 
     @Override
+    public void readEvioEvent(EvioEvent evioEvent) {
+        super.readEvioEvent(evioEvent);
+
+        // Create EPICS data if this is an EPICS control event.
+        if (EvioEventUtilities.isEpicsEvent(evioEvent)) {
+            createEpicsScalarData(evioEvent);
+        }
+    }
+
+    /**
+     * Create and cache an {@link org.hps.record.epics.EpicsScalarData} object.
+     * @param evioEvent The EVIO event data.
+     */
+    void createEpicsScalarData(EvioEvent evioEvent) {
+        epicsProcessor.process(evioEvent);
+        epicsData = epicsProcessor.getEpicsScalarData();
+    }
+
+    /**
+     * Write EVIO scalar data into the LCSim event, if it exists.
+     * @param evioEvent The EVIO event data.
+     * @param lcsimEvent The output LCSim event.
+     */
+    void writeScalarData(EvioEvent evioEvent, EventHeader lcsimEvent) {
+        scalarProcessor.process(evioEvent);
+        if (scalarProcessor.getScalarData() != null) {
+            scalarProcessor.getScalarData().write(lcsimEvent);
+        }
+    }
+
+    @Override
     public EventHeader makeLCSimEvent(EvioEvent evioEvent) {
         if (!EvioEventUtilities.isPhysicsEvent(evioEvent)) {
             throw new RuntimeException("Not a physics event: event tag " + evioEvent.getHeader().getTag());
@@ -60,10 +99,10 @@
 
         // Create a new LCSimEvent.
         EventHeader lcsimEvent = getEventData(evioEvent);
-     
-        // Put DAQ Configuration info into lcsimEvent
-        triggerConfigReader.getDAQConfig(evioEvent,lcsimEvent);
-        
+
+        // Put DAQ Configuration info into lcsimEvent.
+        triggerConfigReader.getDAQConfig(evioEvent, lcsimEvent);
+
         // Make RawCalorimeterHit collection, combining top and bottom section
         // of ECal into one list.
         try {
@@ -72,16 +111,23 @@
             Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error making ECal hits", e);
         }
 
-        // Make SVT RawTrackerHits
+        // FIXME: This is commented out for now while SVT is not integrated.
+        // Make SVT RawTrackerHits.
         // try {
         // svtReader.makeHits(evioEvent, lcsimEvent);
         // } catch (Exception e) {
-        // Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
-        // "Error making SVT hits", e);
+        // Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error making SVT hits", e);
         // }
+
+        // Write the current EPICS data into this event.
+        if (epicsData != null) {
+            epicsData.write(lcsimEvent);
+            epicsData = null;
+        }
+
+        // Write scalars into the event, if they exist in this EVIO data.
+        writeScalarData(evioEvent, lcsimEvent);
+
         return lcsimEvent;
     }
-
-    
-        
-}
+}

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/LCSimTestRunEventBuilder.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/LCSimTestRunEventBuilder.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/LCSimTestRunEventBuilder.java	Wed Mar 25 14:43:27 2015
@@ -5,8 +5,9 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.hps.record.LCSimEventBuilder;
 import org.hps.record.evio.EvioEventConstants;
 import org.hps.record.evio.EvioEventUtilities;
@@ -27,8 +28,8 @@
  */
 public class LCSimTestRunEventBuilder implements LCSimEventBuilder, ConditionsListener {
 
-    ECalEvioReader ecalReader = null;
-    AbstractSvtEvioReader svtReader = null;
+    protected ECalEvioReader ecalReader = null;
+    protected AbstractSvtEvioReader svtReader = null;
     protected long time = 0; //most recent event time (ns), taken from prestart and end events, and trigger banks (if any)
     protected int sspCrateBankTag = 0x1; //bank ID of the crate containing the SSP
     protected int sspBankTag = 0xe106; //SSP bank's tag

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/SVTHitWriter.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/SVTHitWriter.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/SVTHitWriter.java	Wed Mar 25 14:43:27 2015
@@ -1,29 +1,28 @@
 package org.hps.evio;
+
+import static org.hps.evio.EventConstants.SVT_BANK_NUMBER;
+import static org.hps.evio.EventConstants.SVT_BANK_TAG;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+//===> import org.hps.conditions.deprecated.SvtUtils;
+import org.hps.readout.svt.FpgaData;
+import org.hps.readout.svt.HPSSVTConstants;
+import org.hps.readout.svt.SVTData;
 import org.jlab.coda.jevio.DataType;
 import org.jlab.coda.jevio.EventBuilder;
 import org.jlab.coda.jevio.EvioBank;
 import org.jlab.coda.jevio.EvioException;
+import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.detector.tracker.silicon.HpsTestRunSiSensor;
-import org.lcsim.detector.tracker.silicon.SiSensor;
-import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.LCRelation;
 import org.lcsim.event.RawTrackerHit;
 import org.lcsim.geometry.Subdetector;
 import org.lcsim.lcio.LCIOConstants;
-//===> import org.hps.conditions.deprecated.SvtUtils;
-import org.hps.readout.svt.FpgaData;
-import org.hps.readout.svt.HPSSVTConstants;
-import org.hps.readout.svt.SVTData;
-
-import static org.hps.evio.EventConstants.SVT_BANK_NUMBER;
-import static org.hps.evio.EventConstants.SVT_BANK_TAG;
 
 /**
  *

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/TestRunSvtEvioReader.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/TestRunSvtEvioReader.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/TestRunSvtEvioReader.java	Wed Mar 25 14:43:27 2015
@@ -2,15 +2,12 @@
 
 import java.util.List;
 
+import org.hps.util.Pair;
 import org.jlab.coda.jevio.BaseStructure;
 import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.detector.tracker.silicon.HpsTestRunSiSensor;
 import org.lcsim.event.RawTrackerHit;
-import org.lcsim.event.base.BaseRawTrackerHit;
 import org.lcsim.geometry.Subdetector;
-import org.hps.util.Pair;
-
-import static org.hps.evio.EventConstants.TEST_RUN_SVT_BANK_TAG;
 
 /**
  *	Test run SVT EVIO reader used to convert SVT bank integer data to LCIO

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/TestRunTriggeredReconToLcio.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/TestRunTriggeredReconToLcio.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/TestRunTriggeredReconToLcio.java	Wed Mar 25 14:43:27 2015
@@ -161,7 +161,9 @@
         if (event.hasCollection(SimCalorimeterHit.class, ecalCollectionName) && !event.get(SimCalorimeterHit.class, ecalCollectionName).isEmpty()) {
             mcParticles = event.getMCParticles();
             ecalHits = event.get(SimCalorimeterHit.class, ecalCollectionName);
-            trackerHits = event.get(SimTrackerHit.class, trackerCollectionName);
+            if (event.hasCollection(SimTrackerHit.class, trackerCollectionName)) {
+                trackerHits = event.get(SimTrackerHit.class, trackerCollectionName);
+            }
             if (event.hasCollection(SimTrackerHit.class, ecalScoringPlaneHitsCollectionName)) {
                 ecalScoringPlaneHits = event.get(SimTrackerHit.class, ecalScoringPlaneHitsCollectionName);
             }
@@ -170,7 +172,9 @@
             if (event.hasCollection(MCParticle.class)) {
                 triggerMCParticles = event.getMCParticles();
                 triggerECalHits = event.get(SimCalorimeterHit.class, ecalCollectionName);
-                triggerTrackerHits = event.get(SimTrackerHit.class, trackerCollectionName);
+                if (event.hasCollection(SimTrackerHit.class, trackerCollectionName)) {
+                    triggerTrackerHits = event.get(SimTrackerHit.class, trackerCollectionName);
+                }
                 if (event.hasCollection(SimTrackerHit.class, ecalScoringPlaneHitsCollectionName)) {
                     triggerECalScoringPlaneHits = event.get(SimTrackerHit.class, ecalScoringPlaneHitsCollectionName);
                 }

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/TriggerConfigEvioReader.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/TriggerConfigEvioReader.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/TriggerConfigEvioReader.java	Wed Mar 25 14:43:27 2015
@@ -5,7 +5,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.hps.readout.ecal.daqconfig.EvioDAQParser;
+import org.hps.recon.ecal.daqconfig.EvioDAQParser;
 import org.jlab.coda.jevio.BaseStructure;
 import org.jlab.coda.jevio.EvioEvent;
 import org.lcsim.event.EventHeader;

Modified: java/branches/prod/evio/src/main/java/org/hps/evio/TriggerDataWriter.java
 =============================================================================
--- java/branches/prod/evio/src/main/java/org/hps/evio/TriggerDataWriter.java	(original)
+++ java/branches/prod/evio/src/main/java/org/hps/evio/TriggerDataWriter.java	Wed Mar 25 14:43:27 2015
@@ -1,8 +1,9 @@
 package org.hps.evio;
 
 import java.util.List;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.jlab.coda.jevio.BaseStructure;
 import org.jlab.coda.jevio.DataType;
 import org.jlab.coda.jevio.EventBuilder;

Modified: java/branches/prod/monitoring-app/pom.xml
 =============================================================================
--- java/branches/prod/monitoring-app/pom.xml	(original)
+++ java/branches/prod/monitoring-app/pom.xml	Wed Mar 25 14:43:27 2015
@@ -111,6 +111,10 @@
         </dependency>
         <dependency>
             <groupId>org.hps</groupId>
+            <artifactId>hps-ecal-recon</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hps</groupId>
             <artifactId>hps-monitoring-drivers</artifactId>
         </dependency>       
         <dependency>
@@ -130,5 +134,20 @@
             <artifactId>jlfgr</artifactId>
             <version>1.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.freehep</groupId>
+            <artifactId>freehep-jaida-remote</artifactId>
+            <version>3.4.11</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.jdom</groupId>
+                    <artifactId>jdom</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-math</groupId>
+                    <artifactId>commons-math</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
-</project>
+</project>

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java	Wed Mar 25 14:43:27 2015
@@ -11,6 +11,7 @@
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
+import javax.swing.JComponent;
 import javax.swing.JFormattedTextField;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -136,7 +137,7 @@
         c.gridy = currY;
         c.insets = insets;
         c.anchor = GridBagConstraints.WEST;
-        JLabel waitModeLabel = new JLabel(name + ":");
+        JLabel waitModeLabel = new JLabel(name);
         waitModeLabel.setHorizontalAlignment(JLabel.LEFT);
         add(waitModeLabel, c);
 
@@ -278,6 +279,33 @@
         return configurationModel;
     }
     
+    /**
+     * Add a labeled JComponent to the panel.
+     * @param name The label text.
+     * @param component The component to add.
+     */
+    void addComponent(String name, JComponent component) {
+                
+        // Add the label.
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = currY;
+        c.insets = insets;
+        c.anchor = GridBagConstraints.WEST;
+        JLabel label = new JLabel(name + ":");
+        add(label, c);
+
+        // Add the component.
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = currY;
+        c.insets = insets;
+        c.anchor = GridBagConstraints.EAST;
+        add(component, c);
+
+        ++currY;
+    }
+    
     boolean accept(PropertyChangeEvent evt) {
         if (evt.getPropertyName().equals("ancestor")) {
             return false;

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java	Wed Mar 25 14:43:27 2015
@@ -34,14 +34,25 @@
     // Save a screenshot
     static final String SAVE_SCREENSHOT = "saveScreenshot";
     
-    // Save the plots
+    // Plotting actions
     static final String SAVE_PLOTS = "savePlots";
     static final String CLEAR_PLOTS = "resetPlots";
+    static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots";
     
+    // Exit the application.
     static final String EXIT = "exit";
+           
+    // Log to file or standard print stream.
+    static final String LOG_TO_FILE = "logToFile";
+    static final String LOG_TO_TERMINAL = "logToTerminal";
     
-    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";
-        
+    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";    
+    
+    static final String CONDITIONS_TAG_CHANGED = "conditionsTagChanged";
+    
+    static final String START_AIDA_SERVER = "startAIDAServer";
+    static final String STOP_AIDA_SERVER = "stopAIDAServer";
+    
     ////////////////////////////////////////////    
     static final String BLOCKING_CHANGED = "blockingChanged";
     static final String CHOOSE_COMPACT_FILE = "chooseCompactFile";
@@ -59,10 +70,7 @@
     static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged";
     
     static final String LOG_LEVEL_CHANGED = "logLevelChanged";
-    static final String LOG_TO_FILE = "logToFile";
-    static final String LOG_TO_FILE_CHANGED = "logToFileChanged";
-    static final String LOG_TO_TERMINAL = "logToTerminal";
-
+    
     static final String PROCESSING_STAGE_CHANGED = "processingStageChanged";    
     static final String SAVE_LOG_TABLE = "saveLogTable";            
     static final String SELECT_LOG_FILE = "logToFile";

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java	Wed Mar 25 14:43:27 2015
@@ -1,20 +1,4 @@
 package org.hps.monitoring.application;
-
-import static org.hps.monitoring.application.Commands.BLOCKING_CHANGED;
-import static org.hps.monitoring.application.Commands.VERBOSE_CHANGED;
-import static org.hps.monitoring.application.Commands.WAIT_MODE_CHANGED;
-import static org.hps.monitoring.application.model.ConfigurationModel.BLOCKING_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.CHUNK_SIZE_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.ET_NAME_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.HOST_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.PORT_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.PRESCALE_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.QUEUE_SIZE_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.STATION_NAME_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.STATION_POSITION_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.VERBOSE_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.WAIT_MODE_PROPERTY;
-import static org.hps.monitoring.application.model.ConfigurationModel.WAIT_TIME_PROPERTY;
 
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -72,11 +56,11 @@
         portField.addPropertyChangeListener("value", this);
 
         blockingCheckBox = addCheckBox("Blocking", false, true);
-        blockingCheckBox.setActionCommand(BLOCKING_CHANGED);
+        blockingCheckBox.setActionCommand(Commands.BLOCKING_CHANGED);
         blockingCheckBox.addActionListener(this);
 
         verboseCheckBox = addCheckBox("Verbose", false, true);
-        verboseCheckBox.setActionCommand(VERBOSE_CHANGED);
+        verboseCheckBox.setActionCommand(Commands.VERBOSE_CHANGED);
         verboseCheckBox.addActionListener(this);
 
         stationNameField = addField("Station Name", 10);
@@ -92,7 +76,7 @@
         stationPositionField.addPropertyChangeListener("value", this);
 
         waitModeComboBox = addComboBox("Wait Mode", waitModes);
-        waitModeComboBox.setActionCommand(WAIT_MODE_CHANGED);
+        waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED);
         waitModeComboBox.addActionListener(this);
 
         waitTimeField = addField("Wait Time [microseconds]", 8);
@@ -130,29 +114,29 @@
             configurationModel.removePropertyChangeListener(this);
             try {
                 Object value = evt.getNewValue();
-                if (evt.getPropertyName().equals(ET_NAME_PROPERTY)) {
+                if (evt.getPropertyName().equals(ConfigurationModel.ET_NAME_PROPERTY)) {
                     etNameField.setText((String) value);
-                } else if (evt.getPropertyName().equals(HOST_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.HOST_PROPERTY)) {
                     hostField.setText((String) value);
-                } else if (evt.getPropertyName().equals(PORT_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.PORT_PROPERTY)) {
                     portField.setText(value.toString());
-                } else if (evt.getPropertyName().equals(BLOCKING_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.BLOCKING_PROPERTY)) {
                     blockingCheckBox.setSelected((Boolean) value);
-                } else if (evt.getPropertyName().equals(VERBOSE_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.VERBOSE_PROPERTY)) {
                     verboseCheckBox.setSelected((Boolean) value);
-                } else if (evt.getPropertyName().equals(STATION_NAME_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_NAME_PROPERTY)) {
                     stationNameField.setText((String) value);
-                } else if (evt.getPropertyName().equals(CHUNK_SIZE_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.CHUNK_SIZE_PROPERTY)) {
                     chunkSizeField.setText(value.toString());
-                } else if (evt.getPropertyName().equals(QUEUE_SIZE_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.QUEUE_SIZE_PROPERTY)) {
                     queueSizeField.setText(value.toString());
-                } else if (evt.getPropertyName().equals(STATION_POSITION_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_POSITION_PROPERTY)) {
                     stationPositionField.setText(value.toString());
-                } else if (evt.getPropertyName().equals(WAIT_MODE_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_MODE_PROPERTY)) {
                     waitModeComboBox.setSelectedItem(((Mode) value).name());
-                } else if (evt.getPropertyName().equals(WAIT_TIME_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_TIME_PROPERTY)) {
                     waitTimeField.setText(value.toString());
-                } else if (evt.getPropertyName().equals(PRESCALE_PROPERTY)) {
+                } else if (evt.getPropertyName().equals(ConfigurationModel.PRESCALE_PROPERTY)) {
                     prescaleField.setText(value.toString());
                 }
             } finally {
@@ -166,18 +150,9 @@
      */
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
-        
         if (!accept(evt)) {
             return;
-        }
-        
-        //System.out.println("ConnectionSettingsPanel.propertyChange");
-        //System.out.println("  src: " + evt.getSource());
-        //System.out.println("  propName: " + evt.getPropertyName());
-        //System.out.println("  oldValue: " + evt.getOldValue());
-        //System.out.println("  newValue: " + evt.getNewValue());
-        //System.out.println("  propValue: " + evt.getPropagationId());
-        
+        }               
         Object source = evt.getSource();
         configurationModel.removePropertyChangeListener(this);
         try {
@@ -210,11 +185,11 @@
      */
     @Override
     public void actionPerformed(ActionEvent e) {
-        if (WAIT_MODE_CHANGED.equals(e.getActionCommand())) {
+        if (Commands.WAIT_MODE_CHANGED.equals(e.getActionCommand())) {
             configurationModel.setWaitMode(Mode.valueOf((String) waitModeComboBox.getSelectedItem()));
-        } else if (BLOCKING_CHANGED.equals(e.getActionCommand())) {
+        } else if (Commands.BLOCKING_CHANGED.equals(e.getActionCommand())) {
             configurationModel.setBlocking(blockingCheckBox.isSelected());
-        } else if (VERBOSE_CHANGED.equals(e.getActionCommand())) {
+        } else if (Commands.VERBOSE_CHANGED.equals(e.getActionCommand())) {
             configurationModel.setVerbose(verboseCheckBox.isSelected());
         }
     }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java	Wed Mar 25 14:43:27 2015
@@ -45,7 +45,6 @@
         setMinimumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
 
         setLayout(new GridBagLayout());
-        // setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
 
         GridBagConstraints c = new GridBagConstraints();
         c.weightx = c.weighty = 1.0;

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/DatePanel.java	Wed Mar 25 14:43:27 2015
@@ -9,7 +9,7 @@
  */
 class DatePanel extends FieldPanel {
 
-    private SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss");
+    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
     DatePanel(String fieldName, String defaultValue, int size, boolean editable) {
         super(fieldName, defaultValue, size, editable);

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java	Wed Mar 25 14:43:27 2015
@@ -80,10 +80,21 @@
             resumeButton.setEnabled(false);
             connectButton.setActionCommand(Commands.CONNECT);
             connectButton.setIcon(disconnectedIcon);
-        } else {
+            connectButton.setToolTipText("Start new session");
+            connectButton.setEnabled(true);
+        } else if (status.equals(ConnectionStatus.DISCONNECTING)) {
+            nextButton.setEnabled(false);
+            pauseButton.setEnabled(false);
+            resumeButton.setEnabled(false);
+            connectButton.setEnabled(false);
+        } else if (status.equals(ConnectionStatus.CONNECTED)) {
+            nextButton.setEnabled(false);            
             pauseButton.setEnabled(true);
+            resumeButton.setEnabled(false);
             connectButton.setActionCommand(Commands.DISCONNECT);
             connectButton.setIcon(connectedIcon);
+            connectButton.setToolTipText("Disconnect from session");
+            connectButton.setEnabled(true);
         }
     }       
     

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java	Wed Mar 25 14:43:27 2015
@@ -4,6 +4,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.logging.Logger;
 
@@ -14,6 +15,9 @@
 import org.hps.monitoring.application.model.ConnectionStatus;
 import org.hps.monitoring.application.model.SteeringType;
 import org.hps.monitoring.application.util.EtSystemUtil;
+import org.hps.monitoring.application.util.PhysicsSyncEventStation;
+import org.hps.monitoring.application.util.PreStartEtStation;
+import org.hps.monitoring.application.util.RunnableEtStation;
 import org.hps.monitoring.subsys.et.EtSystemMonitor;
 import org.hps.monitoring.subsys.et.EtSystemStripCharts;
 import org.hps.record.LCSimEventBuilder;
@@ -24,24 +28,30 @@
 import org.hps.record.enums.DataSourceType;
 import org.hps.record.et.EtConnection;
 import org.hps.record.evio.EvioDetectorConditionsProcessor;
+import org.jlab.coda.et.EtSystem;
+import org.jlab.coda.et.exception.EtClosedException;
+import org.jlab.coda.et.exception.EtException;
+import org.lcsim.conditions.ConditionsListener;
 import org.lcsim.conditions.ConditionsManager;
 import org.lcsim.conditions.ConditionsReader;
 import org.lcsim.util.Driver;
 
 /**
- * This class encapsulates all of the logic involved with processing events 
- * and managing the related state and objects within the monitoring application.
+ * This class encapsulates all of the logic involved with processing events and managing the related
+ * state and objects within the monitoring application.
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
 class EventProcessing {
-    
+
     MonitoringApplication application;
     Logger logger;
     SessionState sessionState;
     List<CompositeRecordProcessor> processors;
     List<Driver> drivers;
-    
+    List<ConditionsListener> conditionsListeners;
+    int stationPosition;
+
     /**
      * This class is used to organize the objects for an event processing session.
      */
@@ -51,62 +61,89 @@
         CompositeLoop loop;
         EventProcessingThread processingThread;
         Thread sessionWatchdogThread;
+        ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads");
+        List<RunnableEtStation> stations = new ArrayList<RunnableEtStation>();
         EtConnection connection;
     }
-    
-    /**
-     * Initialize with reference to the current monitoring application
-     * and a list of extra processors to add to the loop after 
-     * configuration.
+
+    /**
+     * Initialize with reference to the current monitoring application and a list of extra
+     * processors to add to the loop after configuration.
      * @param application The current monitoring application.
      * @param processors A list of processors to add after configuration is performed.
      */
     EventProcessing(
             MonitoringApplication application, 
-            List<CompositeRecordProcessor> processors,
-            List<Driver> drivers) {
+            List<CompositeRecordProcessor> processors, 
+            List<Driver> drivers, 
+            List<ConditionsListener> conditionsListeners) {
         this.application = application;
-        this.sessionState = new SessionState();        
+        this.sessionState = new SessionState();
         this.logger = MonitoringApplication.logger;
         this.processors = processors;
         this.drivers = drivers;
+        this.conditionsListeners = conditionsListeners;
+        this.stationPosition = application.configurationModel.getStationPosition();
     }
     
+    int getNextStationPosition() {
+        this.stationPosition += 1;
+        return this.stationPosition;        
+    }
+
     /**
      * Setup this class from the global configuration.
      * @param configurationModel The global configuration.
      */
     void setup(ConfigurationModel configurationModel) {
-        MonitoringApplication.logger.info("setting up LCSim");
+        
+        // Setup LCSim from the configuration.
+        setupLcsim(configurationModel);
+
+        // Now setup the CompositeLoop.
+        setupLoop(configurationModel);
+    }
+
+    /**
+     * @param configurationModel
+     */
+    private void setupLcsim(ConfigurationModel configurationModel) {
+        MonitoringApplication.logger.info("setting up lcsim");
 
         // Get steering resource or file as a String parameter.
         String steering = null;
         SteeringType steeringType = configurationModel.getSteeringType();
-        if (steeringType.equals(SteeringType.FILE))
-            try {
-                steering = configurationModel.getSteeringFile().getCanonicalPath();
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        else
+        if (steeringType.equals(SteeringType.FILE)) {
+            steering = configurationModel.getSteeringFile();
+        } else {
             steering = configurationModel.getSteeringResource();
-
-        MonitoringApplication.logger.config("Set steering to " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE"));
+        }
+
+        MonitoringApplication.logger.config("set steering " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE"));
 
         try {
-            // Create and the job manager.  The conditions manager is instantiated from this call but not configured.
+            // Create and the job manager. The conditions manager is instantiated from this call but
+            // not configured.
             sessionState.jobManager = new JobManager();
-            
+
+            // Add conditions listeners after new database conditions manager is initialized from
+            // job manager.
+            DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance();
+            for (ConditionsListener conditionsListener : conditionsListeners) {
+                logger.config("adding conditions listener " + conditionsListener.getClass().getName());
+                conditionsManager.addConditionsListener(conditionsListener);
+            }
+
             if (configurationModel.hasValidProperty(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) {
-                // Set a detector alias.                
+                // Set a detector alias.
                 ConditionsReader.addAlias(configurationModel.getDetectorName(), "file://" + configurationModel.getDetectorAlias());
                 logger.config("using detector alias " + configurationModel.getDetectorAlias());
             }
-                        
+
             // Setup the event builder to translate from EVIO to LCIO.
             // This must happen before Driver setup so the builder's listeners are activated first!
             createEventBuilder(configurationModel);
-            
+
             // Configure the job manager for the XML steering.
             sessionState.jobManager.setPerformDryRun(true);
             if (steeringType == SteeringType.RESOURCE) {
@@ -114,21 +151,27 @@
             } else if (steeringType.equals(SteeringType.FILE)) {
                 setupSteeringFile(steering);
             }
-           
+
+            // Set conditions tag.
+            if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) && !configurationModel.getConditionsTag().equals("")) {
+                logger.config("conditions tag is set to " + configurationModel.getConditionsTag());
+            } else {
+                logger.config("conditions NOT using a tag");
+            }
+
             // Is there a user specified run number from the JobPanel?
             if (configurationModel.hasValidProperty(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) {
                 int userRunNumber = configurationModel.getUserRunNumber();
                 String detectorName = configurationModel.getDetectorName();
-                DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance();
                 logger.config("setting user run number " + userRunNumber + " with detector " + detectorName);
                 conditionsManager.setDetector(configurationModel.getDetectorName(), userRunNumber);
                 if (configurationModel.hasPropertyKey(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
-                    // Freeze the conditions system to ignore run numbers from the events.  
-                    logger.config("user configured to freeze conditions system from monitoring app");
+                    // Freeze the conditions system to ignore run numbers from the events.
+                    logger.config("user configured to freeze conditions system");
                     conditionsManager.freeze();
                 } else {
                     // Allow run numbers to be picked up from the events.
-                    logger.config("user run number specified but conditions system is NOT frozen");
+                    logger.config("user run number provided but conditions system is NOT frozen");
                     conditionsManager.unfreeze();
                 }
             }
@@ -136,18 +179,15 @@
             logger.info("lcsim setup was successful");
 
         } catch (Throwable t) {
-            // Catch all errors and rethrow them as RuntimeExceptions.
+            // Catch all errors and re-throw them as RuntimeExceptions.
             application.errorHandler.setError(t).setMessage("Error setting up LCSim.").printStackTrace().raiseException();
         }
-        
-        // Now setup the CompositeLoop.
-        setupLoop(configurationModel);
-    }
-    
+    }
+
     /**
      * Create the event builder for converting EVIO events to LCSim.
      */
-    void createEventBuilder(ConfigurationModel configurationModel) {
+    private void createEventBuilder(ConfigurationModel configurationModel) {
 
         // Get the class for the event builder.
         String eventBuilderClassName = configurationModel.getEventBuilderClassName();
@@ -162,12 +202,12 @@
         // Add the builder as a listener so it is notified when conditions change.
         ConditionsManager.defaultInstance().addConditionsListener(sessionState.eventBuilder);
     }
-    
+
     /**
      * Setup the loop from the global configuration.
      * @param configurationModel The global configuration.
      */
-    void setupLoop(ConfigurationModel configurationModel) {
+    private void setupLoop(ConfigurationModel configurationModel) {
 
         CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration()
             .setStopOnEndRun(configurationModel.getDisconnectOnEndRun())
@@ -181,13 +221,12 @@
         if (configurationModel.hasValidProperty(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
             long maxEvents = configurationModel.getMaxEvents();
             if (maxEvents > 0L) {
-                //logger.config("processing will stop after max events: " + maxEvents);
                 loopConfig.setMaxRecords(maxEvents);
             }
         }
-        
+
         // Add all Drivers from the JobManager.
-        for (Driver driver : sessionState.jobManager.getDriverExecList()) {            
+        for (Driver driver : sessionState.jobManager.getDriverExecList()) {
             loopConfig.add(driver);
             logger.config("added Driver " + driver.getName() + " to job");
         }
@@ -205,30 +244,30 @@
         }
 
         // Add extra CompositeRecordProcessors to the loop config.
-        for (CompositeRecordProcessor processor : processors) {            
-            loopConfig.add(processor);   
+        for (CompositeRecordProcessor processor : processors) {
+            loopConfig.add(processor);
             logger.config("added extra processor " + processor.getClass().getSimpleName() + " to job");
         }
-        
+
         // Add extra Drivers to the loop config.
-        for (Driver driver : drivers) {            
+        for (Driver driver : drivers) {
             loopConfig.add(driver);
             logger.config("added extra Driver " + driver.getName() + " to job");
         }
-                
-        // Enable conditions system activation from EVIO event information.
+
+        // Enable conditions system activation from EVIO event data in case the PRESTART is missed.
         logger.config("added EvioDetectorConditionsProcessor to job with detector " + configurationModel.getDetectorName());
         loopConfig.add(new EvioDetectorConditionsProcessor(configurationModel.getDetectorName()));
 
         // Create the CompositeLoop with the configuration.
-        sessionState.loop = new CompositeLoop(loopConfig);        
-    }    
-    
+        sessionState.loop = new CompositeLoop(loopConfig);
+    }
+
     /**
      * Setup a steering file on disk.
      * @param steering The steering file.
      */
-    void setupSteeringFile(String steering) {
+    private void setupSteeringFile(String steering) {
         sessionState.jobManager.setup(new File(steering));
     }
 
@@ -237,81 +276,133 @@
      * @param steering The steering resource.
      * @throws IOException if there is a problem setting up or accessing the resource.
      */
-    void setupSteeringResource(String steering) throws IOException {
+    private void setupSteeringResource(String steering) throws IOException {
         InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering);
         if (is == null)
             throw new IOException("Steering resource is not accessible or does not exist.");
         sessionState.jobManager.setup(is);
         is.close();
     }
-    
-    /**
-     * Stop the event processing by executing a <code>STOP</code> command on the record loop and
-     * killing the event processing thread. This is executed after the ET system is disconnected so
-     * that the event processing does not potentially hang in a call to
-     * <code>EtSystem.getEvents()</code> forever.
-     */
+
     synchronized void stop() {
 
-        logger.info("event processing is stopping");
+        // Kill session watchdog thread.
+        killWatchdogThread();
+
+        // Wake up all ET stations to unblock the system and make sure secondary stations are detached.
+        //wakeUpEtStations()
+        // Wake up the primary ET station doing the event processing.
+        logger.finest("waking up event processing station ...");
+        try {
+            if (sessionState.connection != null) {
+                if (sessionState.connection.getEtSystem() != null) {
+                    sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation());
+                    logger.finest("event processing station woken up");
+                }
+            }
+        } catch (IOException | EtException | EtClosedException e) {
+            e.printStackTrace();
+        }
         
-        // Disconnect from ET system.
+        // Stop the event processing now that ET system is unblocked.
+        logger.fine("sending STOP command to loop ...");
+        sessionState.loop.execute(Command.STOP);
+        logger.fine("loop got command STOP");
+
+        // Cleanup the event processing thread since it was told to stop now.
+        try {
+            logger.fine("waiting for event processing thread to end ...");
+            sessionState.processingThread.join();
+            logger.fine("event processing thread ended");   
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        // Notify of last error that occurred in event processing.
+        if (sessionState.loop.getLastError() != null) {
+            // Log the error.
+            application.errorHandler.setError(sessionState.loop.getLastError()).log();
+        }
+
+        // Invalidate the loop.
+        sessionState.loop = null;
+
+        // Disconnect from the ET system.
         disconnect();
         
-        // Is the event processing thread not null?
-        if (sessionState.processingThread != null) {
-
-            // Is the event processing thread actually still alive?
-            if (sessionState.processingThread.isAlive()) {
-
-                // Request the event processing loop to execute stop.
-                sessionState.loop.execute(Command.STOP);
-
-                try {
-                    logger.info("waiting for event processing thread to finish");
-                    // This should always work, because the ET system is disconnected before this.
-                    sessionState.processingThread.join();
-                    logger.info("event processing thread finished");
-                } catch (InterruptedException e) {
-                    // Don't know when this would ever happen.
-                    e.printStackTrace();
+        // Invalidate the event processing object so it is unusable now.
+        invalidate();
+    }
+
+    /**
+     * Wake up all ET stations associated with event processing.
+     */
+    private void wakeUpEtStations() {
+        if (sessionState.connection != null) {
+            logger.fine("waking up ET stations ...");
+
+            // Wake up secondary ET stations.
+            for (RunnableEtStation station : sessionState.stations) {
+                if (station.getEtStation().isUsable()) {
+                    // Wake up the station which will automatically trigger a detach.
+                    try {
+                        logger.finest("waking up " + station.getEtStation().getName() + " ...");
+                        sessionState.connection.getEtSystem().wakeUpAll(station.getEtStation());
+                        logger.finest(station.getEtStation().getName() + " woken up");
+                    } catch (IOException | EtException | EtClosedException e) {
+                        e.printStackTrace();
+                    }
                 }
             }
 
-            // Notify of last error that occurred in event processing.
-            if (sessionState.loop.getLastError() != null) {
-                application.errorHandler.setError(sessionState.loop.getLastError()).log().printStackTrace();
-            }
-
-            // Set the event processing thread to null as it is unusable now.
-            sessionState.processingThread = null;
-        }
-
-        // Set the loop to null as a new one will be created for next session.
-        sessionState.loop = null;
-        
-        logger.info("event processing stopped");
-    }    
-           
-    /**
-     * Start event processing on the event processing thread
-     * and start the watchdog thread.
+            // Wait for station threads to die after being woken up.
+            while (sessionState.stationThreadGroup.activeCount() != 0) {
+                logger.finest("waiting for station threads to die ...");
+                Object lock = new Object();
+                synchronized (lock) {
+                    try {
+                        lock.wait(500);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+            logger.finest("destroying station thread group");
+            sessionState.stationThreadGroup.destroy();
+            logger.finest("station thread group destroyed");
+
+            // Wake up the primary ET station doing the event processing.
+            logger.finest("waking up event processing station ...");
+            try {
+                sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation());
+                logger.finest("event processing station woken up");
+            } catch (IOException | EtException | EtClosedException e) {
+                e.printStackTrace();
+            }
+
+            logger.finest("ET stations woken up");
+        }
+    }
+
+    /**
+     * Start event processing on the event processing thread and start the watchdog thread.
      */
     synchronized void start() {
-        
+
         logger.fine("event processing threads are starting");
-        
+
         // Start the event processing thread.
         sessionState.processingThread = new EventProcessingThread(sessionState.loop);
         sessionState.processingThread.start();
-        
+
         // Start the watchdog thread which will auto-disconnect when event processing is done.
         sessionState.sessionWatchdogThread = new SessionWatchdogThread(sessionState.processingThread);
         sessionState.sessionWatchdogThread.start();
-        
+
         logger.fine("started event processing threads");
     }
-    
+
     /**
      * Notify the event processor to pause processing.
      */
@@ -323,7 +414,7 @@
         }
         logger.finest("paused");
     }
-    
+
     /**
      * Get next event if in pause mode.
      */
@@ -336,7 +427,7 @@
         }
         logger.finest("got next event");
     }
-    
+
     /**
      * Resume processing events from pause mode.
      */
@@ -344,19 +435,19 @@
         logger.finest("resuming");
         if (application.connectionModel.getPaused()) {
             // Notify event processor to continue.
-            sessionState.loop.resume();        
+            sessionState.loop.resume();
             application.connectionModel.setPaused(false);
         }
         logger.finest("resumed");
     }
-    
+
     /**
      * Interrupt and join to the processing watchdog thread.
      */
     synchronized void killWatchdogThread() {
-        logger.fine("killing watchdog thread");
         // Is the session watchdog thread not null?
         if (sessionState.sessionWatchdogThread != null) {
+            logger.finest("killing watchdog thread ...");
             // Is the thread still alive?
             if (sessionState.sessionWatchdogThread.isAlive()) {
                 // Interrupt the thread which should cause it to stop.
@@ -371,24 +462,26 @@
             }
             // Set the thread object to null.
             sessionState.sessionWatchdogThread = null;
-        }
-        logger.fine("watchdog thread killed");
-    }
-    
+            logger.finest("watchdog thread killed");
+        }
+    }
+
     /**
      * Cleanup the ET connection.
      */
     synchronized void closeEtConnection() {
-        logger.fine("closing ET connection");
         if (sessionState.connection != null) {
+            logger.fine("closing ET connection");
             if (sessionState.connection.getEtSystem().alive()) {
+                logger.finest("cleaning up the connection ...");
                 sessionState.connection.cleanup();
+                logger.finest("connection cleanup successful");
             }
             sessionState.connection = null;
-        }
-        logger.fine("ET connection closed");
-    }
-    
+            logger.fine("ET connection closed");
+        }
+    }
+
     /**
      * True if the processing thread is active.
      * @return True if processing thread is active.
@@ -396,74 +489,109 @@
     boolean isActive() {
         return sessionState.processingThread != null && sessionState.processingThread.isAlive();
     }
-    
+
     /**
      * Connect to the ET system using the current connection settings.
      */
-    synchronized void connect() throws IOException {
-        logger.fine("connecting to ET system");
+    synchronized void connect() throws IOException {        
         // Setup the network connection if using an ET server.
         if (usingEtServer()) {
             // Create a connection to the ET server.
             try {
+                logger.fine("connecting to ET system ...");
+                
+                // Create the main ET system connection.
                 createEtConnection();
+
+                // Add an attachment that listens for DAQ configuration changes via physics SYNC events.
+                //createPhysicsSyncStation();
+                
+                // Add an attachment that listens for PRESTART events.
+                //createPreStartStation();
+                
             } catch (Exception e) {
                 throw new IOException(e);
             }
+            
+            logger.fine("ET system is connected");
         } else {
             // This is when a direct file source is used and ET is not needed.
             application.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
         }
-        logger.fine("ET system is connected");
-    }
-    
+        
+    }
+
     /**
      * True if using an ET server.
      * @return True if using an ET server.
      */
     boolean usingEtServer() {
         return application.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER);
-    }    
-    
-    /**
-     * Create a connection to an ET system using current parameters from the GUI. If successful, the
-     * application's ConnectionStatus is changed to CONNECTED.
-     */
-    void createEtConnection() {
+    }
+
+    /**
+     * Create a connection to an ET system using current parameters from the GUI. 
+     */
+    synchronized void createEtConnection() {
         // Setup connection to ET system.
         sessionState.connection = EtSystemUtil.createEtConnection(application.configurationModel);
 
         if (sessionState.connection != null) {
             // Set status to connected as there is now a live ET connection.
             application.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
-            //logger.info("successfully connected to ET system");
         } else {
             application.errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace().raiseException();
         }
     }
+
+    /**
+     * Create the ET that listens for DAQ configuration change via SYNC events.
+     */
+    private void createPhysicsSyncStation() {
+        logger.fine("creating physics SYNC station ...");       
+        PhysicsSyncEventStation configStation = new PhysicsSyncEventStation(
+                this.sessionState.connection.getEtSystem(),
+                this.sessionState.connection.getEtStation().getName() + "_PhysicsSync",
+                getNextStationPosition());
+        sessionState.stations.add(configStation);
+        new Thread(sessionState.stationThreadGroup, configStation).start();
+        logger.fine("physics SYNC station created");
+    }
     
     /**
-     * Disconnect from the current ET session with a particular status.
+     * Create the ET station that listens for GO events in order to initialize the conditions system.
+     */
+    private void createPreStartStation() {
+        logger.fine("creating PRESTART station ...");
+        String detectorName = this.application.configurationModel.getDetectorName();
+        EtSystem system = this.sessionState.connection.getEtSystem();
+        String stationName = this.sessionState.connection.getEtStation().getName() + "_PreStart";
+        int order = getNextStationPosition();
+        PreStartEtStation preStartStation = new PreStartEtStation(
+                detectorName, 
+                system, 
+                stationName, 
+                order);
+        sessionState.stations.add(preStartStation);
+        new Thread(sessionState.stationThreadGroup, preStartStation).start();
+        logger.fine("PRESTART station created");
+    }
+
+    /**
+     * Disconnect from the current ET session.
      * @param status The connection status.
      */
     synchronized void disconnect() {
-        
-        logger.fine("disconnecting");
-        
-        // Kill the session watch dog thread.
-        killWatchdogThread();
-
+                
         // Cleanup the ET connection.
         closeEtConnection();
-                              
+
         // Change application state to disconnected.
         application.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED);
-        
-        logger.fine("disconnected");
-    }    
-               
-    /**
-     * This class notifies the application to disconnect if the event processing thread completes.     
+    }
+
+    /**
+     * This class notifies the application to disconnect if the event processing thread completes.
      */
     class SessionWatchdogThread extends Thread {
 
@@ -472,19 +600,39 @@
         SessionWatchdogThread(Thread processingThread) {
             this.processingThread = processingThread;
         }
-        
+
         public void run() {
             try {
-                // When the event processing thread finishes, the session should be stopped and a
-                // disconnect should occur.
+                // This thread waits on the event processing thread to die.
                 processingThread.join();
-                                
+
                 // Activate a disconnect using the ActionEvent which is used by the disconnect button.
+                logger.finest("processing thread ended so automatic disconnect is happening");
                 application.actionPerformed(new ActionEvent(Thread.currentThread(), 0, Commands.DISCONNECT));
-                               
+
             } catch (InterruptedException e) {
+                logger.finest("SessionWatchdogThread got interrupted");
                 // This happens when the thread is interrupted by the user pressing the disconnect button.
-            }            
-        }
+            }
+        }
+    }
+    
+    void invalidate() {
+
+        this.application = null;
+        this.conditionsListeners = null;
+        this.drivers = null;
+        this.logger = null;
+        this.processors = null;        
+
+        this.sessionState.jobManager = null;
+        this.sessionState.eventBuilder = null;
+        this.sessionState.loop = null;
+        this.sessionState.processingThread = null;
+        this.sessionState.sessionWatchdogThread = null;
+        this.sessionState.stationThreadGroup = null;
+        this.sessionState.stations = null;
+        this.sessionState.connection = null;
+        this.sessionState = null;
     }
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	Wed Mar 25 14:43:27 2015
@@ -1,7 +1,4 @@
 package org.hps.monitoring.application;
-
-import static org.hps.monitoring.application.Commands.*;
-import static org.hps.monitoring.application.model.ConfigurationModel.*;
 
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -18,11 +15,13 @@
 import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
 import javax.swing.filechooser.FileFilter;
 
 import org.hps.monitoring.application.model.ConfigurationModel;
 import org.hps.monitoring.application.model.SteeringType;
 import org.hps.monitoring.application.util.ResourceUtil;
+import org.hps.record.enums.ProcessingStage;
 import org.jdom.Document;
 import org.jdom.Element;
 import org.jdom.JDOMException;
@@ -32,22 +31,26 @@
  * This is the GUI panel for setting job parameters. It is connected to the global configuration via
  * a {@link org.hps.monitoring.model.ConfigurationModel} object.
  */
+// FIXME: Combo boxes should use explicit types.
 class JobSettingsPanel extends AbstractFieldsPanel {
 
     private JComboBox<?> steeringResourcesComboBox;
     private JTextField steeringFileField;
     private JComboBox<?> steeringTypeComboBox;
+    private JComboBox<ProcessingStage> processingStageComboBox;
     private JComboBox<String> detectorNameComboBox;
     private JTextField detectorAliasField;
+    private JComboBox<String> conditionsTagComboBox;
     private JComboBox<String> eventBuilderComboBox;
     private JTextField userRunNumberField;
     private JCheckBox freezeConditionsCheckBox;    
     private JTextField maxEventsField;
     private JCheckBox disconnectOnErrorCheckBox;
-    private JCheckBox disconnectOnEndRunCheckBox;
-    private JTextField logFileNameField;
+    private JCheckBox disconnectOnEndRunCheckBox;    
     private JComboBox<?> logLevelComboBox;
     private JCheckBox logToFileCheckbox;
+    private JTextField logFileNameField;
+    private JTextField aidaServerNameField;
            
     // The package where steering resources must be located.
     static final String STEERING_PACKAGE = "org/hps/steering/monitoring/";
@@ -68,17 +71,22 @@
     /**
      * Class constructor.
      */
-    JobSettingsPanel() {
-
-        super(new Insets(4, 2, 2, 4), true);
-        
+    JobSettingsPanel(ConfigurationModel model) {
+
+        super(new Insets(5, 3, 3, 5), true);
+        
+        setBorder(new EmptyBorder(10, 10, 10, 10));
+                
         setLayout(new GridBagLayout());
+        
+        // Listen on changes to the configuration which will then be automatically pushed to the GUI.
+        model.addPropertyChangeListener(this);
 
         steeringResourcesComboBox = addComboBoxMultiline("Steering File Resource", ResourceUtil.findSteeringResources(STEERING_PACKAGE));
-        steeringResourcesComboBox.setActionCommand(STEERING_RESOURCE_CHANGED);
+        steeringResourcesComboBox.setActionCommand(Commands.STEERING_RESOURCE_CHANGED);
         steeringResourcesComboBox.addActionListener(this);
         
-        steeringFileField = addField("Steering File", 35);
+        steeringFileField = addField("Steering File", 50);
         steeringFileField.addPropertyChangeListener("value", this);
         
         JButton steeringFileButton = addButton("Select Steering File");
@@ -86,15 +94,20 @@
         steeringFileButton.addActionListener(this);
         
         steeringTypeComboBox = addComboBox("Steering Type", new String[] { SteeringType.RESOURCE.name(), SteeringType.FILE.name() });
-        steeringTypeComboBox.setActionCommand(STEERING_TYPE_CHANGED);
+        steeringTypeComboBox.setActionCommand(Commands.STEERING_TYPE_CHANGED);
         steeringTypeComboBox.addActionListener(this);
         
+        processingStageComboBox = new JComboBox<ProcessingStage>(ProcessingStage.values());
+        addComponent("Processing Stage", processingStageComboBox);
+        processingStageComboBox.setActionCommand(Commands.PROCESSING_STAGE_CHANGED);
+        processingStageComboBox.addActionListener(this);
+        
         detectorNameComboBox = addComboBox("Detector Name", ResourceUtil.findDetectorNames());
-        detectorNameComboBox.setActionCommand(DETECTOR_NAME_CHANGED);
+        detectorNameComboBox.setActionCommand(Commands.DETECTOR_NAME_CHANGED);
         detectorNameComboBox.addActionListener(this);
         
         detectorAliasField = addField("Detector Resources Directory", "", 35, true);
-        detectorAliasField.setActionCommand(DETECTOR_ALIAS_CHANGED);
+        detectorAliasField.setActionCommand(Commands.DETECTOR_ALIAS_CHANGED);
         detectorAliasField.addPropertyChangeListener("value", this);
         detectorAliasField.addActionListener(this);
         
@@ -102,15 +115,23 @@
         compactXmlButton.setActionCommand(Commands.CHOOSE_COMPACT_FILE);
         compactXmlButton.addActionListener(this);
 
-        userRunNumberField = addField("User Run Number", "", 10, false);
+        userRunNumberField = addField("User Run Number", "", 10, true);
         userRunNumberField.addPropertyChangeListener("value", this);
-        userRunNumberField.setActionCommand(USER_RUN_NUMBER_CHANGED);
+        userRunNumberField.setActionCommand(Commands.USER_RUN_NUMBER_CHANGED);
         userRunNumberField.setEnabled(true);
         userRunNumberField.setEditable(true);
-        
+                
+        conditionsTagComboBox = addComboBox("Conditions Tag", ResourceUtil.getConditionsTags());
+        conditionsTagComboBox.addItem("");
+        conditionsTagComboBox.setSelectedItem("");
+        conditionsTagComboBox.setActionCommand(Commands.CONDITIONS_TAG_CHANGED);
+        conditionsTagComboBox.addActionListener(this);
+        conditionsTagComboBox.setEditable(false);
+        conditionsTagComboBox.setEnabled(true);
+                
         freezeConditionsCheckBox = addCheckBox("Freeze detector conditions", false, true);
         freezeConditionsCheckBox.addActionListener(this);
-        freezeConditionsCheckBox.setActionCommand(FREEZE_CONDITIONS_CHANGED);
+        freezeConditionsCheckBox.setActionCommand(Commands.FREEZE_CONDITIONS_CHANGED);
         
         maxEventsField = addField("Max Events", "-1", 10, false);
         maxEventsField.addPropertyChangeListener("value", this);
@@ -119,15 +140,15 @@
         
         eventBuilderComboBox = addComboBox("LCSim Event Builder", ResourceUtil.findEventBuilderClassNames());
         eventBuilderComboBox.setSize(24, eventBuilderComboBox.getPreferredSize().height);
-        eventBuilderComboBox.setActionCommand(EVENT_BUILDER_CHANGED);
+        eventBuilderComboBox.setActionCommand(Commands.EVENT_BUILDER_CHANGED);
         eventBuilderComboBox.addActionListener(this);
         
         disconnectOnErrorCheckBox = addCheckBox("Disconnect on error", false, true);
-        disconnectOnErrorCheckBox.setActionCommand(DISCONNECT_ON_ERROR_CHANGED);
+        disconnectOnErrorCheckBox.setActionCommand(Commands.DISCONNECT_ON_ERROR_CHANGED);
         disconnectOnErrorCheckBox.addActionListener(this);
 
         disconnectOnEndRunCheckBox = addCheckBox("Disconnect on end run", false, true);
-        disconnectOnEndRunCheckBox.setActionCommand(DISCONNECT_ON_END_RUN_CHANGED);
+        disconnectOnEndRunCheckBox.setActionCommand(Commands.DISCONNECT_ON_END_RUN_CHANGED);
         disconnectOnEndRunCheckBox.addActionListener(this);
 
         logLevelComboBox = addComboBox("Log Level", LOG_LEVELS);
@@ -136,11 +157,12 @@
                                             
         logToFileCheckbox = addCheckBox("Log to File", false, false);
         logToFileCheckbox.setEnabled(false);
-        logToFileCheckbox.setActionCommand(LOG_TO_FILE_CHANGED);
-        logToFileCheckbox.addActionListener(this);
-
-        logFileNameField = addField("Log File", "", "Full path to log file.", 30, false);
-        logFileNameField.addPropertyChangeListener("value", this);
+
+        logFileNameField = addField("Log File Name", "", "Full path to log file", 50, false);
+        logFileNameField.setEditable(false);
+        
+        aidaServerNameField = addField("AIDA Server Name", "", "Name of AIDA server", 30, true);
+        aidaServerNameField.addPropertyChangeListener("value", this);
     }
 
     @Override
@@ -152,8 +174,6 @@
      * Attaches the ActionListener from the main app to specific GUI components in this class.
      */
     public void addActionListener(ActionListener listener) {
-        logFileNameField.addActionListener(listener);
-        logToFileCheckbox.addActionListener(listener);
         steeringResourcesComboBox.addActionListener(listener);
         freezeConditionsCheckBox.addActionListener(listener);
     }
@@ -171,6 +191,7 @@
             try {
                 checkSteeringFile(file);
                 configurationModel.setSteeringFile(file.getCanonicalPath());
+                configurationModel.setSteeringType(SteeringType.FILE);
             } catch (IOException | JDOMException e) {
                 throw new RuntimeException("Error parsing the selected steering file.", e);
             }
@@ -234,53 +255,52 @@
 
     @Override
     public void actionPerformed(ActionEvent event) {
-
-        //System.out.println("JobSettingsPanel.actionPerformed - " + event.getActionCommand());
-        //System.out.println("  source: " + event.getSource());
-
         try {
             configurationModel.removePropertyChangeListener(this);
+            String command = event.getActionCommand();
             if (event.getActionCommand().equals(Commands.CHOOSE_STEERING_FILE)) {
                 chooseSteeringFile();
             } else if (event.getActionCommand().equals(Commands.CHOOSE_COMPACT_FILE)) {
                 chooseCompactFile();
-            } else if (DISCONNECT_ON_ERROR_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.DISCONNECT_ON_ERROR_CHANGED.equals(command)) {
                 configurationModel.setDisconnectOnError(disconnectOnErrorCheckBox.isSelected());
-            } else if (DISCONNECT_ON_END_RUN_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.DISCONNECT_ON_END_RUN_CHANGED.equals(command)) {
                 configurationModel.setDisconnectOnEndRun(disconnectOnEndRunCheckBox.isSelected());
-            } else if (STEERING_TYPE_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.STEERING_TYPE_CHANGED.equals(command)) {
                 configurationModel.setSteeringType(SteeringType.valueOf((String) steeringTypeComboBox.getSelectedItem()));
-            } else if (STEERING_RESOURCE_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.STEERING_RESOURCE_CHANGED.equals(command)) {
                 configurationModel.setSteeringResource((String) steeringResourcesComboBox.getSelectedItem());
-            } else if (LOG_TO_FILE_CHANGED.equals(event.getActionCommand())) {
-                configurationModel.setLogToFile(logToFileCheckbox.isSelected());
-            } else if (LOG_LEVEL_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) {
                 configurationModel.setLogLevel(Level.parse((String) logLevelComboBox.getSelectedItem()));
-            } else if (EVENT_BUILDER_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.EVENT_BUILDER_CHANGED.equals(command)) {
                 configurationModel.setEventBuilderClassName((String) eventBuilderComboBox.getSelectedItem());
-            } else if (DETECTOR_NAME_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.DETECTOR_NAME_CHANGED.equals(command)) {
                 try {
                     configurationModel.setDetectorName((String) detectorNameComboBox.getSelectedItem());
                 } catch (Exception exception) {
                     exception.printStackTrace();
                 }
-            } else if (FREEZE_CONDITIONS_CHANGED.equals(event.getActionCommand())) {
-                if (configurationModel.hasPropertyKey(USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) {
+            } else if (Commands.FREEZE_CONDITIONS_CHANGED.equals(command)) {
+                if (configurationModel.hasPropertyKey(ConfigurationModel.USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) {
                     configurationModel.setFreezeConditions(freezeConditionsCheckBox.isSelected());
                 } else {
                     throw new IllegalArgumentException("Conditions system may only be frozen if there is a valid user run number.");
                 }
-            } else if (DETECTOR_ALIAS_CHANGED.equals(event.getActionCommand())) {
+            } else if (Commands.DETECTOR_ALIAS_CHANGED.equals(command)) {
                 configurationModel.setDetectorName(detectorAliasField.getText());
-            }
+            } else if (Commands.CONDITIONS_TAG_CHANGED.equals(command)) {
+                configurationModel.setConditionsTag((String) conditionsTagComboBox.getSelectedItem());
+            } else if (Commands.PROCESSING_STAGE_CHANGED.equals(command)) {
+                configurationModel.setProcessingStage((ProcessingStage) processingStageComboBox.getSelectedItem());
+            } 
         } finally {
             configurationModel.addPropertyChangeListener(this);
         }
     }
 
     /**
-     * Updates the configuration with changes from the GUI component values. The changes from the
-     * GUI are distinguishable by their component object.
+     * Updates the configuration with changes from the GUI component values. 
+     * The changes from the GUI are distinguishable by their component object.
      */
     @Override
     public void propertyChange(PropertyChangeEvent evt) {                            
@@ -289,23 +309,18 @@
             Object source = evt.getSource();            
             if (source == steeringFileField) {
                 configurationModel.setSteeringFile(steeringFileField.getText());
-            } else if (source == logFileNameField) {
-                configurationModel.setLogFileName(logFileNameField.getText());
             } else if (source == userRunNumberField) {
                 // Is run number being reset to null or empty?
                 if (userRunNumberField.getText() == null || userRunNumberField.getText().isEmpty()) {
-                    // System.out.println("resetting user run number back to null");
                     // Update the model to null user run number and do not freeze the conditions system.
                     configurationModel.setUserRunNumber(null);
                     configurationModel.setFreezeConditions(false);
                 } else {
                     try {
-                        // System.out.println("setting new user run number " + evt.getNewValue());
                         // Parse the run number. Need to catch errors because it might be an invalid string.
                         int userRunNumber = Integer.parseInt(userRunNumberField.getText());
                         configurationModel.setUserRunNumber(userRunNumber);
                         configurationModel.setFreezeConditions(true);
-                        System.out.println("successfully set run number to userRunNumber");
                     } catch (NumberFormatException e) {
                         System.out.println("bad number format so ignoring user run number " + evt.getNewValue());
                         userRunNumberField.setText((String) evt.getOldValue());
@@ -314,8 +329,26 @@
                 }
             } else if (source == maxEventsField) {
                 configurationModel.setMaxEvents(Long.parseLong(maxEventsField.getText()));
-                System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
-            }
+                //System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
+            } else if (source == aidaServerNameField) {
+                configurationModel.setAIDAServerName(aidaServerNameField.getText());
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
+                // This is getting the log to file prop change from the ConfigurationModel to update a read only component.
+                Boolean logToFile = (Boolean) evt.getNewValue();
+                if (logToFile != null) {
+                    logToFileCheckbox.setSelected(logToFile);
+                }
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
+                // This is getting the log file name prop change from the ConfigurationModel to update a read only component.
+                String logFileName = (String) evt.getNewValue();
+                if (logFileName != null && logFileName.length() > 0) {
+                    logFileNameField.setText(logFileName);
+                } else {
+                    logFileNameField.setText("");
+                }
+            } else if (evt.getPropertyName().equals(ConfigurationModel.CONDITIONS_TAG_PROPERTY)) {
+                conditionsTagComboBox.setSelectedItem(evt.getNewValue()); 
+            } 
         } finally {
             configurationModel.addPropertyChangeListener(this);
         }
@@ -328,57 +361,56 @@
     private class JobSettingsChangeListener implements PropertyChangeListener {
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
-            //System.out.println("JobSettingsChangeListener.propertyChange");
-            //System.out.println("  src: " + evt.getSource());
-            //System.out.println("  propName: " + evt.getPropertyName());
-            //System.out.println("  oldValue: " + evt.getOldValue());
-            //System.out.println("  newValue: " + evt.getNewValue());
-            //System.out.println("  propId: " + evt.getPropagationId());
             if (evt.getSource() instanceof ConfigurationModel) {
                 Object value = evt.getNewValue();
+                String property = evt.getPropertyName();
                 configurationModel.removePropertyChangeListener(this);
                 try {
-                    if (evt.getPropertyName().equals(DETECTOR_NAME_PROPERTY)) {
+                    if (property.equals(ConfigurationModel.DETECTOR_NAME_PROPERTY)) {
                         detectorNameComboBox.setSelectedItem((String) value);
-                    } else if (evt.getPropertyName().equals(DETECTOR_ALIAS_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) {
                         detectorAliasField.setText((String) value);
-                    } else if (evt.getPropertyName().equals(DISCONNECT_ON_ERROR_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY)) {
                         disconnectOnErrorCheckBox.setSelected((Boolean) value);
-                    } else if (evt.getPropertyName().equals(DISCONNECT_ON_END_RUN_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY)) {
                         disconnectOnEndRunCheckBox.setSelected((Boolean) value);
-                    } else if (evt.getPropertyName().equals(EVENT_BUILDER_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.EVENT_BUILDER_PROPERTY)) {
                         eventBuilderComboBox.setSelectedItem((String) value);
-                    } else if (evt.getPropertyName().equals(LOG_FILE_NAME_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
                         logFileNameField.setText((String) value);
-                    } else if (evt.getPropertyName().equals(LOG_LEVEL_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
                         logLevelComboBox.setSelectedItem(value.toString());
-                    } else if (evt.getPropertyName().equals(LOG_TO_FILE_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
                         logToFileCheckbox.setSelected((Boolean) value);
-                    } else if (evt.getPropertyName().equals(STEERING_TYPE_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.STEERING_TYPE_PROPERTY)) {
                         steeringTypeComboBox.setSelectedIndex(((SteeringType) value).ordinal());
-                    } else if (evt.getPropertyName().equals(STEERING_FILE_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.STEERING_FILE_PROPERTY)) {
                         if (value != null) {
-                            steeringFileField.setText((String) value);
+                            steeringFileField.setText((String) evt.getNewValue());
                         } else {
                             // A null value here is actually okay and means this field should be reset to have no value.
                             steeringFileField.setText(null);
                         }
-                    } else if (evt.getPropertyName().equals(STEERING_RESOURCE_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.STEERING_RESOURCE_PROPERTY)) {
                         steeringResourcesComboBox.setSelectedItem(value);
-                    } else if (evt.getPropertyName().equals(USER_RUN_NUMBER_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) {
                         if (value != null) {
                             userRunNumberField.setText(Integer.toString((int) value));
                         } else {
                             userRunNumberField.setText(null);
                         }
-                    } else if (evt.getPropertyName().equals(FREEZE_CONDITIONS_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
                         if (value != null) {
                             freezeConditionsCheckBox.setSelected((Boolean) value);
                         }
-                    } else if (evt.getPropertyName().equals(MAX_EVENTS_PROPERTY)) {
+                    } else if (property.equals(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
                         if (value != null) {
                             maxEventsField.setText(value.toString());
                         }
+                    } else if (property.equals(ConfigurationModel.PROCESSING_STAGE_PROPERTY)) {
+                        processingStageComboBox.setSelectedItem(evt.getNewValue());
+                    } else if (property.equals(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
+                        aidaServerNameField.setText((String) evt.getNewValue());
                     }
                 } finally {
                     configurationModel.addPropertyChangeListener(this);

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	Wed Mar 25 14:43:27 2015
@@ -13,10 +13,10 @@
 import org.hps.monitoring.application.model.ConfigurationModel;
 
 /**
- * 
+ * This is a combo box used to filter the log table messages by level.
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener {
+class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener {
    
     ConfigurationModel configurationModel;
     

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogPanel.java	Wed Mar 25 14:43:27 2015
@@ -17,11 +17,16 @@
  * This is a simple GUI component for the log table and its controls.
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class LogPanel extends JPanel {
+class LogPanel extends JPanel{ 
 
     LogTable logTable;
+    LogLevelFilterComboBox logFilterComboBox;
+    
+    ConfigurationModel configurationModel;
         
     LogPanel(ConfigurationModel configurationModel, ActionListener listener) {
+        
+        this.configurationModel = configurationModel;
         
         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
         
@@ -31,8 +36,8 @@
         controlsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
         
         JLabel label = new JLabel("Log Level Filter");
-        LogLevelFilterComboBox logFilterComboBox = new LogLevelFilterComboBox(configurationModel);
-        logFilterComboBox.setToolTipText("Messages below this level will be filtered out.");              
+        logFilterComboBox = new LogLevelFilterComboBox(configurationModel);
+        logFilterComboBox.setToolTipText("Messages below this level will be filtered out.");
         controlsPanel.add(label);        
         controlsPanel.add(logFilterComboBox);
         
@@ -51,5 +56,5 @@
                 
         add(controlsPanel, BorderLayout.PAGE_START);
         add(tablePane, BorderLayout.PAGE_END);
-    }    
+    }          
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/LogTable.java	Wed Mar 25 14:43:27 2015
@@ -30,7 +30,7 @@
 
     Level filterLevel = Level.ALL;
     
-    final static SimpleDateFormat formatter = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
+    final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             
     LogTable(ConfigurationModel configurationModel) {
         configurationModel.addPropertyChangeListener(this);
@@ -132,5 +132,5 @@
             filterLevel = (Level) event.getNewValue();
             model.fireTableDataChanged();
         }
-    }
+    }    
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/Main.java	Wed Mar 25 14:43:27 2015
@@ -10,7 +10,6 @@
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.PosixParser;
 import org.hps.monitoring.application.model.Configuration;
-
 
 /**
  * This is the front-end for running the monitoring app via a {@link #main(String[])} method.

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MenuBar.java	Wed Mar 25 14:43:27 2015
@@ -1,18 +1,4 @@
 package org.hps.monitoring.application;
-
-import static org.hps.monitoring.application.Commands.EXIT;
-import static org.hps.monitoring.application.Commands.CLOSE_FILE;
-import static org.hps.monitoring.application.Commands.OPEN_FILE;
-import static org.hps.monitoring.application.Commands.CLEAR_PLOTS;
-import static org.hps.monitoring.application.Commands.SAVE_PLOTS;
-import static org.hps.monitoring.application.Commands.LOAD_SETTINGS;
-import static org.hps.monitoring.application.Commands.LOAD_DEFAULT_SETTINGS;
-import static org.hps.monitoring.application.Commands.SAVE_SCREENSHOT;
-import static org.hps.monitoring.application.Commands.SAVE_SETTINGS;
-import static org.hps.monitoring.application.Commands.SHOW_SETTINGS;
-import static org.hps.monitoring.application.Commands.DEFAULT_WINDOW;
-import static org.hps.monitoring.application.Commands.MAXIMIZE_WINDOW;
-import static org.hps.monitoring.application.Commands.MINIMIZE_WINDOW;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -39,37 +25,39 @@
     JMenuItem closeFileItem;
     JMenuItem openFileItem;    
     JMenu settingsMenu;
-    ConfigurationModel configurationModel;
+    JMenuItem logItem;
+    JMenuItem serverItem;
+    ConfigurationModel configurationModel;    
     
     MenuBar(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) {
-        
-        // Do not need to listen for changes on this model.
-        this.configurationModel = configurationModel;
+         
+        this.configurationModel = configurationModel;        
+        this.configurationModel.addPropertyChangeListener(this);
         
         // Need to listen for connection status changes.
-        connectionModel.addPropertyChangeListener(this);                
-
+        connectionModel.addPropertyChangeListener(this);  
+        
         JMenu fileMenu = new JMenu("File");
         fileMenu.setMnemonic(KeyEvent.VK_F);
         add(fileMenu);
         
         openFileItem = new JMenuItem("Open File ...");
         openFileItem.setMnemonic(KeyEvent.VK_P);
-        openFileItem.setActionCommand(OPEN_FILE);
+        openFileItem.setActionCommand(Commands.OPEN_FILE);
         openFileItem.addActionListener(listener);
         openFileItem.setToolTipText("Open an EVIO or LCIO data file");
         fileMenu.add(openFileItem);
         
         closeFileItem = new JMenuItem("Close File");
         closeFileItem.setMnemonic(KeyEvent.VK_C);
-        closeFileItem.setActionCommand(CLOSE_FILE);
+        closeFileItem.setActionCommand(Commands.CLOSE_FILE);
         closeFileItem.addActionListener(listener);
         closeFileItem.setToolTipText("Close the current file data source");
         fileMenu.add(closeFileItem);
               
         JMenuItem exitItem = new JMenuItem("Exit");
         exitItem.setMnemonic(KeyEvent.VK_X);
-        exitItem.setActionCommand(EXIT);
+        exitItem.setActionCommand(Commands.EXIT);
         exitItem.addActionListener(listener);
         exitItem.setToolTipText("Exit from the application");
         fileMenu.add(exitItem);
@@ -80,7 +68,7 @@
         
         JMenuItem settingsItem = new JMenuItem("Open Settings Window ...");
         settingsItem.setMnemonic(KeyEvent.VK_O);
-        settingsItem.setActionCommand(SHOW_SETTINGS);
+        settingsItem.setActionCommand(Commands.SHOW_SETTINGS);
         settingsItem.addActionListener(listener);
         settingsItem.setToolTipText("Show settings dialog");
         settingsMenu.add(settingsItem);
@@ -88,21 +76,21 @@
         JMenuItem loadConfigItem = new JMenuItem("Load Settings ...");
         loadConfigItem.addActionListener(listener);
         loadConfigItem.setMnemonic(KeyEvent.VK_L);
-        loadConfigItem.setActionCommand(LOAD_SETTINGS);
+        loadConfigItem.setActionCommand(Commands.LOAD_SETTINGS);
         loadConfigItem.setToolTipText("Load settings from a properties file");
         settingsMenu.add(loadConfigItem);
 
         JMenuItem saveConfigItem = new JMenuItem("Save Settings ...");
         saveConfigItem.addActionListener(listener);
         saveConfigItem.setMnemonic(KeyEvent.VK_S);
-        saveConfigItem.setActionCommand(SAVE_SETTINGS);
+        saveConfigItem.setActionCommand(Commands.SAVE_SETTINGS);
         saveConfigItem.setToolTipText("Save configuration to a properties file");
         settingsMenu.add(saveConfigItem);
         
         JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings");
         defaultSettingsItem.addActionListener(listener);
         defaultSettingsItem.setMnemonic(KeyEvent.VK_D);
-        defaultSettingsItem.setActionCommand(LOAD_DEFAULT_SETTINGS);
+        defaultSettingsItem.setActionCommand(Commands.LOAD_DEFAULT_SETTINGS);
         defaultSettingsItem.setToolTipText("Load the default settings");
         settingsMenu.add(defaultSettingsItem);
         
@@ -112,7 +100,7 @@
         
         JMenuItem savePlotsItem = new JMenuItem("Save Plots ...");
         savePlotsItem.setMnemonic(KeyEvent.VK_S);
-        savePlotsItem.setActionCommand(SAVE_PLOTS);
+        savePlotsItem.setActionCommand(Commands.SAVE_PLOTS);
         savePlotsItem.addActionListener(listener);
         savePlotsItem.setEnabled(true);
         savePlotsItem.setToolTipText("Save plots to AIDA file");
@@ -120,7 +108,7 @@
 
         JMenuItem clearPlotsItem = new JMenuItem("Clear plots");
         clearPlotsItem.setMnemonic(KeyEvent.VK_C);
-        clearPlotsItem.setActionCommand(CLEAR_PLOTS);
+        clearPlotsItem.setActionCommand(Commands.CLEAR_PLOTS);
         clearPlotsItem.addActionListener(listener);
         clearPlotsItem.setEnabled(true);
         clearPlotsItem.setToolTipText("Clear the AIDA plots");
@@ -132,19 +120,35 @@
         
         JMenuItem screenshotItem = new JMenuItem("Save Screenshot ...");
         screenshotItem.setMnemonic(KeyEvent.VK_S);
-        screenshotItem.setActionCommand(SAVE_SCREENSHOT);
+        screenshotItem.setActionCommand(Commands.SAVE_SCREENSHOT);
         screenshotItem.addActionListener(listener);
         screenshotItem.setEnabled(true);
         screenshotItem.setToolTipText("Save a screenshot to a graphics file");
         toolsMenu.add(screenshotItem);
         
+        logItem = new JMenuItem("Log to File ...");
+        logItem.setMnemonic(KeyEvent.VK_R);
+        logItem.setActionCommand(Commands.LOG_TO_FILE);
+        logItem.addActionListener(listener);
+        logItem.setEnabled(true);
+        logItem.setToolTipText("Redirect System.out to a file instead of terminal");
+        toolsMenu.add(logItem);
+        
+        serverItem = new JMenuItem("Start AIDA Server ...");
+        serverItem.setMnemonic(KeyEvent.VK_A);
+        serverItem.setActionCommand(Commands.START_AIDA_SERVER);
+        serverItem.setEnabled(true);
+        serverItem.setToolTipText("Start AIDA RMI Server");
+        serverItem.addActionListener(listener);
+        toolsMenu.add(serverItem);
+        
         JMenu windowMenu = new JMenu("Window");
         windowMenu.setMnemonic(KeyEvent.VK_W);
         add(windowMenu);
         
         JMenuItem maximizeItem = new JMenuItem("Maximize");
         maximizeItem.setMnemonic(KeyEvent.VK_M);
-        maximizeItem.setActionCommand(MAXIMIZE_WINDOW);
+        maximizeItem.setActionCommand(Commands.MAXIMIZE_WINDOW);
         maximizeItem.addActionListener(listener);
         maximizeItem.setEnabled(true);
         maximizeItem.setToolTipText("Maximize the application window");
@@ -152,7 +156,7 @@
         
         JMenuItem minimizeItem = new JMenuItem("Minimize");
         minimizeItem.setMnemonic(KeyEvent.VK_I);
-        minimizeItem.setActionCommand(MINIMIZE_WINDOW);
+        minimizeItem.setActionCommand(Commands.MINIMIZE_WINDOW);
         minimizeItem.addActionListener(listener);
         minimizeItem.setEnabled(true);
         minimizeItem.setToolTipText("Minimize the application window");
@@ -160,68 +164,38 @@
         
         JMenuItem defaultsItem = new JMenuItem("Restore Defaults");
         defaultsItem.setMnemonic(KeyEvent.VK_D);
-        defaultsItem.setActionCommand(DEFAULT_WINDOW);
+        defaultsItem.setActionCommand(Commands.DEFAULT_WINDOW);
         defaultsItem.addActionListener(listener);
         defaultsItem.setEnabled(true);
         defaultsItem.setToolTipText("Restore the window defaults");
-        windowMenu.add(defaultsItem);        
-        
-        /*                       
-
-        JMenu logMenu = new JMenu("Log");
-        logMenu.setMnemonic(KeyEvent.VK_L);
-        add(logMenu);
-
-        logItem = new JMenuItem("Redirect to File ...");
-        logItem.setMnemonic(KeyEvent.VK_F);
-        logItem.setActionCommand(CHOOSE_LOG_FILE);
-        //logItem.addActionListener(this);
-        logItem.setEnabled(true);
-        logItem.setToolTipText("Redirect std out and err to a file.");
-        logMenu.add(logItem);
-
-        terminalItem = new JMenuItem("Redirect to Terminal");
-        terminalItem.setMnemonic(KeyEvent.VK_T);
-        terminalItem.setActionCommand(LOG_TO_TERMINAL);
-        //terminalItem.addActionListener(this);
-        terminalItem.setEnabled(false);
-        terminalItem.setToolTipText("Redirect std out and err back to the terminal.");
-        logMenu.add(terminalItem);
-
-        JMenuItem saveLogItem = new JMenuItem("Save Log Table to File ...");
-        saveLogItem.setMnemonic(KeyEvent.VK_S);
-        saveLogItem.setActionCommand(SAVE_LOG_TABLE);
-        //saveLogItem.addActionListener(this);
-        saveLogItem.setToolTipText("Save the log records to a tab delimited text file.");
-        logMenu.add(saveLogItem);
-
-        JMenuItem clearLogItem = new JMenuItem("Clear Log Table");
-        //clearLogItem.addActionListener(this);
-        clearLogItem.setMnemonic(KeyEvent.VK_C);
-        clearLogItem.setActionCommand(CLEAR_LOG_TABLE);
-        clearLogItem.setToolTipText("Clear the log table of all messages.");
-        logMenu.add(clearLogItem);
-
-        JMenu utilMenu = new JMenu("Util");
-        plotsMenu.setMnemonic(KeyEvent.VK_U);
-        add(utilMenu);
-
-        JMenuItem screenshotItem = new JMenuItem("Take a Screenshot ...");
-        screenshotItem.setMnemonic(KeyEvent.VK_N);
-        screenshotItem.setActionCommand(SCREENSHOT);
-        //screenshotItem.addActionListener(this);
-        screenshotItem.setToolTipText("Save a screenshot to file");
-        utilMenu.add(screenshotItem);
-        */
+        windowMenu.add(defaultsItem);
     }
 
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
-        if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
-            ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
-            boolean connected = status.equals(ConnectionStatus.CONNECTED);            
-            closeFileItem.setEnabled(!connected);
-            openFileItem.setEnabled(!connected);
+        configurationModel.removePropertyChangeListener(this);        
+        try {            
+            if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
+                ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
+                boolean connected = status.equals(ConnectionStatus.CONNECTED);
+                closeFileItem.setEnabled(!connected);
+                openFileItem.setEnabled(!connected);
+            } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
+                Boolean logToFile = (Boolean) evt.getNewValue();
+                if (logToFile == true) {
+                    // Toggle log item state to send to terminal.
+                    logItem.setText("Log to Terminal ...");
+                    logItem.setActionCommand(Commands.LOG_TO_TERMINAL);
+                    logItem.setToolTipText("Log messages to the terminal");
+                } else {
+                    // Toggle log item state to send to file.
+                    logItem.setText("Log to File ...");
+                    logItem.setActionCommand(Commands.LOG_TO_FILE);
+                    logItem.setToolTipText("Log messages to a file");
+                }
+            }
+        } finally {
+            configurationModel.addPropertyChangeListener(this);
         }
     }
 
@@ -234,6 +208,17 @@
                 closeFileItem.setEnabled(false);
             }
         }        
-    }
-    
+    }    
+    
+    void startAIDAServer() {
+        serverItem.setActionCommand(Commands.STOP_AIDA_SERVER);
+        serverItem.setText("Stop AIDA Server");
+        serverItem.setToolTipText("Stop the remote AIDA server");
+    }
+    
+    void stopAIDAServer() {
+        serverItem.setActionCommand(Commands.START_AIDA_SERVER);
+        serverItem.setText("Start AIDA Server");
+        serverItem.setToolTipText("Start the remote AIDA server");
+    }
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	Wed Mar 25 14:43:27 2015
@@ -3,18 +3,20 @@
 import hep.aida.jfree.AnalysisFactory;
 import hep.aida.jfree.plotter.PlotterRegion;
 import hep.aida.jfree.plotter.PlotterRegionListener;
-
-import java.awt.Dimension;
-import java.awt.Rectangle;
-import java.awt.Robot;
-import java.awt.Toolkit;
+import hep.aida.ref.remote.rmi.client.RmiStoreFactory;
+
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
 import java.awt.image.BufferedImage;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -32,25 +34,25 @@
 import javax.swing.filechooser.FileFilter;
 import javax.swing.filechooser.FileNameExtensionFilter;
 
-import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.monitoring.application.DataSourceComboBox.DataSourceItem;
 import org.hps.monitoring.application.LogTable.LogRecordModel;
 import org.hps.monitoring.application.model.Configuration;
 import org.hps.monitoring.application.model.ConfigurationModel;
+import org.hps.monitoring.application.model.ConnectionStatus;
 import org.hps.monitoring.application.model.ConnectionStatusModel;
 import org.hps.monitoring.application.model.RunModel;
+import org.hps.monitoring.application.util.AIDAServer;
 import org.hps.monitoring.application.util.DialogUtil;
 import org.hps.monitoring.application.util.ErrorHandler;
 import org.hps.monitoring.application.util.EvioFileFilter;
 import org.hps.monitoring.application.util.TableExporter;
 import org.hps.monitoring.plotting.MonitoringAnalysisFactory;
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
-import org.hps.monitoring.subsys.StatusCode;
 import org.hps.monitoring.subsys.SystemStatus;
-import org.hps.monitoring.subsys.SystemStatusListener;
 import org.hps.monitoring.subsys.SystemStatusRegistry;
 import org.hps.record.composite.CompositeRecordProcessor;
 import org.hps.record.enums.DataSourceType;
+import org.lcsim.conditions.ConditionsListener;
 import org.lcsim.util.Driver;
 import org.lcsim.util.aida.AIDA;
 import org.lcsim.util.log.DefaultLogFormatter;
@@ -58,12 +60,11 @@
 /**
  * This is the primary class that implements the monitoring GUI application.
  * It should not be used directly.  Instead the {@link Main} class should be
- * used from the command line or via the supplied script built automatically 
- * by Maven.
+ * used from the command line.
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
-final class MonitoringApplication implements ActionListener, PropertyChangeListener, SystemStatusListener {
+final class MonitoringApplication implements ActionListener, PropertyChangeListener {
 
     // Statically initialize logging, which will be fully setup later.
     static final Logger logger;
@@ -73,13 +74,16 @@
     static final Level DEFAULT_LEVEL = Level.ALL;
 
     // Default log stream.
-    PrintStream logStream = System.out;
+    MonitoringApplicationStreamHandler streamHandler;
+    LogHandler logHandler;
+    PrintStream sysOut = System.out;
+    PrintStream sysErr = System.err;
     
     // Application error handling.
-    final ErrorHandler errorHandler;
+    ErrorHandler errorHandler;
    
     // The main GUI components inside a JFrame.
-    final MonitoringApplicationFrame frame;    
+    MonitoringApplicationFrame frame;    
     
     // The primary data models.
     final RunModel runModel = new RunModel();
@@ -98,6 +102,9 @@
     // Filters for opening files.
     static final FileFilter lcioFilter = new FileNameExtensionFilter("LCIO files", "slcio");
     static final EvioFileFilter evioFilter = new EvioFileFilter();
+    
+    AIDAServer server = new AIDAServer("hps-monitoring-app");
+    static final RmiStoreFactory rsf = new RmiStoreFactory();
             
     /**
      * Default log handler.
@@ -125,43 +132,120 @@
     LogTable getLogTable() {
         return frame.logPanel.logTable;
     }
-             
+    
+    class MonitoringApplicationStreamHandler extends StreamHandler {
+        
+        MonitoringApplicationStreamHandler(PrintStream ps) {
+            super(ps, new DefaultLogFormatter());
+        }
+        
+        public void publish(LogRecord record) {
+            super.publish(record);
+            flush();
+        }
+        
+        public void setOutputStream(OutputStream out) {
+            super.setOutputStream(out);
+        }        
+    }
+                 
     /**
      * Instantiate and show the monitoring application with the given configuration.
      * @param configuration The Configuration object containing application settings.
      */
     MonitoringApplication(Configuration configuration) {
-                
-        // Setup the main GUI component.
-        frame = new MonitoringApplicationFrame(this);
-        
-        // Setup the error handler.
-        errorHandler = new ErrorHandler(frame, logger);
+        
+        try {
+        
+            // Setup the main GUI component.
+            frame = new MonitoringApplicationFrame(this);
+            
+            // Add window listener to perform clean shutdown.
+            frame.addWindowListener(new WindowListener() {
+
+                @Override
+                public void windowOpened(WindowEvent e) {
+                }
+
+                @Override
+                public void windowClosing(WindowEvent e) {
+                }
+
+                @Override
+                public void windowClosed(WindowEvent e) {
+                    exit();
+                }
+
+                @Override
+                public void windowIconified(WindowEvent e) {
+                }
+
+                @Override
+                public void windowDeiconified(WindowEvent e) {
+                }
+
+                @Override
+                public void windowActivated(WindowEvent e) {
+                }
+
+                @Override
+                public void windowDeactivated(WindowEvent e) {
+                }
+            });
+        
+            // Setup the error handler.
+            errorHandler = new ErrorHandler(frame, logger);
                        
-        // Add this class as a listener on the configuration model.
-        configurationModel.addPropertyChangeListener(this);
-        
-        // Setup the logger.
-        setupLogger();
+            // Add this class as a listener on the configuration model.
+            configurationModel.addPropertyChangeListener(this);
+        
+            // Setup the logger.
+            setupLogger();
                
-        // Setup AIDA plotting and connect it to the GUI.
-        setupAida();
-        
-        // Set the configuration.
-        if (configuration != null) {
-            // There was a user specified configuration.
-            this.configuration = configuration;
-        } else {
-            // Use the default configuration.
-            this.configuration = new Configuration(DEFAULT_CONFIGURATION);
-        }
+            // Setup AIDA plotting and connect it to the GUI.
+            setupAida();
+        
+            // Set the configuration.
+            if (configuration != null) {
+                // There was a user specified configuration.
+                this.configuration = configuration;
+            } else {
+                // Use the default configuration.
+                this.configuration = new Configuration(DEFAULT_CONFIGURATION);
+            }
                                       
-        // Load the configuration.
-        loadConfiguration(this.configuration);
-                
-        logger.info("application initialized successfully");
-    }
-    
+            // Load the configuration.
+            loadConfiguration(this.configuration);
+        
+            frame.setEnabled(true);
+        
+            logger.info("application initialized successfully");
+        
+        } catch (Exception e) {
+            // Don't use the ErrorHandler here because we don't know that it initialized successfully.
+            System.err.println("MonitoringApplication failed to initialize without errors!");
+            DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application", "Monitoring application failed to initialize.");
+            e.printStackTrace();
+            System.exit(1);
+        }        
+    }
+    
+    /**
+     * Setup the logger.
+     */
+    void setupLogger() {
+        logger.setUseParentHandlers(false);        
+        logHandler = new LogHandler();
+        logger.addHandler(logHandler);
+        streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        logger.addHandler(streamHandler);
+        for (Handler handler : logger.getHandlers()) {
+            handler.setLevel(DEFAULT_LEVEL);
+        }
+        logger.setLevel(DEFAULT_LEVEL);
+        logger.info("logging initialized");
+    }
+        
     /**
      * Static utility method for creating new instance.
      * @param configuration The application settings.
@@ -177,7 +261,9 @@
      */
     @Override
     public void propertyChange(PropertyChangeEvent evt) {
-        // TODO: Handle log level configuration change here.
+        if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
+            setLogLevel();
+        }
     }
     
     /**
@@ -186,50 +272,59 @@
      */
     public void actionPerformed(ActionEvent e) {
 
-        String cmd = e.getActionCommand();
-        if (Commands.CONNECT.equals(cmd)) {
+        logger.finest("actionPerformed - " + e.getActionCommand());
+        
+        String command = e.getActionCommand();
+        if (Commands.CONNECT.equals(command)) {
             startSession();
-        } else if (Commands.DISCONNECT.equals(cmd)) {
-            processing.stop();
-        } else if (Commands.SAVE_PLOTS.equals(cmd)) {
+        } else if (Commands.DISCONNECT.equals(command)) {
+            runDisconnectThread();
+        } else if (Commands.SAVE_PLOTS.equals(command)) {
             savePlots();
-        } else if (Commands.EXIT.equals(cmd)) {
-            exit();
-        } else if (Commands.PAUSE.equals(cmd)) { 
+        } else if (Commands.EXIT.equals(command)) {
+            // This will trigger the window closing action that cleans everything up.
+            frame.dispose();
+        } else if (Commands.PAUSE.equals(command)) { 
             processing.pause();
-        } else if (Commands.NEXT.equals(cmd)) {
+        } else if (Commands.NEXT.equals(command)) {
             processing.next();
-        } else if (Commands.RESUME.equals(cmd)) {
+        } else if (Commands.RESUME.equals(command)) {
             processing.resume();
-        } else if (Commands.SHOW_SETTINGS.equals(cmd)) {
+        } else if (Commands.SHOW_SETTINGS.equals(command)) {
             showSettingsDialog();
-        } else if (Commands.LOAD_SETTINGS.equals(cmd)) {
+        } else if (Commands.LOAD_SETTINGS.equals(command)) {
             loadSettings();
-        } else if (Commands.SAVE_SETTINGS.equals(cmd)) {
+        } else if (Commands.SAVE_SETTINGS.equals(command)) {
             saveSettings();
-        }  else if (Commands.CLEAR_PLOTS.equals(cmd)) {
+        }  else if (Commands.CLEAR_PLOTS.equals(command)) {
             clearPlots();
-        } else if (Commands.LOAD_DEFAULT_SETTINGS.equals(cmd)) {
+        } else if (Commands.LOAD_DEFAULT_SETTINGS.equals(command)) {
             loadDefaultSettings();
-        } else if (Commands.OPEN_FILE.equals(cmd)) {
+        } else if (Commands.OPEN_FILE.equals(command)) {
             openFile();
-        } else if (Commands.DEFAULT_WINDOW.equals(cmd)) {
+        } else if (Commands.DEFAULT_WINDOW.equals(command)) {
             restoreDefaultWindow();
-        } else if (Commands.MAXIMIZE_WINDOW.equals(cmd)) {
+        } else if (Commands.MAXIMIZE_WINDOW.equals(command)) {
             maximizeWindow();
-        } else if (Commands.MINIMIZE_WINDOW.equals(cmd)) {
+        } else if (Commands.MINIMIZE_WINDOW.equals(command)) {
             minimizeWindow();
-        } else if (Commands.CLOSE_FILE.equals(cmd)) {
+        } else if (Commands.CLOSE_FILE.equals(command)) {
             closeFile();
-        } else if (Commands.SAVE_SCREENSHOT.equals(cmd)) {
+        } else if (Commands.SAVE_SCREENSHOT.equals(command)) {
             saveScreenshot();
-        } else if (Commands.LOG_LEVEL_CHANGED.equals(cmd)) {
-            setLogLevel();
-        } else if (Commands.SAVE_LOG_TABLE.equals(cmd)) {
+        } else if (Commands.SAVE_LOG_TABLE.equals(command)) {
             saveLogTable();
-        } else if (Commands.CLEAR_LOG_TABLE.equals(cmd)) {
+        } else if (Commands.CLEAR_LOG_TABLE.equals(command)) {
             getLogRecordModel().clear();
-        }        
+        } else if (Commands.LOG_TO_FILE.equals(command)) {
+            chooseLogFile();
+        } else if (Commands.LOG_TO_TERMINAL.equals(command)) {
+            logToTerminal();
+        } else if (Commands.START_AIDA_SERVER.equals(command)) {
+            startAIDAServer();
+        } else if (Commands.STOP_AIDA_SERVER.equals(command)) {
+            stopAIDAServer();
+        }
     }    
     
     /**
@@ -255,26 +350,7 @@
         // Perform global configuration of the JFreeChart back end.
         AnalysisFactory.configure();
     }
-    
-    /**
-     * Setup the logger.
-     */
-    void setupLogger() {
-        logger.setUseParentHandlers(false);
-        logger.addHandler(new LogHandler());
-        logger.addHandler(new StreamHandler(logStream, new DefaultLogFormatter()) {
-            public void publish(LogRecord record) {
-                super.publish(record);
-                flush();
-            }
-        });
-        for (Handler handler : logger.getHandlers()) {
-            handler.setLevel(DEFAULT_LEVEL);
-        }
-        logger.setLevel(DEFAULT_LEVEL);
-        logger.info("logging initialized");
-    }
-            
+                
     /**
      * This method sets the configuration on the model, which fires a change for every property.
      * @param configuration The new configuration.
@@ -296,11 +372,14 @@
      * Reset the plots and clear the tabs in the plot window.
      */
     void resetPlots() {
-
+        
+        // Clear global list of registered plotters.
+        MonitoringPlotFactory.getPlotterRegistry().clear();  
+        
         // Clear the static AIDA tree in case plots are hanging around from previous sessions.
         AIDA.defaultInstance().clearAll();
 
-        // Reset plot panel which removes all tabs.
+        // Reset plot panel which removes all its tabs.
         frame.plotPanel.reset();
         
         logger.info("plots were cleared");
@@ -310,43 +389,20 @@
      * Configure the system status monitor panel for a new job.
      */
     void setupSystemStatusMonitor() {
+        
         // Clear the system status monitor table.
-        frame.systemStatusTable.getTableModel().clear();
+        frame.systemStatusPanel.clear();
 
         // Get the global registry of SystemStatus objects.
         SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery();
 
         // Process the SystemStatus objects.
         for (SystemStatus systemStatus : registry.getSystemStatuses()) {
-            // Add a row to the table for every SystemStatus.
-            frame.systemStatusTable.getTableModel().addSystemStatus(systemStatus);
-
-            // Add this class as a listener so all status changes can be logged.
-            systemStatus.addListener(this);
+            // This will add the status to the two tables.
+            frame.systemStatusPanel.addSystemStatus(systemStatus);
         }
         
         logger.info("system status monitor initialized successfully");
-    }
-    
-    /**
-     * Hook for logging all status changes from the system status monitor.
-     */
-    @Override
-    public void statusChanged(SystemStatus status) {
-
-        // Choose the appropriate log level.
-        Level level = Level.FINE;
-        if (status.getStatusCode().equals(Level.WARNING)) {
-            level = Level.WARNING;
-        } else if (status.getStatusCode().ordinal() >= StatusCode.ERROR.ordinal()) {
-            level = Level.SEVERE;
-        }
-        
-        // Log all status changes.
-        logger.log(level, "STATUS, " + "subsys: " + status.getSubsystem() + ", " 
-                + "code: " + status.getStatusCode().name() 
-                + ", " + "descr: " + status.getDescription() 
-                + ", " + "mesg: " + status.getMessage());
     }
     
     /**
@@ -368,13 +424,18 @@
 
             // List of extra composite record processors including the updater for the RunPanel.
             List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>();
-            processors.add(frame.runPanel.new RunPanelUpdater());
-            
+            processors.add(frame.dashboardPanel.new EventDashboardUpdater());
+            
+            // Add Driver to update the trigger diagnostics tables.
             List<Driver> drivers = new ArrayList<Driver>();
             drivers.add(frame.triggerPanel.new TriggerDiagnosticGUIDriver());
-            
-            // Initialize event processing with the list of processors and reference to the application.
-            processing = new EventProcessing(this, processors, drivers);
+
+            // Add listener to push conditions changes to conditions panel.
+            List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>();
+            conditionsListeners.add(frame.conditionsPanel.new ConditionsPanelListener());
+            
+            // Instantiate the event processing wrapper.
+            processing = new EventProcessing(this, processors, drivers, conditionsListeners);
             
             // Connect to the ET system, if applicable.
             processing.connect();
@@ -387,7 +448,7 @@
             // Setup the system status monitor table.
             setupSystemStatusMonitor();
                                             
-            // Start the event processing thread.
+            // Start the event processing thread.            
             processing.start();            
             
             logger.info("new session successfully initialized");
@@ -406,17 +467,17 @@
     }
            
     /**
-     * Exit from the application.
+     * Exit from the application from exit menu item or hitting close window button.
      */
     void exit() {        
-        if (processing != null && processing.isActive()) {
+        if (connectionModel.isConnected()) {
             processing.stop();
         }
-        frame.setVisible(false);
+        logHandler.setLevel(Level.OFF);
         logger.info("exiting the application");
-        logger.getHandlers()[0].flush();
+        streamHandler.flush();
         System.exit(0);
-    }              
+    }
             
     /**
      * Save AIDA plots to a file using a file chooser.
@@ -570,6 +631,7 @@
     /**
      * Save a screenshot to a file using a file chooser.
      */
+    // FIXME: This might need to be on a new thread to allow the GUI to redraw w/o chooser visible.
     void saveScreenshot() {
         JFileChooser fc = new JFileChooser();
         fc.setAcceptAllFileFilterUsed(false);
@@ -584,8 +646,17 @@
             if (!fileName.endsWith("." + format)) {
                 fileName += "." + format;
             }
+            frame.repaint();
+            Object lock = new Object();
+            synchronized (lock) {
+                try {
+                    lock.wait(500);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
             writeScreenshot(fileName, format);
-            DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file.");
+            DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName);
             logger.info("saved screenshot to " + fileName);
         }
     }
@@ -595,15 +666,13 @@
      * @param fileName The name of the output file.
      */
     void writeScreenshot(String fileName, String format) {
-        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-        Rectangle screenRectangle = new Rectangle(screenSize);
+        BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB);
+        frame.paint(image.getGraphics()); 
         try {
-            Robot robot = new Robot();
-            BufferedImage image = robot.createScreenCapture(screenRectangle);
             ImageIO.write(image, format, new File(fileName));
-        } catch (Exception e) {
-            errorHandler.setError(e).setMessage("Failed to take screenshot.").printStackTrace().log().showErrorDialog();
-        }
+        } catch (IOException e) {
+            errorHandler.setError(e).setMessage("Failed to save screenshot.").printStackTrace().log().showErrorDialog();
+        }        
     }            
     
     /**
@@ -644,4 +713,129 @@
     void saveLogTable() {
         saveTable(frame.logPanel.logTable);
     }
+        
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to file chosen
+     * by a file chooser.
+     */
+    void chooseLogFile() {
+        JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setDialogTitle("Save Log Messages to File");       
+        fc.setCurrentDirectory(new File("."));
+        int r = fc.showSaveDialog(frame);
+        if (r == JFileChooser.APPROVE_OPTION) {            
+            String fileName = fc.getSelectedFile().getPath();
+            if (new File(fileName).exists()) {
+                DialogUtil.showErrorDialog(frame, "File Exists", "File already exists.");
+            } else {
+                logToFile(new File(fileName));
+            }
+        }        
+    }
+    
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to a file.
+     * @param file The output log file.
+     * @throws FileNotFoundException if the file does not exist.
+     */
+    void logToFile(File file) {
+        try {
+            
+            // Create the output file stream.
+            PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath()));
+            System.setOut(fileStream);
+            System.setErr(fileStream);
+            
+            // Flush the current handler, but do NOT close here or System.out gets clobbered!
+            streamHandler.flush();
+            
+            // Replace the current handler with one using the file stream.
+            logger.removeHandler(streamHandler);
+            streamHandler = new MonitoringApplicationStreamHandler(fileStream);
+            streamHandler.setLevel(logger.getLevel());
+            logger.addHandler(streamHandler);
+            
+            // Set the properties on the model.
+            configurationModel.setLogFileName(file.getPath());
+            configurationModel.setLogToFile(true);
+            
+            logger.info("Saving log messages to " + configurationModel.getLogFileName());
+            DialogUtil.showInfoDialog(frame, "Logging to File", 
+                    "Log messages redirected to file" + '\n' + configurationModel.getLogFileName());
+            
+        } catch (FileNotFoundException e) {
+            errorHandler.setError(e).log().showErrorDialog();
+        }
+    }      
+    
+    /**
+     * Send <code>System.out</code> and <code>System.err</code> back to the terminal, 
+     * e.g. if they were previously sent to a file.
+     */
+    void logToTerminal() {
+        
+        // Reset System.out and err back to original streams.
+        System.setOut(sysOut);
+        System.setErr(sysErr);
+        
+        // Flush and close the current handler, which is using a file stream.
+        streamHandler.flush();
+        streamHandler.close();
+        
+        // Replace the handler with the one printing to the terminal.
+        logger.removeHandler(streamHandler);               
+        streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        streamHandler.setLevel(logger.getLevel());
+        logger.addHandler(streamHandler);
+        
+        logger.log(Level.INFO, "log messages redirected to terminal");
+        
+        // Update the model to indicate logging to file has been disabled.
+        configurationModel.setLogToFile(false);
+        
+        DialogUtil.showInfoDialog(frame, "Log to Terminal", "Log messages will be sent to the terminal.");
+    }    
+    
+    /**
+     * Start the AIDA server instance.
+     */
+    void startAIDAServer() {
+        if (configurationModel.hasValidProperty(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
+            server.setName(configurationModel.getAIDAServerName());
+        }
+        boolean started = server.start();
+        if (started) {
+            frame.menu.startAIDAServer();
+            logger.info("AIDA server started at " + server.getName());
+            DialogUtil.showInfoDialog(frame, "AIDA Server Started", "The remote AIDA server started successfully.");
+        } else {
+            logger.warning("AIDA server failed to start");
+            DialogUtil.showErrorDialog(frame, "Failed to Start AIDA Server", "The remote AIDA server failed to start.");
+        }
+    }
+    
+    /**
+     * Stop the AIDA server instance.
+     */
+    void stopAIDAServer() {
+        server.disconnect();
+        frame.menu.stopAIDAServer();
+        logger.info("AIDA server was stopped");
+        DialogUtil.showInfoDialog(frame, "AIDA Server Stopped", "The AIDA server was stopped.");
+    }    
+    
+    /**
+     * 
+     */
+    void runDisconnectThread() {
+        new Thread() {
+            public void run() {
+                logger.fine("disconnect thread is running ...");
+                connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING);
+                MonitoringApplication.this.processing.stop();
+                logger.fine("disconnect thread finished!");
+            }
+        }.run();
+    }
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java	Wed Mar 25 14:43:27 2015
@@ -3,14 +3,11 @@
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
-import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
 import java.awt.Rectangle;
 
-import javax.swing.BoxLayout;
-import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
 import javax.swing.JSeparator;
 import javax.swing.JSplitPane;
 import javax.swing.JTabbedPane;
@@ -23,13 +20,15 @@
  */
 class MonitoringApplicationFrame extends JFrame {
             
-    RunPanel runPanel;    
+    EventDashboard dashboardPanel;    
     PlotPanel plotPanel;
     PlotInfoPanel plotInfoPanel;
     LogPanel logPanel;
-    SystemStatusTable systemStatusTable;
     JPanel buttonsPanel;
     TriggerDiagnosticsPanel triggerPanel;
+    ConditionsPanel conditionsPanel;
+    SystemStatusPanel systemStatusPanel;
+    MenuBar menu; 
     
     JSplitPane mainSplitPane;
     JSplitPane rightSplitPane;
@@ -38,14 +37,10 @@
     DataSourceComboBox dataSourceComboBox;
     
     SettingsDialog settingsDialog;
-    
-    // Proportional layout parameters relative to the screen size.
-    static final double FULL_SIZE = 1.0;
-    static final double TOP_PANEL_HEIGHT = 0.05;
-    static final double BOTTOM_PANEL_HEIGHT = FULL_SIZE - TOP_PANEL_HEIGHT;
-    static final double LEFT_PANEL_WIDTH = 0.3;
-    static final double RIGHT_PANEL_WIDTH = FULL_SIZE - LEFT_PANEL_WIDTH;
-    static final double PLOT_PANEL_HEIGHT = 0.8;
+       
+    static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+    static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth();
+    static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight();
     
     /**
      * 
@@ -53,20 +48,22 @@
      */
     public MonitoringApplicationFrame(
             MonitoringApplication application) {
+        
+        // Disable interaction until specifically enabled externally after initialization.
+        setEnabled(false);
                 
         // Create the content panel.
         JPanel contentPanel = new JPanel();
         setContentPane(contentPanel);
-        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
+        contentPanel.setLayout(new BorderLayout());
         contentPanel.setOpaque(true);
-        setProportionalSize(contentPanel, FULL_SIZE, FULL_SIZE);
-        
+        contentPanel.setPreferredSize(new Dimension(PIXEL_WIDTH_MAX, PIXEL_HEIGHT_MAX));
+                
         // Create the top panel.
         JPanel topPanel = new JPanel();
         topPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 0));
-        setProportionalSize(topPanel, FULL_SIZE, TOP_PANEL_HEIGHT);
-        contentPanel.add(topPanel);
-        
+        contentPanel.add(topPanel, BorderLayout.NORTH);
+                
         // Create the connection status panel.
         JPanel connectionPanel = new ConnectionStatusPanel(application.connectionModel);
         topPanel.add(connectionPanel);
@@ -82,7 +79,6 @@
         
         // Add vertical separator.
         sep = new JSeparator(SwingConstants.VERTICAL);
-        sep.setPreferredSize(new Dimension(5, topPanel.getPreferredSize().height));
         topPanel.add(sep);
         
         // Add the data source combo box.
@@ -92,16 +88,14 @@
         // Create the bottom panel.
         JPanel bottomPanel = new JPanel();
         bottomPanel.setLayout(new BorderLayout());
-        setProportionalSize(bottomPanel, FULL_SIZE, BOTTOM_PANEL_HEIGHT);
-        contentPanel.add(bottomPanel);
-                                
+        contentPanel.add(bottomPanel, BorderLayout.CENTER);
+                                        
         // Create the left panel.
         JPanel leftPanel = new JPanel();
         leftPanel.setLayout(new BorderLayout());
-        setProportionalSize(leftPanel, LEFT_PANEL_WIDTH, FULL_SIZE);
-                        
+                            
         // Create the run dashboard.
-        runPanel = new RunPanel(application.runModel);
+        dashboardPanel = new EventDashboard(application.runModel);
 
         // Create the tabbed pane for content in bottom of left panel such as log table and system monitor.
         JTabbedPane tableTabbedPane = new JTabbedPane();
@@ -111,76 +105,58 @@
         tableTabbedPane.addTab("Log Messages", logPanel);
         
         // Create the system monitor.
-        systemStatusTable = new SystemStatusTable();
-        tableTabbedPane.addTab("System Status Monitor", new JScrollPane(systemStatusTable));
+        //systemStatusTable = new SystemStatusTable();
+        systemStatusPanel = new SystemStatusPanel();
+        tableTabbedPane.addTab("System Status Monitor", systemStatusPanel);
         
         // Add the trigger diagnostics tables.
         triggerPanel = new TriggerDiagnosticsPanel();
         tableTabbedPane.addTab("Trigger Diagnostics", triggerPanel);
         
+        // Add the conditions panel.
+        conditionsPanel = new ConditionsPanel();
+        tableTabbedPane.addTab("Detector Conditions", conditionsPanel);
+        
         // Vertical split pane in left panel.
-        leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, runPanel, tableTabbedPane);
-        leftSplitPane.setResizeWeight(0.5);
+        leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, dashboardPanel, tableTabbedPane);
+        leftSplitPane.setDividerLocation(250);
         leftPanel.add(leftSplitPane, BorderLayout.CENTER);
                                 
         // Create the right panel.
         JPanel rightPanel = new JPanel();
         rightPanel.setLayout(new BorderLayout());
-        
+                
         // Create the plot info panel.
         plotInfoPanel = new PlotInfoPanel();
                 
         // Create the plot panel.
-        plotPanel = new PlotPanel();
-        plotPanel.setVisible(true); // DEBUG
-        setProportionalSize(plotPanel, RIGHT_PANEL_WIDTH, PLOT_PANEL_HEIGHT);
+        plotPanel = new PlotPanel();        
+        plotInfoPanel.saveButton.addActionListener(plotPanel);
         
         // Create the right panel vertical split pane for displaying plots and their information and statistics.
         rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, plotPanel, plotInfoPanel);
-        setProportionalSize(rightSplitPane, RIGHT_PANEL_WIDTH, FULL_SIZE);
-        rightSplitPane.setResizeWeight(0.8);
+        rightSplitPane.setResizeWeight(0.7);
         rightPanel.add(rightSplitPane, BorderLayout.CENTER);
                        
         // Create the main horizontal split pane for dividing the left and right panels.
         mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
-        mainSplitPane.setResizeWeight(0.15);
+        mainSplitPane.setDividerLocation(PIXEL_WIDTH_MAX / 2);
         bottomPanel.add(mainSplitPane, BorderLayout.CENTER);
         
         // Create the menu bar.
-        MenuBar menu = new MenuBar(application.configurationModel, application.connectionModel, application);
+        menu = new MenuBar(application.configurationModel, application.connectionModel, application);
         setJMenuBar(menu);
         dataSourceComboBox.addActionListener(menu);
-                        
+        
+        // Setup the settings dialog box (invisible until activated).
+        settingsDialog = new SettingsDialog(application.configurationModel, application);        
+               
         // Setup the frame now that all components have been added.        
         pack();
         setExtendedState(JFrame.MAXIMIZED_BOTH);
-        setVisible(true);
-        
-        // Setup the settings dialog box.
-        settingsDialog = new SettingsDialog(application.configurationModel, application);
+        setVisible(true); 
     }
-    
-    /**
-     * Set the size of a Swing component using proportions of the current screen bounds.
-     * @param component The component to resize.
-     * @param scaleX The X scaling (must be between 0 and 1).
-     * @param scaleY The Y scaling (must be between 0 and 1).
-     * @param setSize Call the setSize method as well as setPreferredSize (which is the default).
-     * @return
-     */
-    void setProportionalSize(JComponent component, double scaleX, double scaleY) {                    
-        GraphicsConfiguration graphics = this.getGraphicsConfiguration();        
-        Rectangle bounds = graphics.getBounds();        
-        if (scaleX < 0 || scaleX > 1) {
-            throw new IllegalArgumentException("scaleX must be > 0 and <= 1.");
-        }
-        if (scaleY < 0 || scaleY > 1) {
-            throw new IllegalArgumentException("scaleY must be > 0 and <= 1.");
-        }
-        Dimension scaledDimension = new Dimension((int)(bounds.getWidth() * scaleX), (int)(bounds.getHeight() * scaleY));
-        component.setPreferredSize(scaledDimension);
-    }           
-    
+             
     /**
      * Restore default window settings.
      */

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	Wed Mar 25 14:43:27 2015
@@ -15,10 +15,10 @@
 import hep.aida.ref.function.FunctionDispatcher;
 import hep.aida.ref.function.FunctionListener;
 
+import java.awt.Color;
 import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.EventObject;
@@ -27,6 +27,8 @@
 import java.util.TimerTask;
 
 import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JList;
 import javax.swing.JPanel;
@@ -38,15 +40,17 @@
 /**
  * <p>
  * This is a GUI component for showing the statistics and other information about an AIDA plot
- * when it is clicked on in the monitoring app.
+ * when it is clicked on in the monitoring application.
  * <p>
- * The information is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
+ * The information in the table is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
  */
 class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener {
 
     JComboBox<Object> plotComboBox;
     JTable infoTable = new JTable();
     DefaultTableModel model;
+    JButton saveButton;
+    
     PlotterRegion currentRegion;
     Object currentObject;
     static final int INSET_SIZE = 5;
@@ -63,11 +67,18 @@
      */
     @SuppressWarnings("unchecked")
     PlotInfoPanel() {
-
-        setLayout(new GridBagLayout());
-        setBorder(BorderFactory.createEmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
-
-        GridBagConstraints c;
+                
+        setLayout(new FlowLayout(FlowLayout.LEFT));
+
+        JPanel leftPanel = new JPanel();
+        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
+           
+        JPanel buttonPanel = new JPanel();
+        saveButton = new JButton("Save Plots ...");
+        saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS);
+        buttonPanel.add(saveButton);       
+        //c.anchor = GridBagConstraints.NORTHWEST;
+        leftPanel.add(buttonPanel);
 
         plotComboBox = new JComboBox<Object>();
         plotComboBox.setActionCommand(PLOT_SELECTED);
@@ -85,26 +96,17 @@
             }
         });
         plotComboBox.addActionListener(this);
-        c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = 0;
-        c.fill = GridBagConstraints.HORIZONTAL;
-        c.insets = new Insets(0, 0, INSET_SIZE, 0);
-        add(plotComboBox, c);
-
+        leftPanel.add(plotComboBox);
+        
         String data[][] = new String[0][0];
         model = new DefaultTableModel(data, COLUMN_NAMES);
         infoTable.setModel(model);
-
-        // FIXME: Are these adequate column size settings? Could prob be bigger...
         infoTable.getColumn("Field").setMinWidth(25);
         infoTable.getColumn("Value").setMinWidth(20);
-
-        c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = 1;
-        c.fill = GridBagConstraints.BOTH;
-        add(infoTable, c);
+        infoTable.setMinimumSize(new Dimension(100, 200));
+        leftPanel.add(infoTable);
+        
+        add(leftPanel);
     }
 
     /**

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java	Wed Mar 25 14:43:27 2015
@@ -1,15 +1,26 @@
 package org.hps.monitoring.application;
 
+import hep.aida.IPlotter;
+
 import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
 
+import javax.swing.JFileChooser;
 import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
 
+import org.hps.monitoring.application.util.DialogUtil;
+import org.hps.monitoring.plotting.MonitoringPlotFactory;
+
 /**
- * This is the panel containing the monitoring plots.
+ * This is the panel containing the tabs with the monitoring plots.
  * @author Jeremy McCormick <[log in to unmask]>
  */
-class PlotPanel extends JPanel {
+class PlotPanel extends JPanel implements ActionListener {
     
     private JTabbedPane plotPane;    
     
@@ -23,8 +34,55 @@
     JTabbedPane getPlotPane() {
         return plotPane;
     }
+
+    /**
+     * Get the indices of the current selected tabs.
+     * @return The indices of the current tabs.
+     */
+    int[] getSelectedTabs() {
+        int[] indices = new int[2];
+        indices[0] = plotPane.getSelectedIndex();
+        Component component = plotPane.getSelectedComponent();
+        if (component instanceof JTabbedPane) {
+            indices[1] = ((JTabbedPane)component).getSelectedIndex();
+        } 
+        return indices;
+    }
+    
+    public void actionPerformed(ActionEvent event) {
+        if (event.getActionCommand().equals(Commands.SAVE_SELECTED_PLOTS)) {
+            int[] indices = getSelectedTabs();
+            IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]);
+            if (plotter != null) {
+                savePlotter(plotter);
+            } else {
+                DialogUtil.showErrorDialog(this, "Error Finding Plots", "No plots found in selected tab.");
+            }
+        }
+    }
+            
+    static final String DEFAULT_FORMAT = "png";
+    void savePlotter(IPlotter plotter) {
+        JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setDialogTitle("Save Plots - " + plotter.title());
+        fc.setCurrentDirectory(new File("."));
+        int r = fc.showSaveDialog(this);
+        if (r == JFileChooser.APPROVE_OPTION) {                        
+            String path = fc.getSelectedFile().getPath();
+            if (path.lastIndexOf(".") == -1) {
+                path += "." + DEFAULT_FORMAT;
+            }
+            try {
+                plotter.writeToFile(path);
+            } catch (IOException e) {
+                e.printStackTrace();
+                DialogUtil.showErrorDialog(this, "Error Saving Plots", "There was an error saving the plots.");
+            }
+        }        
+    }
     
     void reset() {
-        plotPane.removeAll();
-    }
+        plotPane.removeAll();        
+    }    
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SettingsPanel.java	Wed Mar 25 14:43:27 2015
@@ -31,7 +31,7 @@
         this.parent = parent;
         
         connectionPanel = new ConnectionSettingsPanel();        
-        jobPanel = new JobSettingsPanel();
+        jobPanel = new JobSettingsPanel(configurationModel);
         
         // Push configuration to sub-components.
         connectionPanel.setConfigurationModel(configurationModel);
@@ -55,7 +55,6 @@
         add(Box.createRigidArea(new Dimension(1, 5)));
         JPanel buttonsPanel = new JPanel();
         buttonsPanel.add(okayButton);
-        //buttonsPanel.add(defaultsButton);
         buttonsPanel.setLayout(new FlowLayout());
         add(buttonsPanel);
         add(Box.createRigidArea(new Dimension(1, 5)));

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java	Wed Mar 25 14:43:27 2015
@@ -1,8 +1,5 @@
 package org.hps.monitoring.application;
 
-import static org.hps.monitoring.application.model.SystemStatusTableModel.*;
-
-import java.awt.Color;
 import java.awt.Component;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -19,8 +16,7 @@
 import org.hps.monitoring.subsys.StatusCode;
 
 /**
- * A GUI window for showing changes to {@link org.hps.monitoring.subsys.SystemStatus} objects using
- * a <code>JTable</code>.
+ * This table shows the current state of {@link org.hps.monitoring.subsys.SystemStatus} objects.
  */
 class SystemStatusTable extends JTable {
 
@@ -39,34 +35,13 @@
 
                 // Color code the cell by its status.
                 StatusCode statusCode = StatusCode.valueOf((String) value);
-                if (statusCode.ordinal() >= StatusCode.ERROR.ordinal()) {
-                    // Any type of error is red.
-                    label.setBackground(Color.RED);
-                } else if (statusCode.equals(StatusCode.WARNING)) {
-                    // Warnings are yellow.
-                    label.setBackground(Color.YELLOW);
-                } else if (statusCode.equals(StatusCode.OKAY)) {
-                    // Okay is green.
-                    label.setBackground(Color.GREEN);
-                } else if (statusCode.equals(StatusCode.OFFLINE)) {
-                    // Offline is orange.
-                    label.setBackground(Color.ORANGE);
-                } else if (statusCode.equals(StatusCode.UNKNOWN)) {
-                    // Unknown is gray.
-                    label.setBackground(Color.GRAY);
-                } else if (statusCode.equals(StatusCode.CLEARED)) {
-                    // Cleared is light gray.
-                    label.setBackground(Color.LIGHT_GRAY);
-                } else {
-                    // Default is white, though this shouldn't happen!
-                    label.setBackground(Color.WHITE);
-                }
+                label.setBackground(statusCode.getColor());
                 return label;
             }
         });
 
         // Date formatting for last changed.
-        getColumnModel().getColumn(LAST_CHANGED_COL).setCellRenderer(new DefaultTableCellRenderer() {
+        getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COL).setCellRenderer(new DefaultTableCellRenderer() {
 
             final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
 
@@ -80,16 +55,16 @@
         });
 
         // Button for clearing system statuses.
-        getColumnModel().getColumn(RESET_COL).setCellRenderer(new ButtonRenderer("Clear"));
+        getColumnModel().getColumn(SystemStatusTableModel.RESET_COL).setCellRenderer(new ButtonRenderer("Clear"));
         addMouseListener(new JTableButtonMouseListener(this));
         getColumn("Clearable").setWidth(0);
         getColumn("Clearable").setMinWidth(0);
         getColumn("Clearable").setMaxWidth(0);
 
         // Column widths.
-        getColumnModel().getColumn(ACTIVE_COL).setPreferredWidth(8);
-        getColumnModel().getColumn(STATUS_COL).setPreferredWidth(10);
-        getColumnModel().getColumn(SYSTEM_COL).setPreferredWidth(10);
+        getColumnModel().getColumn(SystemStatusTableModel.ACTIVE_COL).setPreferredWidth(8);
+        getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).setPreferredWidth(10);
+        getColumnModel().getColumn(SystemStatusTableModel.SYSTEM_COL).setPreferredWidth(10);
         // TODO: Add default width setting for every column.
 
         setAutoCreateRowSorter(true);
@@ -109,7 +84,7 @@
         }
 
         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-            boolean clearable = (Boolean) table.getModel().getValueAt(row, CLEARABLE_COL);
+            boolean clearable = (Boolean) table.getModel().getValueAt(row, SystemStatusTableModel.CLEARABLE_COL);
             if (clearable)
                 return this;
             else

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	Wed Mar 25 14:43:27 2015
@@ -21,7 +21,7 @@
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
-public class TriggerDiagnosticsPanel extends JPanel {
+class TriggerDiagnosticsPanel extends JPanel {
 
     JTabbedPane tabs = new JTabbedPane();
     ClusterTablePanel clusterPanel = new ClusterTablePanel();
@@ -70,9 +70,7 @@
                 for (DiagnosticUpdatable update : updateList) {
                     update.updatePanel(snapshot);
                 }
-            } else {
-                System.out.println("no diag snapshot in event");
-            }
+            } 
         }
         
         void setDiagnosticCollectionName(String name) {

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java	Wed Mar 25 14:43:27 2015
@@ -1,6 +1,5 @@
 package org.hps.monitoring.application.model;
 
-import java.io.File;
 import java.util.logging.Level;
 
 import org.hps.record.enums.DataSourceType;
@@ -16,6 +15,8 @@
     Configuration configuration;    
     
     // Job setting properties.
+    public static final String AIDA_SERVER_NAME_PROPERTY = "AIDAServerName";
+    public static final String CONDITIONS_TAG_PROPERTY = "ConditionsTag";
     public static final String DETECTOR_NAME_PROPERTY = "DetectorName";
     public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias";
     public static final String DISCONNECT_ON_ERROR_PROPERTY = "DisconnectOnError";
@@ -104,18 +105,14 @@
         firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, getSteeringType());
     }
 
-    public File getSteeringFile() {
-        if (configuration.hasKey(STEERING_FILE_PROPERTY)) {
-            return new File(configuration.get(STEERING_FILE_PROPERTY));
-        } else {
-            return null;
-        }
+    public String getSteeringFile() {        
+        return configuration.get(STEERING_FILE_PROPERTY);
     }
 
     public void setSteeringFile(String steeringFile) {
-        File oldValue = getSteeringFile();
+        String oldValue = getSteeringFile();
         configuration.set(STEERING_FILE_PROPERTY, steeringFile);
-        firePropertyChange(STEERING_FILE_PROPERTY, oldValue, getSteeringFile().getPath());
+        firePropertyChange(STEERING_FILE_PROPERTY, oldValue, getSteeringFile());
     }
 
     public String getSteeringResource() {
@@ -391,6 +388,26 @@
        
     public String getEtPath() {
         return getEtName() + "@" + getHost() + ":" + getPort();
+    }
+    
+    public void setConditionsTag(String conditionsTag) {
+        String oldValue = getConditionsTag();
+        configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag);
+        firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, getConditionsTag());
+    }     
+    
+    public String getConditionsTag() {
+        return configuration.get(CONDITIONS_TAG_PROPERTY);
+    }
+    
+    public void setAIDAServerName(String AIDAServerName) {
+        String oldValue = getAIDAServerName();
+        configuration.set(AIDA_SERVER_NAME_PROPERTY, AIDAServerName);
+        firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, getAIDAServerName());
+    } 
+    
+    public String getAIDAServerName() {
+        return configuration.get(AIDA_SERVER_NAME_PROPERTY);
     }
 
     public void remove(String property) {

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java	Wed Mar 25 14:43:27 2015
@@ -10,6 +10,7 @@
 public enum ConnectionStatus {
 
     DISCONNECTED(Color.RED),
+    DISCONNECTING(Color.YELLOW),
     CONNECTED(Color.GREEN);
     
     Color color;    

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java	Wed Mar 25 14:43:27 2015
@@ -50,4 +50,16 @@
             listener.propertyChange(new PropertyChangeEvent(this, PAUSED_PROPERTY, oldValue, this.paused));
         }
     }
+    
+    public boolean isConnected() {
+        return this.connectionStatus == ConnectionStatus.CONNECTED;
+    }
+    
+    public boolean isDisconnected() {
+        return this.connectionStatus == ConnectionStatus.DISCONNECTED;
+    }
+    
+    public boolean isDisconnecting() {
+        return this.connectionStatus == ConnectionStatus.DISCONNECTING;
+    }
 }

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java	Wed Mar 25 14:43:27 2015
@@ -3,7 +3,7 @@
 import java.util.Date;
 
 /**
- * Backing model for run information that shows in the {@link org.hps.monitoring.application.RunPanel}.
+ * Backing model for run information that shows in the {@link org.hps.monitoring.application.EventDashboard}.
  */
 public final class RunModel extends AbstractModel {
 

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java	Wed Mar 25 14:43:27 2015
@@ -85,7 +85,7 @@
      * @return This object.
      */
     public ErrorHandler log() {
-        logger.log(Level.SEVERE, message);
+        logger.log(Level.SEVERE, message, error);
         return this;
     }
 

Modified: java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java	(original)
+++ java/branches/prod/monitoring-app/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java	Wed Mar 25 14:43:27 2015
@@ -14,6 +14,7 @@
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
+import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.record.LCSimEventBuilder;
 import org.reflections.Reflections;
 
@@ -116,4 +117,8 @@
         Collections.sort(detectorNames);
         return detectorNames.toArray(new String[detectorNames.size()]);
     }        
+    
+    public static String[] getConditionsTags() {
+        return DatabaseConditionsManager.getInstance().getTags().toArray(new String[] {});
+    }
 }

Modified: java/branches/prod/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop	(original)
+++ java/branches/prod/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop	Wed Mar 25 14:43:27 2015
@@ -2,8 +2,9 @@
 # Monitoring Application configuration
 
 # job settings
+AIDAServerName=hps-monitoring-app
 DetectorName=HPS-Proposal2014-v8-6pt6
-DisconnectOnError=false
+DisconnectOnError=true
 DisconnectOnEndRun=true
 EventBuilderClassName=org.hps.evio.LCSimEngRunEventBuilder
 #LogFileName=
@@ -19,20 +20,18 @@
 DataSourceType=ET_SERVER
 #DataSourcePath=
 ProcessingStage=LCIO
-
+ 
 # ET connection settings
+# FIXME: These should really all be prepended by 'Et' so their purpose is clear.
 Blocking=false
 EtName=ETBuffer
 ChunkSize=1
 Host=localhost
 Port=11111
 StationPosition=1
-# Prescale was 1
-Prescale=0
+Prescale=1
 QueueSize=0
 StationName=MY_STATION
 Verbose=false
 WaitMode=TIMED
-WaitTime=1000000000
-
-SaveLayout=false;
+WaitTime=1000000000

Modified: java/branches/prod/monitoring-app/src/main/scripts/evio_file_producer.sh
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/scripts/evio_file_producer.sh	(original)
+++ java/branches/prod/monitoring-app/src/main/scripts/evio_file_producer.sh	Wed Mar 25 14:43:27 2015
@@ -14,6 +14,6 @@
 
 # Run the file producer, sending any additional arguments to the command.
 #prod="java -classpath $classpath org.hps.evio.EvioFileProducer -e ${eviofile} -f ETBuffer -host localhost -s 10000 -d 100 $@"
-prod="java -classpath $classpath org.hps.record.evio.EvioFileProducer -e ${eviofile} -f ETBuffer -host localhost -s 100000 $@"
+prod="java -classpath $classpath org.hps.record.evio.EvioFileProducer -e ${eviofile} -f ETBuffer -host localhost -s 200000 $@"
 echo $prod
 exec $prod

Modified: java/branches/prod/monitoring-app/src/main/scripts/start_et_ring.sh
 =============================================================================
--- java/branches/prod/monitoring-app/src/main/scripts/start_et_ring.sh	(original)
+++ java/branches/prod/monitoring-app/src/main/scripts/start_et_ring.sh	Wed Mar 25 14:43:27 2015
@@ -15,6 +15,6 @@
 fi
 
 # Start the ET ring, sending any script arguments to the end of the command.
-server="java -Xmx1024m -classpath $classpath org.jlab.coda.et.apps.StartEt -f $buffer_file -s 100000 -v $@" 
+server="java -Xmx1024m -classpath $classpath org.jlab.coda.et.apps.StartEt -f $buffer_file -s 200000 -v $@" 
 echo "$server"
 exec $server

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SensorOccupancyPlotsDriver.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SensorOccupancyPlotsDriver.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SensorOccupancyPlotsDriver.java	Wed Mar 25 14:43:27 2015
@@ -5,13 +5,14 @@
 import hep.aida.IHistogramFactory;
 import hep.aida.IPlotter;
 import hep.aida.IPlotterFactory;
+import hep.aida.IPlotterStyle;
+import hep.aida.ref.plotter.style.registry.StyleRegistry;
 
+import java.awt.Color;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.lcsim.detector.identifier.IIdentifier;
-import org.lcsim.detector.identifier.IIdentifierHelper;
 import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.RawTrackerHit;
@@ -19,32 +20,34 @@
 import org.lcsim.util.Driver;
 
 /**
- *	This Driver makes plots of sensor occupancies across a run. It is intended to
- * 	be used with the monitoring system.
+ * This Driver makes plots of sensor occupancies across a run. It is intended to be used with the
+ * monitoring system.
  *
- *  @author Jeremy McCormick <[log in to unmask]>
- *	@author Omar Moreno <[log in to unmask]>
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @author Omar Moreno <[log in to unmask]>
  */
 public class SensorOccupancyPlotsDriver extends Driver {
 
     // TODO: Add documentation
     // TODO: Set plot styles
-	
-	static IHistogramFactory histogramFactory = IAnalysisFactory.create().createHistogramFactory(null);
-	IPlotterFactory plotterFactory = IAnalysisFactory.create().createPlotterFactory();
-	
-	protected Map<String, IPlotter> plotters = new HashMap<String, IPlotter>(); 
-	protected Map<HpsSiSensor, IHistogram1D> occupancyPlots = new HashMap<HpsSiSensor, IHistogram1D>(); 
-	protected Map<HpsSiSensor, int[]> occupancyMap = new HashMap<HpsSiSensor, int[]>(); 
+
+    static IHistogramFactory histogramFactory = IAnalysisFactory.create().createHistogramFactory(null);
+    IPlotterFactory plotterFactory = IAnalysisFactory.create().createPlotterFactory();
+    static StyleRegistry styleRegistry = StyleRegistry.getStyleRegistry();
+
+    protected Map<String, IPlotter> plotters = new HashMap<String, IPlotter>();
+    protected Map<HpsSiSensor, IHistogram1D> occupancyPlots = new HashMap<HpsSiSensor, IHistogram1D>();
+    protected Map<HpsSiSensor, int[]> occupancyMap = new HashMap<HpsSiSensor, int[]>();
     private List<HpsSiSensor> sensors;
-	
+
     private static final String SUBDETECTOR_NAME = "Tracker";
     private String rawTrackerHitCollectionName = "SVTRawTrackerHits";
 
     private int eventCount = 0;
     private int eventRefreshRate = 1;
 
-    public SensorOccupancyPlotsDriver() {}
+    public SensorOccupancyPlotsDriver() {
+    }
 
     public void setRawTrackerHitCollectionName(String rawTrackerHitCollectionName) {
         this.rawTrackerHitCollectionName = rawTrackerHitCollectionName;
@@ -56,83 +59,92 @@
 
     private int computePlotterRegion(HpsSiSensor sensor) {
 
-		if (sensor.getLayerNumber() < 7) {
-			if (sensor.isTopLayer()) {
-				return 6*(sensor.getLayerNumber() - 1); 
-			} else { 
-				return 6*(sensor.getLayerNumber() - 1) + 1;
-			} 
-		} else { 
-		
-			if (sensor.isTopLayer()) {
-				if (sensor.getSide() == HpsSiSensor.POSITRON_SIDE) {
-					return 6*(sensor.getLayerNumber() - 7) + 2;
-				} else { 
-					return 6*(sensor.getLayerNumber() - 7) + 3;
-				}
-			} else if (sensor.isBottomLayer()) {
-				if (sensor.getSide() == HpsSiSensor.POSITRON_SIDE) {
-					return 6*(sensor.getLayerNumber() - 7) + 4;
-				} else {
-					return 6*(sensor.getLayerNumber() - 7) + 5;
-				}
-			}
-		}
-		
-		return -1; 
+        if (sensor.getLayerNumber() < 7) {
+            if (sensor.isTopLayer()) {
+                return 6 * (sensor.getLayerNumber() - 1);
+            } else {
+                return 6 * (sensor.getLayerNumber() - 1) + 1;
+            }
+        } else {
+
+            if (sensor.isTopLayer()) {
+                if (sensor.getSide() == HpsSiSensor.POSITRON_SIDE) {
+                    return 6 * (sensor.getLayerNumber() - 7) + 2;
+                } else {
+                    return 6 * (sensor.getLayerNumber() - 7) + 3;
+                }
+            } else if (sensor.isBottomLayer()) {
+                if (sensor.getSide() == HpsSiSensor.POSITRON_SIDE) {
+                    return 6 * (sensor.getLayerNumber() - 7) + 4;
+                } else {
+                    return 6 * (sensor.getLayerNumber() - 7) + 5;
+                }
+            }
+        }
+
+        return -1;
     }
 
     protected void detectorChanged(Detector detector) {
-    	
-		sensors 
-			= detector.getSubdetector(SUBDETECTOR_NAME).getDetectorElement().findDescendants(HpsSiSensor.class);
-   
+
+        sensors = detector.getSubdetector(SUBDETECTOR_NAME).getDetectorElement().findDescendants(HpsSiSensor.class);
+
         if (sensors.size() == 0) {
             throw new RuntimeException("No sensors were found in this detector.");
         }
 
         plotters.put("Occupancy", plotterFactory.create("Occupancy"));
-		plotters.get("Occupancy").createRegions(6,6);
-		
-		for (HpsSiSensor sensor : sensors) {
-			occupancyPlots.put(sensor, histogramFactory.createHistogram1D(sensor.getName() + " - Occupancy", 640, 0, 640)); 
-			plotters.get("Occupancy").region(this.computePlotterRegion(sensor))
-									 .plot(occupancyPlots.get(sensor));
+        plotters.get("Occupancy").createRegions(6, 6);
+
+        for (HpsSiSensor sensor : sensors) {
+            occupancyPlots.put(sensor, histogramFactory.createHistogram1D(sensor.getName() + " - Occupancy", 640, 0, 640));
+            plotters.get("Occupancy").region(this.computePlotterRegion(sensor)).plot(occupancyPlots.get(sensor), createPlotterStyle());
             occupancyMap.put(sensor, new int[640]);
-		}
-		
-		for (IPlotter plotter : plotters.values()) { 
-			plotter.show();
-		}
+        }
+
+        for (IPlotter plotter : plotters.values()) {
+            plotter.show();
+        }
     }
 
     public void process(EventHeader event) {
-        
-    	if (!event.hasCollection(RawTrackerHit.class, rawTrackerHitCollectionName))
-    		return;
 
-    	eventCount++;
-    	
+        if (!event.hasCollection(RawTrackerHit.class, rawTrackerHitCollectionName))
+            return;
+
+        eventCount++;
+
         // Get RawTrackerHit collection from event.
         List<RawTrackerHit> rawHits = event.get(RawTrackerHit.class, rawTrackerHitCollectionName);
 
-         // Increment strip hit count.
-         for (RawTrackerHit rawHit : rawHits) {
-        	 int[] strips = occupancyMap.get((HpsSiSensor) rawHit.getDetectorElement());
-             strips[rawHit.getIdentifierFieldValue("strip")] += 1;
-         }
+        // Increment strip hit count.
+        for (RawTrackerHit rawHit : rawHits) {
+            int[] strips = occupancyMap.get((HpsSiSensor) rawHit.getDetectorElement());
+            strips[rawHit.getIdentifierFieldValue("strip")] += 1;
+        }
 
-         // Plot strip occupancies.
-         if (eventCount % eventRefreshRate == 0) {
-        	 for (HpsSiSensor sensor : sensors) {
-                 int[] strips = occupancyMap.get(sensor);
-                 for (int i = 0; i < strips.length; i++) {
-                     double stripOccupancy = (double) strips[i] / (double) eventCount;
-                     if (stripOccupancy != 0) {
-                     	occupancyPlots.get(sensor).fill(i, stripOccupancy);
-                     }
-                 }
-             }
-         }
+        // Plot strip occupancies.
+        if (eventCount % eventRefreshRate == 0) {
+            for (HpsSiSensor sensor : sensors) {
+                int[] strips = occupancyMap.get(sensor);
+                for (int i = 0; i < strips.length; i++) {
+                    double stripOccupancy = (double) strips[i] / (double) eventCount;
+                    if (stripOccupancy != 0) {
+                        occupancyPlots.get(sensor).fill(i, stripOccupancy);
+                    }
+                }
+            }
+        }
+    }
+    
+    static IPlotterStyle createPlotterStyle() {
+        IPlotterStyle style = styleRegistry.getStore("DefaultStyleStore").getStyle("DefaultHistogram1DStyle");
+        style.dataStyle().lineStyle().setVisible(false);
+        style.dataStyle().outlineStyle().setVisible(false);
+        style.dataStyle().fillStyle().setVisible(true);
+        style.dataStyle().fillStyle().setColor("blue");
+        style.legendBoxStyle().setVisible(false);
+        style.dataStyle().errorBarStyle().setVisible(false);
+        return style;
     }
 }

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtTimingInPlots.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtTimingInPlots.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/svt/SvtTimingInPlots.java	Wed Mar 25 14:43:27 2015
@@ -9,6 +9,7 @@
 import hep.aida.IHistogram1D;
 import hep.aida.IPlotter;
 import hep.aida.IPlotterFactory;
+import hep.aida.IPlotterStyle;
 
 import org.lcsim.util.Driver; 
 import org.lcsim.detector.tracker.silicon.HpsSiSensor;
@@ -17,8 +18,8 @@
 import org.lcsim.event.LCRelation;
 import org.lcsim.event.RawTrackerHit;
 import org.lcsim.geometry.Detector;
-
 import org.hps.recon.tracking.FittedRawTrackerHit;
+import org.hps.recon.tracking.ShapeFitParameters;
 
 /**
  *  Monitoring driver that will be used when 'timing in' the SVT.
@@ -27,14 +28,24 @@
  *  @author Omar Moreno <[log in to unmask]>
  */
 public class SvtTimingInPlots extends Driver {
-	
+
     // TODO: Add documentation
     // TODO: Set plot styles
-	
+
+    static {
+        hep.aida.jfree.AnalysisFactory.register();
+    } 
+    
 	static IHistogramFactory histogramFactory = IAnalysisFactory.create().createHistogramFactory(null);
 	IPlotterFactory plotterFactory = IAnalysisFactory.create().createPlotterFactory();
 	protected Map<String, IPlotter> plotters = new HashMap<String, IPlotter>(); 
 	protected Map<SiSensor, IHistogram1D> t0Plots = new HashMap<SiSensor, IHistogram1D>(); 
+	protected Map<SiSensor, IHistogram1D> amplitudePlots = new HashMap<SiSensor, IHistogram1D>(); 
+	protected Map<SiSensor, IHistogram1D> chi2Plots = new HashMap<SiSensor, IHistogram1D>(); 
+	protected Map<Integer, List<RawTrackerHit>> topRawHitsPerLayer = new HashMap<Integer, List<RawTrackerHit>>();
+	protected Map<Integer, List<RawTrackerHit>> botRawHitsPerLayer = new HashMap<Integer, List<RawTrackerHit>>();
+	IPlotterStyle style = null; 
+	
 	
     private int computePlotterRegion(HpsSiSensor sensor) {
 
@@ -64,33 +75,53 @@
 		return -1; 
     }
 	
-	
-	
 	protected void detectorChanged(Detector detector) {
-		
+	  
 		List<HpsSiSensor> sensors 
 			= detector.getSubdetector("Tracker").getDetectorElement().findDescendants(HpsSiSensor.class);
 	
-		//--- t0 Plots ---//
-		//----------------//
 		plotters.put("L1-L3 t0", plotterFactory.create("L1-L3 t0"));
 		plotters.get("L1-L3 t0").createRegions(6,2);
 
 		plotters.put("L4-L6 t0", plotterFactory.create("L4-L6 t0"));
 		plotters.get("L4-L6 t0").createRegions(6,4);
-		int index = 0;
+		
+		plotters.put("L1-L3 Amplitude", plotterFactory.create("L1-L3 Amplitude"));
+		plotters.get("L1-L3 Amplitude").createRegions(6,2);
+
+		plotters.put("L4-L6 Amplitude", plotterFactory.create("L4-L6 Amplitude"));
+		plotters.get("L4-L6 Amplitude").createRegions(6,4);
+		
+		plotters.put("L1-L3 Chi^2 Probability", plotterFactory.create("L1-L3 Chi^2 Probability"));
+		plotters.get("L1-L3 Chi^2 Probability").createRegions(6,2);
+
+		plotters.put("L4-L6 Chi^2 Probability", plotterFactory.create("L1-L3 Chi^2 Probability"));
+		plotters.get("L4-L6 Chi^2 Probability").createRegions(6,4);
+		
 		for (HpsSiSensor sensor : sensors) {
 
 			t0Plots.put(sensor,histogramFactory.createHistogram1D(sensor.getName() + " - t0",75, -50, 100.0));
+			amplitudePlots.put(sensor, histogramFactory.createHistogram1D(sensor.getName() + " - Amplitude", 200, 0, 2000));
+			chi2Plots.put(sensor, histogramFactory.createHistogram1D(sensor.getName() + " - Chi^2 Probability", 20, 0, 1));
+			
 			if (sensor.getLayerNumber() < 7) {
 			    plotters.get("L1-L3 t0").region(this.computePlotterRegion(sensor))
 			                            .plot(t0Plots.get(sensor));
+			    plotters.get("L1-L3 Amplitude").region(this.computePlotterRegion(sensor))
+			                                   .plot(amplitudePlots.get(sensor));
+			    plotters.get("L1-L3 Chi^2 Probability").region(this.computePlotterRegion(sensor))
+			                                   .plot(chi2Plots.get(sensor));
+			    
 			} else {
 				plotters.get("L4-L6 t0").region(this.computePlotterRegion(sensor))
 				                        .plot(t0Plots.get(sensor));
+			    plotters.get("L4-L6 Amplitude").region(this.computePlotterRegion(sensor))
+			                                   .plot(amplitudePlots.get(sensor));
+			    plotters.get("L4-L6 Chi^2 Probability").region(this.computePlotterRegion(sensor))
+			                                   .plot(chi2Plots.get(sensor));
 			}
 		}
-	
+		
 		for (IPlotter plotter : plotters.values()) { 
 			plotter.show();
 		}
@@ -103,14 +134,23 @@
 		
 		List<LCRelation> fittedHits = event.get(LCRelation.class, "SVTFittedRawTrackerHits");
 		
-		
 		for (LCRelation fittedHit : fittedHits) { 
 			
+		    RawTrackerHit rawHit = (RawTrackerHit) fittedHit.getFrom();
+		    
 			HpsSiSensor sensor 
-				= (HpsSiSensor) ((RawTrackerHit) fittedHit.getFrom()).getDetectorElement();
+				= (HpsSiSensor) rawHit.getDetectorElement();
 			
 			double t0 = FittedRawTrackerHit.getT0(fittedHit);
 			t0Plots.get(sensor).fill(t0);
+			
+			double amplitude = FittedRawTrackerHit.getAmp(fittedHit);
+			amplitudePlots.get(sensor).fill(amplitude);
+			
+			double chi2Prob = ShapeFitParameters.getChiProb(FittedRawTrackerHit.getShapeFitParameters(fittedHit));
+			chi2Plots.get(sensor).fill(chi2Prob);
+		
+			
 		}	
 	}
 }

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/trackrecon/TrackTimePlots.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/trackrecon/TrackTimePlots.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/drivers/trackrecon/TrackTimePlots.java	Wed Mar 25 14:43:27 2015
@@ -6,9 +6,11 @@
 import hep.aida.IPlotterFactory;
 import hep.aida.IPlotterStyle;
 import hep.aida.ref.plotter.PlotterRegion;
+
 import java.util.List;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.lcsim.detector.tracker.silicon.DopedSilicon;
 import org.lcsim.detector.tracker.silicon.HpsSiSensor;
 import org.lcsim.event.EventHeader;

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalClusterPlots.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalClusterPlots.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalClusterPlots.java	Wed Mar 25 14:43:27 2015
@@ -9,8 +9,8 @@
 import java.util.List;
 
 import org.apache.commons.math.stat.StatUtils;
-import org.hps.readout.ecal.TriggerModule;
 import org.hps.recon.ecal.ECalUtils;
+import org.hps.recon.ecal.triggerbank.TriggerModule;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.Cluster;
 import org.lcsim.event.EventHeader;
@@ -35,9 +35,7 @@
  * <li>The third sub-tab shows the time distribution of the cluster
  * (Histogram1D), taken from the mean of the times forming the cluster,
  * as well as the RMS (Histogram1D).</li>
- * <li>The fourth sub-tab is a larger version of the the cluster centers
- * distribution.</li>
- * <li>The fifth tab displays the cluster pair distribution for the
+ * <li>The fourth tab displays the cluster pair distribution for the
  * energy sum, energy difference, energy slope, and coplanarity cuts
  * for all top/bottom pairs received. It also displays the average x-
  * and y-coordinates for the pairs.</li>
@@ -56,7 +54,7 @@
     private boolean logScale = false;
 	private AIDA aida = AIDA.defaultInstance();
     private double maxE = 5000 * ECalUtils.MeV;
-	private IPlotter[] plotter = new IPlotter[5];
+	private IPlotter[] plotter = new IPlotter[4];
 	private String clusterCollectionName = "EcalClusters";
 	
 	// Monitoring plot variables.
@@ -79,10 +77,9 @@
     private static final int TAB_CLUSTER_COUNT = 0;
     private static final int TAB_CLUSTER_ENERGY = 1;
     private static final int TAB_CLUSTER_TIME = 2;
-    private static final int TAB_CLUSTER_CENTER = 3;
-    private static final int TAB_CLUSTER_PAIR = 4;
+    private static final int TAB_CLUSTER_PAIR = 3;
     private static final String[] TAB_NAMES = { "Cluster Count Plots", "Cluster Energy Plots",
-    	"Cluster Time Plots", "Cluster Center Plot", "Cluster Pair Plots" };
+    	"Cluster Time Plots", "Cluster Pair Plots" };
     
     /**
      * Resets all of the plots for the new detector.
@@ -136,13 +133,7 @@
         plotter[TAB_CLUSTER_TIME].createRegions(1, 2);
         plotter[TAB_CLUSTER_TIME].region(0).plot(clusterTimes);
         plotter[TAB_CLUSTER_TIME].region(1).plot(clusterTimeSigma);
-        
-        // Define the Cluster Center tab.
-        plotter[TAB_CLUSTER_CENTER].createRegion();
-        plotter[TAB_CLUSTER_CENTER].region(0).plot(edgePlot);
-        plotter[TAB_CLUSTER_CENTER].style().setParameter("hist2DStyle", "colorMap");
-        plotter[TAB_CLUSTER_CENTER].style().dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
-        
+               
          // Create the Cluster Pair tab.
         plotter[TAB_CLUSTER_PAIR].createRegions(2, 3);
         plotter[TAB_CLUSTER_PAIR].region(0).plot(pairEnergySum);

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplay.java	Wed Mar 25 14:43:27 2015
@@ -39,200 +39,200 @@
  * <li>If the user clicks on a crystal, the corresponding energy and time
  * distributions (both of type <code>IHistogram1D</code>) are shown in
  * the last panel of the monitoring application, as well as a 2D histogram
- * (hit time vs. hit energy). Finally, if available, the raw waveshape (in
- * mV) is displayed.</li>
+ * (hit time vs. hit energy).The fourth panel reports energy for the crystal.</li>
  * 
  * @author Andrea Celentano
  */
 public class EcalEventDisplay extends Driver implements CrystalListener, ActionListener {
-	// Class variables.
-	private static final int NUM_CHANNELS = 11 * 47;
-	
-	// Plotter objects and variables.
-	private IPlotter plotter;
-	private IPlotterFactory plotterFactory;
-	private AIDA aida = AIDA.defaultInstance();	
-	
-	// LCIO Collection names.
-	private String inputCollection = "EcalCalHits";
-	private String clusterCollection = "EcalClusters";
-	private String inputCollectionRaw = "EcalReadoutHits";
-	
-	// Channel plot lists.
-	private ArrayList<IHistogram1D> channelEnergyPlot;
-	private ArrayList<IHistogram1D> clusterEnergyPlot;
-	private ArrayList<IHistogram1D> channelTimePlot;
-	//private ArrayList<IHistogram1D> channelRawWaveform;
-	private ArrayList<IHistogram2D> channelTimeVsEnergyPlot;
-	
-	// Internal variables.
-	private PEventViewer viewer;								 // Single event display.
-	private int pedSamples = 10;								 // 
-	private IPlotterStyle pstyle;								 // The plotter style for all plots.
-	private long lastEventTime = 0;								 // Tracks the time at which the last event occurred.
-	private int eventRefreshRate = 1;							 // The number of seconds before an update occurs.
-	private boolean resetOnUpdate = true;						 // Clears the event display on each update.
-	private double minEch = 10 * ECalUtils.MeV;					 // The energy scale minimum.
-	private double maxEch = 3500 * ECalUtils.MeV;				 // The energy scale maximum.
-	private int[] windowRaw = new int[NUM_CHANNELS];			 // The number of samples in a waveform for each channel.
-	private boolean[] isFirstRaw = new boolean[NUM_CHANNELS];	 // Whether a waveform plot was initiated for each channel.
-	
-	// Plot style and title variables.
-	private static final String NO_TITLE = "";
-	//private static final String SIGNAL_TIME_TITLE = "Time (ns)";
-	private static final String HIT_TIME_TITLE = "Hit Time (ns)";
-	//private static final String SIGNAL_DATA_STYLE_COLOR = "orange";
-	//private static final String RAW_WAVEFORM_TITLE = "Raw Waveform";
-	private static final String HIT_ENERGY_TITLE = "Hit Energy (GeV)";
-	private static final String CLUSTER_ENERGY_TITLE = "Cluster Energy (GeV)";
-	//private static final String SIGNAL_AMPLITUDE_TITLE = "Signal Amplitude (mV)";
-	
-	/**
-	 * Sets the upper bound of the energy scales used by the driver.
-	 * Energy units are in GeV.
-	 * @param maxEch - The energy scale upper bound.
-	 */
-	public void setMaxEch(double maxEch) {
-		this.maxEch = maxEch;
-	}
-	
-	/**
-	 * Sets the lower bound of the energy scales used by the driver.
-	 * Energy units are in GeV.
-	 * @param minEch - The lower energy scale bound.
-	 */
-	public void setMinEch(double minEch) {
-		this.minEch = minEch;
-	}
-	
-	public void setPedSamples(int pedSamples) {
-		this.pedSamples = pedSamples;
-	}
-	/**
-	 * Sets the LCIO collection name for the processed calorimeter hits.
-	 * @param inputCollection - The LCIO collection name.
-	 */
-	public void setInputCollection(String inputCollection) {
-		this.inputCollection = inputCollection;
-	}
-	
-	/**
-	 * Sets the LCIO collection name for the raw waveform hits.
-	 * @param inputCollectionRaw - The LCIO collection name.
-	 */
-	public void setInputCollectionRaw(String inputCollectionRaw) {
-		this.inputCollectionRaw = inputCollectionRaw;
-	}
-	
-	/**
-	 * Sets the LCIO collection name for calorimeter clusters.
-	 * @param inputClusterCollection - The LCIO collection name.
-	 */
-	public void setInputClusterCollection(String inputClusterCollection) {
-		this.clusterCollection = inputClusterCollection;
-	}
-	
-	/**
-	 * Sets the rate at which the GUI updates its elements,
-	 * @param eventRefreshRate - The rate at which the GUI should be
-	 * updated, in seconds.
-	 */
-	public void setEventRefreshRate(int eventRefreshRate) {
-		this.eventRefreshRate = eventRefreshRate;
-	}
-	
-	/**
-	 * Sets whether the event display should be cleared after event
-	 * or whether it should retain the previously displayed results.
-	 * @param resetOnUpdate - <code>true</code> means that the event
-	 * display should be cleared on each update and <code>false</code>
-	 * that it should not.
-	 */
-	public void setResetOnUpdate(boolean resetOnUpdate) {
-		this.resetOnUpdate = resetOnUpdate;
-	}
-	
-	/**
-	 * Initializes the single channel monitoring plots for all crystal
-	 * channels and defines the plotter region that contains them.
-	 */
-	@Override
-	public void detectorChanged(Detector detector) {
-		// Reset the AIDA tree directory.
-		aida.tree().cd("/");
-		
-		// Store histograms for the crystals.
-		channelEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
-		channelTimePlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
-		//channelRawWaveform = new ArrayList<IHistogram1D>(NUM_CHANNELS);
-		clusterEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
-		channelTimeVsEnergyPlot = new ArrayList<IHistogram2D>(NUM_CHANNELS);
-		
-		// Create the histograms for single channel energy and time
-		// distribution.
-		for(int ii = 0; ii < NUM_CHANNELS; ii++) {
-			// The above instruction is a terrible hack, just to fill
-			// the arrayList with all the elements. They'll be initialized
-			// properly during the event readout, Since we want to account
-			// for possibly different raw waveform dimensions!
-			
-			//Get the x and y indices for the current channel.
-			int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
-			int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
-			
-			// Initialize the histograms for the current crystal channel.
-			channelEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
-						+ inputCollection + " : Hit Energy : " + column + " " + row
-						+ ": " + ii, 100, -0.2, maxEch));
-			channelTimePlot.add(aida.histogram1D(detector.getDetectorName() + " : "
-						+ inputCollection + " : Hit Time : " + column + " " + row + ": "
-						+ ii, 100, 0, 400));     
-			channelTimeVsEnergyPlot.add(aida.histogram2D(detector.getDetectorName()
-					+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
-					+ " " + row + ": " + ii, 100, 0, 400, 100, -0.2, maxEch));              
-			//channelRawWaveform.add(aida.histogram1D(detector.getDetectorName() + " : "
-			//		+ inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii));
-			clusterEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
-					+ inputCollection + " : Cluster Energy : " + column + " " + row
-					+ ": " + ii, 100, -0.2, maxEch));
-			
-			// Note that no raw waveform has yet been read for this
-			// crystal/channel.
-			windowRaw[ii] = 1;
-			isFirstRaw[ii] = true;
-		}
-		
-		// Define the plot region that will display the single channel
-		// plots in the monitoring application.
-		plotterFactory = aida.analysisFactory().createPlotterFactory("Single Channel");
-		plotter = plotterFactory.create("Single Channel");
-		pstyle = this.createDefaultStyle();
-		plotter.setTitle("");
-		plotter.createRegions(2,2);
-		
-		// Define the first plot region.
-		pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
-		pstyle.yAxisStyle().setLabel(NO_TITLE);
-		plotter.region(0).plot(channelEnergyPlot.get(0), pstyle);
-		
-		// Define the second plot region.
-		pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
-		pstyle.yAxisStyle().setLabel(NO_TITLE);
-		plotter.region(1).plot(channelTimePlot.get(0), pstyle);
-		
-		// Define the third plot region; this encompasses the time vs.
-		// energy plots.
-		pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
-		pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
-		plotter.region(2).plot(channelTimeVsEnergyPlot.get(0), pstyle);
-		
-		// Define the fourth plot region; this encompasses the cluster
-		// energy for each channel.
-		pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
-		pstyle.yAxisStyle().setLabel(NO_TITLE);
-		plotter.region(3).plot(clusterEnergyPlot.get(0), pstyle);
-		
-		/**
+    // Class variables.
+    private static final int NUM_CHANNELS = 11 * 47;
+
+    // Plotter objects and variables.
+    private IPlotter plotter;
+    private IPlotterFactory plotterFactory;
+    private AIDA aida = AIDA.defaultInstance();	
+
+    // LCIO Collection names.
+    private String inputCollection = "EcalCalHits";
+    private String clusterCollection = "EcalClusters";
+    private String inputCollectionRaw = "EcalReadoutHits";
+
+    // Channel plot lists.
+    private ArrayList<IHistogram1D> channelEnergyPlot;
+    private ArrayList<IHistogram1D> clusterEnergyPlot;
+    private ArrayList<IHistogram1D> channelTimePlot;
+    //private ArrayList<IHistogram1D> channelRawWaveform;
+    private ArrayList<IHistogram2D> channelTimeVsEnergyPlot;
+
+    // Internal variables.
+    private PEventViewer viewer;								 // Single event display.
+    private int pedSamples = 10;								 // 
+    private IPlotterStyle pstyle;								 // The plotter style for all plots.
+    private long lastEventTime = 0;								 // Tracks the time at which the last event occurred.
+    private int eventRefreshRate = 1;							 // The number of seconds before an update occurs.
+    private boolean resetOnUpdate = true;						 // Clears the event display on each update.
+    private double minEch = 10 * ECalUtils.MeV;					 // The energy scale minimum.
+    private double maxEch = 3500 * ECalUtils.MeV;				 // The energy scale maximum.
+    private int[] windowRaw = new int[NUM_CHANNELS];			 // The number of samples in a waveform for each channel.
+    private boolean[] isFirstRaw = new boolean[NUM_CHANNELS];	 // Whether a waveform plot was initiated for each channel.
+
+    // Plot style and title variables.
+    private static final String NO_TITLE = "";
+    //private static final String SIGNAL_TIME_TITLE = "Time (ns)";
+    private static final String HIT_TIME_TITLE = "Hit Time (ns)";
+    //private static final String SIGNAL_DATA_STYLE_COLOR = "orange";
+    //private static final String RAW_WAVEFORM_TITLE = "Raw Waveform";
+    private static final String HIT_ENERGY_TITLE = "Hit Energy (GeV)";
+    private static final String CLUSTER_ENERGY_TITLE = "Cluster Energy (GeV)";
+    private String detectorName;
+    //private static final String SIGNAL_AMPLITUDE_TITLE = "Signal Amplitude (mV)";
+
+    /**
+     * Sets the upper bound of the energy scales used by the driver.
+     * Energy units are in GeV.
+     * @param maxEch - The energy scale upper bound.
+     */
+    public void setMaxEch(double maxEch) {
+        this.maxEch = maxEch;
+    }
+
+    /**
+     * Sets the lower bound of the energy scales used by the driver.
+     * Energy units are in GeV.
+     * @param minEch - The lower energy scale bound.
+     */
+    public void setMinEch(double minEch) {
+        this.minEch = minEch;
+    }
+
+    public void setPedSamples(int pedSamples) {
+        this.pedSamples = pedSamples;
+    }
+    /**
+     * Sets the LCIO collection name for the processed calorimeter hits.
+     * @param inputCollection - The LCIO collection name.
+     */
+    public void setInputCollection(String inputCollection) {
+        this.inputCollection = inputCollection;
+    }
+
+    /**
+     * Sets the LCIO collection name for the raw waveform hits.
+     * @param inputCollectionRaw - The LCIO collection name.
+     */
+    public void setInputCollectionRaw(String inputCollectionRaw) {
+        this.inputCollectionRaw = inputCollectionRaw;
+    }
+
+    /**
+     * Sets the LCIO collection name for calorimeter clusters.
+     * @param inputClusterCollection - The LCIO collection name.
+     */
+    public void setInputClusterCollection(String inputClusterCollection) {
+        this.clusterCollection = inputClusterCollection;
+    }
+
+    /**
+     * Sets the rate at which the GUI updates its elements,
+     * @param eventRefreshRate - The rate at which the GUI should be
+     * updated, in seconds.
+     */
+    public void setEventRefreshRate(int eventRefreshRate) {
+        this.eventRefreshRate = eventRefreshRate;
+    }
+
+    /**
+     * Sets whether the event display should be cleared after event
+     * or whether it should retain the previously displayed results.
+     * @param resetOnUpdate - <code>true</code> means that the event
+     * display should be cleared on each update and <code>false</code>
+     * that it should not.
+     */
+    public void setResetOnUpdate(boolean resetOnUpdate) {
+        this.resetOnUpdate = resetOnUpdate;
+    }
+
+    /**
+     * Initializes the single channel monitoring plots for all crystal
+     * channels and defines the plotter region that contains them.
+     */
+    @Override
+    public void detectorChanged(Detector detector) {
+        // Reset the AIDA tree directory.
+        aida.tree().cd("/");
+        detectorName=detector.getName();
+        // Store histograms for the crystals.
+        channelEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+        channelTimePlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+        //channelRawWaveform = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+        clusterEnergyPlot = new ArrayList<IHistogram1D>(NUM_CHANNELS);
+        channelTimeVsEnergyPlot = new ArrayList<IHistogram2D>(NUM_CHANNELS);
+
+        // Create the histograms for single channel energy and time
+        // distribution.
+        for(int ii = 0; ii < NUM_CHANNELS; ii++) {
+            // The above instruction is a terrible hack, just to fill
+            // the arrayList with all the elements. They'll be initialized
+            // properly during the event readout, Since we want to account
+            // for possibly different raw waveform dimensions!
+
+            //Get the x and y indices for the current channel.
+            int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
+            int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+
+            // Initialize the histograms for the current crystal channel.
+            channelEnergyPlot.add(aida.histogram1D(detectorName + " : "
+                    + inputCollection + " : Hit Energy : " + column + " " + row
+                    + ": " + ii, 100, -0.2, maxEch));
+            channelTimePlot.add(aida.histogram1D(detectorName + " : "
+                    + inputCollection + " : Hit Time : " + column + " " + row + ": "
+                    + ii, 100, 0, 400));     
+            channelTimeVsEnergyPlot.add(aida.histogram2D(detectorName
+                    + " : " + inputCollection + " : Hit Time Vs Energy : " + column
+                    + " " + row + ": " + ii, 100, 0, 400, 100, -0.2, maxEch));              
+            //channelRawWaveform.add(aida.histogram1D(detector.getDetectorName() + " : "
+            //		+ inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii));
+            clusterEnergyPlot.add(aida.histogram1D(detectorName + " : "
+                    + inputCollection + " : Cluster Energy : " + column + " " + row
+                    + ": " + ii, 100, -0.2, maxEch));
+
+            // Note that no raw waveform has yet been read for this
+            // crystal/channel.
+            windowRaw[ii] = 1;
+            isFirstRaw[ii] = true;
+        }
+
+        // Define the plot region that will display the single channel
+        // plots in the monitoring application.
+        plotterFactory = aida.analysisFactory().createPlotterFactory("Single Channel");
+        plotter = plotterFactory.create("Single Channel");
+        pstyle = this.createDefaultStyle();
+        plotter.setTitle("");
+        plotter.createRegions(2,2);
+
+        // Define the first plot region.
+        pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+        pstyle.yAxisStyle().setLabel(NO_TITLE);
+        plotter.region(0).plot(channelEnergyPlot.get(0), pstyle);
+
+        // Define the second plot region.
+        pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+        pstyle.yAxisStyle().setLabel(NO_TITLE);
+        plotter.region(1).plot(channelTimePlot.get(0), pstyle);
+
+        // Define the third plot region; this encompasses the time vs.
+        // energy plots.
+        pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+        pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+        plotter.region(2).plot(channelTimeVsEnergyPlot.get(0), pstyle);
+
+        // Define the fourth plot region; this encompasses the cluster
+        // energy for each channel.
+        pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
+        pstyle.yAxisStyle().setLabel(NO_TITLE);
+        plotter.region(3).plot(clusterEnergyPlot.get(0), pstyle);
+
+        /**
 		// Define the fourth plot region; this encompasses the raw
 		// wave form plots.
 		pstyle.xAxisStyle().setLabel(RAW_WAVEFORM_TITLE);
@@ -241,160 +241,205 @@
 		pstyle.dataStyle().markerStyle().setColor(SIGNAL_DATA_STYLE_COLOR);
 		pstyle.dataStyle().errorBarStyle().setVisible(false);
 		plotter.region(3).plot(channelRawWaveform.get(0), pstyle);
-		**/
-		
-		// Display the plot region.
-		plotter.show();
-		
-		// Set the time tracker variables.
-		lastEventTime = 0;
-	}
-	
-	/**
-	 * Initializes the <code>Viewer</code> for the single event display.
-	 * If a configuration file is available, then it is used by the
-	 * <code>Viewer</code> to display hardware configuration mappings.
-	 * Otherwise, this is excluded.
-	 */
-	@Override
-	public void startOfData() {
-		// Check if the configuration mapping file exists.
-		File config = new File("ecal-mapping-config.csv");
-		
-		// If the file exists, load the viewer that will display it.
-		if(config.exists() && config.canRead()) {
-			// Account for IO read errors. Only load this version if
-			// the data file can be read successfully.
-			try { viewer = new PDataEventViewer(config.getAbsolutePath()); }
-			
-			// Otherwise, open the regular version.
-			catch (IOException e) { viewer = new PEventViewer(); }
-		}
-		
-		// If the file is not present, then just load the normal version.
-		else { viewer = new PEventViewer(); }
-		
-		// Set the viewer properties.
-		viewer.setScaleMinimum(minEch);
-		viewer.setScaleMaximum(maxEch);
-		viewer.addCrystalListener(this);
-		
-		// Make the Viewer object visible.
-		viewer.setVisible(true);
-	}
-	
-	/**
-	 * Hides the single event display and disposes it from memory.
-	 */
-	@Override
-	public void endOfData() {
-		viewer.setVisible(false);
-		viewer.dispose();
-	}
-	
-	@Override
-	public void process(EventHeader event){
-		// Check whether enough time has passed to perform an update
-		// on the event display.
-		boolean update = false;
-		long currentTime = System.currentTimeMillis() / 1000;
-		if((currentTime - lastEventTime) > eventRefreshRate){
-			lastEventTime = currentTime;
-			update = true;
-		}
-		
-		// If an update should be made, perform the update.
-		if(update && resetOnUpdate) { viewer.resetDisplay(); }
-		
-		// If the event has calorimeter hit objects...
-		if(event.hasCollection(CalorimeterHit.class, inputCollection)) {
-			// Get the list of calorimeter hits.
-			List<CalorimeterHit> hits = event.get(CalorimeterHit.class, inputCollection);
-			
-			// For each of the calorimeter hits...
-			for (CalorimeterHit hit : hits) {
-				// Get the x and y indices for the current hit.
-				int ix = hit.getIdentifierFieldValue("ix");
-				int iy = hit.getIdentifierFieldValue("iy");
-				
-				if (iy != 0 && ix != 0) {
-					// Get the histogram index for the hit.
-					int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
-					
-					// If the hit has energy, populate the plots.
-					if(hit.getCorrectedEnergy() > 0) {
-						channelEnergyPlot.get(id).fill(hit.getCorrectedEnergy());
-						channelTimePlot.get(id).fill(hit.getTime());
-						channelTimeVsEnergyPlot.get(id).fill(hit.getTime(), hit.getCorrectedEnergy());
-					}
-					
-					// If an update to the event display should be
-					// performed, give it the hits.
-					if(update) { viewer.addHit(hit); }
-				}
-			}
-		}
-		
-		// If there are clusters in the event...
-		if (event.hasCollection(Cluster.class, clusterCollection)) {
-			// Get the list of clusters.
-			List<Cluster> clusters = event.get(Cluster.class, clusterCollection);
-			
-			// Iterate over the clusters and add them to the event
-			// display if appropriate.
-			for (Cluster cluster : clusters) {
-				// Get the ix and iy indices for the seed.
-				int ix = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
-				int iy = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
-				
-				// Get the histogram index for the hit.
-				int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
-				
-				// Add the cluster energy to the plot.
-				if(cluster.getEnergy() > 0.0) {
-					clusterEnergyPlot.get(id).fill(cluster.getEnergy());
-				}
-				
-				// If an update is needed, add the cluster to the viewer.
-				if(update) { viewer.addCluster(cluster); }
-			}
-		}
-		
-		/**
+         **/
+
+        // Display the plot region.
+        plotter.show();
+
+        // Set the time tracker variables.
+        lastEventTime = 0;
+    }
+
+    /**
+     * Initializes the <code>Viewer</code> for the single event display.
+     * If a configuration file is available, then it is used by the
+     * <code>Viewer</code> to display hardware configuration mappings.
+     * Otherwise, this is excluded.
+     */
+    @Override
+    public void startOfData() {
+        // Check if the configuration mapping file exists.
+        File config = new File("ecal-mapping-config.csv");
+
+        // If the file exists, load the viewer that will display it.
+        if(config.exists() && config.canRead()) {
+            // Account for IO read errors. Only load this version if
+            // the data file can be read successfully.
+            try { viewer = new PDataEventViewer(config.getAbsolutePath()); }
+
+            // Otherwise, open the regular version.
+            catch (IOException e) { viewer = new PEventViewer(); }
+        }
+
+        // If the file is not present, then just load the normal version.
+        else { viewer = new PEventViewer(); }
+
+        // Set the viewer properties.
+        viewer.setScaleMinimum(minEch);
+        viewer.setScaleMaximum(maxEch);
+        viewer.addCrystalListener(this);
+
+        // Make the Viewer object visible.
+        viewer.setVisible(true);
+    }
+
+    /**
+     * Hides the single event display and disposes it from memory.
+     * Also removes histograms from aida tree. We do not want them in the output aida file, if any..
+     */
+    @Override
+    public void endOfData() {
+        viewer.setVisible(false);
+        viewer.dispose();
+
+        int row,column;
+        String hName;
+        System.out.println("EcalEventDisplay endOfData clear histograms");
+        for(int ii = 0; ii < NUM_CHANNELS; ii++) {
+            // The above instruction is a terrible hack, just to fill
+            // the arrayList with all the elements. They'll be initialized
+            // properly during the event readout, Since we want to account
+            // for possibly different raw waveform dimensions!
+
+            //Get the x and y indices for the current channel.
+            row = EcalMonitoringUtilities.getRowFromHistoID(ii);
+            column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+            hName=detectorName + " : "
+                    + inputCollection + " : Hit Energy : " + column + " " + row
+                    + ": " + ii;
+            aida.tree().rm(hName);
+
+            hName=detectorName + " : "
+                    + inputCollection + " : Hit Time : " + column + " " + row + ": "
+                    + ii;
+            aida.tree().rm(hName);
+
+            hName=detectorName+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
+                    + " " + row + ": " + ii;
+            aida.tree().rm(hName);
+
+
+            if (isFirstRaw[ii]==false){
+                hName=detectorName+
+                        " : " + inputCollectionRaw + " : Raw Waveform : " + column + " "
+                        + row + ": " + ii;
+                aida.tree().rm(hName);
+
+            }
+
+        }
+        System.out.println("EcalEventDisplay endOfData clear histograms done");
+
+
+
+
+
+
+    }
+
+    @Override
+    public void process(EventHeader event){
+        // Check whether enough time has passed to perform an update
+        // on the event display.
+        boolean update = false;
+        long currentTime = System.currentTimeMillis() / 1000;
+        if((currentTime - lastEventTime) > eventRefreshRate){
+            lastEventTime = currentTime;
+            update = true;
+        }
+
+        // If an update should be made, perform the update.
+        if(update && resetOnUpdate) { viewer.resetDisplay(); }
+
+        // If the event has calorimeter hit objects...
+        if(event.hasCollection(CalorimeterHit.class, inputCollection)) {
+            // Get the list of calorimeter hits.
+            List<CalorimeterHit> hits = event.get(CalorimeterHit.class, inputCollection);
+
+            // For each of the calorimeter hits...
+            for (CalorimeterHit hit : hits) {
+                // Get the x and y indices for the current hit.
+                int ix = hit.getIdentifierFieldValue("ix");
+                int iy = hit.getIdentifierFieldValue("iy");
+
+                if (iy != 0 && ix != 0) {
+                    // Get the histogram index for the hit.
+                    int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+
+                    // If the hit has energy, populate the plots.
+                    if(hit.getCorrectedEnergy() > 0) {
+                        channelEnergyPlot.get(id).fill(hit.getCorrectedEnergy());
+                        channelTimePlot.get(id).fill(hit.getTime());
+                        channelTimeVsEnergyPlot.get(id).fill(hit.getTime(), hit.getCorrectedEnergy());
+                    }
+
+                    // If an update to the event display should be
+                    // performed, give it the hits.
+                    if(update) { viewer.addHit(hit); }
+                }
+            }
+        }
+
+        // If there are clusters in the event...
+        if (event.hasCollection(Cluster.class, clusterCollection)) {
+            // Get the list of clusters.
+            List<Cluster> clusters = event.get(Cluster.class, clusterCollection);
+
+            // Iterate over the clusters and add them to the event
+            // display if appropriate.
+            for (Cluster cluster : clusters) {
+                // Get the ix and iy indices for the seed.
+                int ix = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix");
+                int iy = cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy");
+
+                // Get the histogram index for the hit.
+                int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(iy, ix);
+
+                // Add the cluster energy to the plot.
+                if(cluster.getEnergy() > 0.0) {
+                    clusterEnergyPlot.get(id).fill(cluster.getEnergy());
+                }
+
+                // If an update is needed, add the cluster to the viewer.
+                if(update) { viewer.addCluster(cluster); }
+            }
+        }
+
+        /**
 		// Plot the raw waveform only if raw tracker hit exist in the
 		// event.
 		if (event.hasCollection(RawTrackerHit.class, inputCollectionRaw)){
 			// Get the list of raw tracker hits.
 			List<RawTrackerHit> hits = event.get(RawTrackerHit.class, inputCollectionRaw);
-			
+
 			// Process each raw tracker hit.
 			for (RawTrackerHit hit : hits) {
 				// Get the x and y indices for the hit.
 				int ix = hit.getIdentifierFieldValue("ix");
 				int iy = hit.getIdentifierFieldValue("iy");
-				
+
 				if(iy != 0 && ix != 0) {
 					if(!ECalUtils.isInHole(iy, ix)) {
 						// Get the crystal ID for the current hit.
 						int id = ECalUtils.getHistoIDFromRowColumn(iy, ix);
-						
+
 						// The window is length is not known by default.
 						// If this is the first hit, read the window
 						// length and initialize the plot.
 						if(isFirstRaw[id]) {
 							// Note that this plot is initialized.
 							isFirstRaw[id] = false;
-							
+
 							// Set the waveform array.
 							windowRaw[id] = hit.getADCValues().length;
-							
+
 							// Initialize the waveform plot.
 							channelRawWaveform.set(id, aida.histogram1D(detector.getDetectorName()
 									+ " : " + inputCollectionRaw + " : Raw Waveform : " + ix + " "
 									+ iy + ": " + id, windowRaw[id], -0.5 * ECalUtils.ecalReadoutPeriod,
 									(-0.5 + windowRaw[id]) * ECalUtils.ecalReadoutPeriod));
 						}
-						
+
 						// If the plot should be updated, do so.
 						if(update) {
 							channelRawWaveform.get(id).reset();
@@ -412,60 +457,60 @@
 				}
 			}
 		}
-		**/
-		
-		// Update the single event display.
-		if(update) { viewer.updateDisplay(); }
-	}
-	
-	@Override
-	public void actionPerformed(ActionEvent ae) { }
-	
-	@Override
-	public void crystalActivated(CrystalEvent e) { }
-	
-	@Override
-	public void crystalDeactivated(CrystalEvent e) { }
-	
-	/**
-	 * Updates the monitoring plots for the crystal that was clicked.
-	 */
-	@Override
-	public void crystalClicked(CrystalEvent e) {
-		// Get the crystal that was clicked in the LCSim coordinate system.
-		Point ecalPoint = Viewer.toEcalPoint(e.getCrystalID());
-		
-		// Make sure that the clicked crystal is valid. Necessary??
-		if((ecalPoint.x != 0) && (ecalPoint.y != 0))
-			if (!EcalMonitoringUtilities.isInHole(ecalPoint.y, ecalPoint.x)) {
-				// Get the crystal ID.
-				int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(ecalPoint.y, ecalPoint.x);
-				
-				// Clear and replot region 0 for the new crystal.
-				plotter.region(0).clear();
-				pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
-				pstyle.yAxisStyle().setLabel(NO_TITLE);
-				plotter.region(0).plot(channelEnergyPlot.get(id), pstyle);
-				
-				// Clear and replot region 1 for the new crystal.
-				plotter.region(1).clear();
-				pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
-				pstyle.yAxisStyle().setLabel(NO_TITLE);
-				plotter.region(1).plot(channelTimePlot.get(id), pstyle);
-				
-				// Clear and replot region 2 for the new crystal.
-				plotter.region(2).clear();
-				pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
-				pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
-				plotter.region(2).plot(channelTimeVsEnergyPlot.get(id), pstyle);
-				
-				// Process and plot the region 3 plot.
-				plotter.region(3).clear();
-				pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
-				pstyle.yAxisStyle().setLabel(NO_TITLE);
-				plotter.region(3).plot(clusterEnergyPlot.get(id), pstyle);
-				
-				/**
+         **/
+
+        // Update the single event display.
+        if(update) { viewer.updateDisplay(); }
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent ae) { }
+
+    @Override
+    public void crystalActivated(CrystalEvent e) { }
+
+    @Override
+    public void crystalDeactivated(CrystalEvent e) { }
+
+    /**
+     * Updates the monitoring plots for the crystal that was clicked.
+     */
+    @Override
+    public void crystalClicked(CrystalEvent e) {
+        // Get the crystal that was clicked in the LCSim coordinate system.
+        Point ecalPoint = Viewer.toEcalPoint(e.getCrystalID());
+
+        // Make sure that the clicked crystal is valid. Necessary??
+        if((ecalPoint.x != 0) && (ecalPoint.y != 0))
+            if (!EcalMonitoringUtilities.isInHole(ecalPoint.y, ecalPoint.x)) {
+                // Get the crystal ID.
+                int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(ecalPoint.y, ecalPoint.x);
+
+                // Clear and replot region 0 for the new crystal.
+                plotter.region(0).clear();
+                pstyle.xAxisStyle().setLabel(HIT_ENERGY_TITLE);
+                pstyle.yAxisStyle().setLabel(NO_TITLE);
+                plotter.region(0).plot(channelEnergyPlot.get(id), pstyle);
+
+                // Clear and replot region 1 for the new crystal.
+                plotter.region(1).clear();
+                pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+                pstyle.yAxisStyle().setLabel(NO_TITLE);
+                plotter.region(1).plot(channelTimePlot.get(id), pstyle);
+
+                // Clear and replot region 2 for the new crystal.
+                plotter.region(2).clear();
+                pstyle.xAxisStyle().setLabel(HIT_TIME_TITLE);
+                pstyle.yAxisStyle().setLabel(HIT_ENERGY_TITLE);
+                plotter.region(2).plot(channelTimeVsEnergyPlot.get(id), pstyle);
+
+                // Process and plot the region 3 plot.
+                plotter.region(3).clear();
+                pstyle.xAxisStyle().setLabel(CLUSTER_ENERGY_TITLE);
+                pstyle.yAxisStyle().setLabel(NO_TITLE);
+                plotter.region(3).plot(clusterEnergyPlot.get(id), pstyle);
+
+                /**
 				// Process and plot the region 3 plot.
 				if(!isFirstRaw[id]) {
 					pstyle.yAxisStyle().setLabel(SIGNAL_AMPLITUDE_TITLE);
@@ -479,47 +524,47 @@
 					pstyle.yAxisStyle().setLabel("");
 				}
 				plotter.region(3).plot(channelRawWaveform.get(id), pstyle);
-				**/
-		}
-	}
-	
-	/**
-	 * Initializes the default style for plots.
-	 * @return Returns an <code>IPlotterStyle</code> object that
-	 * represents the default style for plots.
-	 */
-	public IPlotterStyle createDefaultStyle() {
-		IPlotterStyle pstyle = plotterFactory.createPlotterStyle();
-		// Set the appearance of the axes.
-		pstyle.xAxisStyle().labelStyle().setBold(true);
-		pstyle.yAxisStyle().labelStyle().setBold(true);
-		pstyle.xAxisStyle().tickLabelStyle().setBold(true);
-		pstyle.yAxisStyle().tickLabelStyle().setBold(true);
-		pstyle.xAxisStyle().lineStyle().setColor("black");
-		pstyle.yAxisStyle().lineStyle().setColor("black");
-		pstyle.xAxisStyle().lineStyle().setThickness(2);
-		pstyle.yAxisStyle().lineStyle().setThickness(2);
-		
-		// Set color settings.
-		pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
-		pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins", Boolean.FALSE.toString());
-		pstyle.dataStyle().errorBarStyle().setVisible(false);
-		pstyle.setParameter("hist2DStyle", "colorMap");
-		
-		// Force auto range to zero.
-		pstyle.yAxisStyle().setParameter("allowZeroSuppression", "false");
-		pstyle.xAxisStyle().setParameter("allowZeroSuppression", "false");
-		
-		// Set the title style.
-		pstyle.titleStyle().textStyle().setFontSize(20);
-		
-		// Draw caps on error bars.
-		pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
-		
-		// Turn off grid lines until explicitly enabled.
-		pstyle.gridStyle().setVisible(false);
-		
-		// Return the style.
-		return pstyle;
-	}
+                 **/
+            }
+    }
+
+    /**
+     * Initializes the default style for plots.
+     * @return Returns an <code>IPlotterStyle</code> object that
+     * represents the default style for plots.
+     */
+    public IPlotterStyle createDefaultStyle() {
+        IPlotterStyle pstyle = plotterFactory.createPlotterStyle();
+        // Set the appearance of the axes.
+        pstyle.xAxisStyle().labelStyle().setBold(true);
+        pstyle.yAxisStyle().labelStyle().setBold(true);
+        pstyle.xAxisStyle().tickLabelStyle().setBold(true);
+        pstyle.yAxisStyle().tickLabelStyle().setBold(true);
+        pstyle.xAxisStyle().lineStyle().setColor("black");
+        pstyle.yAxisStyle().lineStyle().setColor("black");
+        pstyle.xAxisStyle().lineStyle().setThickness(2);
+        pstyle.yAxisStyle().lineStyle().setThickness(2);
+
+        // Set color settings.
+        pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+        pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins", Boolean.FALSE.toString());
+        pstyle.dataStyle().errorBarStyle().setVisible(false);
+        pstyle.setParameter("hist2DStyle", "colorMap");
+
+        // Force auto range to zero.
+        pstyle.yAxisStyle().setParameter("allowZeroSuppression", "false");
+        pstyle.xAxisStyle().setParameter("allowZeroSuppression", "false");
+
+        // Set the title style.
+        pstyle.titleStyle().textStyle().setFontSize(20);
+
+        // Draw caps on error bars.
+        pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
+
+        // Turn off grid lines until explicitly enabled.
+        pstyle.gridStyle().setVisible(false);
+
+        // Return the style.
+        return pstyle;
+    }
 }

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalEventDisplayWithRawWaveform.java	Wed Mar 25 14:43:27 2015
@@ -20,7 +20,6 @@
 import org.hps.monitoring.ecal.eventdisplay.util.CrystalEvent;
 import org.hps.monitoring.ecal.eventdisplay.util.CrystalListener;
 import org.hps.monitoring.ecal.plots.EcalMonitoringUtilities;
-
 import org.hps.recon.ecal.ECalUtils;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.RawTrackerHit;
@@ -89,6 +88,7 @@
 	private static final String HIT_ENERGY_TITLE = "Hit Energy (GeV)";
 	private static final String CLUSTER_ENERGY_TITLE = "Cluster Energy (GeV)";
 	private static final String SIGNAL_AMPLITUDE_TITLE = "Signal Amplitude (mV)";
+	private String detectorName;
 	
 	/**
 	 * Sets the upper bound of the energy scales used by the driver.
@@ -161,6 +161,7 @@
 	 */
 	@Override
 	public void detectorChanged(Detector detector) {
+	    detectorName=detector.getName();
 		// Reset the AIDA tree directory.
 		aida.tree().cd("/");
 		
@@ -184,18 +185,18 @@
 			int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
 			
 			// Initialize the histograms for the current crystal channel.
-			channelEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+			channelEnergyPlot.add(aida.histogram1D(detectorName + " : "
 						+ inputCollection + " : Hit Energy : " + column + " " + row
 						+ ": " + ii, 100, -0.2, maxEch));
-			channelTimePlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+			channelTimePlot.add(aida.histogram1D(detectorName + " : "
 						+ inputCollection + " : Hit Time : " + column + " " + row + ": "
 						+ ii, 100, 0, 400));     
-			channelTimeVsEnergyPlot.add(aida.histogram2D(detector.getDetectorName()
+			channelTimeVsEnergyPlot.add(aida.histogram2D(detectorName 
 					+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
 					+ " " + row + ": " + ii, 100, 0, 400, 100, -0.2, maxEch));              
-			channelRawWaveform.add(aida.histogram1D(detector.getDetectorName() + " : "
+			channelRawWaveform.add(aida.histogram1D(detectorName  + " : "
 					+ inputCollection + " : Hit Energy : " + column + " " + row + ": " + ii));
-			clusterEnergyPlot.add(aida.histogram1D(detector.getDetectorName() + " : "
+			clusterEnergyPlot.add(aida.histogram1D(detectorName  + " : "
 					+ inputCollection + " : Cluster Energy : " + column + " " + row
 					+ ": " + ii, 100, -0.2, maxEch));
 			
@@ -289,6 +290,50 @@
 	public void endOfData() {
 		viewer.setVisible(false);
 		viewer.dispose();
+		
+		
+
+        int row,column;
+        String hName;
+        System.out.println("EcalEventDisplay endOfData clear histograms");
+        for(int ii = 0; ii < NUM_CHANNELS; ii++) {
+            // The above instruction is a terrible hack, just to fill
+            // the arrayList with all the elements. They'll be initialized
+            // properly during the event readout, Since we want to account
+            // for possibly different raw waveform dimensions!
+            
+            //Get the x and y indices for the current channel.
+            row = EcalMonitoringUtilities.getRowFromHistoID(ii);
+            column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
+            hName=detectorName + " : "
+                    + inputCollection + " : Hit Energy : " + column + " " + row
+                    + ": " + ii;
+            aida.tree().rm(hName);
+           
+            hName=detectorName + " : "
+                    + inputCollection + " : Hit Time : " + column + " " + row + ": "
+                    + ii;
+            aida.tree().rm(hName);
+            
+            hName=detectorName+ " : " + inputCollection + " : Hit Time Vs Energy : " + column
+                    + " " + row + ": " + ii;
+            aida.tree().rm(hName);
+            
+            hName=detectorName + " : "
+                    + inputCollection + " : Cluster Energy : " + column + " " + row
+                    + ": " + ii;
+            aida.tree().rm(hName);
+        
+            hName=detectorName + " : "
+                    + inputCollection + " : Cluster Energy : " + column + " " + row
+                    + ": " + ii;
+            aida.tree().rm(hName);
+        
+        
+        }
+      System.out.println("EcalEventDisplay endOfData clear histograms done");
+		
+		
 	}
 	
 	@Override

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalHitPlots.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalHitPlots.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalHitPlots.java	Wed Mar 25 14:43:27 2015
@@ -9,13 +9,13 @@
 import java.util.List;
 
 import org.hps.recon.ecal.ECalUtils;
+import org.hps.recon.ecal.triggerbank.SSPData;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;
 import org.lcsim.geometry.Detector;
 import org.lcsim.util.Driver;
 import org.lcsim.util.aida.AIDA;
-//import org.jfree.chart.ChartPanel;
 
 /**
  * The driver <code>EcalHitPlots</code> implements the histogram shown to the user 
@@ -45,20 +45,19 @@
     IHistogram1D topTimePlot, botTimePlot, orTimePlot;
     IHistogram1D topTrigTimePlot, botTrigTimePlot, orTrigTimePlot;
     IHistogram2D topTimePlot2D, botTimePlot2D, orTimePlot2D;
-   // IHistogram2D topX, botX, topY, botY;
-//    IHistogram2D hitNumberPlot;
-//    IHistogram2D occupancyPlot;
-   
-  
+    IHistogram2D hitNumberPlot;
+    IHistogram2D occupancyPlot;
+
+
     IPlotterFactory plotterFactory;
-  
+
     int eventn = 0;
 
     double maxE = 5000 * ECalUtils.MeV;
-    
+
     boolean logScale = false;
     boolean hide = false;
-    
+
     public void setInputCollection(String inputCollection) {
         this.inputCollection = inputCollection;
     }
@@ -66,7 +65,7 @@
     public void setMaxE(double maxE) {
         this.maxE = maxE;
     }
-    
+
 
     public void setLogScale(boolean logScale) {
         this.logScale = logScale;
@@ -74,35 +73,36 @@
 
     @Override
     protected void detectorChanged(Detector detector) {
-        
+
         System.out.println("Detector changed called: "+ detector.getClass().getName());
         aida.tree().cd("/");
         plotterFactory = aida.analysisFactory().createPlotterFactory("Ecal Hit Plots");
 
-       
-        
+
+
         // Setup plots.
-        hitCountPlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Hit Count In Event", 10, -0.5, 9.5);
-        hitTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time", 100, 0 * 4.0, 100 * 4.0);
-      //  hitNumberPlot = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Count");        
-      //  occupancyPlot = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Occupancy");
+        hitCountPlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Hit Count In Event", 30, -0.5, 29.5);     
+        hitNumberPlot = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Rate KHz");        
+        occupancyPlot = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Occupancy");
         topTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : First Hit Time, Top", 100, 0, 100 * 4.0);
         botTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : First Hit Time, Bottom", 100, 0, 100 * 4.0);
         orTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : First Hit Time, Or", 100, 0, 100 * 4.0);
 
-        topTrigTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Trigger Time, Top", 1024, 0, 4096);
-        botTrigTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Trigger Time, Bottom", 1024, 0, 4096);
+        
+        hitTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time", 100, 0 * 4.0, 100 * 4.0);
+        topTrigTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Trigger Time, Top", 101, -2, 402);
+        botTrigTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Trigger Time, Bottom", 101, -2, 402);
         orTrigTimePlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Trigger Time, Or", 1024, 0, 4096);
 
-        topTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Top", 100, 0, 100 * 4.0, 512, 0, 4096);
-        botTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Bottom", 100, 0, 100 * 4.0, 512, 0, 4096);
-        orTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Or", 100, 0, 100 * 4.0, 512, 0, 4096);
+        topTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Top", 100, 0, 100 * 4.0, 101, -2, 402);
+        botTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Bottom", 100, 0, 100 * 4.0, 101, -2, 402);
+        orTimePlot2D = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Hit Time vs. Trig Time, Or", 100, 0, 100 * 4.0, 101, -2, 402);
 
         hitEnergyPlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Hit Energy", 100, -0.1, maxE);
         hitMaxEnergyPlot = aida.histogram1D(detector.getDetectorName() + " : " + inputCollection + " : Maximum Hit Energy In Event", 100, -0.1, maxE);
 
-        
-    
+
+
         // Setup the plotter.
         plotter = plotterFactory.create("Hit Counts");
         plotter.setTitle("Hit Counts");
@@ -110,65 +110,65 @@
         pstyle.setParameter("hist2DStyle", "colorMap");
         pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
         pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins",Boolean.FALSE.toString());
-        
-        
+
+
         // Create the plotter regions.
         plotter.createRegions(2,2);
-//        plotter.region(0).plot(hitNumberPlot);
+        plotter.region(0).plot(hitNumberPlot);
         plotter.region(1).plot(hitTimePlot,pstyle);
-//        plotter.region(2).plot(occupancyPlot,pstyle);
+        plotter.region(2).plot(occupancyPlot,pstyle);
         plotter.region(3).plot(hitCountPlot,pstyle);
-      
-        
-     
+
+
+
         if (logScale){
-        	 pstyle.zAxisStyle().setParameter("scale", "log");
+            pstyle.zAxisStyle().setParameter("scale", "log");
         }
         else pstyle.zAxisStyle().setParameter("scale", "lin");
-//        plotter.region(0).plot(hitNumberPlot,pstyle);
-        
-        
+        //        plotter.region(0).plot(hitNumberPlot,pstyle);
+
+
         // Setup the plotter.
         plotter2 = plotterFactory.create("Hit Energies");
         plotter2.setTitle("Hit Energies");
         pstyle.zAxisStyle().setParameter("scale", "lin");
-        
+
         if (logScale) {
-        	 pstyle.yAxisStyle().setParameter("scale", "log");
+            pstyle.yAxisStyle().setParameter("scale", "log");
         }
         else  pstyle.yAxisStyle().setParameter("scale", "lin");
         // Create the plotter regions.
         plotter2.createRegions(1, 2);
         plotter2.region(0).plot(hitEnergyPlot,pstyle);
         plotter2.region(1).plot(hitMaxEnergyPlot,pstyle); 
-               
+
         plotter3 = plotterFactory.create("Hit Times");
         plotter3.setTitle("Hit Times");
         plotter3.createRegions(3, 3);      
-        
+
         if (logScale) {
-       	 pstyle.yAxisStyle().setParameter("scale", "log");
-       }
-       else  pstyle.yAxisStyle().setParameter("scale", "lin");
-        
+            pstyle.yAxisStyle().setParameter("scale", "log");
+        }
+        else  pstyle.yAxisStyle().setParameter("scale", "lin");
+
         plotter3.region(0).plot(topTimePlot,pstyle);
         plotter3.region(1).plot(botTimePlot,pstyle);
         plotter3.region(2).plot(orTimePlot,pstyle);
         plotter3.region(3).plot(topTrigTimePlot,pstyle);
         plotter3.region(4).plot(botTrigTimePlot,pstyle);
         plotter3.region(5).plot(orTrigTimePlot,pstyle);
-        
+
         pstyle.yAxisStyle().setParameter("scale", "lin");
         if (logScale){
-        	 pstyle.zAxisStyle().setParameter("scale", "log");
+            pstyle.zAxisStyle().setParameter("scale", "log");
         }
         else pstyle.zAxisStyle().setParameter("scale", "lin");
-      
+
         plotter3.region(6).plot(topTimePlot2D,pstyle);
         plotter3.region(7).plot(botTimePlot2D,pstyle);
         plotter3.region(8).plot(orTimePlot2D,pstyle);
-       
-        
+
+
         if (!hide) {
             plotter.show();
             plotter2.show();
@@ -178,28 +178,29 @@
 
     @Override
     public void process(EventHeader event) {
-        
-        
+
+
         int orTrigTime=4097;
         int topTrigTime=4097;
         int botTrigTime=4097;
-        
+
         if (event.hasCollection(GenericObject.class, "TriggerBank")) {
             List<GenericObject> triggerList = event.get(GenericObject.class, "TriggerBank");
             if (!triggerList.isEmpty()) {
                 GenericObject triggerData = triggerList.get(0);
-/*  mgraham12/14/2014 ...comment this out for now as it seems to through a null pointer
+               
                 if (triggerData instanceof SSPData){ 
                 	orTrigTime=((SSPData)triggerData).getOrTrig();
                 	topTrigTime=((SSPData)triggerData).getTopTrig();
                 	botTrigTime =((SSPData)triggerData).getBotTrig(); 
-                    
+
+                	
                 	orTrigTimePlot.fill(orTrigTime);
                     topTrigTimePlot.fill(topTrigTime);
                 	botTrigTimePlot.fill(botTrigTime);
-                	
+
                 }       
-                */
+                
             }//end if triggerList isEmpty
         }
 
@@ -215,11 +216,11 @@
             double orTime = Double.POSITIVE_INFINITY;
             for (CalorimeterHit hit : hits) {
 
-               
+
                 hitEnergyPlot.fill(hit.getRawEnergy());
                 hitTimePlot.fill(hit.getTime());
-               
-                
+
+
                 if (hit.getTime() < orTime) {
                     orTime = hit.getTime();
                 }
@@ -233,7 +234,7 @@
                     maxEnergy = hit.getRawEnergy();
                 }
             }
-            
+
             if (orTime != Double.POSITIVE_INFINITY) {
                 orTimePlot.fill(orTime);
                 orTimePlot2D.fill(orTime, orTrigTime);
@@ -247,22 +248,6 @@
                 botTimePlot2D.fill(botTime, botTrigTime);
             }
             hitMaxEnergyPlot.fill(maxEnergy);
-        
-            for (int i = 0; i < hits.size(); i++) {
-                CalorimeterHit hit1 = hits.get(i);
-                int x1 = hit1.getIdentifierFieldValue("ix");
-                int y1 = hit1.getIdentifierFieldValue("iy");
-                for (int j = i + 1; j < hits.size(); j++) {
-                    CalorimeterHit hit2 = hits.get(j);
-                    int x2 = hit2.getIdentifierFieldValue("ix");
-                    int y2 = hit2.getIdentifierFieldValue("iy");
-                    if ((Math.abs(x1 - x2) <= 1 || x1 * x2 == -1) && (Math.abs(y1 - y2) <= 1)) {
-                        if (x1 != x2 || y1 != y2) {
-                         //  edgePlot.fill((x1 + x2) / 2.0, (y1 + y2) / 2.0);
-                        }
-                    }
-                }
-            }
         } else {
             hitCountPlot.fill(0);
         }         
@@ -277,54 +262,54 @@
     {
         this.hide=hide;
     }
-        
-    
+
+
     /**
-	 * Initializes the default style for plots.
-	 * @return Returns an <code>IPlotterStyle</code> object that
-	 * represents the default style for plots.
-	 */
-	public IPlotterStyle createDefaultStyle() {
-		IPlotterStyle pstyle = plotterFactory.createPlotterStyle();
-		// Set the appearance of the axes.
-		pstyle.xAxisStyle().labelStyle().setBold(true);
-		pstyle.yAxisStyle().labelStyle().setBold(true);
-		pstyle.xAxisStyle().tickLabelStyle().setBold(true);
-		pstyle.yAxisStyle().tickLabelStyle().setBold(true);
-		pstyle.xAxisStyle().lineStyle().setColor("black");
-		pstyle.yAxisStyle().lineStyle().setColor("black");
-		pstyle.xAxisStyle().lineStyle().setThickness(2);
-		pstyle.yAxisStyle().lineStyle().setThickness(2);
-		
-		// Set color settings.
-		pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
-		pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins", Boolean.FALSE.toString());
-		pstyle.dataStyle().errorBarStyle().setVisible(false);
-		pstyle.setParameter("hist2DStyle", "colorMap");
-		
-		// Force auto range to zero.
-		pstyle.yAxisStyle().setParameter("allowZeroSuppression", "false");
-		pstyle.xAxisStyle().setParameter("allowZeroSuppression", "false");
-		
-		// Set the title style.
-		pstyle.titleStyle().textStyle().setFontSize(20);
-		
-		// Draw caps on error bars.
-		pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
-		
-		// Turn off grid lines until explicitly enabled.
-		pstyle.gridStyle().setVisible(false);
-		
-		// Return the style.
-		return pstyle;
-	}
-    
-    
-    
-    
-    
-    
-    
+     * Initializes the default style for plots.
+     * @return Returns an <code>IPlotterStyle</code> object that
+     * represents the default style for plots.
+     */
+    public IPlotterStyle createDefaultStyle() {
+        IPlotterStyle pstyle = plotterFactory.createPlotterStyle();
+        // Set the appearance of the axes.
+        pstyle.xAxisStyle().labelStyle().setBold(true);
+        pstyle.yAxisStyle().labelStyle().setBold(true);
+        pstyle.xAxisStyle().tickLabelStyle().setBold(true);
+        pstyle.yAxisStyle().tickLabelStyle().setBold(true);
+        pstyle.xAxisStyle().lineStyle().setColor("black");
+        pstyle.yAxisStyle().lineStyle().setColor("black");
+        pstyle.xAxisStyle().lineStyle().setThickness(2);
+        pstyle.yAxisStyle().lineStyle().setThickness(2);
+
+        // Set color settings.
+        pstyle.dataStyle().fillStyle().setParameter("colorMapScheme", "rainbow");
+        pstyle.dataStyle().fillStyle().setParameter("showZeroHeightBins", Boolean.FALSE.toString());
+        pstyle.dataStyle().errorBarStyle().setVisible(false);
+        pstyle.setParameter("hist2DStyle", "colorMap");
+
+        // Force auto range to zero.
+        pstyle.yAxisStyle().setParameter("allowZeroSuppression", "false");
+        pstyle.xAxisStyle().setParameter("allowZeroSuppression", "false");
+
+        // Set the title style.
+        pstyle.titleStyle().textStyle().setFontSize(20);
+
+        // Draw caps on error bars.
+        pstyle.dataStyle().errorBarStyle().setParameter("errorBarDecoration", (new Float(1.0f)).toString());
+
+        // Turn off grid lines until explicitly enabled.
+        pstyle.gridStyle().setVisible(false);
+
+        // Return the style.
+        return pstyle;
+    }
+
+
+
+
+
+
+
 }
 
-   
+

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringPlots.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringPlots.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringPlots.java	Wed Mar 25 14:43:27 2015
@@ -42,10 +42,12 @@
     IHistogram2D clusterCountDrawPlot;
     int eventRefreshRate = 1;
     int eventn = 0;
+    int thisEventN,prevEventN;
+
     boolean hide = false;
-    boolean accumulateHits = false;
     long thisTime,prevTime;
-    
+    double thisEventTime,prevEventTime;
+
     public EcalMonitoringPlots() {
     }
 
@@ -61,9 +63,7 @@
         this.hide = hide;
     }
 
-    public void setAccumulateHits(boolean accumulateHits) {
-        this.accumulateHits = accumulateHits;
-    }
+
     /**
      * Set the refresh rate for histograms in this driver
      * @param eventRefreshRate: the refresh rate, defined as number of events to accumulate before
@@ -80,21 +80,20 @@
         // Setup plots.
         aida.tree().cd("/");
         String hitCountDrawPlotTitle;
-       if (accumulateHits)  hitCountDrawPlotTitle = detector.getDetectorName() + " : " + inputCollection + " : Hit Count (accumulated)";
-       else hitCountDrawPlotTitle = detector.getDetectorName() + " : " + inputCollection + " : Hit Count (refreshed)";
-       
-       hitCountDrawPlot = aida.histogram2D(hitCountDrawPlotTitle, 47, -23.5, 23.5, 11, -5.5, 5.5);
-       hitCountFillPlot = makeCopy(hitCountDrawPlot);
+        hitCountDrawPlotTitle = detector.getDetectorName() + " : " + inputCollection + " : Hit Rate KHz";
+
+        hitCountDrawPlot = aida.histogram2D(hitCountDrawPlotTitle, 47, -23.5, 23.5, 11, -5.5, 5.5);
+        hitCountFillPlot = makeCopy(hitCountDrawPlot);
         occupancyDrawPlot = aida.histogram2D(detector.getDetectorName() + " : " + inputCollection + " : Occupancy", 47, -23.5, 23.5, 11, -5.5, 5.5);
-        clusterCountDrawPlot = aida.histogram2D(detector.getDetectorName() + " : " + clusterCollection + " : Cluster Center Count", 47, -23.5, 23.5, 11, -5.5, 5.5);
+        clusterCountDrawPlot = aida.histogram2D(detector.getDetectorName() + " : " + clusterCollection + " : Cluster Rate KHz", 47, -23.5, 23.5, 11, -5.5, 5.5);
         clusterCountFillPlot = makeCopy(clusterCountDrawPlot);
 
-      
+
         NoccupancyFill=1; //to avoid a "NaN" at beginning
         for (int ii = 0; ii < (11 * 47); ii++) {
             int row = EcalMonitoringUtilities.getRowFromHistoID(ii);
             int column = EcalMonitoringUtilities.getColumnFromHistoID(ii);
-            occupancyFill[ii]=0;
+            occupancyFill[ii]=0.;
         }
 
         // Create the plotter regions.
@@ -122,24 +121,18 @@
         }
         prevTime=0; //init the time 
         thisTime=0; //init the time 
+
+        thisEventN=0;
+        prevEventN=0;
+
+        thisEventTime=0;
+        prevEventTime=0;
     }
 
     public void process(EventHeader event) {
         int nhits = 0;
         int chits[] = new int[11 * 47];
-        /*
-         * if (event.hasCollection(BaseRawCalorimeterHit.class, inputCollection)) {
-         * List<BaseRawCalorimeterHit> hits = event.get(BaseRawCalorimeterHit.class,
-         * inputCollection); for (BaseRawCalorimeterHit hit : hits) { int
-         * column=hit.getIdentifierFieldValue("ix"); int row=hit.getIdentifierFieldValue("iy"); int
-         * id=EcalMonitoringUtils.getHistoIDFromRowColumn(row, column);
-         * hitCountFillPlot.fill(column,row); chits[id]++; nhits++; } } if
-         * (event.hasCollection(RawTrackerHit.class, inputCollection)) { List<RawTrackerHit> hits =
-         * event.get(RawTrackerHit.class, inputCollection); for (RawTrackerHit hit : hits) { int
-         * column=hit.getIdentifierFieldValue("ix"); int row=hit.getIdentifierFieldValue("iy"); int
-         * id=EcalMonitoringUtils.getHistoIDFromRowColumn(row, column);
-         * hitCountFillPlot.fill(column,row); chits[id]++; nhits++; } }
-         */
+
         if (event.hasCollection(CalorimeterHit.class, inputCollection)) {
             List<CalorimeterHit> hits = event.get(CalorimeterHit.class, inputCollection);
             for (CalorimeterHit hit : hits) {
@@ -148,15 +141,15 @@
                 int id = EcalMonitoringUtilities.getHistoIDFromRowColumn(row, column);
                 hitCountFillPlot.fill(column, row);
                 {
-                 chits[id]++;
-                 nhits++;
+                    chits[id]++;
+                    nhits++;
                 }
             }
         }
 
         if (nhits > 0) {
             for (int ii = 0; ii < (11 * 47); ii++) {
-                occupancyFill[ii]+=1.*chits[ii]/nhits;
+                occupancyFill[ii]+=(1.*chits[ii])/nhits;
             }
         }
 
@@ -166,16 +159,32 @@
                 clusterCountFillPlot.fill(cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("ix"), cluster.getCalorimeterHits().get(0).getIdentifierFieldValue("iy"));
             }
         }
-       
+
         thisTime=System.currentTimeMillis()/1000;
-        
+        thisEventN=event.getEventNumber();
+        thisEventTime=event.getTimeStamp()/1E9;
         if ((thisTime-prevTime)>eventRefreshRate){
-        	prevTime=thisTime;
-        	redraw();
-        	NoccupancyFill=0;
+            double scale=1.;
+
+            if (NoccupancyFill>0){
+                scale=(thisEventN-prevEventN)/NoccupancyFill;
+                scale=scale/(thisEventTime-prevEventTime);
+                scale/=1000. ; //do KHz
+            }
+            //System.out.println("Event: "+thisEventN+" "+prevEventN);
+            //System.out.println("Time: "+thisEventTime+" "+prevEventTime);
+            // System.out.println("Monitor: "+thisTime+" "+prevTime+" "+NoccupancyFill);
+
+            hitCountFillPlot.scale(scale);
+            clusterCountFillPlot.scale(scale);
+            redraw();
+            prevTime=thisTime;
+            prevEventN=thisEventN;
+            prevEventTime=thisEventTime;
+            NoccupancyFill=0;
         }
         else{
-        	NoccupancyFill++;
+            NoccupancyFill++;
         }
     }
 
@@ -190,22 +199,21 @@
         plotter.region(0).clear();
         plotter.region(0).plot(hitCountDrawPlot);
         plotter.region(0).refresh();
-        
-        if (!accumulateHits){
-        	hitCountFillPlot.reset();
-        }
+        hitCountFillPlot.reset();
+
         clusterCountDrawPlot.reset();
         clusterCountDrawPlot.add(clusterCountFillPlot);
         plotter.region(1).clear();
         plotter.region(1).plot(clusterCountDrawPlot);
         plotter.region(1).refresh();
-        
+        clusterCountFillPlot.reset();
+
         occupancyDrawPlot.reset();
         for (int id = 0; id < (47 * 11); id++) {
             int row = EcalMonitoringUtilities.getRowFromHistoID(id);
             int column = EcalMonitoringUtilities.getColumnFromHistoID(id);
             double mean = occupancyFill[id]/NoccupancyFill;
-            
+
             occupancyFill[id]=0;
             if ((row != 0) && (column != 0) && (!EcalMonitoringUtilities.isInHole(row, column)))
                 occupancyDrawPlot.fill(column, row, mean);

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringUtilities.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringUtilities.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalMonitoringUtilities.java	Wed Mar 25 14:43:27 2015
@@ -35,6 +35,8 @@
                 return true;
             }
         }
+        else if (row == 0) return true;
+        else if (column ==0) return true;
         return false;
     }
     

Modified: java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalPedestalViewer.java
 =============================================================================
--- java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalPedestalViewer.java	(original)
+++ java/branches/prod/monitoring-drivers/src/main/java/org/hps/monitoring/ecal/plots/EcalPedestalViewer.java	Wed Mar 25 14:43:27 2015
@@ -31,7 +31,7 @@
 public class EcalPedestalViewer extends Driver implements CrystalListener, ActionListener {
 
     // this has to match the one in EcalPedstalCalculator:
-    private String histoNameFormat = "Ecal/Pedestals/Mode7/ped%3d";
+    private String histoNameFormat = "Ecal/Pedestals/Mode7/ped%03d";
     
 	private AIDA aida = AIDA.defaultInstance();	
 	private IPlotter plotter;
@@ -39,12 +39,33 @@
 	private IPlotterStyle pstyle;
 	private PEventViewer viewer;
 
+	static final String[] colors={"red","black","blue","green","yellow","pink","cyan","magenta","brown"};
+	static final int nRows=3;
+	static final int nColumns=3;
+	private int theRegion=0;
+	
 	@Override
 	public void detectorChanged(Detector detector) {
 		plotterFactory = aida.analysisFactory().createPlotterFactory("ECal Peds");
 		plotter = plotterFactory.create("ECal Peds");
-		plotter.createRegions(1,1);
+		plotter.createRegions(nColumns,nRows);
+		// Plot dummmy histos, else null plotter regions later:
+		for (int ii=0; ii<nColumns*nRows; ii++) {
+  	    	plotter.region(ii).plot(aida.histogram1D("ASDF"+ii,100,11e9,11e11));
+		}
 		plotter.show();
+		
+		pstyle=plotterFactory.createPlotterStyle();
+		pstyle.xAxisStyle().labelStyle().setBold(true);
+		pstyle.yAxisStyle().labelStyle().setBold(true);
+		pstyle.xAxisStyle().tickLabelStyle().setBold(true);
+		pstyle.yAxisStyle().tickLabelStyle().setBold(true);
+		pstyle.xAxisStyle().lineStyle().setColor("black");
+		pstyle.yAxisStyle().lineStyle().setColor("black");
+		pstyle.xAxisStyle().lineStyle().setThickness(2);
+		pstyle.yAxisStyle().lineStyle().setThickness(2);
+		pstyle.dataStyle().errorBarStyle().setThickness(0);
+		pstyle.legendBoxStyle().setVisible(false);
 	}
 	
 	@Override
@@ -78,8 +99,12 @@
 	    if (hist==null) {
 	        System.err.println("Running the Driver?");
 	    } else {
-	        plotter.region(0).clear();
-	        plotter.region(0).plot(hist,pstyle);
+     	    hist.setTitle(String.format("(%d,%d)",ecalPoint.x,ecalPoint.y));
+            pstyle.dataStyle().lineStyle().setParameter("color", colors[theRegion%colors.length]);
+	        plotter.region(theRegion).clear();
+	        plotter.region(theRegion).plot(hist,pstyle);
+	        plotter.region(theRegion).refresh();
+	        theRegion=(theRegion+1)%(nColumns*nRows);
 	    }
 	}
 	

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/MonitoringPlotFactory.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/MonitoringPlotFactory.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/MonitoringPlotFactory.java	Wed Mar 25 14:43:27 2015
@@ -13,6 +13,7 @@
 
 import org.jfree.chart.ChartPanel;
 import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.RegularTimePeriod;
 
 /**
  * This class implements an AIDA <code>IPlotterFactory</code> for the monitoring application. It
@@ -22,7 +23,10 @@
  * by the MonitoringApplication before any calls to AIDA are made from Drivers.
  */
 public class MonitoringPlotFactory extends PlotterFactory {
-
+    
+    // Global plotter registry.
+    static PlotterRegistry plotters = new PlotterRegistry();
+    
     // The name of the factory which will be used in naming tabs in the monitoring app.
     String name = null;
 
@@ -32,14 +36,22 @@
     // Root pane where this factory's top-level tab will be inserted.
     private static JTabbedPane rootPane = null;
 
+    // The region listener for handling mouse clicks in a region.
     private static PlotterRegionListener regionListener;
-
+    
+    // The current tab index.
+    int tabIndex;
+
+    /**
+     * Set the plot region listener.
+     * @param regionListener The plot region listener.
+     */
     public static void setPlotterRegionListener(PlotterRegionListener regionListener) {
         MonitoringPlotFactory.regionListener = regionListener;
     }
 
     /**
-     * Class constructor.
+     * Class constructor for unnamed factory.
      */
     MonitoringPlotFactory() {
         super();
@@ -50,7 +62,7 @@
     }
 
     /**
-     * Class constructor.
+     * Class constructor for named factory.
      * @param name The name of the factory.
      */
     MonitoringPlotFactory(String name) {
@@ -62,11 +74,16 @@
             addPlotterRegionListener(regionListener);
     }
 
+    /**
+     * Setup the root GUI pane of this factory for display of plots in tabs.
+     * @param name The tab's label.
+     */
     private void setupRootPane(String name) {
         // FIXME: Hack to disregard call from an AIDA related class.
         if (!(new RuntimeException()).getStackTrace()[2].getClassName().equals("hep.aida.ref.plotter.style.registry.StyleStoreXMLReader")) {
             rootPane.addTab(name, tabs);
-            rootPane.setTabComponentAt(rootPane.getTabCount() - 1, new JLabel(name));
+            tabIndex = rootPane.getTabCount() - 1;
+            rootPane.setTabComponentAt(tabIndex, new JLabel(name));
         }
     }
 
@@ -97,36 +114,90 @@
         MonitoringPlotFactory.rootPane = rootPane;
     }
 
+    /**
+     * Setup a plotter tab.
+     * @param plotterName The name of the plotter.
+     * @param plotter The IPlotter which will plot into the tab.
+     */
     private void setupPlotterTab(String plotterName, IPlotter plotter) {
+        
+        // Setup the plotter's GUI pane and tab.
         JPanel plotterPanel = new JPanel(new BorderLayout());
         plotterPanel.add(PlotterUtilities.componentForPlotter(plotter), BorderLayout.CENTER);
         tabs.addTab(plotterName, plotterPanel);
-        tabs.setTabComponentAt(tabs.getTabCount() - 1, new JLabel(plotterName));
-    }
-
+        int plotterIndex = tabs.getTabCount() - 1;
+        tabs.setTabComponentAt(plotterIndex, new JLabel(plotterName));
+        
+        // Register plotter globally with its tab indices.
+        plotters.register(plotter, tabIndex, plotterIndex);
+    }
+
+    /**
+     * Add a <code>JFreeChart</code> to one of the tabs.
+     * @param chart The JFreeChart object to add.
+     */
     private void addChart(JFreeChart chart) {
         ChartPanel panel = new ChartPanel(chart);
         tabs.addTab(chart.getTitle().getText(), panel);
         tabs.setTabComponentAt(tabs.getTabCount() - 1, new JLabel(chart.getTitle().getText()));
     }
-
-    /**
-     * Create a strip chart using a JFreeChart implementation. It will be automatically updated from
-     * a {@link StripChartUpdater}. Similar to AIDA plots, the chart will be given a sub-tab in the
-     * tab of this factory.
-     * 
-     * @param title The title of the chart.
-     * @param yAxisLabel The y axis label.
-     * @param size The buffer size of the series which determines how much data displays.
-     * @param updater The updater which will update the chart in real time.
-     * @return The modified <tt>StripChartUpdater</tt> which points to the new chart.
-     */
-    public StripChartUpdater createStripChart(String title, String yAxisLabel, int size, StripChartUpdater updater) {
-        JFreeChart stripChart = StripChartBuilder.createDynamicTimeSeriesChart(title, yAxisLabel, size);
-        stripChart.getLegend().setVisible(false); /* Legend turned off for now. */
-        addChart(stripChart);
-        updater.setChart(stripChart);
+    
+    /**
+     * This creates a strip chart with full parameter settings, which will automatically
+     * update at a certain time interval.
+     * @param name The title of the chart.
+     * @param rangeLabel The range axis label text.
+     * @param seriesCount The number of series in the data set.
+     * @param seriesNames The names of the series (if non-null the length must match seriesCount).
+     * @param itemCount The maximum number of items in the series.
+     * @param timeBase The time unit for updates.
+     * @param valueProvider The interface for providing the series values.
+     * @param rangeView The view in the domain axis around the current data point (applied to plus and minus).
+     * @return The StripChartUpdater for the chart.
+     */
+    public StripChartUpdater createStripChart(
+            String name, 
+            String rangeLabel,
+            int seriesCount, 
+            String[] seriesNames,
+            int itemCount,
+            RegularTimePeriod timeBase,
+            ValueProvider valueProvider,
+            long rangeView) {
+        StripChartUpdater updater = StripChartBuilder.createDynamicTimeSeriesChart(
+                name, 
+                rangeLabel, 
+                seriesCount, 
+                seriesNames,
+                itemCount, 
+                timeBase, 
+                valueProvider, 
+                rangeView);
+        addChart(updater.getChart());
         return updater;
+    }
+    
+    /**
+     * Create a strip chart with simple parameter settings.
+     * @param name The title of the strip chart.
+     * @param seriesCount The number of series in the data set.
+     * @param timeBase The time interval for updating.
+     * @param valueProvider The interface for providing values.
+     * @return The StripChartUpdater for the chart.
+     */
+    public StripChartUpdater createStripChart(
+            String name, 
+            int seriesCount, 
+            RegularTimePeriod timeBase,
+            ValueProvider valueProvider) {
+        return createStripChart(
+                name, "Values", 
+                seriesCount, 
+                null, 
+                9999, 
+                timeBase, 
+                valueProvider, 
+                10000L);
     }
 
     /**
@@ -143,5 +214,24 @@
         stripChart.getLegend().setVisible(false); /* Legend turned off for now. */
         addChart(stripChart);
         return stripChart;
-    }
-}
+    }       
+    
+    public JFreeChart createTimeSeriesChart(
+            String title, 
+            String yAxisLabel, 
+            int seriesCount,
+            String[] datasetNames,
+            double rangeSize) {
+        JFreeChart chart = StripChartBuilder.createTimeSeriesChart(title, yAxisLabel, seriesCount, datasetNames, rangeSize);
+        addChart(chart);
+        return chart;
+    }
+    
+    /**
+     * Get the global registry of plotters.
+     * @return The global plotter registry.
+     */
+    public static PlotterRegistry getPlotterRegistry() {
+        return plotters;
+    }
+}

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartBuilder.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartBuilder.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartBuilder.java	Wed Mar 25 14:43:27 2015
@@ -1,45 +1,90 @@
 package org.hps.monitoring.plotting;
-
-import java.util.Date;
 
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.plot.XYPlot;
 import org.jfree.data.time.DynamicTimeSeriesCollection;
-import org.jfree.data.time.Second;
+import org.jfree.data.time.RegularTimePeriod;
 import org.jfree.data.time.TimeSeries;
 import org.jfree.data.time.TimeSeriesCollection;
 
 /**
- * Utility methods for building strip charts using JFreeChart backend.
+ * Utility methods for building strip charts using JFreeChart back end.
  */
 public final class StripChartBuilder {
 
     private StripChartBuilder() {
     }
-
-    /**
-     * This creates a strip chart that will be updated at fixed intervals from a timer.
-     * @param title
-     * @param yAxisLabel
-     * @param size
-     * @return
-     */
-    public static JFreeChart createDynamicTimeSeriesChart(String title, String yAxisLabel, int size) {
-        final DynamicTimeSeriesCollection dataset = new DynamicTimeSeriesCollection(1, size, new Second());
-        dataset.setTimeBase(new Second(new Date()));
-        dataset.addSeries(new float[] {}, 0, "Default Dataset");
-
-        final JFreeChart result = ChartFactory.createTimeSeriesChart(title, "hh:mm:ss", yAxisLabel, dataset, true, true, false);
-        final XYPlot plot = result.getXYPlot();
-        plot.getDomainAxis().setAutoRange(true);
-        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
-        rangeAxis.setAutoRange(true);
-        rangeAxis.setAutoRangeIncludesZero(true);
-        return result;
+    
+    /**
+     * Create a strip chart with simple parameter settings.
+     * @param name The title of the strip chart.
+     * @param seriesCount The number of series in the data set.
+     * @param timeBase The time interval for updating.
+     * @param valueProvider The interface for providing values.
+     * @return The StripChartUpdater for the chart.
+     */
+    static StripChartUpdater createDynamicTimeSeriesChart(
+            String name, 
+            int seriesCount, 
+            RegularTimePeriod timeBase,
+            ValueProvider valueProvider) {
+        return createDynamicTimeSeriesChart(name, "Values", seriesCount, null, 9999, timeBase, valueProvider, 10000L);
     }
-
+    
+    /**
+     * This creates a strip chart with full parameter settings, which will automatically
+     * update at a certain time interval.
+     * @param name The title of the chart.
+     * @param rangeLabel The range axis label text.
+     * @param seriesCount The number of series in the data set.
+     * @param seriesNames The names of the series (if non-null the length must match seriesCount).
+     * @param itemCount The maximum number of items in the series.
+     * @param timeBase The time unit for updates.
+     * @param valueProvider The interface for providing the series values.
+     * @param rangeView The view in the domain axis around the current data point (milliseconds).
+     * @return The StripChartUpdater for the chart.
+     */
+    static StripChartUpdater createDynamicTimeSeriesChart(
+            String name, 
+            String rangeLabel,
+            int seriesCount, 
+            String[] seriesNames,
+            int itemCount,
+            RegularTimePeriod timeBase,
+            ValueProvider valueProvider,
+            long rangeView) {
+                
+        if (seriesNames != null && seriesCount != seriesNames.length) {
+            throw new IllegalArgumentException("seriesNames is wrong length");
+        }
+        final DynamicTimeSeriesCollection dataset = new DynamicTimeSeriesCollection(seriesCount, itemCount, timeBase);
+        dataset.setTimeBase(timeBase);
+        for (int series = 0; series < seriesCount; series++) {
+            String seriesName = name + " " + series;
+            if (seriesNames != null) {
+                seriesName = seriesNames[series];
+            }
+            dataset.addSeries(new float[] {}, series, seriesName);
+        }
+        
+        final JFreeChart chart = ChartFactory.createTimeSeriesChart(name, "hh:mm:ss", rangeLabel, dataset, false, false, false);
+        
+        chart.getXYPlot().getRangeAxis().setAutoRange(true);
+
+        StripChartUpdater updater = new StripChartUpdater(
+                chart, 
+                valueProvider,
+                rangeView,
+                timeBase
+                );
+        
+        updater.start();
+        
+        return updater;
+    }
+        
     /**
      * This should be used when the time period for updating is variable.
      * 
@@ -47,13 +92,18 @@
      * 
      * <code>sensorSeries.add(new Minute(new Date()), newData);</code>
      * 
-     * @param title
-     * @param yAxisLabel
-     * @param maxAge
-     * @param maxCount
-     * @return
-     */
-    public static JFreeChart createTimeSeriesChart(String title, String yAxisLabel, int maxAge, int maxCount, int rangeSize) {
+     * @param title The title of the chart.
+     * @param yAxisLabel The range axis label.
+     * @param maxAge The maximum age of an item.
+     * @param maxCount The maximum count of items in the single data set series.
+     * @return The chart that was created.
+     */
+    static JFreeChart createTimeSeriesChart(
+            String title, 
+            String yAxisLabel, 
+            int maxAge, 
+            int maxCount,
+            int rangeSize) {
 
         TimeSeriesCollection dataset = new TimeSeriesCollection();
         TimeSeries timeSeries = new TimeSeries("Default Dataset");
@@ -61,7 +111,14 @@
         timeSeries.setMaximumItemCount(maxCount);
         dataset.addSeries(timeSeries);
 
-        final JFreeChart result = ChartFactory.createTimeSeriesChart(title, "hh:mm:ss", yAxisLabel, dataset, true, true, false);
+        final JFreeChart result = ChartFactory.createTimeSeriesChart(
+                title, 
+                "hh:mm:ss", 
+                yAxisLabel, 
+                dataset, 
+                true, 
+                false, 
+                false);
         final XYPlot plot = result.getXYPlot();
         plot.getDomainAxis().setAutoRange(true);
         plot.getDomainAxis().setAutoRangeMinimumSize(rangeSize);
@@ -69,6 +126,75 @@
         rangeAxis.setAutoRange(true);
         rangeAxis.setAutoRangeIncludesZero(true);
         return result;
-    }
-
+    }    
+    
+    /**
+     * <p>
+     * This can be used to create a strip chart with multiple <code>TimeSeries</code> 
+     * in the data set.
+     * <p>
+     * To update a chart of this type, use the following types of method calls:
+     * <pre>
+     * dataset.getSeries(0).add(new Second(time), value1);
+     * dataset.getSeries(1).add(new Second(time), value2);
+     * </pre>
+     * <p>
+     * It is not updated manually but will refresh will values are added to the backing dataset.
+     * 
+     * @param title The title of the chart.
+     * @param yAxisLabel The range axis label.
+     * @param seriesCount The number of series in the dataset.
+     * @param datasetNames The names of the datasets (can be null to use defaults).
+     * @param rangeSize The range of values to show for auto-ranging in domain axis (in milliseconds).
+     * @return The chart that was created.
+     */
+    static JFreeChart createTimeSeriesChart(
+            String title, 
+            String yAxisLabel, 
+            int seriesCount,
+            String[] datasetNames,
+            double rangeSize) {
+
+        // If dataset names are given, the length must match the number of series requested.
+        if (datasetNames != null && seriesCount != datasetNames.length) {
+            throw new IllegalArgumentException("datasetNames has wrong length: " + datasetNames.length);
+        }
+        
+        // Create the dataset and add empty series to it.
+        TimeSeriesCollection dataset = new TimeSeriesCollection();
+        for (int i = 0; i < seriesCount; i++) {
+            
+            // Uses title for dataset names if none given explicitly.            
+            String datasetName = title;
+            
+            if (datasetNames != null) {
+                // Use the explicitly given dataset names.
+                datasetName = datasetNames[i];
+            }
+            TimeSeries timeSeries = new TimeSeries(datasetName);
+            dataset.addSeries(timeSeries);
+        }
+               
+        // Create the chart.
+        final JFreeChart result = ChartFactory.createTimeSeriesChart(
+                title, 
+                "hh:mm:ss", 
+                yAxisLabel, 
+                dataset, 
+                true, 
+                false, 
+                false);
+        final XYPlot plot = result.getXYPlot();
+
+        // Configure range axis.
+        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
+        rangeAxis.setAutoRange(true);
+        rangeAxis.setAutoRangeIncludesZero(true);
+        
+        // Configure domain axis.
+        plot.getDomainAxis().setAutoRange(true);
+        plot.getDomainAxis().setAutoRangeMinimumSize(rangeSize);
+        
+        return result;
+    }        
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartUpdater.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartUpdater.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/plotting/StripChartUpdater.java	Wed Mar 25 14:43:27 2015
@@ -1,38 +1,67 @@
 package org.hps.monitoring.plotting;
 
+import java.util.Date;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
 import org.jfree.data.time.DynamicTimeSeriesCollection;
+import org.jfree.data.time.RegularTimePeriod;
 
 /**
  * An abstract <tt>TimerTask</tt> to update a strip chart at a regular interval.
  */
-public abstract class StripChartUpdater extends TimerTask {
+public class StripChartUpdater {
+    
+    final JFreeChart chart;
+    final DateAxis domainAxis;
+    final DynamicTimeSeriesCollection dataset;
+    final Timer timer;
+    final TimerTask task;
+    final Long rangeMillis;
+    final ValueProvider valueProvider;
+    long updateInterval;
+        
+    StripChartUpdater(JFreeChart chart, ValueProvider valueProvider, Long rangeMillis, RegularTimePeriod timeBase) {
+        this.chart = chart;                        
+        this.domainAxis = (DateAxis) chart.getXYPlot().getDomainAxis();
+        this.dataset = (DynamicTimeSeriesCollection) chart.getXYPlot().getDataset();
+        this.rangeMillis = rangeMillis;
+        this.updateInterval = timeBase.getLastMillisecond() - timeBase.getFirstMillisecond();            
+        this.valueProvider = valueProvider;
+        timer = new Timer(chart.getTitle().getText() + " Timer");
+        task = new TimerTask() {
+    
+            @Override
+            public void run() {
+                StripChartUpdater.this.chart.setNotify(false);
+        
+                dataset.advanceTime();
+                long time = dataset.getNewestTime().getEnd().getTime();
+                
+                float values[] = StripChartUpdater.this.valueProvider.getValues();
+                dataset.appendData(values);
+        
+                domainAxis.setRange(
+                        new Date(time - StripChartUpdater.this.rangeMillis), 
+                        new Date(time + updateInterval));
 
-    DynamicTimeSeriesCollection dataset;
-    long updateIntervalMillis = 1000;
-
-    public StripChartUpdater() {
+                StripChartUpdater.this.chart.setNotify(true);
+                StripChartUpdater.this.chart.fireChartChanged();                  
+            }            
+        };
     }
-
-    public void setChart(JFreeChart chart) {
-        this.dataset = (DynamicTimeSeriesCollection) chart.getXYPlot().getDataset();
+    
+    JFreeChart getChart() {
+        return chart;
     }
-
-    public void setUpdateIntervalMillis(long updateIntervalMillis) {
-        this.updateIntervalMillis = updateIntervalMillis;
+     
+    void start() {
+        timer.scheduleAtFixedRate(task, 0, updateInterval);
+    }        
+    
+    public void stop() {
+        timer.cancel();
     }
-
-    public void run() {
-        dataset.advanceTime();
-        dataset.appendData(new float[] { nextValue() });
-    }
-
-    public void schedule(Timer timer) {
-        timer.schedule(this, 0, updateIntervalMillis);
-    }
-
-    public abstract float nextValue();
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/StatusCode.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/StatusCode.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/StatusCode.java	Wed Mar 25 14:43:27 2015
@@ -1,16 +1,29 @@
 package org.hps.monitoring.subsys;
+
+import java.awt.Color;
 
 /**
  * Code that represents a sub-system status.
  */
 public enum StatusCode {
-    OKAY,
-    UNKNOWN,
-    CLEARED,
-    OFFLINE,
-    INFO,
-    WARNING,
-    ERROR,
-    ALARM,
-    HALT;
+    
+    OKAY(Color.GREEN),
+    UNKNOWN(Color.GRAY),
+    CLEARED(Color.LIGHT_GRAY),
+    OFFLINE(Color.ORANGE),
+    INFO(Color.WHITE),
+    WARNING(Color.YELLOW),
+    ERROR(Color.RED),
+    ALARM(Color.RED),
+    HALT(Color.RED);
+    
+    Color color;
+    
+    StatusCode(Color color) {
+        this.color = color;
+    }
+    
+    public Color getColor() {
+        return color;
+    }    
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatistics.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatistics.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatistics.java	Wed Mar 25 14:43:27 2015
@@ -1,7 +1,6 @@
 package org.hps.monitoring.subsys;
 
 import java.io.PrintStream;
-import java.util.TimerTask;
 
 /**
  * This is an interface for a set of basic statistics about an online event processing system.
@@ -12,13 +11,20 @@
      * Set the desired timer tick length in millis.
      * @param tickLengthMillis The desired tick length in millis.
      */
-    void setTickLengthMillis(long tickLengthMillis);
+    void setNominalTickLengthMillis(long tickLengthMillis);
 
     /**
-     * Get the nominal length of one tick in millis. Actual ticks lengths may vary slightly.
+     * Get the nominal length of one tick in millis.
+     *  Actual tick lengths lengths may vary slightly.
      * @return The nominal tick length in millis.
      */
-    long getTickLengthMillis();
+    long getNominalTickLengthMillis();
+    
+    /**
+     * Get the end of the tick in Unix time (milliseconds since the epoch).
+     * @return The tick end in Unix time.
+     */
+    long getTickEndTimeMillis();
 
     /**
      * Start the timer thread for accumulating statistics.
@@ -106,6 +112,13 @@
      * @return The data rate in [bytes/second].
      */
     public double getBytesPerSecond();
+    
+    /**
+     * Get the immediate data rate which is the amount of data in megabytes received in the current tick
+     * over the time elapsed in the tick.
+     * @return The data rate in [bytes/second].
+     */
+    public double getMegabytesPerSecond();
 
     /**
      * Get the number of milliseconds since the last tick.
@@ -124,10 +137,10 @@
      * @param ps The PrintStream for display.
      */
     void printTick(PrintStream ps);
-
+    
     /**
-     * Add subtask which will execute right before a new tick.
-     * @param subtask The subtask to execute.
+     * 
+     * @param listener
      */
-    void addSubTask(TimerTask subtask);
+    void addSystemStatisticsListener(SystemStatisticsListener listener);   
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java	Wed Mar 25 14:43:27 2015
@@ -7,52 +7,53 @@
 import java.util.Timer;
 import java.util.TimerTask;
 
-import org.hps.monitoring.plotting.StripChartUpdater;
+import org.hps.monitoring.plotting.ValueProvider;
 
 /**
  * Implementation of {@link SystemStatistics}.
  */
-// FIXME: Rolling averages need to happen over a greater time period like 30 seconds
-// instead of 1 second, because otherwise the statistics don't look right.
 public class SystemStatisticsImpl implements SystemStatistics {
 
-    long tickLengthMillis = 1000; // default is one second tick
-    long sessionElapsedMillis;
+    long nominalTickLengthMillis = 1000; // default is 1 second tick
+    long tickStartTimeMillis;
+    long tickEndTimeMillis;    
+
+    long eventsInTick;
+    long bytesInTick;
+    
     long startTimeMillis;
     long stopTimeMillis;
-    long eventsSinceTick;
-    long bytesSinceTick;
+    
     long totalEvents;
     long totalBytes;
-    long tickStartMillis;
-    long tickElapsedMillis;
+
     static final long Kb = 1 * 1024;
     static final long Mb = Kb * 1024;
     static final double milliToSecond = 0.001;
     static final DecimalFormat decimalFormat = new DecimalFormat("#.####");
     Timer timer;
-    List<TimerTask> subtasks = new ArrayList<TimerTask>();
-
+    
+    List<SystemStatisticsListener> listeners = new ArrayList<SystemStatisticsListener>();
+    
     @Override
     public void update(int size) {
         addEvent();
         addData(size);
-        updateElapsedTime();
-    }
-
-    @Override
-    public void setTickLengthMillis(long tickLengthMillis) {
-        this.tickLengthMillis = tickLengthMillis;
-    }
-
-    @Override
-    public long getTickLengthMillis() {
-        return tickLengthMillis;
+    }
+
+    @Override
+    public void setNominalTickLengthMillis(long tickLengthMillis) {
+        this.nominalTickLengthMillis = tickLengthMillis;
+    }
+
+    @Override
+    public long getNominalTickLengthMillis() {
+        return nominalTickLengthMillis;
     }
 
     @Override
     public long getTotalElapsedMillis() {
-        return sessionElapsedMillis;
+        return System.currentTimeMillis() - startTimeMillis;
     }
 
     @Override
@@ -67,7 +68,12 @@
     
     @Override
     public long getTickElapsedMillis() {
-        return tickElapsedMillis;
+        return System.currentTimeMillis() - tickStartTimeMillis;
+    }
+    
+    @Override
+    public long getTickEndTimeMillis() {
+        return tickEndTimeMillis;
     }
 
     /**
@@ -76,7 +82,7 @@
     
     @Override
     public long getEventsReceived() {
-        return eventsSinceTick;
+        return eventsInTick;
     }
      
     @Override
@@ -86,10 +92,11 @@
     
     @Override
     public double getEventsPerSecond() {
-        if (eventsSinceTick > 0 && tickElapsedMillis > 0)
-            return (double) eventsSinceTick / millisToSeconds(tickElapsedMillis);
-        else
+        if (eventsInTick > 0 && getTickElapsedMillis() > 0) {
+            return (double) eventsInTick / millisToSeconds(getTickElapsedMillis());
+        } else {
             return 0.;
+        }
     }
 
     @Override
@@ -107,7 +114,7 @@
     
     @Override
     public long getBytesReceived() {
-        return bytesSinceTick;
+        return bytesInTick;
     }
     
     @Override
@@ -126,34 +133,59 @@
    
     @Override
     public double getBytesPerSecond() {
-        if (bytesSinceTick > 0 && tickElapsedMillis > 0)
-            return (double) bytesSinceTick / millisToSeconds(tickElapsedMillis);
+        if (bytesInTick > 0 && getTickElapsedMillis() > 0)
+            return (double) bytesInTick / millisToSeconds(getTickElapsedMillis());
         else
             return 0.;
     }
-
+    
+    @Override
+    public double getMegabytesPerSecond() {
+        double bytes = getBytesPerSecond();
+        if (bytes > 0) {
+            return bytesToMb(bytes);
+        } else {
+            return 0;
+        }
+    }
+    
     @Override
     public void start() {
 
-        // Set time variables.
+        // Set session start time variables.
         long currentTimeMillis = System.currentTimeMillis();
         startTimeMillis = currentTimeMillis;
-        tickStartMillis = currentTimeMillis;
-
-        // Start Timer task which executes at tick length.
+        tickStartTimeMillis = currentTimeMillis;
+        
+        // Notify listeners of start.
+        for (SystemStatisticsListener listener : listeners) {
+            listener.started(this);
+        }
+        
+        // Start timer task which executes at the nominal tick length to calculate statistics periodically.
         TimerTask task = new TimerTask() {
             public void run() {
-
-                // Run sub-tasks.
-                for (TimerTask subtask : subtasks) {
-                    subtask.run();
-                }
-
+                
+                // End the current tick.
+                endTick();
+               
+                // Start the new tick.
                 nextTick();
             }
         };
         timer = new Timer();
-        timer.schedule(task, 0, tickLengthMillis);
+        timer.schedule(task, 0, nominalTickLengthMillis);
+    }
+    
+    void endTick() {
+ 
+        // Set absolute end time of current tick.
+        this.tickEndTimeMillis = System.currentTimeMillis();
+        
+        // Activate listeners.
+        for (SystemStatisticsListener listener : listeners) {
+            listener.endTick(this);
+        }
     }
 
     @Override
@@ -166,8 +198,17 @@
 
         // Set stop time.
         stopTimeMillis = System.currentTimeMillis();
-    }
-
+        
+        // Notify listeners of stop.
+        for (SystemStatisticsListener listener : listeners) {
+            listener.stopped(this);
+        }
+    }
+    
+    public void addSystemStatisticsListener(SystemStatisticsListener listener) {
+        listeners.add(listener);
+    }    
+    
     @Override
     public void printSession(PrintStream ps) {
         ps.println("session statistics ...");
@@ -185,115 +226,104 @@
         ps.println("  eventsSinceTick = " + this.getEventsReceived());
         ps.println("  bytesSinceTick = " + this.getBytesReceived());
     }
-
-    @Override
-    public void addSubTask(TimerTask subtask) {
-        this.subtasks.add(subtask);
-    }
-
+   
     void addEvent() {
-        eventsSinceTick += 1;
+        eventsInTick += 1;
         totalEvents += 1;
     }
 
     void addData(int size) {
-        bytesSinceTick += size;
+        bytesInTick += size;
         totalBytes += size;
-    }
-
-    void updateElapsedTime() {
-        tickElapsedMillis = System.currentTimeMillis() - tickStartMillis;
-        sessionElapsedMillis = System.currentTimeMillis() - startTimeMillis;
     }
 
     // Bytes to megabytes to 2 decimal places.
     static final double bytesToMb(long size) {
         return Double.parseDouble(decimalFormat.format((double) size / Mb));
     }
+    
+    // Bytes to megabytes to 2 decimal places.
+    static final double bytesToMb(double size) {
+        return Double.parseDouble(decimalFormat.format(size / Mb));
+    }
 
     static final double millisToSeconds(long millis) {
         return ((double) millis) / 1000.;
     }
 
     synchronized void nextTick() {
-        eventsSinceTick = 0;
-        bytesSinceTick = 0;
-        tickElapsedMillis = 0;
-        tickStartMillis = System.currentTimeMillis();
-    }
-    
-    public abstract class SystemStatisticsUpdater extends StripChartUpdater {
-        SystemStatisticsUpdater() {
-            addSubTask(this);
-        }
-    }
-    
-    public class AverageEventsPerSecondUpdater extends SystemStatisticsUpdater {
-
-        @Override
-        public float nextValue() {
-            return (float) getAverageEventsPerSecond();
-        }
-    }
-    
-    public class EventsPerSecondUpdater extends SystemStatisticsUpdater {
-
-        @Override
-        public float nextValue() {
-            return (float) getEventsPerSecond();
+        eventsInTick = 0;
+        bytesInTick = 0;
+        tickStartTimeMillis = System.currentTimeMillis();
+    }
+    
+    public abstract class SystemStatisticsProvider implements ValueProvider {
+    }
+
+    public class AverageEventsPerSecondProvider extends SystemStatisticsProvider {
+
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getAverageEventsPerSecond()};
+        }
+    }
+    
+    public class EventsPerSecondProvider extends SystemStatisticsProvider {
+
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getEventsPerSecond()};
         }
     }
             
-    public class EventsReceivedUpdater extends SystemStatisticsUpdater {
-
-        @Override
-        public float nextValue() {
-            return getEventsReceived();
-        }
-    }
-
-    public class TotalEventsUpdater extends SystemStatisticsUpdater {
-        @Override
-        public float nextValue() {
-            return getTotalEvents();
-        }
-    }
-
-    public class BytesReceivedUpdater extends SystemStatisticsUpdater {
-        @Override
-        public float nextValue() {
-            return getBytesReceived();
-        }
-    }
-
-    public class AverageMegabytesPerSecondUpdater extends SystemStatisticsUpdater {
-        @Override
-        public float nextValue() {
-            return (float) getAverageMegabytesPerSecond();
-        }
-    }
-
-    public class TotalMegabytesUpdater extends SystemStatisticsUpdater {
-        @Override
-        public float nextValue() {
-            return (float) getTotalMegabytes();
-        }
-    }
-    
-    public class BytesPerSecondUpdater extends SystemStatisticsUpdater {
-
-        @Override
-        public float nextValue() {
-            return (float) getBytesPerSecond();
-        }
-    }
-    
-    public class MegabytesPerSecondUpdater extends SystemStatisticsUpdater {
-        @Override
-        public float nextValue() {
-            return (float) getBytesPerSecond() / 1000000;
-        }
-    }
-    
-    
-}
+    public class EventsReceivedProvider extends SystemStatisticsProvider {
+
+        @Override
+        public float[] getValues() {
+            return new float[] {getEventsReceived()};
+        }
+    }
+
+    public class TotalEventsProvider extends SystemStatisticsProvider {
+        @Override
+        public float[] getValues() {
+            return new float[] {getTotalEvents()};
+        }
+    }
+
+    public class BytesReceivedProvider extends SystemStatisticsProvider {
+        @Override
+        public float[] getValues() {
+            return new float[]{getBytesReceived()};
+        }
+    }
+
+    public class AverageMegabytesPerSecondProvider extends SystemStatisticsProvider {
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getAverageMegabytesPerSecond()};
+        }
+    }
+
+    public class TotalMegabytesProvider extends SystemStatisticsProvider {
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getTotalMegabytes()};
+        }
+    }
+    
+    public class BytesPerSecondProvider extends SystemStatisticsProvider {
+
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getBytesPerSecond()};
+        }
+    }
+    
+    public class MegabytesPerSecondProvider extends SystemStatisticsProvider {
+        @Override
+        public float[] getValues() {
+            return new float[] {(float) getBytesPerSecond() / 1000000};
+        }
+    }
+}

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java	Wed Mar 25 14:43:27 2015
@@ -8,14 +8,16 @@
  */
 public final class SystemStatusImpl implements SystemStatus {
 
+    
     StatusCode code = StatusCode.UNKNOWN;
+    Subsystem systemName;
+    String message;
+    String description;
     long lastChangedMillis;
-    String message;
+    boolean active = true;
+    boolean clearable;
+    
     List<SystemStatusListener> listeners = new ArrayList<SystemStatusListener>();
-    final Subsystem systemName;
-    final String description;
-    boolean active = true;
-    final boolean clearable;
 
     /**
      * Fully qualified constructor.
@@ -29,6 +31,36 @@
         this.clearable = clearable;
         setLastChangedTime();
         SystemStatusRegistry.getSystemStatusRegistery().register(this);
+    }
+    
+    /**
+     * Copy constructor from implementation class.
+     * The list of listeners is NOT copied.  
+     * @param status The status to copy.
+     */
+    public SystemStatusImpl(SystemStatusImpl status) {
+        this.code = status.code;
+        this.systemName = status.systemName;
+        this.message = status.message;
+        this.description = status.description;
+        this.lastChangedMillis = status.lastChangedMillis;
+        this.active = status.active;
+        this.clearable = status.clearable;
+    }
+    
+    /**
+     * Copy constructor from interface.
+     * The list of listeners is NOT copied.  
+     * @param status The status to copy.
+     */
+    public SystemStatusImpl(SystemStatus status) {
+        this.code = status.getStatusCode();
+        this.systemName = status.getSubsystem();
+        this.message = status.getMessage();
+        this.description = status.getDescription();
+        this.lastChangedMillis = status.getLastChangedMillis();
+        this.active = status.isActive();
+        this.clearable = status.isClearable();
     }
 
     @Override
@@ -97,5 +129,5 @@
     @Override
     public boolean isClearable() {
         return clearable;
-    }
+    }    
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalPedestalMonitor.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalPedestalMonitor.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalPedestalMonitor.java	Wed Mar 25 14:43:27 2015
@@ -1,108 +1,66 @@
 package org.hps.monitoring.subsys.ecal;
 
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.hps.conditions.database.DatabaseConditionsManager;
 import org.hps.conditions.ecal.EcalChannel;
 import org.hps.conditions.ecal.EcalConditions;
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
-import org.hps.monitoring.plotting.StripChartUtil;
 import org.jfree.chart.JFreeChart;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.data.time.Second;
+import org.jfree.data.time.TimeSeriesCollection;
 import org.lcsim.event.EventHeader;
 import org.lcsim.geometry.Detector;
 import org.lcsim.util.Driver;
 import org.lcsim.util.aida.AIDA;
+
 /*
  * Reads output of org.hps.recon.ecal.RunningPedestalDriver and makes strip charts.
- * 
- * Are we going to lose/reinitialize these plots when run ends?
- * Or can we keep on going off ET-ring across runs?
  * 
  * Baltzell
  */
 public class EcalPedestalMonitor extends Driver {
 
-    long previousTime;
+    static final int REFRESH_RATE = 10*1000; // units = ms
+    static final double DOMAIN_SIZE = 4*60*60*1000; // x-axis range (ms)
+    static final int crates[]={1,2};
+    static final int slots[]={3,4,5,6,7,8,9,14,15,16,17,18,19,20};
+    static final String slotNames[]={"Sl3","Sl4","Sl5","Sl6","Sl7","Sl8","Sl9","Sl14","Sl15","Sl16","Sl17","Sl18","Sl19","Sl20"};
+    static final String collectionName = "EcalRunningPedestals";
+   
     long currentTime;
-    int refreshRate=1000; // units = ms
-   
+    long previousTime=0;
     int nDetectorChanges=0;
-   
-    int maxAge = 999999999;
-    int maxCount = 100000;
-    int rangeSize = 100000;
-   
-    // None of this "works":
-    //int maxAge = 86400000; // 1 day (units ms)
-    //int maxCount = 999999999;//(int)maxAge/refreshRate;
-    //int rangeSize = 999999999;//maxAge; // what is this?
-   
-    final int crates[]={1,2};
-    final int slots[]={3,4,5,6,7,8,9,14,15,16,17,18,19,20};
+    private EcalConditions ecalConditions = null;
+    List<JFreeChart> charts = new ArrayList<JFreeChart>();
+    MonitoringPlotFactory plotFactory = 
+            (MonitoringPlotFactory) AIDA.defaultInstance().analysisFactory().createPlotterFactory("ECal Pedestal Monitoring");
     
-    String collectionName = "EcalRunningPedestals";
-    
-    MonitoringPlotFactory plotFactory = (MonitoringPlotFactory) AIDA.defaultInstance()
-            .analysisFactory().createPlotterFactory("ECal Pedestal Monitoring");
-
-    Map<Integer, Map<Integer, JFreeChart>> stripCharts = new HashMap<Integer, Map<Integer, JFreeChart>>();
-    Map<Integer, Map<Integer, TimeSeries>> stripCharts2 = new HashMap<Integer, Map<Integer, TimeSeries>>();
-
-    private EcalConditions ecalConditions = null;
-    
-    public void startOfData() {
-        //plotFactory.createStripChart("X","Y",maxAge,maxCount,rangeSize);
-        plotFactory.create().show();
-        
-        //System.out.println("----------------------------    "+maxCount);
-    }
-
-    @Override
     public void detectorChanged(Detector detector) {
-        
-        // this would defeat the purpose.
         if (nDetectorChanges++ > 0) return;
-        
-        currentTime=0;
-        previousTime=0;
-        
         ecalConditions = DatabaseConditionsManager.getInstance().getEcalConditions();
-        
-        // put them in order:
         for (int crate : crates) {
-            stripCharts.put(crate,new HashMap<Integer, JFreeChart>());
-            stripCharts2.put(crate,new HashMap<Integer, TimeSeries>());
-            for (int slot : slots) {
-                
-                final double ped=getAveragePedestal(crate,slot);
-                
-                String name = String.format("C%dS%02d",crate,slot);
-                JFreeChart stripChart = plotFactory.createStripChart(name,"asdf",
-                        maxAge,maxCount,rangeSize);
-//                stripChart.getXYPlot().getRangeAxis().setRange(70,140);
-//                stripChart.getXYPlot().getRangeAxis().setFixedAutoRange(10);
-//                stripChart.getXYPlot().getRangeAxis().setAutoRange(true);
-                stripChart.getXYPlot().getRangeAxis().setRangeAboutValue(ped,10);
-                stripCharts.get(crate).put(slot,stripChart);
-                stripCharts2.get(crate).put(slot,StripChartUtil.getTimeSeries(stripChart));
-            }
+            charts.add(plotFactory.createTimeSeriesChart(
+                    "Crate " + crate,
+                    "Offset Pedestal (ADC)", 
+                    slots.length, slotNames,
+                    DOMAIN_SIZE));
         }
     }
-
+    
     @Override
     public void process(EventHeader event) {
 
-        if (!event.hasItem(collectionName)) {
-            return;
-        }
+        if (!event.hasItem(collectionName)) return;
 
-        currentTime=System.currentTimeMillis();
-        if (currentTime - previousTime < refreshRate) return;
-        previousTime=currentTime;
+        currentTime = System.currentTimeMillis();
+        if (currentTime - previousTime < REFRESH_RATE) return;
+        previousTime = currentTime;
 
         // get the running pedestals:
         Map<EcalChannel, Double> peds = (Map<EcalChannel, Double>) event.get(collectionName);
@@ -110,6 +68,7 @@
         // tally slot pedestals:
         Map<Integer, Map<Integer, Double>> pedsum = new HashMap<Integer, Map<Integer, Double>>();
         Map<Integer, Map<Integer, Integer>> npedsum = new HashMap<Integer, Map<Integer, Integer>>();
+
         for (EcalChannel cc : peds.keySet()) {
             final Double ped = peds.get(cc);
             final int crate = cc.getCrate();
@@ -131,17 +90,24 @@
         }
 
         // fill strip charts:
+        long now = System.currentTimeMillis();
         for (int crate : pedsum.keySet()) {
-            for (int slot : pedsum.get(crate).keySet()) {
-
-                final double ped = pedsum.get(crate).get(slot) / npedsum.get(crate).get(slot);
-                stripCharts2.get(crate).get(slot).add(new Millisecond(new Date()),ped);
+            TimeSeriesCollection cc=getTimeSeriesCollection(crate-1);
+            JFreeChart chart=charts.get(crate-1);
+            DateAxis ax=(DateAxis)chart.getXYPlot().getDomainAxis();
+            ax.setRange(now-DOMAIN_SIZE,now);
+            for (int slot=0; slot<slots.length; slot++) {
+                double ped = pedsum.get(crate).get(slots[slot]) / npedsum.get(crate).get(slots[slot]);
+                ped -= getAveragePedestal(crate,slots[slot])-slot+9;
+                cc.getSeries(slot).addOrUpdate(new Second(new Date()),ped);
             }
         }
-
     }
     
-    
+    TimeSeriesCollection getTimeSeriesCollection(int chartIndex) {
+        return (TimeSeriesCollection) charts.get(chartIndex).getXYPlot().getDataset();
+    }
+
     public EcalChannel findChannel(int crate, int slot, int chan) {
         for (EcalChannel cc : ecalConditions.getChannelCollection()) {
             if (crate == cc.getCrate() && slot == cc.getSlot() && chan == cc.getChannel()) {

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalStripChartTestDriver.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalStripChartTestDriver.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/ecal/EcalStripChartTestDriver.java	Wed Mar 25 14:43:27 2015
@@ -1,13 +1,9 @@
 package org.hps.monitoring.subsys.ecal;
 
-import java.util.Date;
-import java.util.TimerTask;
-
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
-import org.hps.monitoring.plotting.StripChartUtil;
-import org.jfree.chart.JFreeChart;
-import org.jfree.data.time.Millisecond;
-import org.jfree.data.time.TimeSeries;
+import org.hps.monitoring.plotting.StripChartUpdater;
+import org.hps.monitoring.plotting.ValueProvider;
+import org.jfree.data.time.Second;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.RawCalorimeterHit;
 import org.lcsim.util.Driver;
@@ -21,22 +17,27 @@
     int eventInterval = 1000;
     static String collectionName = "EcalReadoutHits";
 
-    MonitoringPlotFactory plotFactory = (MonitoringPlotFactory) AIDA.defaultInstance().analysisFactory().createPlotterFactory("ECAL System Monitoring");
-    TimeSeries series;
-    JFreeChart stripChart;
-    TimerTask updateTask;
+    MonitoringPlotFactory plotFactory = 
+            (MonitoringPlotFactory) AIDA.defaultInstance().analysisFactory().createPlotterFactory("ECAL System Monitoring");
+
     EventHeader currentEvent;
     int hits;
+    
     int events;
-
+    double averageHits;
+    
+    StripChartUpdater updater;
+       
     public void startOfData() {
-        stripChart = plotFactory.createStripChart("Average ECAL Hits per " + eventInterval + " Events", "Hits", 99999999, /*
-                                                                                                                           * max
-                                                                                                                           * age
-                                                                                                                           */
-                1000, /* max count */
-                100000 /* range size */);
-        series = StripChartUtil.getTimeSeries(stripChart);
+        plotFactory.createStripChart(
+                "Average ECAL Hits per " + eventInterval + " Events", 
+                "Hits", 
+                1, 
+                new String[] { "Date" }, 
+                1, 
+                new Second(), 
+                new AverageHitsProvider(), 
+                20000L);        
     }
 
     public void process(EventHeader event) {
@@ -44,10 +45,19 @@
         ++events;
         hits += size;
         if (event.getEventNumber() % eventInterval == 0) {
-            double averageHits = (double) hits / (double) events;
-            series.add(new Millisecond(new Date()), averageHits);
+            averageHits = (double) hits / (double) events;
             hits = 0;
             events = 0;
         }
     }
+    
+    public void endOfData() {
+        updater.stop();
+    }
+    
+    class AverageHitsProvider implements ValueProvider {
+        public float[] getValues() {
+            return new float[] {(float) averageHits};
+        }
+    }
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/et/EtSystemStripCharts.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/et/EtSystemStripCharts.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/subsys/et/EtSystemStripCharts.java	Wed Mar 25 14:43:27 2015
@@ -1,33 +1,95 @@
+/**
+ * 
+ */
 package org.hps.monitoring.subsys.et;
 
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
+import org.hps.monitoring.subsys.SystemStatistics;
 import org.hps.monitoring.subsys.SystemStatisticsImpl;
+import org.hps.monitoring.subsys.SystemStatisticsListener;
 import org.hps.record.et.EtEventProcessor;
+import org.jfree.chart.JFreeChart;
+import org.jfree.data.time.Second;
+import org.jfree.data.time.TimeSeriesCollection;
 import org.jlab.coda.et.EtEvent;
 import org.lcsim.util.aida.AIDA;
 
 /**
- * A basic set of strip charts for monitoring the ET system.
+ * This will show a series of strip charts from ET system performance statistics
+ * such as event and data rates.
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
  */
-public final class EtSystemStripCharts extends EtEventProcessor {
+public class EtSystemStripCharts extends EtEventProcessor implements SystemStatisticsListener {
 
+    // The system statistics.
     SystemStatisticsImpl stats = new SystemStatisticsImpl();
-    MonitoringPlotFactory plotFactory = (MonitoringPlotFactory) AIDA.defaultInstance().analysisFactory().createPlotterFactory("ET System Monitoring");
-
-    public EtSystemStripCharts() {
-        stats.setTickLengthMillis(2000);
+    
+    // Plotting API.
+    MonitoringPlotFactory plotFactory = 
+            (MonitoringPlotFactory) AIDA.defaultInstance().analysisFactory().createPlotterFactory("ET System Monitoring");
+    
+    // List of charts.
+    List<JFreeChart> charts = new ArrayList<JFreeChart>();
+    
+    // Range size in milliseconds.
+    static final double RANGE_SIZE = 200000;
+    
+    // Chart collection indices.
+    static final int DATA_RATE_COLLECTION_INDEX = 0;    
+    static final int TOTAL_DATA_COLLECTION_INDEX = 1;    
+    static final int EVENT_RATE_COLLECTION_INDEX = 2;
+    static final int TOTAL_EVENTS_COLLECTION_INDEX = 3;
+        
+    public EtSystemStripCharts() {          
+        // Set 2 seconds between statistics updates.
+        stats.setNominalTickLengthMillis(1000);
     }
     
     /**
      * Setup the strip charts for ET system monitoring and start accumulating statistics.
      */
     @Override
-    public void startJob() {        
-        plotFactory.createStripChart("Data Rate", "MB / second", 100, stats.new MegabytesPerSecondUpdater()); 
-        plotFactory.createStripChart("Total Data", "Megabytes", 100, stats.new TotalMegabytesUpdater());      
-        plotFactory.createStripChart("Event Rate", "Events / second",  100, stats.new EventsPerSecondUpdater());
-        plotFactory.createStripChart("Total Events", "Number of Events", 100, stats.new TotalEventsUpdater());
+    public void startJob() {
+           
+        // Register this class as a listener to activate update at end of statistics clock tick.
+        stats.addSystemStatisticsListener(this);
+
+        // Start systems statistics task.
         stats.start();
+    }
+
+    /**
+     * Create the strip charts for plotting the basic ET system statistics.
+     */
+    private void createStripCharts() {
+        
+        // Data rate and average data reate in megabytes per second.
+        charts.add(plotFactory.createTimeSeriesChart(
+                "Data Rate", 
+                "MB / second",
+                2, 
+                new String[] { "Data Rate", "Average Data Rate" },
+                RANGE_SIZE));
+                
+        // Total megabytes received.
+        charts.add(plotFactory.createTimeSeriesChart("Total Data", "Megabytes", 1, null, RANGE_SIZE));
+        
+        // Event rate and average event rate in hertz.
+        charts.add(plotFactory.createTimeSeriesChart(
+                "Event Rate", 
+                "Hz", 
+                2, 
+                new String[] { "Event Rate", "Average Event Rate" }, 
+                RANGE_SIZE));
+        
+        // Total number of events received.
+        charts.add(plotFactory.createTimeSeriesChart("Total Events", "Number of Events", 1, null, RANGE_SIZE));
+              
     }
 
     @Override
@@ -35,8 +97,47 @@
         stats.update(event.getLength());
     }
 
-    @Override
     public void endJob() {
+        // Stop system statistics task.
         stats.stop();
     }
-}
+    
+    TimeSeriesCollection getTimeSeriesCollection(int chartIndex) {
+        return (TimeSeriesCollection) charts.get(chartIndex).getXYPlot().getDataset();
+    }
+
+    /**
+     * Hook for updating the charts at end of statistics clock tick.
+     * @param stats The statistics with the system information.
+     */
+    @Override
+    public void endTick(SystemStatistics stats) {
+        
+        Date now = new Date(stats.getTickEndTimeMillis());
+                
+        getTimeSeriesCollection(DATA_RATE_COLLECTION_INDEX).getSeries(0).addOrUpdate(
+                new Second(now), stats.getMegabytesPerSecond());
+        getTimeSeriesCollection(DATA_RATE_COLLECTION_INDEX).getSeries(1).addOrUpdate(
+                new Second(now), stats.getAverageMegabytesPerSecond());
+        
+        getTimeSeriesCollection(TOTAL_DATA_COLLECTION_INDEX).getSeries(0).addOrUpdate(
+                new Second(now), stats.getTotalMegabytes());
+        
+        getTimeSeriesCollection(EVENT_RATE_COLLECTION_INDEX).getSeries(0).addOrUpdate(
+                new Second(now), stats.getEventsPerSecond());
+        getTimeSeriesCollection(EVENT_RATE_COLLECTION_INDEX).getSeries(1).addOrUpdate(
+                new Second(now), stats.getAverageEventsPerSecond());
+        
+        getTimeSeriesCollection(TOTAL_EVENTS_COLLECTION_INDEX).getSeries(0).addOrUpdate(
+                new Second(now), stats.getTotalEvents());
+    }
+     
+    @Override
+    public void started(SystemStatistics stats) {
+        createStripCharts();
+    }
+   
+    @Override
+    public void stopped(SystemStatistics stats) {
+    }
+}

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/ClusterTablePanel.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/ClusterTablePanel.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/ClusterTablePanel.java	Wed Mar 25 14:43:27 2015
@@ -82,11 +82,6 @@
 			setGlobalRowValue(ROW_RECON_COUNT, String.format(countFormat, clusterValue[2]));
 			setGlobalRowValue(ROW_SSP_COUNT,   String.format(countFormat, clusterValue[3]));
 			
-			
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_RECON_COUNT, 1, String.format(countFormat, clusterValue[0]));
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_SSP_COUNT,   1, String.format(countFormat, clusterValue[1]));
-			
-			
 			// Output the tracked statistical data.
 			int total;
 			String percentFormat = "%" + spaces + "d / %" + spaces + "d (%7.3f)";
@@ -112,12 +107,6 @@
 			setGlobalRowValue(ROW_FAILED_POSITION,  String.format(percentFormat, statValue[5], total, 100.0 * statValue[5] / total));
 			setGlobalRowValue(ROW_FAILED_ENERGY,    String.format(percentFormat, statValue[6], total, 100.0 * statValue[6] / total));
 			setGlobalRowValue(ROW_FAILED_HIT_COUNT, String.format(percentFormat, statValue[7], total, 100.0 * statValue[7] / total));
-			
-			
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_MATCHED,          1, String.format(percentFormat, statValue[0], total, 100.0 * statValue[0] / total));
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_FAILED_POSITION,  1, String.format(percentFormat, statValue[1], total, 100.0 * statValue[1] / total));
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_FAILED_ENERGY,    1, String.format(percentFormat, statValue[2], total, 100.0 * statValue[2] / total));
-			System.out.printf("(row = %d, col = %d) --> %s%n", ROW_FAILED_HIT_COUNT, 1, String.format(percentFormat, statValue[3], total, 100.0 * statValue[3] / total));
 		}
 	}
 }

Modified: java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/TableTextModel.java
 =============================================================================
--- java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/TableTextModel.java	(original)
+++ java/branches/prod/monitoring-util/src/main/java/org/hps/monitoring/trigger/TableTextModel.java	Wed Mar 25 14:43:27 2015
@@ -81,6 +81,9 @@
 		
 		// Set the value.
 		values[rowIndex][columnIndex] = value;
+		
+		// Update the table.
+		this.fireTableCellUpdated(rowIndex, columnIndex);
 	}
 	
 	/**

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/RecordProcessingException.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/RecordProcessingException.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/RecordProcessingException.java	Wed Mar 25 14:43:27 2015
@@ -11,4 +11,8 @@
         super(message, x);
     }
     
+    public RecordProcessingException(String message) {
+        super(message);
+    }
+    
 }

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoop.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoop.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoop.java	Wed Mar 25 14:43:27 2015
@@ -15,9 +15,15 @@
 import org.hps.record.enums.ProcessingStage;
 import org.hps.record.et.EtEventProcessor;
 import org.hps.record.et.EtEventSource;
-import org.hps.record.et.EtEventSource.EtSourceException;
 import org.hps.record.evio.EvioEventProcessor;
 import org.hps.record.evio.EvioFileSource;
+import org.jlab.coda.et.exception.EtBusyException;
+import org.jlab.coda.et.exception.EtClosedException;
+import org.jlab.coda.et.exception.EtDeadException;
+import org.jlab.coda.et.exception.EtEmptyException;
+import org.jlab.coda.et.exception.EtException;
+import org.jlab.coda.et.exception.EtTimeoutException;
+import org.jlab.coda.et.exception.EtWakeUpException;
 import org.lcsim.util.Driver;
 import org.lcsim.util.loop.LCIOEventSource;
 
@@ -149,8 +155,8 @@
                 Throwable cause = x.getCause();
                 if (cause instanceof MaxRecordsException || 
                         cause instanceof EndRunException || 
-                        cause instanceof EtSourceException || 
-                        cause instanceof NoSuchRecordException) {
+                        cause instanceof NoSuchRecordException ||
+                        isEtReadException(cause)) {
                     // These types of exceptions are never ignored.
                     return false;
                 } else {
@@ -160,6 +166,21 @@
             } 
         }
         return false;               
+    }
+    
+    /**
+     * True if the Throwable is a type that can be thrown by the ET
+     * system when it is attempting to read events from the server.
+     * The <code>IOException</code> type is ignored but can actually 
+     * be thrown.
+     * @param e The Exception.
+     * @return True if the object can be thrown by ET event reading.
+     */
+    private static boolean isEtReadException(Throwable e) {
+        return e instanceof EtException || e instanceof EtDeadException 
+                || e instanceof EtClosedException || e instanceof EtEmptyException
+                || e instanceof EtBusyException || e instanceof EtTimeoutException
+                || e instanceof EtWakeUpException;
     }
             
     /**

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoopConfiguration.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoopConfiguration.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/composite/CompositeLoopConfiguration.java	Wed Mar 25 14:43:27 2015
@@ -39,7 +39,6 @@
     EtConnection connection = null;
     RecordSource recordSource = null;
     LCSimEventBuilder eventBuilder = null;
-    String detectorName = null;
     
     // Event processors.
     List<EvioEventProcessor> evioProcessors = new ArrayList<EvioEventProcessor>();
@@ -119,17 +118,7 @@
         this.eventBuilder = eventBuilder;
         return this;
     }
-    
-    /**
-     * Set the name of the detector definition to be used e.g. from detector-data/detectors dir. 
-     * @param detectorName The name of the detector.
-     * @return This object.
-     */
-    public CompositeLoopConfiguration setDetectorName(String detectorName) {
-        this.detectorName = detectorName;
-        return this;
-    }
-    
+        
     /**
      * Set whether the loop will stop when event processing errors occur.
      * Certain types of errors are considered fatal or are used to control

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventConstants.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventConstants.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventConstants.java	Wed Mar 25 14:43:27 2015
@@ -2,19 +2,31 @@
 
 public class EvioEventConstants {
     
+    // This is the old tag for physics events.
     public static final int PHYSICS_EVENT_TAG = 1;
+    
+    // CODA control event tags.
     public static final int SYNC_EVENT_TAG = 16;
     public static final int PRESTART_EVENT_TAG = 17;
     public static final int GO_EVENT_TAG = 18;
     public static final int PAUSE_EVENT_TAG = 19;
     public static final int END_EVENT_TAG = 20;
     
+    // Special tag for events with EPICS scalars.
+    public static final int EPICS_EVENT_TAG = 31;
+    
+    // Event tags greater than or equal to this will be physics events.
+    public static final int PHYSICS_START_TAG = 32;
+    
     public static final int EVENTID_BANK_TAG = 0xC000;
-    
+  
+    // Bank tag for header bank with run and event numbers in physics events.
     public static final int HEAD_BANK_TAG = 0xe10F;
   
-    public static final int EPICS_EVENT_TAG = 31;
+    public static final int EPICS_BANK_TAG = 57620;
     public static final int EPICS_BANK_TAG_2s = -1;
     public static final int EPICS_BANK_TAG_20s = -1;
+    //public static final int EPICS_BANK_TAG_2s = -1;
+    //public static final int EPICS_BANK_TAG_20s = -1;
     
 }

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventUtilities.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventUtilities.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioEventUtilities.java	Wed Mar 25 14:43:27 2015
@@ -1,11 +1,6 @@
 package org.hps.record.evio;
 
-import static org.hps.record.evio.EvioEventConstants.END_EVENT_TAG;
-import static org.hps.record.evio.EvioEventConstants.GO_EVENT_TAG;
-import static org.hps.record.evio.EvioEventConstants.PAUSE_EVENT_TAG;
-import static org.hps.record.evio.EvioEventConstants.PHYSICS_EVENT_TAG;
-import static org.hps.record.evio.EvioEventConstants.PRESTART_EVENT_TAG;
-import static org.hps.record.evio.EvioEventConstants.SYNC_EVENT_TAG;
+import static org.hps.record.evio.EvioEventConstants.*;
 
 import org.jlab.coda.jevio.BaseStructure;
 import org.jlab.coda.jevio.EvioEvent;
@@ -19,6 +14,15 @@
 public final class EvioEventUtilities {
 
     private EvioEventUtilities() {
+    }
+    
+    /**
+     * Get the event tag from the header bank.
+     * @param event The input EvioEvent.
+     * @return The event tag from the header bank.
+     */
+    public static int getEventTag(EvioEvent event) {
+        return event.getHeader().getTag();
     }
 
     /**
@@ -69,7 +73,7 @@
      * @return True if this event is a physics event.
      */
     public static boolean isPhysicsEvent(EvioEvent event) {
-        return (event.getHeader().getTag() >= SYNC_EVENT_TAG+16 ||
+        return (event.getHeader().getTag() >= PHYSICS_START_TAG ||
                 event.getHeader().getTag() < SYNC_EVENT_TAG);
         // return event.getHeader().getTag() == PHYSICS_EVENT_TAG;
     }
@@ -82,6 +86,29 @@
      */
     public static boolean isSyncEvent(EvioEvent event) {
         return event.getHeader().getTag() == SYNC_EVENT_TAG;
+    }
+    
+    /**
+     * Check if this event is an EPICS event containing scalar data.
+     * 
+     * @param event The EvioEvent.
+     * @return True if this event is an EPICS event.
+     */
+    public static boolean isEpicsEvent(EvioEvent event) {
+        return event.getHeader().getTag() == EPICS_EVENT_TAG;
+    }
+    
+    /**
+     * True if <code>event</code> is an EVIO control event.
+     * @return True if event is a control event.
+     */
+    public static boolean isControlEvent(EvioEvent event) {
+        return isPreStartEvent(event) || 
+                isGoEvent(event) || 
+                isPauseEvent(event) || 
+                isEndEvent(event) || 
+                isSyncEvent(event) ||
+                isEpicsEvent(event);
     }
 
     /**
@@ -108,7 +135,7 @@
         if (data != null) { //found the data in the top-level bank
             return data;
         } else { //data is not in event bank; look for the data bank whose tag matches the event type
-            for (BaseStructure bank : event.getChildren()) {
+            for (BaseStructure bank : event.getChildrenList()) {
                 if (bank.getHeader().getTag() == eventTag) {
                     return bank.getIntData(); //return whatever int data this bank has
                 }
@@ -125,9 +152,9 @@
      */
     public static BaseStructure getHeadBank(EvioEvent evioEvent) {
         if (evioEvent.getChildCount() > 0) {
-            for (BaseStructure topBank : evioEvent.getChildren()) {
-                if (topBank.getChildren() != null) {
-                    for (BaseStructure nestedBank : topBank.getChildren()) {
+            for (BaseStructure topBank : evioEvent.getChildrenList()) {
+                if (topBank.getChildrenList() != null) {
+                    for (BaseStructure nestedBank : topBank.getChildrenList()) {
                         if (nestedBank.getHeader().getTag() == EvioEventConstants.HEAD_BANK_TAG) {
                             return nestedBank;
                         }
@@ -137,4 +164,24 @@
         }
         return null;        
     }
+    
+    /**
+     * Get the run number from an EVIO event.
+     * @return The run number.
+     */
+    public static int getRunNumber(EvioEvent event) {
+        if (isControlEvent(event)) {
+            return getControlEventData(event)[1];
+        } else if (isPhysicsEvent(event)) {
+            BaseStructure headBank = EvioEventUtilities.getHeadBank(event);
+            if (headBank != null) {                                        
+                return headBank.getIntData()[1];   
+            } else {
+                throw new IllegalArgumentException("Head bank is missing from physics event.");
+            }
+        } else {
+            // Not sure if this would ever happen.
+            throw new IllegalArgumentException("Wrong event type: " + event.getHeader().getTag());
+        }
+    }
 }

Modified: java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioFileProducer.java
 =============================================================================
--- java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioFileProducer.java	(original)
+++ java/branches/prod/record-util/src/main/java/org/hps/record/evio/EvioFileProducer.java	Wed Mar 25 14:43:27 2015
@@ -5,6 +5,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.jlab.coda.et.EtAttachment;
@@ -228,6 +229,8 @@
                     if (debug) {
                         System.out.println("new events - size=" + size + "; group=" + group);
                     }
+                    
+                    int eventTag = EvioEventUtilities.getEventTag(event);
 
                     // Create a new array of ET events.  This always has one event.
                     mevs = sys.newEvents(
@@ -238,7 +241,12 @@
                             1, // number of events
                             size, // size of event but overwritten later
                             group); // group number; default value is arbitrary
-
+                                        
+                    // Create control data array for event selection.
+                    int[] control = new int[EtConstants.stationSelectInts];
+                    Arrays.fill(control, eventTag);
+                    mevs[0].setControl(control);
+                    
                     // Delay for X millis if applicable.
                     if (delay > 0) {
                         Thread.sleep(delay);

Modified: java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/ECalLedCommissioning.lcsim
 =============================================================================
--- java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/ECalLedCommissioning.lcsim	(original)
+++ java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/ECalLedCommissioning.lcsim	Wed Mar 25 14:43:27 2015
@@ -19,7 +19,7 @@
             <inputCollectionRaw>EcalReadoutHits</inputCollectionRaw>
             <inputClusterCollection>EcalClusters</inputClusterCollection>
             <pedSamples>20</pedSamples>
-            <maxEch>10.0</maxEch>
+            <maxEch>5.0</maxEch>
             <minEch>0.005</minEch>
             <eventRefreshRate>5</eventRefreshRate>
         </driver>

Modified: java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/EcalMonitoringFinal.lcsim
 =============================================================================
--- java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/EcalMonitoringFinal.lcsim	(original)
+++ java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/EcalMonitoringFinal.lcsim	Wed Mar 25 14:43:27 2015
@@ -8,12 +8,17 @@
     <execute>
         <!-- <driver name="EventMarkerDriver"/> -->
         <driver name="EcalRawConverter" />
-        <driver name="EcalClusterer" />
+        <driver name="DAQConfig"/> 
+        <driver name="DAQConfigDriver" />
+<!--	<driver name="EcalClusterer" />		--><!-- This is done elsewhere! -->
+        <driver name="GTPTestDriver" />
+        <driver name="TriggerDiagnostics" /> 
         <driver name="EcalMonitoringPlots" />      <!-- General plots -->
         <driver name="EcalHitPlots" />             <!-- Single hit distributions -->
         <driver name="EcalClusterPlots" />         <!-- Clusters distributions -->
         <driver name="EcalDaqPlots" />             <!-- DAQ Plots -->
         <driver name="EcalEventDisplay" />         <!-- Ecal event display -->        
+        <driver name="ClockDriver" />
         <!-- <driver name="EcalWindowPlots"/>  -->
         <!-- <driver name="EcalEvsX"/>         -->           
         <!-- <driver name="TriggerPlots"/>     -->
@@ -24,23 +29,69 @@
         <driver name="EventMarkerDriver" type="org.lcsim.job.EventMarkerDriver">
             <eventInterval>1</eventInterval>
         </driver>
+        <driver name="DAQConfig" type="org.hps.recon.ecal.daqconfig.DAQConfigDriver"/>
+
+	<driver name="DAQConfigDriver" type="org.hps.recon.ecal.daqconfig.DAQConfigDriver">
+	</driver>
+
         <driver name="EcalRawConverter" type="org.hps.recon.ecal.EcalRawConverterDriver">
-            <applyBadCrystalMap>false</applyBadCrystalMap>
+            <ecalCollectionName>EcalCalHits</ecalCollectionName>
             <use2014Gain>false</use2014Gain>
+            <useTimestamps>false</useTimestamps>
+            <useTruthTime>false</useTruthTime>
+            <useRunningPedestal>false</useRunningPedestal>
+            <useTimeWalkCorrection>false</useTimeWalkCorrection>
+            <emulateFirmware>true</emulateFirmware>
+            <emulateMode7>false</emulateMode7>
+            <leadingEdgeThreshold>12</leadingEdgeThreshold>
+            <nsa>100</nsa>
+            <nsb>20</nsb>
+            <nPeak>3</nPeak>
         </driver>
-        <driver name="EcalClusterer" type="org.hps.recon.ecal.cluster.GTPOnlineClusterDriver">
+        <driver name="GTPTestDriver" type="org.hps.recon.ecal.cluster.GTPOnlineClusterDriver">
+            <inputHitCollectionName>EcalCalHits</inputHitCollectionName>
+            <!-- <seedEnergyThreshold>0.500</seedEnergyThreshold>
+            <windowBefore>3</windowBefore>
+            <windowAfter>3</windowAfter> -->
+            <seedEnergyThreshold>0.010</seedEnergyThreshold>
+            <windowBefore>2</windowBefore>
+            <windowAfter>2</windowAfter>
+            <useDAQConfig>true</useDAQConfig>
             <verbose>false</verbose>
+        </driver>
+
+        <driver name="TriggerDiagnostics" type="org.hps.analysis.trigger.TriggerDiagnosticDriver">
+	    <printResultsEveryNEvents>10000</printResultsEveryNEvents>
+            <hitAcceptanceWindow>0</hitAcceptanceWindow>
+            <noiseThresholdCount>100</noiseThresholdCount>
+            <energyAcceptanceWindow>0.009</energyAcceptanceWindow>
+            <printOnClusterFailure>false</printOnClusterFailure>
+            <printOnSinglesSSPFailure>false</printOnSinglesSSPFailure>
+            <printOnSinglesEfficiencyFailure>false</printOnSinglesEfficiencyFailure>
+            <printOnPairSSPFailure>false</printOnPairSSPFailure>
+            <printOnPairEfficiencyFailure>false</printOnPairEfficiencyFailure>
+            <enforceStrictTimeCompliance>true</enforceStrictTimeCompliance> <!-- Set to false for mode-7 -->
+            <readDAQConfig>true</readDAQConfig>
+            <verbose>false</verbose>
+        </driver>
+
+        <driver name="GUIDiagnostics" type="org.hps.monitoring.trigger.TriggerDiagnosticGUIDriver"/>
+
+        <driver name="EcalClusterer" type="org.hps.recon.ecal.cluster.ReconClusterDriver">
             <logLevel>WARNING</logLevel>
-            <windowAfter>2</windowAfter>
-            <windowBefore>2</windowBefore>
-            <seedEnergyThreshold>0.100</seedEnergyThreshold>
-            <inputHitCollectionName>EcalCalHits</inputHitCollectionName>
             <outputClusterCollectionName>EcalClusters</outputClusterCollectionName>
+            <hitEnergyThreshold>0.01</hitEnergyThreshold>
+            <seedEnergyThreshold>0.100</seedEnergyThreshold> 
+            <clusterEnergyThreshold>0.200</clusterEnergyThreshold>
+            <minTime>0.0</minTime>
+            <timeWindow>25.0</timeWindow>
+            <useTimeCut>true</useTimeCut>
+            <writeRejectedHitCollection>false</writeRejectedHitCollection>
         </driver>
+        
         <driver name="EcalMonitoringPlots" type="org.hps.monitoring.ecal.plots.EcalMonitoringPlots">
             <inputCollection>EcalCalHits</inputCollection>
             <eventRefreshRate>5</eventRefreshRate>
-            <accumulateHits>false</accumulateHits>
         </driver>
         <driver name="EcalHitPlots" type="org.hps.monitoring.ecal.plots.EcalHitPlots">
             <inputCollection>EcalCalHits</inputCollection>
@@ -63,28 +114,6 @@
             <minEch>0.005</minEch>
             <eventRefreshRate>1</eventRefreshRate>
         </driver>        
-        <!--<driver name="EcalClusterer" type="org.hps.recon.ecal.HPSEcalCTPClusterer"> -->
-        
-        <!--  <driver name="EcalEvsX" type="org.hps.monitoring.ecal.EcalEvsX">
-            <targetZ>674</targetZ>
-            <inputCollection>EcalClusters</inputCollection>
-        </driver> -->
-        
-        <!-- <driver name="EcalWindowPlots" type="org.hps.monitoring.drivers.ecal.plots.EcalWindowPlots">
-            <inputCollection>EcalReadoutHits</inputCollection>
-        </driver> -->
-        
-        <!-- <driver name="EcalPedestalPlots" type="org.hps.monitoring.drivers.ecal.EcalPedestalPlots">
-            <inputCollection>EcalCalHits</inputCollection>
-            <eventRefreshRate>100</eventRefreshRate>
-        </driver> -->
-        
-        <!--  <driver name="TriggerPlots" type="org.hps.monitoring.ecal.TriggerPlots">
-            <clusterEnergyCut>0.500</clusterEnergyCut>
-        </driver> -->
-        
-        <!-- <driver name="AidaSaveDriver" type="org.lcsim.job.AidaSaveDriver">
-            <outputFileName>triggerEPlots</outputFileName>
-        </driver> -->
+        <driver name="ClockDriver" type="org.hps.readout.ecal.ClockDriver" />
     </drivers>
 </lcsim>

Modified: java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/TriggerDiagnosticsMonitoring.lcsim
 =============================================================================
--- java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/TriggerDiagnosticsMonitoring.lcsim	(original)
+++ java/branches/prod/steering-files/src/main/resources/org/hps/steering/monitoring/TriggerDiagnosticsMonitoring.lcsim	Wed Mar 25 14:43:27 2015
@@ -5,24 +5,16 @@
         <printDriversDetailed>false</printDriversDetailed>
     </control>
     <execute>
-        <driver name="EventMarkerDriver" />
-        <driver name="ConditionsDriver" /> 
-        <driver name="DAQConfig" />
+        <!-- <driver name="EventMarkerDriver" /> -->
         <driver name="EcalRawConverter" />
         <driver name="GTPTestDriver" />
         <driver name="TriggerDiagnostics" />
-        <!-- <driver name="AidaSaveDriver" />  -->
         <driver name="ClockDriver" />
-        <!-- <driver name="CleanupDriver" />  -->
     </execute>
     <drivers>
         <driver name="EventMarkerDriver" type="org.lcsim.job.EventMarkerDriver">
-            <eventInterval>1000</eventInterval>
+            <eventInterval>1</eventInterval>
         </driver>
-        <driver name="ConditionsDriver" type="org.hps.conditions.ConditionsDriver">
-            <tag>pass0</tag>
-        </driver>
-        <driver name="DAQConfig" type="org.hps.readout.ecal.daqconfig.DAQConfigDriver" />
         <driver name="EcalRawConverter" type="org.hps.recon.ecal.EcalRawConverterDriver">
             <ecalCollectionName>EcalCalHits</ecalCollectionName>
             <use2014Gain>false</use2014Gain>
@@ -37,13 +29,16 @@
         </driver>
         <driver name="GTPTestDriver" type="org.hps.recon.ecal.cluster.GTPOnlineClusterDriver">
             <inputHitCollectionName>EcalCalHits</inputHitCollectionName>
+            <!--
             <seedEnergyThreshold>0.500</seedEnergyThreshold>
             <windowBefore>3</windowBefore>
             <windowAfter>3</windowAfter>
-            <!-- <seedEnergyThreshold>0.010</seedEnergyThreshold>
+            -->
+            <!-- cuts used for GTP -->
+            <seedEnergyThreshold>0.010</seedEnergyThreshold>
             <windowBefore>2</windowBefore>
             <windowAfter>2</windowAfter>
-            <verbose>true</verbose> -->
+            <verbose>false</verbose>
         </driver>
         <driver name="TriggerDiagnostics" type="org.hps.analysis.trigger.TriggerDiagnosticDriver">
             <noiseThresholdCount>100</noiseThresholdCount>
@@ -51,18 +46,12 @@
             <printOnSinglesSSPFailure>false</printOnSinglesSSPFailure>
             <printOnSinglesEfficiencyFailure>false</printOnSinglesEfficiencyFailure>
             <printOnPairSSPFailure>false</printOnPairSSPFailure>
-            <printOnPairEfficiencyFailure>false</printOnPairEfficiencyFailure>
-            <!-- <readDAQConfig>true</readDAQConfig> -->
+            <printOnPairEfficiencyFailure>false</printOnPairEfficiencyFailure>            
+            <readDAQConfig>true</readDAQConfig>
             <verbose>true</verbose>
+            <!-- determines snapshot readout time which is set to 1 second here -->
+            <localWindowThresholdMilliseconds>1000</localWindowThresholdMilliseconds>
         </driver>
-<!--         
-        <driver name="AidaSaveDriver" type="org.lcsim.job.AidaSaveDriver">
-            <outputFileName>${outputFile}_triggerPlots</outputFileName>
-        </driver>
- -->        
         <driver name="ClockDriver" type="org.hps.readout.ecal.ClockDriver" />
-        <driver name="CleanupDriver" type="org.lcsim.recon.tracking.digitization.sisim.config.ReadoutCleanupDriver">
-            <collectionNames>TrackerHits</collectionNames>
-        </driver>
     </drivers>
 </lcsim>

Modified: java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/celentan/LedAnalysisFromEvio.lcsim
 =============================================================================
--- java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/celentan/LedAnalysisFromEvio.lcsim	(original)
+++ java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/celentan/LedAnalysisFromEvio.lcsim	Wed Mar 25 14:43:27 2015
@@ -30,6 +30,7 @@
         </driver>       
         <driver name="LedAnalysisDriver" type="org.hps.users.celentan.LedAnalysis">    
            <useRawEnergy>true</useRawEnergy>
+           <energyCut>5</energyCut>
         </driver>
         <driver name="AidaSaveDriver" type="org.lcsim.job.AidaSaveDriver">
             <outputFileName>${outputFile}.aida</outputFileName>

Modified: java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/mgraham/AlignmentMonitorTest.lcsim
 =============================================================================
--- java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/mgraham/AlignmentMonitorTest.lcsim	(original)
+++ java/branches/prod/steering-files/src/main/resources/org/hps/steering/users/mgraham/AlignmentMonitorTest.lcsim	Wed Mar 25 14:43:27 2015
@@ -5,16 +5,16 @@
 <lcsim xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/lcsim/1.0/lcsim.xsd">
     <execute>
         <driver name="EventMarkerDriver" />
-      <driver name="TrackerDigiDriver"/>
+<!--      <driver name="TrackerDigiDriver"/> -->
 <!--  the 3 drivers below are for reading out 6-sample ADC data -->
-<!--        <driver name="RawTrackerHitSensorSetup" /> 
+      <driver name="RawTrackerHitSensorSetup" /> 
         <driver name="RawTrackerHitFitterDriver" /> 
-        <driver name="TrackerHitDriver" />  -->
+       <driver name="TrackerHitDriver" />  
         <driver name="HelicalTrackHitDriver" />
          <driver name="TrackerL1to3ReconDriver"/> 
   <driver name="TrackerL4to6ReconDriver"/> 
 <!--           <driver name="TrackDataDriver"/>   
-        <driver name="EcalRawConverter" />
+       <driver name="EcalRawConverter" /> 
         <driver name="EcalClusterer" />
        <driver name="ReconParticle" />
         <driver name="TrackingMonitoring" />
@@ -46,7 +46,6 @@
             <useTimestamps>false</useTimestamps>
             <correctT0Shift>false</correctT0Shift>
             <useTruthTime>false</useTruthTime>
-            <subtractTOF>false</subtractTOF>
             <debug>false</debug>
         </driver>
         <driver name="TrackerHitDriver" type="org.hps.recon.tracking.DataTrackerHitDriver">
@@ -61,11 +60,10 @@
         </driver>
         <driver name="TrackerL1to3ReconDriver" type="org.hps.recon.tracking.TrackerReconDriver">
             <debug>false</debug>
-<!--            <strategyResource>/org/hps/recon/tracking/strategies/HPS-Full.xml</strategyResource> -->
         <trackCollectionName>L1to3Tracks</trackCollectionName>
             <strategyResource>/org/hps/recon/tracking/strategies/HPS-Full-L1-3.xml</strategyResource>
         </driver>
- <driver name="TrackerL4to6ReconDriver" type="org.hps.recon.tracking.TrackerReconDriver">
+        <driver name="TrackerL4to6ReconDriver" type="org.hps.recon.tracking.TrackerReconDriver">
             <debug>false</debug>
         <trackCollectionName>L4to6Tracks</trackCollectionName>
             <strategyResource>/org/hps/recon/tracking/strategies/HPS-Full-L4-6.xml</strategyResource>
@@ -81,19 +79,7 @@
         </driver>
         <driver name="ReconParticle" type="org.hps.recon.particle.HpsReconParticleDriver">
             <debug>false</debug>
-        </driver>
-        <driver name="BSTrackReconParticle" type="org.hps.recon.particle.HpsReconParticleDriver">
-            <debug>true</debug>
-            <tracksCollectionName>BeamSpotTracks</tracksCollectionName>
-            <finalStateParticlesColName>BSFinalStateParticles</finalStateParticlesColName>
-            <unconstrainedV0CandidatesColName>BSUnconstrainedV0Candidates</unconstrainedV0CandidatesColName>
-            <beamConV0CandidatesColName>BSBeamspotConstrainedV0Candidates</beamConV0CandidatesColName>
-            <targetConV0CandidatesColName>BSTargetConstrainedV0Candidates</targetConV0CandidatesColName>
-            <unconstrainedV0VerticesColName>BSUnconstrainedV0Vertices</unconstrainedV0VerticesColName>
-            <beamConV0VerticesColName>BSBeamspotConstrainedV0Vertices</beamConV0VerticesColName>
-            <targetConV0VerticesColName>BSTargetConstrainedV0Vertices</targetConV0VerticesColName>
-        </driver>
-     
+        </driver>   
         <driver name="TrackingMonitoring" type="org.hps.monitoring.drivers.trackrecon.TrackingReconPlots">         
         <outputPlots>tracking</outputPlots>
         </driver>
@@ -103,7 +89,7 @@
          <driver name="V0Monitoring" type="org.hps.monitoring.drivers.trackrecon.V0ReconPlots">         
         <outputPlots>v0recon</outputPlots>
         </driver>      
-  <driver name="SVTAlignment" type="org.hps.monitoring.drivers.trackrecon.SVTOpeningAlignment">         
+      <driver name="SVTAlignment" type="org.hps.monitoring.drivers.trackrecon.SVTOpeningAlignment">         
         <outputPlots>alignment</outputPlots>
         </driver>
 

Modified: java/branches/prod/tracking/src/main/java/org/hps/readout/svt/SimpleSvtReadout.java
 =============================================================================
--- java/branches/prod/tracking/src/main/java/org/hps/readout/svt/SimpleSvtReadout.java	(original)
+++ java/branches/prod/tracking/src/main/java/org/hps/readout/svt/SimpleSvtReadout.java	Wed Mar 25 14:43:27 2015
@@ -198,8 +198,10 @@
                 for (int sampleN = 0; sampleN < 6; sampleN++) {
                     double time = sampleN * HPSSVTConstants.SAMPLING_INTERVAL - timeOffset;
                     double tp = sensor.getShapeFitParameters(channel)[HpsSiSensor.TP_INDEX];
-                    signal[sampleN] = amplitude * pulseAmplitude(time, tp);
+                    signal[sampleN] += amplitude * pulseAmplitude(time, tp);//add the pulse to the pedestal
                     samples[sampleN] = (short) Math.round(signal[sampleN]);
+                    if (verbosity >= 1)
+                        System.out.println("\t\tMaking samples: sample#" + sampleN + " has " + samples[sampleN] + " ADC counts");
                 }
 
                 long channel_id = sensor.makeChannelID(channel);
@@ -290,15 +292,18 @@
 
     private boolean readoutCuts(RawTrackerHit hit) {
         if (enableThresholdCut && !samplesAboveThreshold(hit)) {
-            //System.out.println("Failed threshold cut");
+            if (verbosity > 1)
+                System.out.println("Failed threshold cut");
             return false;
         }
         if (enablePileupCut && !pileupCut(hit)) {
-            //System.out.println("Failed pileup cut");
+            if (verbosity > 1)
+                System.out.println("Failed pileup cut");
             return false;
         }
         if (dropBadChannels && !badChannelCut(hit)) {
-            //System.out.println("Failed bad channel cut");
+            if (verbosity > 1)
+                System.out.println("Failed bad channel cut");
             return false;
         }
         return true;
@@ -325,19 +330,18 @@
         for (int sampleN = 0; sampleN < samples.length; sampleN++) {
             pedestal = sensor.getPedestal(channel, sampleN);
             noise = sensor.getNoise(channel, sampleN);
-            //System.out.format("%d, %d\n", samples[sampleN] - pedestal, noise * 3.0);
-            if (samples[sampleN] - pedestal > noise * noiseThreshold) {
+            if (verbosity > 1)
+                System.out.format("%f, %f\n", samples[sampleN] - pedestal, noise * noiseThreshold);
+            if (samples[sampleN] - pedestal > noise * noiseThreshold)
                 count++;
-            }
         }
         return count >= samplesAboveThreshold;
     }
 
     @Override
     protected void processTrigger(EventHeader event) {
-        if (noPileup) {
+        if (noPileup)
             return;
-        }
         //System.out.println("Got trigger");
 
         // Create a list to hold the analog data
@@ -438,20 +442,18 @@
         @Override
         public int compareTo(Object o) {
             double deltaT = time - ((StripHit) o).time;
-            if (deltaT > 0) {
+            if (deltaT > 0)
                 return 1;
-            } else if (deltaT < 0) {
+            else if (deltaT < 0)
                 return -1;
-            } else {
+            else
                 return 0;
-            }
         }
     }
 
     private double pulseAmplitude(double time, double tp) {
-        if (time <= 0.0) {
+        if (time <= 0.0)
             return 0.0;
-        }
         return (time / tp) * Math.exp(1.0 - time / tp);
     }
 

Modified: java/branches/prod/users/src/main/java/org/hps/users/celentan/DummyDriverRaw.java
 =============================================================================
--- java/branches/prod/users/src/main/java/org/hps/users/celentan/DummyDriverRaw.java	(original)
+++ java/branches/prod/users/src/main/java/org/hps/users/celentan/DummyDriverRaw.java	Wed Mar 25 14:43:27 2015
@@ -6,10 +6,9 @@
 import org.lcsim.geometry.Detector;
 import org.lcsim.util.Driver;
 import org.lcsim.util.aida.AIDA;
-
-import org.hps.readout.ecal.triggerbank.SSPData;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
 import org.hps.recon.ecal.ECalUtils;
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.SSPData;
 import org.lcsim.event.CalorimeterHit;
 import org.lcsim.event.EventHeader;
 import org.lcsim.event.GenericObject;

Modified: java/branches/prod/users/src/main/java/org/hps/users/phansson/ROOTFlatTupleDriver.java
 =============================================================================
--- java/branches/prod/users/src/main/java/org/hps/users/phansson/ROOTFlatTupleDriver.java	(original)
+++ java/branches/prod/users/src/main/java/org/hps/users/phansson/ROOTFlatTupleDriver.java	Wed Mar 25 14:43:27 2015
@@ -7,6 +7,7 @@
 import hep.physics.vec.BasicHep3Vector;
 import hep.physics.vec.Hep3Vector;
 import hep.physics.vec.VecOp;
+
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -18,9 +19,10 @@
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+
 import org.hps.analysis.ecal.HPSMCParticlePlotsDriver;
-import org.hps.readout.ecal.triggerbank.AbstractIntData;
-import org.hps.readout.ecal.triggerbank.TestRunTriggerData;
+import org.hps.recon.ecal.triggerbank.AbstractIntData;
+import org.hps.recon.ecal.triggerbank.TestRunTriggerData;
 import org.hps.recon.tracking.BeamlineConstants;
 import org.hps.recon.tracking.EventQuality;
 import org.hps.recon.tracking.HPSTrack;

Top of Message | Previous Page | Permalink

Advanced Options


Options

Log In

Log In

Get Password

Get Password


Search Archives

Search Archives


Subscribe or Unsubscribe

Subscribe or Unsubscribe


Archives

November 2017
August 2017
July 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013

ATOM RSS1 RSS2



LISTSERV.SLAC.STANFORD.EDU

Secured by F-Secure Anti-Virus CataList Email List Search Powered by the LISTSERV Email List Manager

Privacy Notice, Security Notice and Terms of Use