Print

Print


Commit in lcio on MAIN
doc/lcio.xml+6-11.69 -> 1.70
src/aid/EVENT/LCIO.aid+3-11.73 -> 1.74
             /TrackerPulse.aid+11-61.3 -> 1.4
src/cpp/include/IMPL/TrackerPulseImpl.h+21-101.3 -> 1.4
src/cpp/src/IMPL/TrackerPulseImpl.cc+33-121.2 -> 1.3
src/cpp/src/SIO/SIOTrackerPulseHandler.cc+17-41.2 -> 1.3
src/cpp/src/TESTS/test_trackerpulse.cc+57-41.1 -> 1.2
src/java/hep/lcio/implementation/event/ITrackerPulse.java+33-201.3 -> 1.4
src/java/hep/lcio/implementation/sio/SIOTrackerPulse.java+31-71.3 -> 1.4
src/python/lcio_swig.i+3-21.9 -> 1.10
+215-67
10 modified files
replaced chargeError and timeError with covariance matrix (LCIO-72)

lcio/doc
lcio.xml 1.69 -> 1.70
diff -u -r1.69 -r1.70
--- lcio.xml	4 May 2010 15:04:04 -0000	1.69
+++ lcio.xml	12 May 2010 14:50:00 -0000	1.70
@@ -336,9 +336,14 @@
             </if>
             <data type="float" name="time">time of pulse</data>
             <data type="float" name="charge">charge</data>
-            <if condition="1000*major+minor&gt;1012">
+            <!--if condition="1000*major+minor&gt;1012">
                 <data type="float" name="timeError"></data>
                 <data type="float" name="chargeError"></data>
+            </if-->
+            <if condition="1000*major+minor&gt;1012">
+                <if condition="(flags&amp;(1&lt;&lt;30)) != 0">
+                    <data type="float[3]" name="covariance">Covariance Matrix of charge (c) and time (t) measurements</data>
+                </if>
             </if>
             <data type="int" name="quality">quality flag word</data>
  	    <data type="pntr" name="tpcCorrectedData">the spectrum used to create the pulse</data>

lcio/src/aid/EVENT
LCIO.aid 1.73 -> 1.74
diff -u -r1.73 -r1.74
--- LCIO.aid	30 Apr 2010 15:28:24 -0000	1.73
+++ LCIO.aid	12 May 2010 14:50:00 -0000	1.74
@@ -16,7 +16,7 @@
 /** Global constants used in LCIO.
  *
  * @author gaede
- * @version $Id: LCIO.aid,v 1.73 2010/04/30 15:28:24 engels Exp $
+ * @version $Id: LCIO.aid,v 1.74 2010/05/12 14:50:00 engels Exp $
  * @see LCObject
  * @see LCIO
  */
@@ -50,6 +50,7 @@
 
     // raw tracker data (pulses)
     static const int TRAWBIT_ID1   = 31 ;  //  cellid1 stored
+    static const int TRAWBIT_CM    = 30 ;  //  cov matrix stored(1) - not stored(0)
 
     // SimTrackerHit
     static const int THBIT_BARREL = 31 ; // barrel(1) - endcap(0)
@@ -136,6 +137,7 @@
 
   // raw tracker data (pulses)
   public static const int TRAWBIT_ID1   = 31 ;  //  cellid1 stored
+  public static const int TRAWBIT_CM    = 30 ;  //  cov matrix stored(1) - not stored(0)
 
   // SimTrackerHit
   public static const int THBIT_BARREL = 31 ; // barrel(1) - endcap(0)

lcio/src/aid/EVENT
TrackerPulse.aid 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- TrackerPulse.aid	4 May 2010 15:04:04 -0000	1.3
+++ TrackerPulse.aid	12 May 2010 14:50:00 -0000	1.4
@@ -6,7 +6,7 @@
  *  @see TrackerData
  * 
  * @author gaede
