text:
//here be dragons
package org.iontorrent.sam2flowgram.util;

import org.broadinstitute.sting.utils.collections.Pair;
import org.iontorrent.sam2flowgram.flowalign.*;

import net.sf.samtools.*;

/**
 * Stores information for query alignment and re-alignment.
 *
 * @author nils.homer@lifetech.com
 */
public class FlowAlignRecord implements Cloneable {

    /**
     * The SAM record associated with this query.
     */
    public SAMRecord record;
    /**
     * The zero-based input file index from which this query was read.
     */
    public int fileIndex; // to which input/output file does this belong?
    /**
     * The one-based start position of the alignment, where we include any upstream
     * matching bases as to always start at the beginning of a homopolymer.
     */
    public int positionStart;
    /**
     * The one-based end position of the alignment.
     */
    public int positionEnd; // one-based
    /**
     * The zero-based reference sequence index.
     */
    public int referenceIndex; // zero-based
    /**
     * The strand (true - reverse, false - forward).
     */
    public boolean strand;
    /**
     * The flow order for the read, phased to match the first sequenced base
     * in the read.
     */
    public FlowOrder flowOrder;
    /**
     * The flow signals for the read according to the flow order, in sequencing
     * order.
     */
    public FlowSeq readFlows;
    /**
     * The read sequence, with soft-clipping inforation partitioned, relative
     * to the genomic forward strand.
     */
    public ReadSeq readSeq;
    /**
     * The read bases in integer format relative to the forward genomic strand.
     */
    public byte[] readBases;
    /**
     * The flow space representation of the alignment relative to the forward
     * genomic strand.
     */
    public FlowgramAlignment alignment;
    /**
     * True if we are to perform a base space start local alignment.
     */
    public int flowOrderIndexStart;

    /**
     * @param record the original SAM record.
     * @param fileIndex the zero-based file index from which the query was read.
     */
    public FlowAlignRecord(SAMRecord record, int fileIndex, FlowOrder flowOrder) {
        this.record = record;
        this.fileIndex = fileIndex;
        this.readSeq = new ReadSeq(record);
        this.readBases = readSeq.getReadBytes();
        this.referenceIndex = record.getReferenceIndex();
        this.positionStart = record.getAlignmentStart();
        this.positionEnd = record.getAlignmentEnd();
        this.strand = record.getReadNegativeStrandFlag();
        this.flowOrder = new FlowOrder(flowOrder);
        this.alignment = null;
    }

    public FlowAlignRecord(FlowAlignRecord toCopy) {

    }

