diff --git a/src/THcTimeSyncEvtHandler.cxx b/src/THcTimeSyncEvtHandler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2ec522580abf3ffb9aea3ce05c27a13a6c49fe90
--- /dev/null
+++ b/src/THcTimeSyncEvtHandler.cxx
@@ -0,0 +1,277 @@
+/** \class THcTimeSyncEvtHandler
+    \ingroup base
+
+  Event handler for to check syncronization of 4ns clock times
+  recorded by the TIs and the FADCs.
+
+  To use as a plugin, add to the analysis script:
+
+  THcTimeSyncEvtHandler *timesync = new THcTimeSyncEvtHandler("timesync","ADC/TI Time synchrnoziation"));
+  timesync->AddEvtType(1);
+  timesync->AddEvtType(2);
+  ...
+  gHaEvtHandlers->Add(timesync);
+
+  Assumes that all FADCs are in banks with the tag 250 and all
+  TIblob banks are tag 4.  And that these banks are contained
+  without further structure in ROC banks.  Also asssumes that the
+  only banks containing banks are ROC banks.
+
+\author Stephen Wood (saw@jlab.org)
+*/
+
+#include "THcTimeSyncEvtHandler.h"
+#include "THaEvData.h"
+#include "THaGlobals.h"
+#include "THcGlobals.h"
+#include "THcParmList.h"
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <iomanip>
+
+using namespace std;
+
+THcTimeSyncEvtHandler::THcTimeSyncEvtHandler(const char *name, const char* description)
+  : THaEvtTypeHandler(name,description)
+{
+  ExpectedOffsetMap.clear();
+}
+
+THcTimeSyncEvtHandler::~THcTimeSyncEvtHandler()
+{
+}
+
+//Float_t THcTimeSyncEvtHandler::GetData(const std::string& tag)
+//{
+//  // A public method which other classes may use
+//  if (theDataMap.find(tag) == theDataMap.end())
+//    return 0;
+// return theDataMap[tag];
+//}
+
+
+Int_t THcTimeSyncEvtHandler::Analyze(THaEvData *evdata)
+{
+
+  if ( !IsMyEvent(evdata->GetEvType()) ) return -1;
+
+  if (fDebug) cout << "------------------\n  Time Syncronization Checker"<<endl;
+
+  Int_t evlen = evdata->GetEvLength();
+  UInt_t *rdata = (UInt_t*) evdata->GetRawDataBuffer();
+
+  UInt_t *p = (UInt_t*) rdata;
+  UInt_t *plast = p+*p;		// Index to last word in the bank
+  Int_t roc = -1;
+
+  CrateTimeMap.clear();
+
+  while(p<plast) {
+    Int_t banklen = *p;
+    p++;
+    if (fDebugFile) {
+      *fDebugFile << "Bank: " << hex << *p << dec << " len: " << banklen << endl;
+    }
+    if((*p & 0xff00) == 0x1000) {	// Bank Containing banks
+      if(evlen-*(p-1) > 1) { // Don't use overall event header
+        roc = (*p>>16) & 0xf;
+	if(fDebug) cout << "ROC: " << roc << " " << evlen << " " << *(p-1) << hex << " " << *p << dec << endl;
+        CrateTimeMap[roc] = new RocTimes_t;
+      }
+      p++;				// Now pointing to a bank in the bank
+    } else if (((*p & 0xff00) == 0x100) && (*p != 0xC0000100)) {
+      // Bank containing integers.
+      // This is either ROC bank containing integers or
+      // a bank within a ROC containing data from modules of a single type
+      // Look for TI and FADC banks.
+      UInt_t tag = (*p>>16) & 0xffff;
+      UInt_t *pnext = p+banklen;	// Next bank
+      p++;			// First data word
+      if(tag==4) { // This is a TI blob banks
+        // Actually second word is usually a filler
+	// This could be done in a safer way, but it works for now
+        Int_t ifill = ((((*p)>>27)&0x1F) == 0x1F) ? 1 : 0;
+        if(ifill) {
+          p++; banklen--;  // Skip filler word
+        }
+        if(banklen>=5) {   // Need bank header, at least 2 TI  headers, the  trailer and 2 data words
+          UInt_t titime = p[4];
+	  if(fDebug) cout << roc << ": TItime " << titime << endl;
+          CrateTimeMap[roc]->has_ti_ttime = kTRUE;
+          CrateTimeMap[roc]->ti_ttime = titime;
+        }
+      } else if (tag==250) { // This is an FADC banks
+	if(fDebug) cout << roc << ": FADC" << endl;
+        // Walk through this bank looking for FADC headers.
+        Int_t slot=-1;
+        while(p<pnext) {
+          UInt_t code = (*p >> 27) & 0x1F;
+          switch(code) {
+	  case 0x10: // block header
+	    slot = (*p >> 22) & 0x1F;
+	    p++;
+	    break;
+	  case 0x13:  // trigger time word
+	    {
+	      UInt_t fadctime = ((*p)&0xFFFFFF) + (((*(p+1))&0xFF)<<24);
+	      if(fDebug) cout << "    " << slot << ": " << fadctime << endl;
+        CrateTimeMap[roc]->fadcTimesMap[slot] = fadctime;
+	      p += 2;
+	      break;
+	    }
+	  default: // event headers, trailers, fillers, data nwords
+	    p++;
+	    break;
+	  }
+	}
+      }
+      p=pnext;    // Skip to next bank
+    } else {
+      p = p+*(p-1);
+    }
+  }
+
+  if(fFirstTime) {
+    InitStats();
+    fFirstTime = kFALSE;
+  }
+  AccumulateStats();
+
+  return 1;
+}
+
+void THcTimeSyncEvtHandler::InitStats() {
+  /** Initialize structure to hold statistics
+      Record the offset of each TI and FADC time relative to the
+      trigger time of the master TI.
+  */
+  // Assume the smallest ROC # is the TI master
+  if(fMasterRoc < 0) {
+    fMasterRoc = CrateTimeMap.begin()->first;
+  }
+  if(fDebug) cout << "fMasterRoc " << fMasterRoc << endl;
+  UInt_t master_ttime = CrateTimeMap[fMasterRoc]->ti_ttime;
+  if(fDebug) cout << "master_ttime " << master_ttime << endl;
+
+  CrateStatsMap.clear();
+
+  std::map<Int_t, struct RocTimes *>::iterator it = CrateTimeMap.begin();
+  while(it != CrateTimeMap.end()) {
+    Int_t roc = it->first;
+    struct RocTimes *roctimes = it->second;
+    it++;
+    CrateStatsMap[roc] = new RocStats_t;
+    CrateStatsMap[roc]->ti_ttime_offset = roctimes->ti_ttime - master_ttime;
+    if(roctimes->fadcTimesMap.size()>0) {
+      if(fDebug) cout << endl << " FADC";
+      std::map<Int_t, UInt_t>::iterator itt = roctimes->fadcTimesMap.begin();
+      Bool_t use_expected_offset = kFALSE;
+      Int_t expected_offset = 0;
+      if(ExpectedOffsetMap.find(roc) != ExpectedOffsetMap.end()) {
+	expected_offset = ExpectedOffsetMap[roc];
+	use_expected_offset = kTRUE;
+      }
+      while(itt != roctimes->fadcTimesMap.end()) {
+        Int_t slot = itt->first;
+        UInt_t fadctime = itt->second;
+        itt++;
+	if(use_expected_offset) {
+	  CrateStatsMap[roc]->fadcOffsetMap[slot] = expected_offset;
+	} else {
+	  CrateStatsMap[roc]->fadcOffsetMap[slot] = fadctime - master_ttime;
+	}
+        CrateStatsMap[roc]->fadcEarlySlipCountMap[slot] = 0;
+        CrateStatsMap[roc]->fadcLateSlipCountMap[slot] = 0;
+      }
+    }
+  }
+}
+
+void THcTimeSyncEvtHandler::AccumulateStats() {
+  fNEvents++;
+  // Get trigger time from master CrateInfo
+  UInt_t master_ttime = CrateTimeMap[fMasterRoc]->ti_ttime;
+  std::map<Int_t, RocStats_t *>::iterator it = CrateStatsMap.begin();
+  while(it != CrateStatsMap.end()) {
+    Int_t roc = it->first;
+    RocStats* rocstats = it->second;
+    it++;
+    if(CrateTimeMap[roc]->ti_ttime < master_ttime + rocstats->ti_ttime_offset) {
+      rocstats->ti_earlyslipcount++;
+    } else if(CrateTimeMap[roc]->ti_ttime > master_ttime + rocstats->ti_ttime_offset) {
+      rocstats->ti_lateslipcount++;
+    }
+    if(rocstats->fadcOffsetMap.size()>0) {
+      std::map<Int_t, Int_t>::iterator itt = rocstats->fadcOffsetMap.begin();
+      while(itt != rocstats->fadcOffsetMap.end()) {
+        Int_t slot = itt->first;
+        Int_t fadcoffset = itt->second;
+        itt++;
+        if(CrateTimeMap[roc]->fadcTimesMap[slot] < master_ttime+fadcoffset) {
+          rocstats->fadcEarlySlipCountMap[slot]++;
+	} else if(CrateTimeMap[roc]->fadcTimesMap[slot] > master_ttime+fadcoffset) {
+	  rocstats->fadcLateSlipCountMap[slot]++;
+        }
+      }
+    }
+  }
+}
+void THcTimeSyncEvtHandler::PrintStats()
+/* Print time syncrhonization statistics.
+   Need to add an optional filename argument
+*/
+{
+  cout << "-------------------------------------------------------------------" << endl;
+  cout << "------ TI and FADC250 trigger time synchronization statitics ------" << endl;
+  cout << "-------------------------------------------------------------------" << endl;
+  cout << "      " << fNEvents << " events analyzed" << endl;
+  // Dump the map to see if we did it right.
+  std::map<Int_t, RocStats_t *>::iterator it = CrateStatsMap.begin();
+  while(it != CrateStatsMap.end()) {
+    Int_t roc = it->first;
+    struct RocStats *rocstats = it->second;
+    it++;
+    cout << "ROC " << roc << "  TI Offset " << rocstats->ti_ttime_offset << "  Slips " << rocstats->ti_earlyslipcount << "   " << rocstats->ti_lateslipcount << endl;
+    std::map<Int_t, Int_t>::iterator itt = rocstats->fadcEarlySlipCountMap.begin();
+    while(itt != rocstats->fadcEarlySlipCountMap.end()) {
+      Int_t slot = itt->first;
+      Int_t earlyslips = itt->second;
+      Int_t lateslips = rocstats->fadcLateSlipCountMap[slot];
+      itt++;
+      if(earlyslips+lateslips > 0) { // Only print slots with slippage
+	cout << "    " << slot << " " << rocstats->fadcOffsetMap[slot] << "    " << earlyslips << "    " << lateslips << endl;
+      }
+    }
+  }
+  cout << "-------------------------------------------------------------------" << endl;
+}
+void THcTimeSyncEvtHandler::SetExpectedOffset(Int_t roc, Int_t offset) {
+  ExpectedOffsetMap.clear();
+  AddExpectedOffset(roc, offset);
+}
+void THcTimeSyncEvtHandler::AddExpectedOffset(Int_t roc, Int_t offset) {
+  ExpectedOffsetMap[roc] = offset;
+}
+		      
+THaAnalysisObject::EStatus THcTimeSyncEvtHandler::Init(const TDatime& date)
+{
+
+  cout << "Howdy !  We are initializing THcTimeSyncEvtHandler !!   name =   "<<fName<<endl;
+
+  if(eventtypes.size()==0) {
+    eventtypes.push_back(125);  // what events to look for
+  }
+
+  fFirstTime = kTRUE;
+  fMasterRoc = -1;
+  fNEvents = 0;
+  CrateTimeMap.clear();
+  //CrateStatsMap.clear();
+
+  fStatus = kOK;
+  return kOK;
+}
+
+ClassImp(THcTimeSyncEvtHandler)
diff --git a/src/THcTimeSyncEvtHandler.h b/src/THcTimeSyncEvtHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccb3b3c5840f5c17d8f45409619b8bda5081b268
--- /dev/null
+++ b/src/THcTimeSyncEvtHandler.h
@@ -0,0 +1,74 @@
+#ifndef THcTimeSyncEvtHandler_
+#define THcTimeSyncEvtHandler_
+
+/////////////////////////////////////////////////////////////////////
+//
+//   THcTimeSyncEvtHandler
+//
+/////////////////////////////////////////////////////////////////////
+
+#include "THaEvtTypeHandler.h"
+#include <string>
+#include <vector>
+#include <map>
+
+class THcTimeSyncEvtHandler : public THaEvtTypeHandler {
+
+public:
+
+  THcTimeSyncEvtHandler(const char* name, const char* description);
+  virtual ~THcTimeSyncEvtHandler();
+
+  virtual Int_t Analyze(THaEvData *evdata);
+  virtual EStatus Init( const TDatime& run_time);
+  virtual void PrintStats();
+  virtual void SetExpectedOffset(Int_t roc, Int_t offset);
+  virtual void AddExpectedOffset(Int_t roc, Int_t offset);
+
+ //  Float_t GetData(const std::string& tag);
+
+private:
+
+  virtual void InitStats();
+  virtual void AccumulateStats();
+
+  Bool_t fFirstTime;
+  Int_t fMasterRoc; // ROC with the TI master
+  Int_t fNEvents;   // Number of events analyzed
+
+  typedef struct RocTimes {
+    Bool_t has_ti_ttime;
+    UInt_t ti_ttime;
+    std::map<Int_t, UInt_t> fadcTimesMap;
+    RocTimes() : has_ti_ttime(kFALSE) {fadcTimesMap.clear();}
+  } RocTimes_t;
+
+  typedef struct RocStats {
+    Int_t ti_ttime_offset;
+    Int_t ti_earlyslipcount;
+    Int_t ti_lateslipcount;
+    Int_t fadc_expected_offset;
+    std::map<Int_t, Int_t> fadcOffsetMap;
+    std::map<Int_t, Int_t> fadcEarlySlipCountMap;
+    std::map<Int_t, Int_t> fadcLateSlipCountMap;
+    RocStats() : ti_ttime_offset(0), ti_earlyslipcount(0), ti_lateslipcount(0),
+      fadc_expected_offset(0)
+    {
+      fadcOffsetMap.clear();
+      fadcEarlySlipCountMap.clear();
+      fadcLateSlipCountMap.clear();
+    }
+  } RocStats_t;
+
+  std::map<Int_t, RocTimes_t *> CrateTimeMap;
+  std::map<Int_t, RocStats_t *> CrateStatsMap;
+  std::map<Int_t, Int_t> ExpectedOffsetMap;
+
+  THcTimeSyncEvtHandler(const THcTimeSyncEvtHandler& fh);
+  THcTimeSyncEvtHandler& operator=(const THcTimeSyncEvtHandler& fh);
+
+  ClassDef(THcTimeSyncEvtHandler,0)  // Hall C event type 125
+
+};
+
+#endif