- * @version $Id: TrackerPulse.aid,v 1.3 2010/05/04 15:04:04 engels Exp $
+ * @version $Id: TrackerPulse.aid,v 1.4 2010/05/12 14:50:00 engels Exp $
  */
 
 public interface TrackerPulse extends LCObject {
@@ -32,17 +32,22 @@
      */
     public float getTime() const ;	
     
-    /** The time error.
-     */
-    public float getTimeError() const ;	
+    //The time error.
+    //public float getTimeError() const ;	
 
      /** The integrated charge of the pulse - arbitrary units.
      */
     public float getCharge() const ;	
     
-    /** The charge error.
+    // The charge error.
+    //public float getChargeError() const ;	
+
+
+    /** Covariance matrix of the charge (c) and time (t) measurements. Stored as lower triangle matrix, i.e.
+     *  cov(c,c) , cov(t,c) , cov(t,t).
      */
-    public float getChargeError() const ;	
+    public const FloatVec& getCovMatrix() const ;
+
 
      /** The quality bit flag of the pulse - check/set collection parameters 
      *  TrackerPulseQualityNames and TrackerPulseQualityNamesValues.

lcio/src/cpp/include/IMPL
TrackerPulseImpl.h 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- TrackerPulseImpl.h	4 May 2010 15:04:05 -0000	1.3
+++ TrackerPulseImpl.h	12 May 2010 14:50:00 -0000	1.4
@@ -4,12 +4,14 @@
 #include "EVENT/TrackerPulse.h"
 #include "AccessChecked.h"
 
+#define TRKPULSENCOVMATRIX 3
+
 namespace IMPL {
 
 /** Default implementation of TrackerPulse.
  * 
  * @author gaede
- * @version $Id: TrackerPulseImpl.h,v 1.3 2010/05/04 15:04:05 engels Exp $
+ * @version $Id: TrackerPulseImpl.h,v 1.4 2010/05/12 14:50:00 engels Exp $
  */
 
   class TrackerPulseImpl :  public EVENT::TrackerPulse , public AccessChecked {
@@ -39,17 +41,22 @@
      */
     virtual float getTime() const { return _time ; }
 
-    /** The time error
-     */
-    virtual float getTimeError() const { return _timeError ; }
+    // The time error
+    //virtual float getTimeError() const { return _timeError ; }
 
     /** The integrated charge of the pulse // FIXME: unit ?.
      */
     virtual float getCharge() const { return _charge ; }
 
-    /** The charge error
+    //The charge error
+    //virtual float getChargeError() const { return _chargeError ; }
+
+    /** Covariance matrix of the charge (c) and time (t) measurements. Stored as lower triangle matrix, i.e.
+     *  cov(c,c) , cov(t,c) , cov(t,t).
+     *  Optional, check/set flag(LCIO::TRAWBIT_CM)==1.
      */
-    virtual float getChargeError() const { return _chargeError ; }
+    virtual const EVENT::FloatVec & getCovMatrix() const { return _cov ; }
+
 
     /** The quality bit flag of the pulse - use the defined constants for referring to the bits.
      */
@@ -66,9 +73,12 @@
     void setCellID0( int cellID0 ) ; 
     void setCellID1( int cellID1 ) ; 
     void setTime( float time ) ; 
-    void setTimeError( float timeError ) ; 
+    //void setTimeError( float timeError ) ; 
     void setCharge( float charge ) ; 
-    void setChargeError( float chargeError ) ; 
+    //void setChargeError( float chargeError ) ; 
+    //void setCovMatrix( const float cov[TRKPULSENCOVMATRIX] ) ;
+    void setCovMatrix( const float* cov ) ;
+    void setCovMatrix( const EVENT::FloatVec & ) ;
     void setQuality( int quality ) ; 
     void setQualityBit( int bit , bool val=true ) ; 
     void setTrackerData( EVENT::TrackerData * corrData ) ; 
@@ -78,10 +88,11 @@
     int _cellID0 ;
     int _cellID1 ;
     float _time ;
-    float _timeError ;
+    //float _timeError ;
     float _charge ;
-    float _chargeError ;
+    //float _chargeError ;
     int   _quality ;
+    EVENT::FloatVec _cov ;
     EVENT::TrackerData* _corrData ;
     
   }; // class

lcio/src/cpp/src/IMPL
TrackerPulseImpl.cc 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- TrackerPulseImpl.cc	4 May 2010 15:04:05 -0000	1.2
+++ TrackerPulseImpl.cc	12 May 2010 14:50:00 -0000	1.3
@@ -12,11 +12,17 @@
     _cellID0(0) ,
     _cellID1(0) ,
     _time(0),
-    _timeError(0),
+    //_timeError(0),
     _charge(0),
-    _chargeError(0),
+    //_chargeError(0),
     _quality(0),
     _corrData(0) {
+
+    _cov.resize( TRKPULSENCOVMATRIX ) ;
+    //for(int i=0; i<TRKPULSENCOVMATRIX; i++){
+    //  _cov.push_back(0.0) ;
+    //}
+
   }    
   
   /// Destructor.
@@ -38,21 +44,36 @@
     _time = time ;
     
   } 