    /**
     * Note that this does a shallow copy of everything, except for the attribute list, for which a copy of the list
     * is made, but the attributes themselves are copied by reference.  This should be safe because callers should
     * never modify a mutable value returned by any of the get() methods anyway.
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        final FlowAlignRecord newRecord = (FlowAlignRecord)super.clone();
        newRecord.fileIndex = this.fileIndex;
        newRecord.referenceIndex = this.referenceIndex;
        newRecord.flowOrder = new FlowOrder(this.flowOrder);
        newRecord.alignment = this.alignment;
        try{
            newRecord.record = (SAMRecord)this.record.clone();
            newRecord.readSeq = new ReadSeq(this.record);
            newRecord.readBases = readSeq.getReadBytes();
            newRecord.positionStart = this.record.getAlignmentStart();
            newRecord.positionEnd = this.record.getAlignmentEnd();
            newRecord.strand = this.record.getReadNegativeStrandFlag();

        } catch (Exception e) {

        }
        return newRecord;
    }

    /**
     * @param start true if we are to examine from the start of the alignment, false if we want to examine from the end of the alignment.
     * @return the first non-empty target flow in the alignment.
     */
    private int getTSeqJ(boolean start) {
        int j;
        if(start) {
            j = 0;
            while(FlowgramAlignment.ALN_INS == this.alignment.aln[j] || SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.tseq[j]) <= 0) {
                j++;
                if(j == this.alignment.length) {
                    break;
                }
            }
        }
        else {
            j = this.alignment.length - 1;
            while(FlowgramAlignment.ALN_INS == this.alignment.aln[j] || SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.tseq[j]) <= 0) {
                j--;
                if(j == 0) {
                    break;
                }
            }
        }
        return j;
    }

    /**
     * Adjust the start position based on hps.
     * @param sequence the reference sequence.
     * @param adjustTseq adjust the tseq value in the alignment.
     */
    private void adjustPositionStart(ReferenceSequence sequence, boolean adjustTseq)
        throws Exception {
        int i, j;
        byte base, curBase;
        if(1 < this.positionStart) {
            if(!sequence.isIupac(this.referenceIndex, this.positionStart)) {
                base = sequence.getBase(this.referenceIndex, this.positionStart, true, false);
                i = 0;
                while(1 <= this.positionStart - i - 1) { // examine the previous bases
                    curBase = sequence.getBase(this.referenceIndex, this.positionStart - 1 - i, true, false);
                    if(curBase != base) {
                        break;
                    }
                    i++;
                }
                // adjust tseq
                if(0 < i) {
                    this.positionStart -= i;
                    if(adjustTseq) {
                        j = getTSeqJ(true);
                        this.alignment.tseq[j] += i * 100;
                    }
                }
            }
        }
    }

    /**
     * Adjust the end position based on hps.
     * @param sequence the reference sequence.
     * @param adjustTseq adjust the tseq value in the alignment.
     */
    private void adjustPositionEnd(ReferenceSequence sequence, boolean adjustTseq)
        throws Exception {
        int i, j;
        byte base, curBase;
        if(this.positionEnd < sequence.length(this.referenceIndex)) {
            if(!sequence.isIupac(this.referenceIndex, this.positionEnd)) {
                base = sequence.getBase(this.referenceIndex, this.positionEnd, true, false);
                i = 0;
                while(this.positionEnd + i + 1 <= sequence.length(this.referenceIndex)) {
                    curBase = sequence.getBase(this.referenceIndex, this.positionEnd + i + 1, true, false);
                    if(curBase != base) {
                        break;
                    }
                    i++;
                }
                // adjust tseq
                if(0 < i) {
                    this.positionEnd += i;
                    if(adjustTseq) {
                        j = getTSeqJ(false);
                        this.alignment.tseq[j] += i * 100;
                    }
                }
            }
        }
    }

    public FlowgramAlignment setAlignment(ReferenceSequence sequence, int phasePenalty)
        throws Exception
    {
        return this.setAlignment(sequence, phasePenalty, false);
    }

    /**
     * Fills in the alignment and flow information for this read.
     * @param sequence the reference sequence.
     * @param phasePenalty the flow space phase penalty.
     * @param validateAlignments validate alignments.
     * @return the flow alignment.
     */
    public FlowgramAlignment setAlignment(ReferenceSequence sequence, int phasePenalty, boolean validateAlignments)
        throws Exception
    {
        return this.setAlignment(sequence, phasePenalty, 0, validateAlignments);
    }

    /**
     * Fills in the alignment and flow information for this read.
     * @param sequence the reference sequence.
     * @param phasePenalty the flow space phase penalty.
     * @param offset the alignment offset in bases
     * @return the flow alignment.
     */
    public FlowgramAlignment setAlignment(ReferenceSequence sequence, int phasePenalty, int offset, boolean validateAlignments)
        throws Exception
    {
        int i, j, k, n;
        byte base, curBase;
        byte[] referenceBases = null;
        byte[] readBases = null;
        int[] flowSignals = null;
        int[] tmpFlowSignals = null;
        int[] hardClipBases = null;
        boolean tmpBoolean;
        boolean startLocalAlignment, endLocalAlignment;
        int score;

        this.alignment = null;

        // default to local alignment
        startLocalAlignment = endLocalAlignment = true; // prove otherwise

        // NB: we could extend to the previous/next homopolymers
        this.positionStart -= offset;
        if(this.positionStart < 1) {
            this.positionStart = 1;
        }
        this.positionEnd += offset;
        if(sequence.length(this.referenceIndex) < this.positionEnd) {
            this.positionEnd = sequence.length(this.referenceIndex);
        }

        // extend the start
        base = sequence.getBase(this.referenceIndex, this.positionStart, true, false);
        while(1 < this.positionStart && base < 4) {
            curBase = sequence.getBase(this.referenceIndex, this.positionStart-1, true, false);
            if(4 <= curBase || curBase != base) {
                break;
            }
            this.positionStart--;
        }
        // extend the end
        base = sequence.getBase(this.referenceIndex, this.positionEnd, true, false);
        while(this.positionEnd < sequence.length(this.referenceIndex) && base < 4) {
            curBase = sequence.getBase(this.referenceIndex, this.positionEnd+1, true, false);
            if(4 <= curBase || curBase != base) {
                break;
            }
            this.positionEnd++;
        }

        // read and reference bases for the flow space alignment
        readBases = new byte[this.readBases.length];
        System.arraycopy(this.readBases, 0, readBases, 0, this.readBases.length);
        referenceBases = sequence.getBases(this.referenceIndex, this.positionStart, this.positionEnd);

        // Note: readBases and referenceBases are on the forward strand
        // Reverse compliment
        if(this.strand) {
            SamToFlowgramAlignUtil.reverseCompliment(readBases);
            SamToFlowgramAlignUtil.reverseCompliment(referenceBases);
            // swap
            tmpBoolean = startLocalAlignment;
            startLocalAlignment = endLocalAlignment;
            endLocalAlignment = tmpBoolean;
        }

        /*
        System.err.println("this.positionStart=" + this.positionStart);
        System.err.println("this.positionEnd=" + this.positionEnd);
        for(i=0;i<readBases.length;i++) {
        System.err.print(SamToFlowgramAlignUtil.DNA[(int)readBases[i]]);
        }
        System.err.println("");
        for(i=0;i<referenceBases.length;i++) {
        System.err.print(SamToFlowgramAlignUtil.DNA[(int)referenceBases[i]]);
        }
        System.err.println("");
        */

        // retrieve the flow signals
        flowSignals = SamToFlowgramAlignUtil.getFlowSignals(this.record);
        if(null == flowSignals) {
            throw new Exception("The FZ optional tag (flow signals) was not present");
        }

        // a. if there are hard clip bases, retrieve them from the flow signals
        // b. get the flow order start index, given the key sequence, hard clip bases, and soft clip bases
        // c. adjust the flow signals based on the start index, and last non-read base (last base of the key, or last base of the hard clip)
        // TODO
        flowSignals = this.readSeq.updateFlowInformation(this.strand, this.flowOrder, flowSignals, SamToFlowgramAlignUtil.getFlowSignalsStart(this.record));
        this.flowOrderIndexStart = this.readSeq.getFlowOrderIndexStart();

        /*
        System.err.println("FLOW SIGNALS!");
        System.err.println("this.flowOrderIndexStart=" + this.flowOrderIndexStart);
        for(i=0;i<flowSignals.length;i++) {
            if(0 < i) {
                System.err.print(",");
            }

            System.err.print("" + flowSignals[i]);
        }
        System.err.print("");
        */

        // rotate the flow order to match the first flow in readBases for the flow space pre-alignment
        this.flowOrder.rotate(this.flowOrderIndexStart, true);

        // read flows
        //this.readFlows = new FlowSeq(readBases, this.flowOrder.flowOrder);
        this.readFlows = new FlowSeq(readBases, flowSignals, this.flowOrder.flowOrder);

        // represent the alignment in flow space
        this.alignment = new FlowgramAlignment(this.readFlows, referenceBases, this.flowOrder,
            startLocalAlignment,
            endLocalAlignment,
            phasePenalty);

        //this.alignment.print(System.err);

        // swap back
        if(this.strand) {
            // swap
            tmpBoolean = startLocalAlignment;
            startLocalAlignment = endLocalAlignment;
            endLocalAlignment = tmpBoolean;
            // reverse the alignment
            this.alignment.reverseCompliment();
        }

        // adjust start position and end position based on alignment
        if(0 < this.alignment.tseqStart) {
            this.positionStart += this.alignment.tseqStart;
        }
        if(this.alignment.tseqEnd < this.alignment.tseqLength - 1) {
            this.positionEnd -= (this.alignment.tseqLength - this.alignment.tseqEnd - 1);
        }

        // adjust if we start with an insertion
        if(FlowgramAlignment.ALN_INS == this.alignment.aln[0]) {
            this.positionStart--;
        }

        if(validateAlignments) {
            // get the score before validating
            score = recalculateAlignmentScore(phasePenalty);

            // This is required for the graph ordering to work.
            this.alignment.rightAdjustIndels();

            // validate the alignment
            validateAlignment(sequence, score);
        }
        else {
            // This is required for the graph ordering to work.
            this.alignment.rightAdjustIndels();
        }

        // split reference flows
        this.alignment.splitReferenceFlows();

        return this.alignment;
    }

    private String validateAlignmentTestOne()
    {
        /**
         * Test 1
         * Check that the target length is equal to the flow space alignment target length
         */
        int i, length;
        int positionStart;

        for(i=length=0;i<this.alignment.length;i++) {
            if(FlowgramAlignment.ALN_INS != this.alignment.aln[i]) {
                length += this.alignment.tseq[i];
            }
        }
        // convert from flow signals
        length = SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(length);

        positionStart = this.positionStart;
        if(FlowgramAlignment.ALN_INS == this.alignment.aln[0]) {
            positionStart++;
        }

        if(this.positionEnd - positionStart + 1 != length) {
            return new String("Test one: target lengths do not match!\n(" + this.positionEnd + " - " + positionStart + " + 1) != " + length + "\n");
        }
        else {
            return "";
        }
    }

    private String validateAlignmentTestTwo(ReferenceSequence sequence)
        throws Exception
    {
        /**
         * Test 2
         * Check that the target sequence is equal to the target sequence implied by the flow space alignment
         */
        int i, j, length;
        byte[] referenceBases = null;
        byte[] fsReferenceBases = null;
        boolean differ = false;
        int positionStart;

        positionStart = this.positionStart;
        if(FlowgramAlignment.ALN_INS == this.alignment.aln[0]) {
            positionStart++;
        }

        referenceBases = sequence.getBases(this.referenceIndex, positionStart, this.positionEnd, false, true);

        fsReferenceBases = new byte[this.positionEnd - this.positionStart + 1];
        for(i=j=0;i<this.alignment.length;i++) {
            if(FlowgramAlignment.ALN_INS != this.alignment.aln[i]) {
                length = SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.tseq[i]);
                while(0 < length) {
                    fsReferenceBases[j] = (byte) SamToFlowgramAlignUtil.DNA[this.alignment.flowOrder[i]];
                    if(referenceBases.length <= j || fsReferenceBases[j] != referenceBases[j]) {
                        differ = true;
                    }
                    j++;
                    length--;
                }
            }
        }

        if(differ) {
            return new String("Test two: target sequences do not match!\n" + new String(referenceBases) + "\n" + new String(fsReferenceBases) + "\n");
        }
        else {
            return "";
        }
    }

    private String validateAlignmentTestThree(ReferenceSequence sequence)
        throws Exception
    {
        /**
         * Test 3
         * Check that the first and last target homopolymers are fully extended.
         */
        byte curBase;

        positionStart = this.positionStart;
        if(FlowgramAlignment.ALN_INS == this.alignment.aln[0]) {
            positionStart++;
        }

        curBase = sequence.getBase(this.referenceIndex, positionStart);
        if(1 < positionStart && !sequence.isIupac(this.referenceIndex, positionStart) && sequence.getBase(this.referenceIndex, positionStart) == sequence.getBase(this.referenceIndex, positionStart-1))  {
            return new String("Test three: target sequence is not fully extended at the start (" + positionStart + ")!\n");
        }
        if(this.positionEnd < sequence.length(this.referenceIndex) && !sequence.isIupac(this.referenceIndex, this.positionEnd) && sequence.getBase(this.referenceIndex, this.positionEnd) == sequence.getBase(this.referenceIndex, this.positionEnd+1))  {
            return new String("Test three: target sequence is not fully extended at the end (" + this.positionEnd + ")!\n");
        }
        return "";
    }

    private String validateAlignmentTestFour()
        throws Exception
    {
        /**
         * Test 4
         * Check that the query's flow signals match the record flow signals.
         */
        int i, j, length;
        int[] flowSignals = null;
        int[] fsFlowSignals = null;
        boolean differ = false;

        length = this.readFlows.nonEmptyFlowLast - this.readFlows.nonEmptyFlowFirst + 1;
        flowSignals = new int[length];
        System.arraycopy(this.readFlows.flow, this.readFlows.nonEmptyFlowFirst, flowSignals, 0, length);
        if(this.strand) {
            // swap
            for(i=0;i<flowSignals.length / 2;i++) {
                j = flowSignals[i];
                flowSignals[i] = flowSignals[flowSignals.length-i-1];
                flowSignals[flowSignals.length-i-1] = j;
            }
        }

        fsFlowSignals = new int[this.alignment.length];
        for(i=j=0;i<this.alignment.length;i++) {
            if(FlowgramAlignment.ALN_DEL != this.alignment.aln[i]) {
                if(flowSignals[j] != this.alignment.qseq[i]) {
                    differ = true;
                }
                fsFlowSignals[j] = this.alignment.qseq[i];
                j++;
            }
        }
        length = j;

        if(differ) {
            String s = new String("Test four: flow signals differ!\n");
            for(i=0;i<flowSignals.length;i++) {
                if(0 < i) {
                    s += ",";
                }
                s += flowSignals[i];
            }
            s += "\n";
            for(i=0;i<length;i++) {
                if(0 < i) {
                    s += ",";
                }
                s += fsFlowSignals[i];
            }
            s += "\n";
            return s;
        }
        else {
            return "";
        }
    }

    // NB: compute this before right-justifying
    private int recalculateAlignmentScore(int phasePenalty)
        throws Exception
    {
        int i, score;
        byte prevBase = 'N';
        int n;

        int start, end, by;

        score = n = 0;
        if(strand) { // reverse
            start=this.alignment.length-1;
            end=-1;
            by=-1;
        }
        else {
            start=0;
            end=this.alignment.length;
            by=1;
        }
        for(i=start;i!=end;i+=by) {
            if(FlowgramAlignment.ALN_INS == this.alignment.aln[i]) {
                score -= this.alignment.qseq[i];
                if(prevBase == this.alignment.flowOrder[i]) {
                    n++;
                    score -= phasePenalty;
                }
            }
            else if(FlowgramAlignment.ALN_DEL == this.alignment.aln[i]) {
                score -= this.alignment.tseq[i];
                prevBase = this.alignment.flowOrder[i];
            }
            else if(FlowgramAlignment.ALN_MATCH == this.alignment.aln[i] || FlowgramAlignment.ALN_MISMATCH == this.alignment.aln[i]) {
                if(0 == i || this.alignment.length - 1 == i) {
                    int s = SamToFlowgramAlignUtil.getFlowSignalFromBaseCall(SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.qseq[i]));
                    if(s < this.alignment.qseq[i]) {
                        score -= (this.alignment.qseq[i] - s);
                    }
                    else {
                        score -= (s - this.alignment.qseq[i]);
                    }
                }
                else {
                    if(this.alignment.tseq[i] <  this.alignment.qseq[i]) {
                        score -= (this.alignment.qseq[i] - this.alignment.tseq[i]);
                    }
                    else {
                        score -= (this.alignment.tseq[i] - this.alignment.qseq[i]);
                    }
                }
                prevBase = this.alignment.flowOrder[i];
            }
            else {
                throw new Exception("Unknown operator: " + this.alignment.aln[i]);
            }
            /*
               System.err.println("score=" + score
               + " " + this.alignment.qseq[i]
               + " " + this.alignment.aln[i]
               + " " + this.alignment.tseq[i]
               + " " + this.alignment.flowOrder[i]);
               */
        }
        return score;
    }

    private String validateAlignmentTestFive(int score)
        throws Exception
    {
        /**
         * Test 5
         * Check that the alignment score is correct
         */
        if(score != this.alignment.getScore()) {
            return new String("Test five: alignment score was wrong (" + score + " != " + this.alignment.getScore() + ")!\n");
        }
        else {
            return "";
        }
    }

    public void validateAlignment(ReferenceSequence sequence, int score)
        throws Exception
    {
        String out = new String("");

        // run tests
        out += validateAlignmentTestOne();
        out += validateAlignmentTestTwo(sequence);
        out += validateAlignmentTestThree(sequence);
        out += validateAlignmentTestFour();
        out += validateAlignmentTestFive(score);

        if(0 < out.length()) {
            out += this.getSAMString();
            out += this.alignment.getAlignmentString(150, true);
            throw new Exception(out);
        }
    }

    public void clear() {
        this.record = null;
        this.flowOrder = null;
        this.readFlows = null;
        this.readSeq = null;
        this.readBases = null;
        this.alignment = null;
    }

     public String getSAMString() {
        StringBuilder sb = new StringBuilder();
        //sb.append(
        String FIELD_SEPARATOR = "\t";
        sb.append(this.record.getReadName());
        sb.append(FIELD_SEPARATOR);
        sb.append(Integer.toString(this.record.getFlags()));
        sb.append(FIELD_SEPARATOR);
        sb.append(this.record.getReferenceName());
        sb.append(FIELD_SEPARATOR);
        sb.append(Integer.toString(this.record.getAlignmentStart()));
        sb.append(FIELD_SEPARATOR);
        sb.append(Integer.toString(this.record.getMappingQuality()));
        sb.append(FIELD_SEPARATOR);
        sb.append(this.record.getCigarString());
        sb.append(FIELD_SEPARATOR);

        //  == is OK here because these strings are interned
        if (this.record.getReferenceName() == this.record.getMateReferenceName() &&
                SAMRecord.NO_ALIGNMENT_REFERENCE_NAME != this.record.getReferenceName()) {
            sb.append("=");
        } else {
            sb.append(this.record.getMateReferenceName());
        }

        sb.append(FIELD_SEPARATOR);
        sb.append(Integer.toString(this.record.getMateAlignmentStart()));
        sb.append(FIELD_SEPARATOR);
        sb.append(Integer.toString(this.record.getInferredInsertSize()));
        sb.append(FIELD_SEPARATOR);
        sb.append(this.record.getReadString());
        sb.append(FIELD_SEPARATOR);
        sb.append(this.record.getBaseQualityString());
        //SAMBinaryTagAndValue attribute = this.record.getBinaryAttributes();

        //StringBuilder mdTag = new StringBuilder();
        String[] stringAttributes       = {"MD", "PG", "RG" };
        String[] integerAttributes      = {"NM", "AS", "XS", "XT" };
        String[] byteArrayAttributes    = {"FZ"};
        String stringAttr = ":Z:";
        String intAttr = ":i:";
        String byteArrayAttr = ":B:S,";

        for (String attr : stringAttributes) {
            sb.append(FIELD_SEPARATOR);
            sb.append(attr);
            sb.append(stringAttr);
            //System.out.println( attr+":Z:" + this.record.getStringAttribute( attr ) );
            sb.append( this.record.getStringAttribute(attr) );
        }

        for (String attr : integerAttributes) {
            sb.append( FIELD_SEPARATOR );
            sb.append(attr);
            sb.append(intAttr);
            //System.out.println( attr+":i:" + this.record.getIntegerAttribute( attr ) );

            sb.append( this.record.getIntegerAttribute(attr) );
        }

        int[] flowSignals = SamToFlowgramAlignUtil.getFlowSignals(this.record);
        sb.append( FIELD_SEPARATOR );
        sb.append("FZ");
        sb.append(byteArrayAttr);
        for (int flow : flowSignals) {
            sb.append(flow);
            sb.append(",");
        }

        sb.append("\n");

        return sb.toString();
     }

     public void getSignalAndOffset(long position, Tuple<Integer> signalOffset) {
         getSignalOrIndexAndOffset(position,signalOffset,true);
     }

     public void getIndexAndOffset(long position, Tuple<Integer> signalOffset) {
         getSignalOrIndexAndOffset(position,signalOffset,false);
     }

     public void getSignalOrIndexAndOffset(long position, Tuple<Integer> tuple, Boolean returnSignal) {
         int i;
         long t;
         tuple.one = tuple.two = -1;
         if(position < this.positionStart || this.positionEnd < position || null == this.alignment) {
             // TODO: throw exception
             return;
         }
         // TODO: precompute these...

         if(!this.strand) { // forward
             t = this.positionStart;
             for(i=0;i<this.alignment.tseq.length;i++) {
                 //if(this.alignment.aln[i] == FlowgramAlignment.FROM_I) continue;
                 int l = SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.tseq[i]);
                 if(position <= t + l - 1) {
                     // TODO: we may want to avoid creating a tuple object each time
                     tuple.one = returnSignal ? this.alignment.qseq[i] : i;
                     tuple.two = (int)(position - t);
                     return;
                 }
                 if(this.alignment.aln[i] != FlowgramAlignment.FROM_I) { // TODO: is this necessary
                     t += l;
                 }
             }
         }
         else { // reverse
             t = this.positionEnd;
             for(i=this.alignment.tseq.length-1;0<=i;i--) {
                 //if(this.alignment.aln[i] == FlowgramAlignment.FROM_I) continue;
                 int l = SamToFlowgramAlignUtil.getBaseCallFromFlowSignal(this.alignment.tseq[i]);
                 if(t - l + 1 <= position) {
                     // TODO: we may want to avoid creating a tuple object each time
                     tuple.one = returnSignal? this.alignment.qseq[i] : i;
                     tuple.two = (int)(position - (t - l + 1));
                     return;
                 }
                 if(this.alignment.aln[i] != FlowgramAlignment.FROM_I) { // TODO: is this necessary
                     t -= l;
                 }
             }
         }
         return;
     }

     public Tuple<Integer> getSignalAndOffset(long position) {
         Tuple<Integer> t = new Tuple();
         this.getSignalAndOffset(position, t);
         if(-1 == t.one && -1 == t.two) {
             return null;
         }
         return t;
     }

     public int getSignal(long position) {
         Tuple<Integer> t = getSignalAndOffset(position);
         if(null == t) {
             return -1;
         }
         return t.one;
     }

    public int getAlignIndex(long position) {
         Tuple<Integer> t = new Tuple<Integer>();
        this.getIndexAndOffset(position, t);
         if(null == t) {
             return -1;
         }
         return t.one;
    }

    /**
     * Extracts a subregion of the alignment, based on a queried genomic location.
     *
     * @param subregionPos the genomic position around where the subregion will be taken
     * @param windowNumFlows the number of flows before and after the position
     * @param variantDependentWindow if true, then window will start after the end of the variant
     */
    public FlowgramAlignment extractPartialRegion(long subregionPos,
                                                  int windowNumFlows, Boolean variantDependentWindow) throws Exception {
        FlowgramAlignment subAlign;
        subAlign = new FlowgramAlignment(this.alignment,false);

        /*
        FlowgramAlignment subAlign = read.flowAlign.extractPartialRegion(variantPosition, numFlowWindowSize,true);
        flowAlignContextPileupStrm.printf("addRead:" + threadId + ";" + variantNum + ";" + subAlign.variantStart + ";" + subAlign.length + ";");
        */

        //Todo check if this returns an invalid value like -1.
        int alignIndex = this.getAlignIndex(subregionPos);
        //System.err.printf("getAlignIndex(" + subregionPos + ") = " + alignIndex + "\n");
        int minAlignIndex;
        if (alignIndex < windowNumFlows) minAlignIndex = 0;
        else minAlignIndex = alignIndex - windowNumFlows;

        Boolean reachedAlignPos = false;
        Boolean reachedMatchAfterAlign = false;
        int positionsAfter = 0;

        subAlign.flowOrder = new byte[this.alignment.length-minAlignIndex];
        subAlign.qseq = new int[this.alignment.length-minAlignIndex];
        subAlign.tseq = new int[this.alignment.length-minAlignIndex];
        subAlign.aln = new char[this.alignment.length-minAlignIndex];

        subAlign.variantStart = -1;

        for(int curAlignIndex = minAlignIndex; curAlignIndex<this.alignment.length; curAlignIndex++) {
            //System.err.printf(curAlignIndex + "," + alignIndex + "," + subAlign.length + "\n");
            if(curAlignIndex==alignIndex) {
                reachedAlignPos = true;
                subAlign.variantStart = curAlignIndex - minAlignIndex;
                subAlign.variantEnd = subAlign.variantStart;
            } else if(reachedAlignPos) {
                if (this.alignment.aln[curAlignIndex] == this.alignment.ALN_MATCH || !variantDependentWindow) {
                    reachedMatchAfterAlign = true;
                    subAlign.variantEnd = curAlignIndex - minAlignIndex - 1;
                }
            }
            if (reachedMatchAfterAlign) {
                positionsAfter++;
                if (positionsAfter > windowNumFlows) {
                    break;
                }
            }
            subAlign.length =  curAlignIndex-minAlignIndex;
            subAlign.flowOrder[subAlign.length] =  this.alignment.flowOrder[curAlignIndex];
            subAlign.qseq[subAlign.length] =  this.alignment.qseq[curAlignIndex];
            subAlign.tseq[subAlign.length] =  this.alignment.tseq[curAlignIndex];
            subAlign.aln[subAlign.length] = this.alignment.aln[curAlignIndex];
        }
        subAlign.length++;
        return subAlign;
    }
}

redpajama_set_name: RedPajamaGithub


text:
package org.apache.commons.io.output;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

/**
 * FileWriter that will create and honor lock files to allow simple
 * cross thread file lock handling.
 *

 * This class provides a simple alternative to FileWriter
 * that will use a lock file to prevent duplicate writes.
 *

 * N.B. the lock file is deleted when {@link #close()} is called
 * - or if the main file cannot be opened initially.
 * In the (unlikely) event that the lockfile cannot be deleted,
 * this is not reported, and subsequent requests using
 * the same lockfile will fail.
 *

 * By default, the file will be overwritten, but this may be changed to append.
 * The lock directory may be specified, but defaults to the system property
 * java.io.tmpdir.
 * The encoding may also be specified, and defaults to the platform default.
 *
 * @author Scott Sanders
 * @author Michael Salmon
 * @author Jon S. Stevens
 * @author Daniel Rall
 * @author Stephen Colebourne
 * @author Andy Lehane
 * @version $Id: LockableFileWriter.java 1002182 2010-09-28 14:39:19Z sebb $
 */
public class LockableFileWriter extends Writer {
    // Cannot extend ProxyWriter, as requires writer to be
    // known when super() is called

    /** The extension for the lock file. */
    private static final String LCK = ".lck";

    /** The writer to decorate. */
    private final Writer out;
    /** The lock file. */
    private final File lockFile;