-  void TrackerPulseImpl::setTimeError( float timeError ) {
-    checkAccess("TrackerPulseImpl::setTimeError") ;
-    _timeError = timeError ;
-    
-  } 
+  //void TrackerPulseImpl::setTimeError( float timeError ) {
+  //  checkAccess("TrackerPulseImpl::setTimeError") ;
+  //  _timeError = timeError ;
+  //  
+  //} 
   void TrackerPulseImpl::setCharge( float charge ) {
     checkAccess("TrackerPulseImpl::setCharge") ;
     _charge = charge ;
     
   } 
-  void TrackerPulseImpl::setChargeError( float chargeError ) {
-    checkAccess("TrackerPulseImpl::setChargeError") ;
-    _chargeError = chargeError ;
-    
-  } 
+  //void TrackerPulseImpl::setChargeError( float chargeError ) {
+  //  checkAccess("TrackerPulseImpl::setChargeError") ;
+  //  _chargeError = chargeError ;
+  //  
+  //} 
+
+  void TrackerPulseImpl::setCovMatrix( const FloatVec& cov ){
+    checkAccess("TrackerPulseImpl::setCovMatrix") ;
+    for(int i=0;i<TRKPULSENCOVMATRIX;i++){
+      _cov[i] = cov[i] ;
+    }
+  }
+  //void TrackerPulseImpl::setCovMatrix( float cov[TRKPULSENCOVMATRIX]  ){
+  void TrackerPulseImpl::setCovMatrix( const float* cov  ){
+    checkAccess("TrackerPulseImpl::setCovMatrix") ;
+    for(int i=0;i<TRKPULSENCOVMATRIX;i++){
+      _cov[i] = cov[i] ;
+    }
+  }
+
   void TrackerPulseImpl::setQuality( int quality ) {
     checkAccess("TrackerPulseImpl::setQuality") ;
     _quality = quality ;

lcio/src/cpp/src/SIO
SIOTrackerPulseHandler.cc 1.2 -> 1.3
diff -u -r1.2 -r1.3
--- SIOTrackerPulseHandler.cc	4 May 2010 15:04:05 -0000	1.2
+++ SIOTrackerPulseHandler.cc	12 May 2010 14:50:00 -0000	1.3
@@ -35,8 +35,15 @@
     SIO_DATA( stream ,  &(hit->_time) , 1  ) ;
     SIO_DATA( stream ,  &(hit->_charge )  , 1  ) ;
     if( _vers > SIO_VERSION_ENCODE( 1, 12 )   ){
-        SIO_DATA( stream ,  &(hit->_timeError) , 1  ) ;
-        SIO_DATA( stream ,  &(hit->_chargeError )  , 1  ) ;
+
+        //SIO_DATA( stream ,  &(hit->_timeError) , 1  ) ;
+        //SIO_DATA( stream ,  &(hit->_chargeError )  , 1  ) ;
+
+        if( lcFlag.bitSet( LCIO::TRAWBIT_CM ) ){
+            float cov[TRKPULSENCOVMATRIX] ;
+            SIO_DATA( stream ,  cov  ,  TRKPULSENCOVMATRIX ) ;
+            hit->setCovMatrix( cov ) ;
+        }
     }
     SIO_DATA( stream ,  &(hit->_quality )  , 1  ) ;
     
@@ -62,8 +69,14 @@
       LCSIO_WRITE( stream, hit->getCellID1()  ) ;
     LCSIO_WRITE( stream, hit->getTime()  ) ;
     LCSIO_WRITE( stream, hit->getCharge()  ) ;
-    LCSIO_WRITE( stream, hit->getTimeError()  ) ;
-    LCSIO_WRITE( stream, hit->getChargeError()  ) ;
+    //LCSIO_WRITE( stream, hit->getTimeError()  ) ;
+    //LCSIO_WRITE( stream, hit->getChargeError()  ) ;
+    if( lcFlag.bitSet( LCIO::TRAWBIT_CM ) ){
+        const FloatVec& cov = hit->getCovMatrix() ;
+        for(unsigned int i=0; i<cov.size(); i++){
+            LCSIO_WRITE( stream, cov[i]  ) ;
+        }
+    }
     LCSIO_WRITE( stream, hit->getQuality()  ) ;
 
     TrackerData* corr = hit->getTrackerData() ;

lcio/src/cpp/src/TESTS
test_trackerpulse.cc 1.1 -> 1.2
diff -u -r1.1 -r1.2
--- test_trackerpulse.cc	4 May 2010 15:04:05 -0000	1.1
+++ test_trackerpulse.cc	12 May 2010 14:50:00 -0000	1.2
@@ -55,16 +55,37 @@
             evt->setEventNumber( i ) ;
 
             LCCollectionVec* trkPulses = new LCCollectionVec( LCIO::TRACKERPULSE )  ;
+            LCCollectionVec* trkPulsesCov = new LCCollectionVec( LCIO::TRACKERPULSE )  ;
+
+            LCFlagImpl flag( trkPulsesCov->getFlag() ) ;
+            flag.setBit( LCIO::TRAWBIT_CM ) ;
+            trkPulsesCov->setFlag( flag.getFlag() ) ;
+
 
             for(int j=0;j<NPULSES;j++){
                 TrackerPulseImpl* trkPulse = new TrackerPulseImpl ;
                 trkPulse->setTime( 3.1415 + 0.1 * i ) ;
-                trkPulse->setTimeError( (i+j) * .003 ) ;
+                //trkPulse->setTimeError( (i+j) * .003 ) ;
                 trkPulse->setCharge( 3.1415 + 0.1 * j ) ;
-                trkPulse->setChargeError( (i+j)*.005 ) ;
+                //trkPulse->setChargeError( (i+j)*.005 ) ;
+                
                 trkPulses->addElement( trkPulse ) ;
             }
+            for(int j=0;j<NPULSES;j++){
+                TrackerPulseImpl* trkPulse = new TrackerPulseImpl ;
+                trkPulse->setTime( 3.1415 + 0.1 * i ) ;
+                //trkPulse->setTimeError( (i+j) * .003 ) ;
+                trkPulse->setCharge( 3.1415 + 0.1 * j ) ;
+                //trkPulse->setChargeError( (i+j)*.005 ) ;
+
+                float cov[3] = { i, j, i*j } ;
+                trkPulse->setCovMatrix( cov );
+
+                trkPulsesCov->addElement( trkPulse ) ;
+            }
+
             evt->addCollection( trkPulses , "TrackerPulses") ;
+            evt->addCollection( trkPulsesCov , "TrackerPulsesWithCovMatrix") ;
 
             lcWrt->writeEvent(evt) ;
 
@@ -93,6 +114,8 @@
 
             LCCollection* trkPulses = evt->getCollection( "TrackerPulses") ;
 
+            //MYTEST.LOG(" reading back TrackerPulses from file " ) ;
+
             for(int j=0;j<NPULSES;j++) {
 
                 //std::cout << " testing pulse " << j << std::endl ;
@@ -100,11 +123,41 @@
                 TrackerPulse* trkPulse = dynamic_cast<TrackerPulse*>(trkPulses->getElementAt(j)) ;
 
                 MYTEST( trkPulse->getTime(),  float( 3.1415 + 0.1 * i ), "time" ) ;
-                MYTEST( trkPulse->getTimeError(),  float( (i + j) * .003 ), "time error" ) ;
+                //MYTEST( trkPulse->getTimeError(),  float( (i + j) * .003 ), "time error" ) ;
                 MYTEST( trkPulse->getCharge(),  float( 3.1415 + 0.1 * j ), "charge" ) ;
-                MYTEST( trkPulse->getChargeError(), float( (i + j) * .005 ), "charge error" ) ;
+                //MYTEST( trkPulse->getChargeError(), float( (i + j) * .005 ), "charge error" ) ;
+
+
+                const FloatVec& cov = trkPulse->getCovMatrix() ;
+                
+                // should be initialized to 0
+                MYTEST( cov[0] , 0 , " cov[0] " ) ;
+                MYTEST( cov[1] , 0 , " cov[1] " ) ;
+                MYTEST( cov[2] , 0 , " cov[2] " ) ;
 
             }
+
+            LCCollection* trkPulsesCov = evt->getCollection( "TrackerPulsesWithCovMatrix") ;
+
+            //MYTEST.LOG(" reading back TrackerPulsesWithCovMatrix from file " ) ;
+
+            for(int j=0;j<NPULSES;j++) {
+
+                //std::cout << " testing pulse " << j << std::endl ;
+
+                TrackerPulse* trkPulse = dynamic_cast<TrackerPulse*>(trkPulsesCov->getElementAt(j)) ;
+
+                MYTEST( trkPulse->getTime(),  float( 3.1415 + 0.1 * i ), "time" ) ;
+                //MYTEST( trkPulse->getTimeError(),  float( (i + j) * .003 ), "time error" ) ;
+                MYTEST( trkPulse->getCharge(),  float( 3.1415 + 0.1 * j ), "charge" ) ;
+                //MYTEST( trkPulse->getChargeError(), float( (i + j) * .005 ), "charge error" ) ;
+                const FloatVec& cov = trkPulse->getCovMatrix() ;
+                
+                MYTEST( cov[0] , i , " cov[0] " ) ;
+                MYTEST( cov[1] , j , " cov[1] " ) ;
+                MYTEST( cov[2] , i*j , " cov[2] " ) ;
+            }
+
         }
         lcRdr->close() ;
 