    /**
     * Constructs a LockableFileWriter.
     * If the file exists, it is overwritten.
     *
     * @param fileName  the file to write to, not null
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(String fileName) throws IOException {
        this(fileName, false, null);
    }

    /**
     * Constructs a LockableFileWriter.
     *
     * @param fileName  file to write to, not null
     * @param append  true if content should be appended, false to overwrite
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(String fileName, boolean append) throws IOException {
        this(fileName, append, null);
    }

    /**
     * Constructs a LockableFileWriter.
     *
     * @param fileName  the file to write to, not null
     * @param append  true if content should be appended, false to overwrite
     * @param lockDir  the directory in which the lock file should be held
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(String fileName, boolean append, String lockDir) throws IOException {
        this(new File(fileName), append, lockDir);
    }

    /**
     * Constructs a LockableFileWriter.
     * If the file exists, it is overwritten.
     *
     * @param file  the file to write to, not null
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(File file) throws IOException {
        this(file, false, null);
    }

    /**
     * Constructs a LockableFileWriter.
     *
     * @param file  the file to write to, not null
     * @param append  true if content should be appended, false to overwrite
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(File file, boolean append) throws IOException {
        this(file, append, null);
    }

    /**
     * Constructs a LockableFileWriter.
     *
     * @param file  the file to write to, not null
     * @param append  true if content should be appended, false to overwrite
     * @param lockDir  the directory in which the lock file should be held
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(File file, boolean append, String lockDir) throws IOException {
        this(file, null, append, lockDir);
    }

    /**
     * Constructs a LockableFileWriter with a file encoding.
     *
     * @param file  the file to write to, not null
     * @param encoding  the encoding to use, null means platform default
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(File file, String encoding) throws IOException {
        this(file, encoding, false, null);
    }

    /**
     * Constructs a LockableFileWriter with a file encoding.
     *
     * @param file  the file to write to, not null
     * @param encoding  the encoding to use, null means platform default
     * @param append  true if content should be appended, false to overwrite
     * @param lockDir  the directory in which the lock file should be held
     * @throws NullPointerException if the file is null
     * @throws IOException in case of an I/O error
     */
    public LockableFileWriter(File file, String encoding, boolean append,
            String lockDir) throws IOException {
        super();
        // init file to create/append
        file = file.getAbsoluteFile();
        if (file.getParentFile() != null) {
            FileUtils.forceMkdir(file.getParentFile());
        }
        if (file.isDirectory()) {
            throw new IOException("File specified is a directory");
        }

        // init lock file
        if (lockDir == null) {
            lockDir = System.getProperty("java.io.tmpdir");
        }
        File lockDirFile = new File(lockDir);
        FileUtils.forceMkdir(lockDirFile);
        testLockDir(lockDirFile);
        lockFile = new File(lockDirFile, file.getName() + LCK);

        // check if locked
        createLock();

        // init wrapped writer
        out = initWriter(file, encoding, append);
    }

    //-----------------------------------------------------------------------
    /**
     * Tests that we can write to the lock directory.
     *
     * @param lockDir  the File representing the lock directory
     * @throws IOException if we cannot write to the lock directory
     * @throws IOException if we cannot find the lock file
     */
    private void testLockDir(File lockDir) throws IOException {
        if (!lockDir.exists()) {
            throw new IOException(
                    "Could not find lockDir: " + lockDir.getAbsolutePath());
        }
        if (!lockDir.canWrite()) {
            throw new IOException(
                    "Could not write to lockDir: " + lockDir.getAbsolutePath());
        }
    }

    /**
     * Creates the lock file.
     *
     * @throws IOException if we cannot create the file
     */
    private void createLock() throws IOException {
        synchronized (LockableFileWriter.class) {
            if (!lockFile.createNewFile()) {
                throw new IOException("Can't write file, lock " +
                        lockFile.getAbsolutePath() + " exists");
            }
            lockFile.deleteOnExit();
        }
    }

    /**
     * Initialise the wrapped file writer.
     * Ensure that a cleanup occurs if the writer creation fails.
     *
     * @param file  the file to be accessed
     * @param encoding  the encoding to use
     * @param append  true to append
     * @return The initialised writer
     * @throws IOException if an error occurs
     */
    private Writer initWriter(File file, String encoding, boolean append) throws IOException {
        boolean fileExistedAlready = file.exists();
        OutputStream stream = null;
        Writer writer = null;
        try {
            if (encoding == null) {
                writer = new FileWriter(file.getAbsolutePath(), append);
            } else {
                stream = new FileOutputStream(file.getAbsolutePath(), append);
                writer = new OutputStreamWriter(stream, encoding);
            }
        } catch (IOException ex) {
            IOUtils.closeQuietly(writer);
            IOUtils.closeQuietly(stream);
            FileUtils.deleteQuietly(lockFile);
            if (fileExistedAlready == false) {
                FileUtils.deleteQuietly(file);
            }
            throw ex;
        } catch (RuntimeException ex) {
            IOUtils.closeQuietly(writer);
            IOUtils.closeQuietly(stream);
            FileUtils.deleteQuietly(lockFile);
            if (fileExistedAlready == false) {
                FileUtils.deleteQuietly(file);
            }
            throw ex;
        }
        return writer;
    }

    //-----------------------------------------------------------------------
    /**
     * Closes the file writer and deletes the lockfile (if possible).
     *
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void close() throws IOException {
        try {
            out.close();
        } finally {
            lockFile.delete();
        }
    }

    //-----------------------------------------------------------------------
    /**
     * Write a character.
     * @param idx the character to write
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void write(int idx) throws IOException {
        out.write(idx);
    }

    /**
     * Write the characters from an array.
     * @param chr the characters to write
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void write(char[] chr) throws IOException {
        out.write(chr);
    }

    /**
     * Write the specified characters from an array.
     * @param chr the characters to write
     * @param st The start offset
     * @param end The number of characters to write
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void write(char[] chr, int st, int end) throws IOException {
        out.write(chr, st, end);
    }

    /**
     * Write the characters from a string.
     * @param str the string to write
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void write(String str) throws IOException {
        out.write(str);
    }

    /**
     * Write the specified characters from a string.
     * @param str the string to write
     * @param st The start offset
     * @param end The number of characters to write
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void write(String str, int st, int end) throws IOException {
        out.write(str, st, end);
    }

    /**
     * Flush the stream.
     * @throws IOException if an I/O error occurs
     */
    @Override
    public void flush() throws IOException {
        out.flush();
    }

}


* 1. Which Docks & Harbors facility did you use?
* 2. How well did the Docks & Harbors facility meet your needs?
* 3. Did you find Administrative Staff knowledgeable and courteous?
* 4. Did you find Field/Dock Staff knowledgeable and courteous?
* 5. How would you rate your overall experience?
* 6. Do you have any additional comments or suggestions for Docks & Harbors to improve our facilities and services?


This program is hosted by Rancho Los Amigos National Rehabilitation Center. Their employees will make up the primary audience.
All others, up to ten non-County attendees, may register for $20 via this CHIA webpage to ensure a spot and to receive information about the building, room number, and parking.
About the program: After a brief presentation about patients' rights to language access services, the importance of trained and qualified interpreters, and how the publication, CALIFORNIA STANDARDS FOR HEALTHCARE INTERPRETERS: Ethical Principles, Protocols, and Guidance on Roles & Intervention, is structured to guide interpreters through the complex task of healthcare interpreting, participants will consult their own free copies of the booklet as they discuss common dilemmas in small groups. Bring your own anecdotes about challenging situations. This session can be helpful to individuals preparing for certification and for experienced interpreters seeking a review of fundamentals.
Who should attend this session? Individuals who are new to the field, ASL interpreters new to healthcare interpreting, individuals responsible for ensuring that their interpreters have training in ethics and roles, professional interpreters preparing for national certification, and attendees who want to attend a session in which they will have ample opportunity to talk with other interpreters about ethical dilemmas.
With special introduction by Victoria Alvarenga RN, BSN, CRRN, Clinical Instructor, Rancho Los Amigos National Rehabilitation Center.
Certificate of Attendance & a CHIA Standards booklet will be available for all attendees.
DHS County employees wear County badges. All others should present proof of online registration received from this website (printed or visible on your smart phone).


text:
Cheyenne Woods, Tiger's niece, wins Australian Ladies Masters
February 16, 2014	Category: Sports	Posted by: Philadelphia Sun Staff
ABOVE PHOTO: Cheyenne Woods (AP Photo / Tim Ireland/P.)
GOLD COAST, Australia — Cheyenne Woods won the Australian Ladies Masters on Sunday for her first major professional tour victory, holding off 17-year-old Australian amateur Minjee Lee by two strokes.
The 23-year-old Woods, Tiger Woods' niece, closed with a 4-under-par 69 at Royal Pines to finish at 16-under 276. Lee also shot 69 in the event sanctioned by the European and Australian tours.
Woods birdied the par-5 15th to open a two-stroke lead, hitting a wedge from about 120 yards to within 4 feet. On the par-5 18th, she matched Lee with a birdie, holing out from 1½ feet.
From Phoenix, Woods is the daughter of Earl Woods Jr., Tiger Woods' half brother.
"I've been pro for two years and, for the majority of it, people just think of me as Tiger Woods' niece, so now I have a game of my own and I have a title now, a win, which is exciting," she said. "It's nice now to say to people that I can play and I'm not just a name. Growing up with the last name of Woods, there's a lot of expectations and pressure and spotlight on you, but I always knew that I was able to win. I always knew I'd be able to compete with these ladies, so now it's kind of a weight off my shoulders because now everybody knows, not just me."
Woods earned $51,000 and a two-year exemption on the Ladies European Tour. She will play this week in the LPGA Tour-sanctioned Women's Australian Open in Victoria.
Cheyenne Woods, niece of Tiger, wins The ACC Women's Golf individual title Tiger Woods, the closer, can't close another one Woods to return to golf at the Masters

redpajama_set_name: RedPajamaCommonCrawl


text:
April 3, 1974 Commentary
Remembering Leiber and Stoller
Back in the 50s, when most rock artists were not composing their own material, the non-performing songwriters who worked behind the scenes played an important role. Two such writers, Jerry Leiber and Mike Stoller, became perhaps as critical a part of the era's music as the recording artists themselves.
The Coasters were among the best interpreters of Leiber & Stoller's material.
The pair wrote and produced songs that became hits for the Coasters, the Drifters, Elvis Presley, the Shangri-Las, and many other groups and solo singers. During one five-year period, they helped make records that sold a total of more thna 30 million copies.
Their first chart success came in 1951, with Charles Brown's "Hard Times." During the two years that followed, they wrote for such artists as Big Mama Thornton and Little Willie Littlefield. Thornton's "Hound Dog," composed by Leiber and Stoller, was a hit for her in 1953, and Elvis Presley's version of the song achieved much greater sales three years later. Leiber and Stoller's "K.C. Lovin'," a 1953 single recorded by Littlefield, reached the top of the charts as "Kansas City" in Wilbert Harrison's 1959 cover.
In 1953, Leiber and Stoller launched their own record label, Spark, in Los Angeles. A group called the Robins, which had previously worked with the pair, signed to Spark and began scoring regional hits—"Riot in Cell Block Number Nine," "Smokey Joe's Cafe," and others.
"Smokey Joe's" attracted the attention of the Atlantic label, which bought out rights to the best of the Robins' material and took over their contract in 1956. Leiber and Stoller, discontinuing Spark, also came to Atlantic in that year. But, while producing and writing songs for that label, they maintained an independent status and were able to work for other companies as well.
When the Robins' lead and bass singers joined with two friends to form a new group, the Coasters, Leiber and Stoller found one of the best outlets for their talent. "Searchin'/Youngblood," the group's first pop hit, raced up the charts in 1957. Following up on that song, the band released such chart-toppers as "Poison Ivy," "Along Came Jones," "Yakety Yak," and "Charlie Brown." All of them were penned by Leiber and Stoller.
Leiber and Stoller with Elvis Presley
As producers, the pair had equal success. In 1958, they joined forces with the Drifters, producing the hit "Drip Drop" and, the following year, "There Goes My Baby." The latter song, which debuted Ben E. King as the lead vocalist replacement for Clyde McPhatter, was a giant success and is now remembered as one of the first R&B songs ever to use a string arrangement. When Ben E. King left the Drifters, Leiber and Stoller helped write his first single, "Spanish Harlem"—the recording of which was supervised by Phil Spector, then a Leiber and Stoller apprentice.
Out of all their accomplishments, Leiber and Stoller will probably be best remembered for their pioneering work with the Coasters. "Yakety Yak," a typical Leiber and Stoller song and one of the Coasters' biggest sellers, shows the songwriting duo at their best. A masterpiece of the vernacular, the tune drove home the plight of teenagers with humor rather than preaching. Featuring, for example, Leiber and Stoller's trademark rhythm break, filled by a line from the bass singer, the song was as much fun musically as it was lyrically.
At first, some people viewed many of Leiber and Stoller's tunes as nothing more than good novelty hits. But laced with truths about human nature that still strike home today, they have proved to be much more than that. It's no wonder that their work is regularly recorded by everyone from Leon Russell to the Beach Boys to Loudon Wainwright III.
James Griffin: A Slice of Bread
Hits Permeate the 'American Graffiti' Soundtrack


text:
TRANSFER: Aidan Finnegan Joins Sky Blues!
The midfielder agrees a two-year-deal...
We are pleased to confirm the signing of midfielder Aidan Finnegan on a two-year-deal.
The 17-year-old has put pen-to-paper on his first professional deal, commiting his future with the Sky Blues until 2022.
Finnegan links up with City, following his departure from Birmingham City, where he had risen through the ranks in the youth set-up.
Aidan is a centre midfielder by trade and has played for both the Sky Blues Under-18s and the Under-23s already this season.
Finnegan will link-up with the Development side and speaking upon his arrival, Under-23s Head Coach, Luke Tisdale was pleased to secure the services of the youngster.
"We're pleased to welcome Aidan on board.
"He was sought after following his departure from Birmingham, so we're delighted he's chosen to join us and we're looking forward to working with him during the next stage of his development.
"Aidan's a good technical midfielder, who is aggressive and is strong in the counter press and you can tell he's had a good academy background with Birmingham."


I had a lot of toys delivered while I was gone!
The solar recharger for AA batteries arrived. Very cool. Bit bigger than I thought, even though they had the dimension and I measured them off a couple of times.
Here's the coolest gizmo to arrive so far: a Xincom DPG-402. This is a dual WAN NAT router. I already have the equivalent device from Nexland, but since they were bought by Symantec, the product seems all but dead.
Yes, I have two Internet connections - DSL and Cable. I hate being offline, most of the time these are both up. When either one of them is down, the dual WAN NAT router takes care of switching everyone over to the other WAN connection. Its quite transparent - if it wasn't for the warning emails, I'd have no idea one of my connections was down.
Unfortunately, like most NAT routers, the Nexland can only handle one IP per WAN port. But the Xincom can handle more. You can pass multiple IPs through a given WAN port, only one of the IPs uses NAT, the rest pass through to specific machines. Cool.
Skype is beta Voice-Over-IP (VOIP) software, free to download, that lets you use your PC like a telephone, albeit just to contact other Skype users. Scott had a friend who was going overseas and wanted to stay in touch with loved ones.
One of my fundamental rules at conferences is "Thou shalt not install software on your computer before you have finished all your sessions." And I have one session to go.
I was connected to the Internet via the TechEd wireless network, which is not all that fast (there are 10,000 geeks online, after all) and is heavily filtered.
I have no external speakers or microphone set up for my laptop.
But Scott was persistant, so I figured what the heck, and downloaded Skype.
Now since it was the end of the day, there were relatively few people on the Tech Ed network, so my download went quickly. But what I didn't expect was that I could install the software, sign up an account, enter Scott as a contact and press connect in less than five minutes.
And I was totally blown away when Scott's voice came out over my laptop speakers clear and crisp, and even more stunned that he could hear me as well, although apparently I was quite quiet.
No tuning, no fiddling, no specialized hardware - download, install, connect, and it just works!
The life of a speaker at Tech Ed is rather surreal, so I decided to spend the day as a regular attendee, just going to sessions and soaking up the Tech Ed experience.
Well, Stephen Forte and I pulled off the Oracle/SQL Server Interoperate session today. The crowd wasn't huge, but they were definitely into it – the questions were outstanding, everyone gets the idea that there are hard choices to make in interoperability. Running three operating systems (Window XP host, VPC of Windows 2003 Server and VPC of Red Hat Fedora) isn't all roses and sunshine, either!
We've been handing out lots of RD Bingo cards, and signing even more (you have to get an RD on the card to sign their picture, get a line and you win)… the loot is great. I'm astounded at the number of folks here, getting a cellphone connection (or WiFi connection) is a serious challenge.
Now I get to relax for a couple of days and soak up some sessions before my SQL Server Profiler for the Developer session on Friday.
Look ma, there's a puddle under my computer!
Not a good hardware day.
I like water-cooled computers. Why? Because they're quiet. No 5000rpm high velocity fans on the processor, video card, etc, etc. Just a couple of slow, silent fans on the radiator and the power supply. The way it oughta be.
Putting water cooling into a computer system isn't a trivial task, but its not rocket science either. I've built three of them so far, and noise level in my office is better for it.
Unfortunately, now I have to deal with a new kind of problem... leaks.
See if you can see where this machine is leaking from.
Steve Forte is a bit upset at the 9/11 Commission over its criticism of the rescue workers at the World Trade Center (and I say that with typical Canadian understatement). I can certainly appreciate why he's angry, I think its a bit too close and personal for him.
On one hand, you have to admit that there's no point in putting together a commission to say "hey, we handled this brilliantly"... the idea is to learn how things could have been handled better. But I would debate whether there is any way to handle people crashing 767s into buildings more effectively. In fact, I would debate that there is even a need to figure out a better way.
For starters, until 9/11, hijackings were pretty darn survivable. With few exceptions, passengers on the hijacked airliner usually walk away unscathed. So it was in the passengers best interest to just sit back, wait it out, and stay low. But once these nutballs starting using the aircraft as a weapon, all bets are off - you're gonna die anyway, why not take 'em with you? I suspect that hijacking is pretty much obsolete now, no one is going to attempt it when you can virtually guarantee that the entire aircraft will go after you.
So no one had done such a thing before, and no one is likely to ever do such a thing again, so what possibility is there in trying to improve on handling it?
What surprised me more than anything was the gallery folks angry with Giuliani. What could he have done differently? What could he possibly do about it now? It shocks me that 30 months after losing their loved ones, people are still angry. As someone who has lost immediate family on more than one occasion, you only get to grieve properly once you get past the anger. If these folks are still that focused on the deaths, they've basically been frozen in time for two and a half years. Is this what these people died for? So that you can stay angry?
The best way to remember a loved one you've lost is to live, and live well.
Ah yes, the panic is on... one more day before I fly down to Los Angeles on my way to Tech Ed San Diego. Naturally, every piece of hardware I own (and I own a lot) is acting up, knowing I'm about to leave town.
I'm presenting two sessions. The first one on Monday is called From Interoperability to Migration: SQL Server and Linux Databases Working Together which I'm doing as a duet with my buddy Steve Forte. The session stems from my time spent "on the dark side" doing database work in Linux. Although most of my work is done in postgres, this session is going to show interoperability between Oracle 10g on Red Hat Fedora and SQL Server 2000 on Windows Server 2003 (hey, that's what the Microsoft folks wanted, so that's what they get).
I've had to migrate lots of applications over the years, and I see it as the worst kind of development. The problem is, the users see nothing, except the fact that stuff that used to work (on the old app) is now broken (on the new app). And the instinctual order of migration is flawed: we always start by migrating the data, then building the app. After all, you need some data to work from to build the new app. And so you build a tool to repeatedly copy the data from the old system to the new, and one day, you do the dead drop - you migrate the data one last time, and then everybody has to stop using the old app, and use the new app.
And then, inevitably, you find some nasty bug a few hours (or days) later. Now the question is, do you switch back to the old app, or have everyone wait until you fix the new one? If you go back, what about all the work done in the new one? Reverse migration anyone? Aaaugh!
The session focuses on how you can interoperate between applications via their databases, either long term or short term to facilitate migration. The key to the whole thing is SQL Server's ability to use OLE DB to speak to the Oracle database directly. The trick to migration is to move the data last - build your new .NET application to speak to SQL Server using stored procedures, and in the stored procedures you call to Oracle to retrieve the data.
This methodology avoids dead drop migration, since you move the data last. Since there's only one copy of the data, and both applications have access to it, the users can use whatever client they want. In fact, I've done migrations this way where I never cut off the old app, I just kept adding features to the new app until everyone wanted to use the new one, and then quietly turned off the old one.
The second session is SQL Server Profiler for the Developer. I presented the original version of this session waaay back in 1998, with Visual Basic 5 and SQL Server 7. The session came out of my experiences of dealing with even older versions of SQL Server and Visual Basic, and discovering how DAO and ODBC messed with my queries before sending them to the SQL Server. Middleware does stuff, and Profiler is the best way to find out what's really going on with your SQL Server.
Its my first Tech Ed as a Regional Director, so I guess I'll have to go spend some time at the RD Booth and see what craziness Scott Hanselman has come up with.
My buddy Stephen Forte has convinced me to climb Mt. Kilimanjaro with him this October.
Its not a technical climb (no hanging from ropes here), really its just a hike... to 19,300 feet. It takes place over 18 days, although only (heh - only) nine days of climbing. There's a four day safari at the end.
When I travel, I like to take lots of pictures. Like, a couple of hundred in a day. A digital camera is essential, but so is the laptop to dump all those photos out (and write silly captions for them).
Needless to say, laptops are not considered essential hardware for a hike like this, but I still want to take lots of pictures. So, I have two problems to deal with. The first is capacity - where am I going to store all these pictures? The second problem is power - not a lot of outlets on Kilimanjaro.
My camera of choice for the moment is the Olympus C-750 my wife bought me for Christmas. It uses xD picture cards, up to 512MB. Each 512MB card should hold about 600 pictures, so three ought to do it, if I can limit myself to a hundred photos a day.
One of the best things about this camera (besides the amazing 10x optical zoom) is that it uses AA batteries. I have a couple of sets of Nickel-Metal-Hydride batteries for it. So I suppose I could carry ten pounds of AA batteries for it to cover all those pictures, but then I had a better idea. Silicon Solar makes a fairly small solar AA battery recharger. It does four batteries at a time, the same number of batteries the camera takes. So I can have one set charging while I'm snapping away with the other.
Of course, now that I'm thinking solar, maybe a bringing a laptop along isn't so crazy after all.
Yeah, I'm caving in to peer pressure, I admit it.