lcio/src/java/hep/lcio/implementation/event
ITrackerPulse.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- ITrackerPulse.java	5 May 2010 09:25:03 -0000	1.3
+++ ITrackerPulse.java	12 May 2010 14:50:01 -0000	1.4
@@ -6,18 +6,20 @@
 /**
  *
  * @author tonyj
- * @version $Id: ITrackerPulse.java,v 1.3 2010/05/05 09:25:03 engels Exp $
+ * @version $Id: ITrackerPulse.java,v 1.4 2010/05/12 14:50:01 engels Exp $
  */
 public class ITrackerPulse extends ILCObject implements TrackerPulse
 {
    protected int cellID0;
    protected int cellID1;
    protected float charge;
-   protected float chargeError;
+   //protected float chargeError;
    protected int quality;
    protected TrackerData correctedData;
    protected float time;
-   protected float timeError;
+   //protected float timeError;
+   protected static int covMatrixSize=3;
+   protected float[] covMatrix = new float[covMatrixSize];
    
  
    
@@ -49,10 +51,10 @@
    {
       return charge;
    }
-   public float getChargeError()
-   {
-      return chargeError;
-   }
+   //public float getChargeError()
+   //{
+   //   return chargeError;
+   //}
    
    public int getQuality()
    {
@@ -68,22 +70,33 @@
    {
       return time;
    }
-   public float getTimeError()
+   //public float getTimeError()
+   //{
+   //   return timeError;
+   //}
+      
+   public float[] getCovMatrix()
    {
-      return timeError;
+      return covMatrix;
    }
-   
-   
-   public void setCharge(float charge)
+
+   public void setCovMatrix(float[] matrix)
    {
+      if (matrix.length != covMatrixSize) throw new IllegalArgumentException();
       checkAccess();
-      this.charge = charge;
+      this.covMatrix = matrix;
    }
-   public void setChargeError(float chargeError)
+
+   public void setCharge(float charge)
    {
       checkAccess();
-      this.chargeError = chargeError;
+      this.charge = charge;
    }
+   //public void setChargeError(float chargeError)
+   //{
+   //   checkAccess();
+   //   this.chargeError = chargeError;
+   //}
    
    public void setQuality(int quality)
    {
@@ -103,9 +116,9 @@
       checkAccess();
       this.time = time;
    }
-   public void setTimeError(float timeError)
-   {
-      checkAccess();
-      this.timeError = timeError;
-   }
+   //public void setTimeError(float timeError)
+   //{
+   //   checkAccess();
+   //   this.timeError = timeError;
+   //}
 }

lcio/src/java/hep/lcio/implementation/sio
SIOTrackerPulse.java 1.3 -> 1.4
diff -u -r1.3 -r1.4
--- SIOTrackerPulse.java	5 May 2010 09:02:25 -0000	1.3
+++ SIOTrackerPulse.java	12 May 2010 14:50:01 -0000	1.4
@@ -12,7 +12,7 @@
 /**
  *
  * @author tonyj
- * @version $Id: SIOTrackerPulse.java,v 1.3 2010/05/05 09:02:25 engels Exp $
+ * @version $Id: SIOTrackerPulse.java,v 1.4 2010/05/12 14:50:01 engels Exp $
  */
 public class SIOTrackerPulse extends ITrackerPulse
 {
@@ -27,11 +27,20 @@
 
       time = in.readFloat();
       charge = in.readFloat();
-      timeError = 0;
-      chargeError = 0;
+      //timeError = 0;
+      //chargeError = 0;
+
+      for (int i = 0; i < covMatrixSize; i++)
+        covMatrix[i] = 0;
+
       if( SIOVersion.encode(major,minor) > SIOVersion.encode(1,12)){
-        timeError = in.readFloat();
-        chargeError = in.readFloat();
+        //timeError = in.readFloat();
+        //chargeError = in.readFloat();
+        if ((flags & (1 << LCIO.TRAWBIT_CM)) != 0){
+          for (int i = 0; i < covMatrixSize; i++){
+              covMatrix[i] = in.readFloat();
+          }
+        }
       }
       quality = in.readInt();
       data = in.readPntr();
@@ -47,6 +56,15 @@
          if ((flags & (1 << LCIO.TRAWBIT_ID1)) != 0) out.writeInt(hit.getCellID1()); 
          out.writeFloat(hit.getTime());
          out.writeFloat(hit.getCharge());
+         //out.writeFloat(hit.getTimeError());
+         //out.writeFloat(hit.getChargeError());
+
+         if ((flags & (1 << LCIO.TRAWBIT_CM)) != 0){
+             float[] matrix = hit.getCovMatrix();
+             for (int i = 0; i < matrix.length; i++)
+                 out.writeFloat(matrix[i]);
+         }
+
          out.writeInt(hit.getQuality());
          out.writePntr(hit.getTrackerData());
          out.writePTag(hit);
@@ -58,8 +76,14 @@
       if ((flags & (1 << LCIO.TRAWBIT_ID1)) != 0) out.writeInt(cellID1);
       out.writeFloat(time);
       out.writeFloat(charge);
-      out.writeFloat(timeError);
-      out.writeFloat(chargeError);
+      //out.writeFloat(timeError);
+      //out.writeFloat(chargeError);
+
+      if ((flags & (1 << LCIO.TRAWBIT_CM)) != 0){
+          for (int i = 0; i < covMatrix.length; i++)
+              out.writeFloat(covMatrix[i]);
+      }
+      
       out.writeInt(quality);
       out.writePntr(correctedData);
       out.writePTag(this);

lcio/src/python
lcio_swig.i 1.9 -> 1.10
diff -u -r1.9 -r1.10
--- lcio_swig.i	4 Jun 2008 17:37:16 -0000	1.9
+++ lcio_swig.i	12 May 2010 14:50:01 -0000	1.10
@@ -1,4 +1,4 @@
-// $Id: lcio_swig.i,v 1.9 2008/06/04 17:37:16 engels Exp $
+// $Id: lcio_swig.i,v 1.10 2010/05/12 14:50:01 engels Exp $
 
 /*
  * Process this file with Swig to make a Python wrapper for LCIO.
@@ -379,6 +379,7 @@
             static const int RCHBIT_TIME;
             static const int RCHBIT_ENERGY_ERROR;
             static const int TRAWBIT_ID1;
+            static const int TRAWBIT_CM;
             static const int THBIT_BARREL;
             static const int THBIT_MOMENTUM;
             static const int TRBIT_HITS;
@@ -423,7 +424,7 @@
             static const char* LCRELATION = "LCRelation";
             static const char* LCGENERICOBJECT = "LCGenericObject";
             static const char* PARTICLEID = "ParticleID";
-	    static const char* VERTEX = "Vertex";
+            static const char* VERTEX = "Vertex";
 %mutable;
     };
 }
CVSspam 0.2.8