text:
<?php

/**
* Smarty method Register_Postfilter
*
* Registers a PHP function as postfilter
*
* @package Smarty
* @subpackage SmartyMethod
* @author Uwe Tews
*/

/**
* Registers a postfilter function to apply
* to a compiled template after compilation
*
* @param object $smarty
* @param callback $function
*/
function  Smarty_Method_Register_Postfilter($smarty, $function)
{
    $smarty->registered_filters['post'][$smarty->_get_filter_name($function)] = $function;
}

?>


text:
Not a member? Register »
City of Davis
Budget/Fiscal
Davis Enterprise
Labor Issues
Land Use/Open Space
Vanguard Court Watch
Social Services/Issues
DJUSD
Vanguard Court Watch Council
IRS Filings
Author Pointers
Yolo Leaks
Commentary: What is a Moderate Path Forward on Growth For Davis?
Immigrant Representation in Court in Doubt as Move to Van Nuys Is Planned
Taxpayers Face Escalating Liability as Wrongly Convicted Inmate Sues CDCR for Facilitating Hate Crime
Stockton Jury Says It Believes Victim of Police Beating in 1st Phase of Civil Rights Suit Decision
Why So Many Prosecutors Enjoy Uncontested Re-Election
Commentary: Davis Teachers Do Deserve Better – That's Why District Is Seeking More Funding
Judge Rules Man in Prison Since 1974 Not Actual Killer, Defers on Resentencing Under 1437
LA Police Union Contributes $1 Million To Anti-George Gascón PAC
Trial of Alleged Gang Member Making Criminal Threats Resumes
Monday Morning Thoughts: The Chickens Have Come Home on Our Roads
Analysis: Rolling the Dice on Measure O
Posted by David Greenwald
in: Breaking News, Budget/Fiscal, City of Davis, Elections
It is no secret that we have been concerned about the possibility that Measure O will not pass. While the Measure O proponents are fortunate, with a lack of a realistic opposition (with only nominal opposition from Jose Granda and the folks that have opposed every parcel tax in the last eight years – all of which passed with at least 67% of the vote), they have not run a robust campaign to date.
The op-ed on Sunday signifies the latest fuel on the fire. The op-ed, co-written by councilmembers Lucas Frerichs and Brett Lee among others, says, "This modest increase in our sales tax rate will go into the city's general fund to help pay for essential community needs that will be far more costly if further delayed. These include repair of roads, sidewalks, bike paths and street lights; parks and landscaping projects; and water conservation projects."
We don't regard this is as the best foot forward by the proponents. If we accept that there is a $5.1 structural imbalance, Measure O would fund about $3.6 million of that once the council decided to reduce the proposed tax from .075 percent down to .05 percent. That effectively stripped out $1.5 million that was ticketed for infrastructure and reduced it down to $1 million.
With about a $1.2 million outstanding deficit, one could argue that no money from Measure O will go to roads.
Thus, the bulk of the revenue would go to increased city employee costs. Of that $2.3 million, $360,000 went to the COLAs given to city employees, $250,000 when the police department filled two vacant positions, another nearly half a million because fire and DCEA failed to agree to terms, and then another $1.24 million "outside city control" going to increased retiree medical costs, PERS costs, leave benefit costs, and health insurance costs.
This analysis led Mark West to argue, "It is difficult to accept anything that these authors have to say when they lead with this piece of fiction. The sales tax increase will predominantly be used to pay for increasing compensation costs, not roads, sidewalks, etc. I am extremely disappointed that two sitting members of the City Council would put their name to this op-ed, as they both clearly know that the statement is at best misleading. This is yet another example of why there is so much distrust between the public and our City's leadership."
"What is completely baffling to me is why our leaders don't think we can accept and understand the truth?" he asks, and we agree.
A few key points before moving on. First, as our "How We Got Here" article last week shows, the biggest problems leading up to this problem were as follows. During good times, 1999 to 2008, we increased salaries and compensation to levels never before seen. We failed to recognize that the benefits were unsustainable once the real estate boom died. And once the economy collapsed, we treated it as temporary, balancing the budget through attrition and deferred maintenance rather than dealing with the core issues.
However, that changed starting in 2010 with the election of Joe Krovoza and Rochelle Swanson. By 2012, no one from the 2004 to 2010 councils remained. So this is a different council, not the council that brought us these problems, and, really, since 2010 the council has made good strides.
We do not fear a return to 2009 policies – we fear that the mistrust engendered by those councils has not abated and anything less than the full and complete truth will be detrimental.
However, the Vanguard had some extensive conversations yesterday and there seems to be a belief, at least by some, that the council will implement the proposed $1.2 million in cuts, most of which is not tied to positions of employment, and that there might be additional money left for roads.
Dan Carson, who co-wrote the piece and sits on the Finance and Budget Commission, argued that our statements yesterday were in error.
He writes, "The fact of the matter is that if Measure O fails, leaving the city with an immediate $2.7 million budget hole in 2014-15 and a $3.6 million gap to fill in subsequent years, all bets are off. The City Council could choose to balance the books with deep cuts entirely to city operations, but it might also choose to scale back road and other maintenance and infrastructure projects. No one can know what will happen for sure, in part because we don't even know who will be making that decision. Two seats on the City Council are also up for a June 3 vote."
He adds, "If Measure O fails, the city manager has provided a blueprint of the types of cuts to city operations that he is building into the budget plan that will be finalized in June. And that blueprint makes it clear that the city would have to make difficult reductions in services that every Davis citizen will see."
He continues, "But those cuts in city operations will not necessarily be the only choices that the City Council could make if Measure O falls short. In January and February, the City Council openly and publicly discussed the possibility that its newly inaugurated road improvement program – money already built into the city budget — might also have to be severely scaled back if it did not have enough revenue to close the structural budget shortfall."
He writes, "The op-ed piece that ran Sunday fairly and accurately put voters on notice that these important projects are also at risk if Measure O fails."
Finally Mr. Carson makes the point, "A parcel tax may still need to be considered even if Measure O passes in order to undertake a more ambitious effort to address city deferred maintenance and infrastructure projects. But if Measure O, a simple majority-vote measure, is voted down in June, in my opinion, the new City Council will have to think long and hard about putting a parcel tax requiring two-thirds voter approval before city voters anytime soon."
While that is a fair review of what happens if Measure O does not pass, we would have preferred that argument being put forward to the public. The Vanguard has the space for such arguments, which we feel would have been more accurate.
We are concerned that the issue of employee compensation has neither been discussed nor acknowledged by the city.
Following Michelle Millet's comment, where she stated, "We could have gone with, 'despite that fact that we have laid off 100 employees and renegotiated employee contracts so that employes are paying more towards their retirement and health care coverage employee costs have continued to rise, and while employees are paying more its not enough to cover these increased cost, a lot of which is out of the city's control. The sales tax will go to cover these costs,'" we believe the following needs to be laid out to the voters:
The city during good times made promises to city employees that were not immediately funded. When the economy collapsed, that left the city with huge unfunded obligations to current employees. The city first attempted to deal with those problems with employee reduction – more than 100 position were eliminated through attrition, deferred maintenance, and finally two sets of restructured contracts.
Despite these changes, costs for pensions, for health care, and for everything has gone up and we have to fill that gap.
This tax measure represents a short-term fix. And then we have to deal with the issue of revenue from increasing our tax base, which, if you read our other analysis, is a much more complicated fix than people want to believe.
We fear that sugar-coating this stuff leads to more distrust and we have to have an open and honest dialogue here. Unfortunately, we have what we have always had here – a rush job sales tax campaign, mixed into a city council and water rate campaign, with no community discussion. It may pass, but we will be no better off than we were.
—David M. Greenwald reporting
Tags:Brett LeeCity of DavisLucas FrerichsMeasure OOPEBparcel taxPensionsRoadsSales TaxUnfunded Liabilities
Previous : Commentary: Forget Mace 391, We Are Failing Now
Next : Talamantes' Sister Can't Recall Past Statements
David Greenwald
David Greenwald is the founder, editor, and executive director of the Davis Vanguard. He founded the Vanguard in 2006. David Greenwald moved to Davis in 1996 to attend Graduate School at UC Davis in Political Science. He lives in South Davis with his wife Cecilia Escamilla Greenwald and three children.
12 thoughts on "Analysis: Rolling the Dice on Measure O"
Dan Carson May 20, 2014 at 9:33 am
Your column today asserts that, because the size of the sales tax measure put before voters was reduced from three-quarters cent to a half-cent, "one could argue that no money from Measure O will go to roads." You can argue that, but it would be misleading your readers as to the potential consequences of the failure of Measure O.
As I pointed out in your pages yesterday, the base budget prepared by the city manager includes the $2.5 million for a road improvement program consistent with the policy of the current City Council. Your readers can see so for themselves in the footnotes to the five-year forecast presented to the City Council at its meeting on December 17, 2013. (See Attachment B, page 1 at http://administrative-services.cityofdavis.org/Media/Default/Documents/PDF/Finance/2013-2014-Budget/Budget-Preview/11A-2013-2014-Midyear-Budget-and-2014-2015-Preview.pdf) This did not change after the council set the size of the sales tax measure at one-half cent.
If Measure O fails, leaving a $2.7 million hole in the 2014-15 budget and a $3.6 million gap in city finances in the ensuing years, that infrastructure money is surely at risk. These important projects could be scaled back if cutbacks to city operations alone didn't resolve the gap. We don't know what will happen for sure, in part because two City Council seats are also on the June ballot. Depending upon who is elected, the approach to closing such a gap could be very different.
On your other main point, everyone acknowledges that dramatic increases in costs for pensions and other health benefits are a major parts of the city's structural budget shortfall. That has been a main component of every city presentation to the community on the current fiscal problems. Nobody is "sugar-coating" anything. But, as our Sunday op-ed piece in the Davis Enterprise noted, the current City Council has taken important steps to contain these costs, both by reducing the size of city government and by negotiating bigger employee contributions to pensions and health benefits.
I would appreciate it if you could clarify your position on Measure O. Initially, you stated your opposition to the sales tax measure. Then you reversed course after a few days and said you supported it. However you have closed today's column with an assertion that "we will be no better off than we were" even if Measure O is approved – another clearly erroneous assertion, given the huge negative consequences for city services and road improvements if it fails. Are you opposing the measure once again? If you are still supporting it, that does not seem to square with your closing statement.
David Greenwald Post author May 20, 2014 at 9:51 am
My position is that I support Measure O but believe it achieves only a small piece of what we need to accomplish this year in conjunctions with (1) Parcel tax for roads and parks, (2) Economic Development, and (3) continued talks with employees groups that will lead up to next year's resumption of collective bargaining as the current contracts expire in just a year (believe it or not).
Those other elements you mention — a parcel tax, economic development, and continued fiscal constraint in bargaining with employee groups — are all very important. But your assertion in your column that "we will be no better off than we were" if Measure O passes doesn't hold water. It is an important piece of getting the city's fiscal house back in order.
David Greenwald Post author May 20, 2014 at 10:22 am
That was a sloppy finish, I meant that in terms of advancing the discourse and understanding of the community about the magnitude of the problem we face. As it stands now, if we push forward a parcel tax this fall, many people's reaction will be "wtf, didn't we fix that with the sales tax vote in June"?
Mark West May 20, 2014 at 11:03 pm
"$2.5 million for a road improvement program consistent with the policy of the current City Council."
How much is budgeted is interesting, but more so how much was actually spent. How much money did the City spend on road improvement in the previous year? Did that amount spent match that amount that was budgeted for the year? If not, why not?
The budgeted numbers are only of interest if there is a matching expenditure to indicate that the funds were actually used for the budgeted item, and not simply acting as a place holder from some other unidentified expected expense.
As I recall they let the contracts in the spring and do the work in the summer. So there is a delayed impact from putting money in.
Davis Progressive May 20, 2014 at 10:40 am
i was troubled with the op-ed for the reasons that mark west laid out yesterday. it seemed a lot like bait and switch and the counter-argument by carson seems peripheral – if measure o goes down, roads will go with it.
Sam May 20, 2014 at 11:31 am
Yes, if measure O goes down then the City will be unable to pay for the roads. Then in November if the parcel tax goes down the City will be unable to pay for the roads. Next year will be the same thing. That is because it is hard to get the public to vote for additional taxes by telling them that "for years the actuaries have been decreasing life expectancy and increasing projected future returns to decrease required pension payments so that the pensions promised to public employees seemed affordable. Now that PERS is about 55% funded and due to changes in accounting rules the City of Davis is going to need a LOT more money each year to operate at its current level." That message just does not sell.
Davis Progressive May 20, 2014 at 2:11 pm
so we expected the voters in the second most educated town in america to buy anything less than the truth, the whole truth, and nothing but the truth?
Frankly May 20, 2014 at 12:06 pm
If Measure O passes it will absolutely will not be enough. Then we have a parcel tax measure in November, and that too will not be enough.
So, other than the obvious point of inadequacy, what else is missing from this discussion?
South of Davis May 20, 2014 at 1:48 pm
Frankly wrote:
> If Measure O passes it will absolutely will not be enough.
> Then we have a parcel tax measure in November, and
> that too will not be enough.
As anyone who has boiled a frog knows you need to turn up the heat SLOWLY…
Maybe another business tax after the parcel tax, than citywide parking permits with an annual fee for the stickers, then even more paid parking downtown and…
P.S. I just heard from an ACE hardware employee yesterday that the city is planning to charge to park in the G Street lot next to ACE
how can you possibly know that an unspecified parcel tax is not enough?
Matt Williams on Commentary: What is a Moderate Path Forward on Growth For Davis?
Don Shor on Commentary: What is a Moderate Path Forward on Growth For Davis?
Bill Marshall on Commentary: What is a Moderate Path Forward on Growth For Davis?
Ron Oertel on Commentary: What is a Moderate Path Forward on Growth For Davis?
The Vanguard provides the Davis Community with incisive in-depth coverage of local government on a wide variety of issues. Since 2006, The Vanguard has provided Davis and Yolo County with some of the best groundbreaking news coverage on local government and policy issues affecting our city, our schools, the county, and the Sacramento Region.
Just interviewed Michael Tirpak for an upcoming podcast. Served 25 years for crime he didn't commit before becoming… https://t.co/Ku4004YjAg
RT @NancySkinnerCA: Privilege to meet with progressive San Francisco DA @chesaboudin in the state capitol! Honored that @chesaboudin also…
The .@SFDAOffice under .@chesaboudin has ended cash bail in San Francisco. I hope all other counties will shortly follow suit.
The People's Vanguard of Davis
Phone: (530) 400-2512 info@davisvanguard.org
© 2014 The People's Vanguard of Davis | Sacramento Website design and Implementation by Uptown Studios | Privacy Policy | Terms of Use
Monthly Subscriber Sign-Up
Enter the maximum amount you want to pay each month


text:
Report: Austin Daye reaches two-year deal with Raptors
By Kurt HelinJul 30, 2013, 8:13 PM EDT
On the bright side, last season Austin Daye stopped his trend of getting worse and worse each season he was in the league. He wasn't great — a PER of 12.9, below the league average — but he was knocking down threes at a 41.8 percent clip.
Which is why he gets a chance to see if he can take another step forward with the Raptors — he has reached a two-year, $2 million deal with the team, reports Adrian Wojnarowski of Yahoo Sports.
Daye was drafted by Detroit out of Gonzaga and had been with the Pistons for three-and-a-half seasons until he was shipped to Memphis last year as part of the Rudy Gay trade.
The 6'11" Daye could have value for the Raptors as a backup stretch four if he keeps hitting his threes. His inconsistency and lack of defense could remind Toronto fans of another stretch four they just got rid of, one that was not all that popular north of the border, but maybe Daye's game has matured and he can find a role with Toronto.


text:
Home SA Racing Veteran Ferraris quits training after grooms' protest
Veteran Ferraris quits training after grooms' protest
A potentially serious situation was diffused at Turffontein on Saturday when racing officials persuaded a group of about 50 protestors assembled on the racetrack to leave the course so that racing could continue following its interruption after Race 2 on Champions Day.
While racing resumed after a delay of about an hour – the result of a grooms' protest against working conditions – one sad and unfortunate consequence was the decision by veteran trainer Ormond Ferraris to hand in his licence.
The 87-year old Ferraris, upset and severely stressed by the grooms' actions, had to be taken to hospital for a check-up and observation when his staff decided to desert the yard around 4am on Saturday morning. He was released on Saturday afternoon and told Turf Talk on Sunday: "I have made my decision, I am giving up training."
Grooms prevented horses from cantering up the straight before the start of Race 3.
Ferraris, who has served the horseracing industry with great distinction for 70 years, said that trainers at Turffontein were aware of the pending strike on Friday. "I arranged with my 20 grooms to come to work Saturday at 3am, an hour earlier, so they could attend their meeting which was scheduled for 5am.
"All I wanted them to do was the bedding, and to feed and water the horses. Just a few came along at three but soon disappeared leaving me and my Head Lad of 40 years, John Sibeko, to get by on our own. I was distressed, they had to take me to the Union Clinic but I am feeling better now. This is it, this is the third protest action of this nature we've had to endure recently and I am not prepared to put up with this any longer. I am out."
Ferraris said that there were "troublemakers" in the grooms' ranks who have stirred up the rest with a variety of demands, including higher wages and for an office to be allocated to one of their faction officials at Turffontein.
"I would love to pay the grooms what they want, big salaries, but it is simply not possible. The sport of racing cannot contain this. The costs of feeding and training horses today are astronomical and stakes haven't increased in proportion to the high expenses. The few millionaires in racing can afford it, but I fear for the middle man, the smaller owner. This kind of pressure is going to hit them and the smaller stables the hardest. They are battling to feed themselves, let alone their horses. There is just no way they can survive!"
Ferraris said that he had fought for trainers' rights and many other issues for as long as he can remember, serving in a leadership capacity on many boards, over many decades. In the 1950's, for example, he and a few others stood their ground to prevent the (first anticipated) sale of Newmarket Racecourse, not afraid to speak up in industry matters ever since. More recently he had done sterling work on the Trainers Benevolent Fund.
He recalled: "In those days, training racehorses was a relatively cheap profession. We could buy 150 pounds of feed for just 10 shillings and our workers were paid well because everything was affordable. In the 60s and 70s the big trainers had 30 horses in their stables, the smaller ones had 10 or 12, but we all made a good living. We raced twice a week and the sport was simply great. But the good times are over now.
"Today, costs are out of hand and this has had various ramifications. Racing is in trouble with escalating expenses and all the demands from workers. Look at the outcome of this issue. I have 10 horses leaving tomorrow for Durban. They are owned by Hong Kong Syndicates who want to see their runners in barrier trials. My son David sent them a list of KZN trainers and they decided on Garth Puller. A further 20 horses will be sent to other trainers. Thereafter, my grooms will be paid off. They will be unemployed."
Recently described as "a racing institution", Ormond Ferraris first took out his licence in 1952 and training winners has been his business for a remarkable sixty-seven years. He holds a record of 10 SA Oaks and eight SA Derbies and has twice been SA champion trainer. He took second place in one of the most controversial Durban Julys with the disqualified Distinctly in 1975, third with an unlucky Rakeen in 1989 and won the 1994 Summer Cup with Sizzling Sun. Ferraris trained his first winner, Shenandoah, at Gosforth Park in 1952 and on 12 March 2016, celebrated a milestone 2,500th career success when Romany Prince won the Listed Drum Star Handicap.
Dozens of equine legends passed through his hands, including fillies Pretty Border, Tracey's Element, Daddy's Darling, St Just, Miss Averof and Cherry On The Top, the 2013 Triple Tiara winner, and colts like Wagga Wagga, Noon Flight, Vigliotto, Rakeen and Surveyor.
Reflecting on his career, Ferraris said: "I've had a marvellous time, I wouldn't have it any other way. To come to the end of my career in this way is disappointing, to use a moderate word. But perhaps making the break, seeing things from the outside without involvement will be good for my health."
Three generations of horsemen: Ormond Ferraris (right) with son David and grandson Luke. (Candiese Marnewick)
Tributes came in on Sunday from another multiple champion Mike de Kock, who honed his skills under Ferraris in the early 1980s, and Weiho Marwing, a later understudy to the accomplished horseman.
De Kock noted: "Ormond Ferraris was the Sergeant Major of racehorse trainers. He taught us about stable management, feeding and attention to detail. He was regimental and had a huge influence on my career, also taught his son David, Weiho Marwing, Michael Clements and recently his grandson Luke has enjoyed the privilege of working with him as a jockey. I remember working with him and some of his best horses including Royal Line, Never Blue, Winter Lass and Northern March. It was such a privilege. He is one of the greatest trainers in SA history and his legacy will live on."
Marwing said: "He laid my foundations, he taught me everything I know and being based at Turffontein we have remained friends, he has always been there for advice. He is a wonderful man."
A distraught David Ferraris, speaking from his base in Hong Kong, commented: "Mike de Kock's comments strike a nerve because he is dead right. We worked together in my father's yard, he was a hard-assed taskmaster who often screamed at us, swearing, 'You two are useless. You're a pair of c***s!'
"If you think he is strict today, imagine what he was like 30, 40 years ago. We had a hard time, but he taught me everything I know about horses and training. I owe my own career entirely to him, I am grateful and sad. To see my father having to leave in this way is a disgrace. He loves horses, lives for them. He has been up at 3am for most of his life looking after them.
"Beneath his hard exterior he has a heart of gold, people don't even know how he supports others and how the Trainers Benevolent Fund pays allowances every month to the wives of trainers who have long passed. He's tried to help everyone, even the battling trainers and their families from years ago."
Ferraris added: "I am horrified by what is going on. I spent R25-million between horse imports and the SA Sales the last two years and to see how people are trying to bring the industry to its knees is disturbing. I hope these matters are addressed fast."
De Kock agreed, saying: "There are agitators among the grooms who do not realise the damage they are doing. Soon, 20 of their colleagues will be unemployed and then unemployable in current circumstances. They'll be a burden to society.
"There are transformation issues to be addressed, but we've already dug deep and made significant progress. The agitators don't realise that racehorse owners lose R600-million per year in racing. They race for pleasure, achievements and the dream of owning a champion horse. They accept their losses while the industry employs tens of thousands of people on the back of their investments.
"If this type of unrest continues, we are going to have serious problems in SA racing. Owners are going to stop and say, 'We don't need this, we want to race and watch our horses in peace and we want our investments protected.' If the big owners call it a day, we'll see a major collapse."
De Kock feels that security is a "soft spot" for agitators and that the matter should be given urgent attention. "Whenever a situation like this arises, the security officers are the first to run away. They are not sighted. There is expensive horseflesh stabled at the training centres and courses and we need to take preventative measures before the horses are hurt. There were several intoxicated and unruly elements among the strikers on Saturday, there always are. They should be stopped before they can cause injury to others or hurt horses."
Phumelela's Racing Executive, Patrick Davis, said that Saturday's strike had nothing to do with the racing operator. "We are not going to comment on the matter at this stage, it happened as a result of friction between grooms' factions. We will, however, be issuing a statement in the course of next week."
Vee Moodley, CEO of the National Horseracing Authority, said that he, too, preferred not comment at this point and referred us back to Davis.
Headline photo: Candiese Marnewick.
David Ferraris
EFF Grooms' strike
Luke Ferraris
Mike de Kock
Miss Averof
Ormond Ferraris
Patrick Davis
Pretty Border
racing grooms
Rakeen
Tracey's Element
Vee Moodley
Weiho Marwing
Previous articleCountry House wins dramatic KY Derby on objection
Next articleTurffontein meeting on Election Day
South Africans shine in Hong Kong
Hawaam, Barahin won't be far apart
Syndication of horses is racing's way forward
Allan Preddy May 5, 2019 at 3:44 pm
I bought my first horse in 1983 because I love the game- arrived yesterday to relax and watch my beloved horse run in the Gold Bowl & get greeted by this?
(Letter severely edited due to potentially damaging comments. Mr Preddy for your protection, and ours.) – Ed.
Warren May 5, 2019 at 5:40 pm
Like I said earlier.. Industry in serious trouble
David Michael May 11, 2019 at 6:20 am
Protest action is not only having an effect on the "sport of kings" but also on the country holistically…some bread is better than no bread at all.
'PK', racing legend Part 1
FORMER top trainer Peter Kannemeyer passed away at his Milnerton home on Monday, aged 85. Turf Talk editor Charl Pretorius remembers him as "perhaps the most interesting horseman I have ever interviewed" and in tribute to "PK" we publish...
Racing and the power of social networks
Bring racing to the young people!
Klawervlei anchors CPYS with depth of sire power
Eyes Wide Open secures VDJ spot
Quality and Quantity at Sibaya KZN Yearling Sale
Saturday's Vaal interviews
Hawwaam is rated World No 10


''Cut the pie any way you like, 'meanings' just ain't in the head,'' Dr. Putnam wrote.
Hilary Putnam had an academic breadth few philosophers achieved and he resisted attempts to simplify the complexity of what he contemplated. "Any philosophy that can be put in a nutshell belongs in one," he once wrote.
"There is no philosopher since Aristotle who has made creative and foundational contributions in all the following areas: logic, philosophy of mathematics, philosophy of science, metaphysics, philosophy of mind, ethics, political thought, philosophy of economics, philosophy of literature," Martha C. Nussbaum, a professor of law and ethics at the University of Chicago, wrote about Dr. Putnam in an online tribute published by the Huffington Post.
Dr. Putnam, the Cogan university professor emeritus at Harvard, where he was a leading opponent of US involvement in the Vietnam War in the 1960s and '70s, died of metastasized mesothelioma March 13 in his Arlington home. He was 89 and had posted entries on his blog until last September.
While he had little taste for simplifying, Dr. Putnam could craft plainspoken phrases that opened a door into his longer, deeper musings. "Cut the pie any way you like, 'meanings' just ain't in the head," he wrote in "The Meaning of 'Meaning,' " one of his most famous works.
During the 48 years he taught at Harvard University, the Massachusetts Institute of Technology, and Princeton and Northwestern universities, Dr. Putnam also was known for questioning his previous stances and changing his mind altogether.
Though Dr. Putnam once wrote that critics and admirers alike shouldn't exaggerate "the extent to which I 'change my mind,' " he stressed the importance of occasionally doing so.
"I find two things that help me develop new ideas: self-criticism, that is criticism of whatever I have previously published, and reading great philosophers," he said in an interview published in the spring 1991 issue of the Harvard Review of Philosophy.
Born in Chicago, Hilary Whitehall Putnam spent his early years living just outside Paris, where his parents moved when he was a few months old.
His father, Samuel Putnam, who was descended from British colonists in Virginia, was a translator whose works included the Modern Library edition of "Don Quixote." The parents of his mother, the former Riva Sampson, had emigrated from the part of the Russian empire that became Lithuania.
Dr. Putnam didn't speak English when he was about 7 and his parents returned to the United States. The family settled in Philadelphia, where Dr. Putnam graduated from the University of Pennsylvania in 1948. He started a philosophy club in high school, but didn't consider pursuing the subject academically until his last year at college. Initially, he thought of becoming a writer, and was fond of poets such as W.H. Auden and Rainer Maria Rilke. At the University of Pennsylvania, Dr. Putnam's fellow students included Noam Chomsky, who would become a friend in the years ahead.
In the fall of 1948, Dr. Putnam began his graduate studies at Harvard and also married Erna Diesendruck, with whom he had a daughter. Their marriage ended in divorce.
He finished his doctorate at the University of California, Los Angeles, and taught at Northwestern and Princeton before returning to Cambridge in 1961 to build a graduate philosophy department at MIT.
Dr. Putnam had met the former Ruth Anna Jacobs at an international Congress on Logic, Methodology, and Philosophy of Science and they "were madly in love before the conference ended," he wrote in "Intellectual Autobiography," the first chapter of "The Philosophy of Hilary Putnam," a collection of essays by colleagues that was published last year. They married in 1962.
After tiring "of the responsibilities that leading the 'Graduate Program in Philosophy' at MIT had turned out to entail," Dr. Putnam joined the Harvard faculty in 1965, he wrote in the autobiographical essay.
Politically active during the tumult of the 1960s, he started a committee of faculty and students to oppose US involvement in Vietnam, joined and later left the Progressive Labor Party, and served as a faculty adviser to Students for a Democratic Society at a time when protesters often were arrested.
A service has been held for Dr. Putnam, who in addition to his wife and son Samuel, leaves two daughters, Erika Chin of Acton and Maxima Kahn of Grass Valley, Calif.; another son, Joshua, of Medford; and four grandchildren.
"What was really remarkable about my dad is he was just an incredibly generous person with his interest in people. He just paid so much attention to everybody. He was willing to talk with people for hours," Samuel said.