text:
/**
 * @file RealFirFilter.h
 *
 * Definition of the template class RealFirFilter.
 */

#ifndef NimbleDSP_RealFirFilter_h
#define NimbleDSP_RealFirFilter_h

#include <complex>
#include <math.h>
#include "RealVector.h"
#include "ParksMcClellan.h"

namespace NimbleDSP {

/**
 * \brief Class for real FIR filters.
 */
template <class T>
class RealFirFilter : public RealVector<T> {
 protected:
    /**
     * \brief Saved data that is used for stream filtering.
     */
    std::vector<char> savedData;

    /**
     * \brief Indicates how many samples are in \ref savedData.  Used for stream filtering.
     */
    int numSavedSamples;

    /**
     * \brief Indicates the filter phase.  Used for stream filtering.
     */
    int phase;

    /**
     * \brief Applies a Hamming window on the current contents of "this".
     */
    void hamming(void);

 public:
    /**
     * \brief Determines how the filter should filter.
     *
     * NimbleDSP::ONE_SHOT_RETURN_ALL_RESULTS is equivalent to "trimTails = false" of the Vector convolution methods.
     * NimbleDSP::ONE_SHOT_TRIM_TAILS is equivalent to "trimTails = true" of the Vector convolution methods.
     * NimbleDSP::STREAMING maintains the filter state from call to call so it can produce results as if it had
     *      filtered one continuous set of data.
     */
    FilterOperationType filtOperation;

    /*****************************************************************************************
                                        Constructors
    *****************************************************************************************/
    /**
     * \brief Basic constructor.
     *
     * Just sets the size of \ref buf and the pointer to the scratch buffer, if one is provided.
     * \param size Size of \ref buf.
     * \param scratch Pointer to a scratch buffer.  The scratch buffer can be shared by multiple
     *      objects (in fact, I recommend it), but if there are multiple threads then it should
     *      be shared only by objects that are accessed by a single thread.  Objects in other
     *      threads should have a separate scratch buffer.  If no scratch buffer is provided
     *      then one will be created in methods that require one and destroyed when the method
     *      returns.
     */
    RealFirFilter<T>(unsigned size = DEFAULT_BUF_LEN, FilterOperationType operation = STREAMING, std::vector<T> *scratch = NULL) : RealVector<T>(size, scratch)
            {if (size > 0) {savedData.resize((size - 1) * sizeof(std::complex<T>)); numSavedSamples = size - 1;}
             else {savedData.resize(0); numSavedSamples = 0;} phase = 0; filtOperation = operation;}

    /**
     * \brief Vector constructor.
     *
     * Sets buf equal to the input "data" parameter and sets the pointer to the scratch buffer,
     *      if one is provided.
     * \param data Vector that \ref buf will be set equal to.
     * \param scratch Pointer to a scratch buffer.  The scratch buffer can be shared by multiple
     *      objects (in fact, I recommend it), but if there are multiple threads then it should
     *      be shared only by objects that are accessed by a single thread.  Objects in other
     *      threads should have a separate scratch buffer.  If no scratch buffer is provided
     *      then one will be created in methods that require one and destroyed when the method
     *      returns.
     */
    template <typename U>
    RealFirFilter<T>(std::vector<U> data, FilterOperationType operation = STREAMING, std::vector<T> *scratch = NULL) : RealVector<T>(data, scratch)
            {savedData.resize((data.size() - 1) * sizeof(std::complex<T>)); numSavedSamples = data.size() - 1; phase = 0; filtOperation = operation;}

    /**
     * \brief Array constructor.
     *
     * Sets buf equal to the input "data" array and sets the pointer to the scratch buffer,
     *      if one is provided.
     * \param data Array that \ref buf will be set equal to.
     * \param dataLen Length of "data".
     * \param scratch Pointer to a scratch buffer.  The scratch buffer can be shared by multiple
     *      objects (in fact, I recommend it), but if there are multiple threads then it should
     *      be shared only by objects that are accessed by a single thread.  Objects in other
     *      threads should have a separate scratch buffer.  If no scratch buffer is provided
     *      then one will be created in methods that require one and destroyed when the method
     *      returns.
     */
    template <typename U>
    RealFirFilter<T>(U *data, unsigned dataLen, FilterOperationType operation = STREAMING, std::vector<T> *scratch = NULL) : RealVector<T>(data, dataLen, scratch)
            {savedData.resize((dataLen - 1) * sizeof(std::complex<T>)); numSavedSamples = dataLen - 1; phase = 0; filtOperation = operation;}

    /**
     * \brief Copy constructor.
     */
    RealFirFilter<T>(const RealFirFilter<T>& other) {this->vec = other.vec; savedData = other.savedData;
            numSavedSamples = other.numSavedSamples; phase = other.phase; filtOperation = other.filtOperation;}

    /*****************************************************************************************
                                            Operators
    *****************************************************************************************/
    /**
     * \brief Assignment operator.
     */
    RealFirFilter<T>& operator=(const Vector<T>& rhs) {this->vec = rhs.vec; savedData.resize(this->size() - 1); phase = 0; filtOperation = STREAMING; return *this;}

    /*****************************************************************************************
                                            Methods
    *****************************************************************************************/
    /**
     * \brief Convolution method.
     *
     * \param data The buffer that will be filtered.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the convolution.
     */
    virtual RealVector<T> & conv(RealVector<T> & data, bool trimTails = false);

    /**
     * \brief Convolution method for complex data.
     *
     * \param data The buffer that will be filtered.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the convolution.
     */
    virtual ComplexVector<T> & convComplex(ComplexVector<T> & data, bool trimTails = false);

    /**
     * \brief Decimate method.
     *
     * This method is equivalent to filtering with the \ref conv method and downsampling
     * with the \ref downsample method, but much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param rate Indicates how much to downsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the decimation.
     */
    virtual RealVector<T> & decimate(RealVector<T> & data, int rate, bool trimTails = false);

    /**
     * \brief Decimate method for complex data.
     *
     * This method is equivalent to filtering with the \ref conv method and downsampling
     * with the \ref downsample method, but much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param rate Indicates how much to downsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the decimation.
     */
    virtual ComplexVector<T> & decimateComplex(ComplexVector<T> & data, int rate, bool trimTails = false);

    /**
     * \brief Interpolation method.
     *
     * This method is equivalent to upsampling followed by filtering, but is much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param rate Indicates how much to upsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the interpolation.
     */
    virtual RealVector<T> & interp(RealVector<T> & data, int rate, bool trimTails = false);

    /**
     * \brief Interpolation method for complex data.
     *
     * This method is equivalent to upsampling followed by filtering, but is much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param rate Indicates how much to upsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the interpolation.
     */
    virtual ComplexVector<T> & interpComplex(ComplexVector<T> & data, int rate, bool trimTails = false);

    /**
     * \brief Resample method.
     *
     * This method is equivalent to upsampling by "interpRate", filtering, and downsampling
     *      by "decimateRate", but is much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param interpRate Indicates how much to upsample.
     * \param decimateRate Indicates how much to downsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the resampling.
     */
    virtual RealVector<T> & resample(RealVector<T> & data, int interpRate, int decimateRate, bool trimTails = false);

    /**
     * \brief Resample method for complex data.
     *
     * This method is equivalent to upsampling by "interpRate", filtering, and downsampling
     *      by "decimateRate", but is much more efficient.
     *
     * \param data The buffer that will be filtered.
     * \param interpRate Indicates how much to upsample.
     * \param decimateRate Indicates how much to downsample.
     * \param trimTails This parameter is ignored.  The operation of the filter is determined by how
     *      \ref filtOperation is set.
     * \return Reference to "data", which holds the result of the resampling.
     */
    virtual ComplexVector<T> & resampleComplex(ComplexVector<T> & data, int interpRate, int decimateRate, bool trimTails = false);

    /**
     * \brief Parks-McClellan algorithm for generating equiripple FIR filter coefficients.
     *
     * Application of the remez algorithm to producing equiripple FIR filter coefficients.  It has issues with
     * convergence.  It can generally converge up to 128 taps- more than that and it gets iffy.
     *
     * The PM algorithm implementation is a somewhat modified version of Iowa Hills Software's port of the
     * PM algorithm from the original Fortran to C.  Much appreciation to them for their work.
     *
     * \param filterOrder Indicates that the number of taps should be filterOrder + 1.
     * \param numBands The number of pass and stop bands.  Maximum of 10 bands.
     * \param freqPoints Pairs of points specify the boundaries of the bands, thus the length of this array
     *          must be 2 * numBands.  The frequencies in between the bands are the transition bands.  "0"
     *          corresponds to 0 Hz, and "1" corresponds to the Nyquist frequency.  Example: "0.0 0.3 .5 1.0"
     *          specifies two bands, one from 0 Hz to .3 * Nyquist and the other from 0.5 Nyquist to Nyquist.
     *          .3 * Nyquist to .5 * Nyquist is the transition band.
     * \param desiredBandResponse Indicates what the desired amplitude response is in the corresponding band.
     *          This array must have "numBands" elements.
     * \param weight Indicates how much weight should be given the performance of the filter in that band.  If
     *          all of the elements are "1" then they will have equal weight which will produce a true
     *          equiripple filter (same amount of ripple in the pass and stop bands).  If the stop bands are
     *          assigned more weight than the passbands then the attenuation in the stop bands will be increased
     *          at the expense of more ripple in the pass bands.
     * \param lGrid Grid density.  Defaults to 16.  This value should generally not be set lower than 16.
     *          Setting it higher than 16 can produce a filter with a better fit to the desired response at
     *          the cost of increased computations.
     * \return Boolean that indicates whether the filter converged or not.
     */
    bool firpm(int filterOrder, int numBands, double *freqPoints, double *desiredBandResponse,
                double *weight, int lGrid = 16);

    /**
     * \brief Generates a filter that can delay signals by an arbitrary sub-sample time.
     *
     * \param numTaps Number of taps to use in the filter.  If the only purpose of the filter is to delay
     *          the signal then the number of taps is not crucial.  If it is doing actual stop-band filtering
     *          too then the number of taps is important.
     * \param bandwidth The approximate bandwidth of the filter, normalized to the range 0.0 to 1.0, where
     *          1.0 is the Nyquist frequency.  The bandwidth must be greater than 0 and less than 1.
     * \param delay Amount of sample time to delay.  For example, a delay value of 0.1 would indicate to delay
     *          by one tenth of a sample.  "delay" can be positive or negative.
     */
    void fractionalDelayFilter(int numTaps, double bandwidth, double delay);

    /**
     * \brief Correlation method.
     *
     * \param data The buffer that will be correlated.
     * \return Reference to "data", which holds the result of the convolution.
     */
    virtual RealVector<T> & corr(RealVector<T> & data);

    /**
     * \brief Generates a Hamming window.
     *
     * \param len The window length.
     */
     void hamming(unsigned len);

    /**
     * \brief Generates a Hann window.
     *
     * \param len The window length.
     */
     void hann(unsigned len);

    /**
     * \brief Generates a generalized Hamming window.
     *
     * \param len The window length.
     * \param alpha
     * \param beta
     */
     void generalizedHamming(unsigned len, double alpha, double beta);

    /**
     * \brief Generates a Blackman window.
     *
     * \param len The window length.
     */
     void blackman(unsigned len);

    /**
     * \brief Generates a Blackman-harris window.
     *
     * \param len The window length.
     */
     void blackmanHarris(unsigned len);

};

template <class T>
RealVector<T> & RealFirFilter<T>::conv(RealVector<T> & data, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    std::vector<T> scratch;
    std::vector<T> *dataTmp;
    T *savedDataArray = (T *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING:
        dataTmp->resize((this->size() - 1) + data.size());
        for (int i=0; i<this->size()-1; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + this->size() - 1] = data[i];
        }

        for (resultIndex=0; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex, filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        for (int i=0; i<this->size()-1; i++) {
            savedDataArray[i] = (*dataTmp)[i + data.size()];
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(data.size() + this->size() - 1);

        // Initial partial overlap
        for (resultIndex=0; resultIndex<(int)this->size()-1; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<(int)dataTmp->size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - (this->size()-1), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - (this->size()-1), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0; resultIndex<((int)this->size()-1) - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<(int)dataTmp->size() - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;
    }
    return data;
}

template <class T>
ComplexVector<T> & RealFirFilter<T>::convComplex(ComplexVector<T> & data, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    std::vector< std::complex<T> > scratch;
    std::vector< std::complex<T> > *dataTmp;
    std::complex<T> *savedDataArray = (std::complex<T> *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING:
        dataTmp->resize((this->size() - 1) + data.size());
        for (int i=0; i<this->size()-1; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + this->size() - 1] = data[i];
        }

        for (resultIndex=0; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex, filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        for (int i=0; i<this->size()-1; i++) {
            savedDataArray[i] = (*dataTmp)[i + data.size()];
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(data.size() + this->size() - 1);

        // Initial partial overlap
        for (resultIndex=0; resultIndex<(int)this->size()-1; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<(int)dataTmp->size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - (this->size()-1), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - (this->size()-1), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0; resultIndex<((int)this->size()-1) - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<(int)dataTmp->size() - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;
    }
    return data;
}

template <class T>
RealVector<T> & RealFirFilter<T>::decimate(RealVector<T> & data, int rate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    std::vector<T> scratch;
    std::vector<T> *dataTmp;
    T *savedDataArray = (T *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        data.resize((data.size() + numSavedSamples - (this->size() - 1) + rate - 1)/rate);
        for (resultIndex=0; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate, filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        int nextResultDataPoint = resultIndex * rate;
        numSavedSamples = (unsigned) dataTmp->size() - nextResultDataPoint;

        for (int i=0; i<numSavedSamples; i++) {
            savedDataArray[i] = (*dataTmp)[i + nextResultDataPoint];
        }
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(((data.size() + this->size() - 1) + (rate - 1)) / rate);

        // Initial partial overlap
        for (resultIndex=0; resultIndex<((int)this->size()-1+rate-1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex*rate; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()+rate-1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - (this->size()-1), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - (this->size()-1), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        data.resize((data.size() + rate - 1) / rate);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0; resultIndex<(((int)this->size()-1) - initialTrim + rate - 1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex*rate; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size() - initialTrim + rate - 1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;
    }
    return data;
}

template <class T>
ComplexVector<T> & RealFirFilter<T>::decimateComplex(ComplexVector<T> & data, int rate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    std::vector< std::complex<T> > scratch;
    std::vector< std::complex<T> > *dataTmp;
    std::complex<T> *savedDataArray = (std::complex<T> *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        data.resize((data.size() + numSavedSamples - (this->size() - 1) + rate - 1)/rate);
        for (resultIndex=0; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate, filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        int nextResultDataPoint = resultIndex * rate;
        numSavedSamples = ((int) dataTmp->size()) - nextResultDataPoint;

        for (int i=0; i<numSavedSamples; i++) {
            savedDataArray[i] = (*dataTmp)[i + nextResultDataPoint];
        }
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(((data.size() + this->size() - 1) + (rate - 1)) / rate);

        // Initial partial overlap
        for (resultIndex=0; resultIndex<((int)this->size()-1+rate-1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex*rate; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()+rate-1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - (this->size()-1), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - (this->size()-1), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        data.resize((data.size() + rate - 1) / rate);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0; resultIndex<(((int)this->size()-1) - initialTrim + rate - 1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex*rate; filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size() - initialTrim + rate - 1)/rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 filterIndex>=0; dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=resultIndex*rate - ((this->size()-1) - initialTrim), filterIndex=this->size()-1;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex--) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }
        break;
    }
    return data;
}

template <class T>
RealVector<T> & RealFirFilter<T>::interp(RealVector<T> & data, int rate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    int dataStart, filterStart;
    std::vector<T> scratch;
    std::vector<T> *dataTmp;
    T *savedDataArray = (T *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        int numTaps = (this->size() + rate - 1) / rate;
        if (numSavedSamples >= numTaps) {
            // First call to interp, have too many "saved" (really just the initial zeros) samples
            numSavedSamples = numTaps - 1;
            phase = (numTaps - 1) * rate;
        }

        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        data.resize((unsigned) dataTmp->size() * rate);
        bool keepGoing = true;
        for (resultIndex=0, dataStart=0, filterStart=phase; keepGoing; ++resultIndex) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
                if (dataTmp->size() - dataStart == numSavedSamples) {
                    keepGoing = false;
                    phase = filterStart;
                }
            }
        }
        data.resize(resultIndex);

        int i;
        for (i=0; dataStart<dataTmp->size(); i++, dataStart++) {
            savedDataArray[i] = (*dataTmp)[dataStart];
        }
        numSavedSamples = i;
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(data.size() * rate + this->size() - 1 - (rate - 1));

        // Initial partial overlap
        for (resultIndex=0, dataStart=0; resultIndex<(int)this->size()-1; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex; filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (dataStart=0, filterStart=resultIndex; resultIndex<(int)dataTmp->size()*rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int) this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        data.resize(data.size() * rate);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0, dataStart=0; resultIndex<(int)this->size()-1 - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex; filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (dataStart=0, filterStart=(int)this->size()-1; resultIndex<(int)dataTmp->size()*rate - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }
        break;
    }
    return data;
}

template <class T>
ComplexVector<T> & RealFirFilter<T>::interpComplex(ComplexVector<T> & data, int rate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    int dataStart, filterStart;
    std::vector< std::complex<T> > scratch;
    std::vector< std::complex<T> > *dataTmp;
    std::complex<T> *savedDataArray = (std::complex<T> *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        int numTaps = (this->size() + rate - 1) / rate;
        if (numSavedSamples >= numTaps) {
            // First call to interp, have too many "saved" (really just the initial zeros) samples
            numSavedSamples = numTaps - 1;
            phase = (numTaps - 1) * rate;
        }

        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        data.resize((unsigned) dataTmp->size() * rate);
        bool keepGoing = true;
        for (resultIndex=0, dataStart=0, filterStart=phase; keepGoing; ++resultIndex) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
                if (dataTmp->size() - dataStart == numSavedSamples) {
                    keepGoing = false;
                    phase = filterStart;
                }
            }
        }
        data.resize(resultIndex);

        int i;
        for (i=0; dataStart<dataTmp->size(); i++, dataStart++) {
            savedDataArray[i] = (*dataTmp)[dataStart];
        }
        numSavedSamples = i;
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        data.resize(data.size() * rate + this->size() - 1 - (rate - 1));

        // Initial partial overlap
        for (resultIndex=0, dataStart=0; resultIndex<(int)this->size()-1; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=resultIndex; filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (dataStart=0, filterStart=resultIndex; resultIndex<(int)dataTmp->size()*rate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int) this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        data.resize(data.size() * rate);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0, dataStart=0; resultIndex<(int)this->size()-1 - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=initialTrim + resultIndex; filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
        }

        // Middle full overlap
        for (dataStart=0, filterStart=(int)this->size()-1; resultIndex<(int)dataTmp->size()*rate - initialTrim; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=rate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            ++filterStart;
            if (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= rate;
                ++dataStart;
            }
        }
        break;
    }
    return data;
}

template <class T>
RealVector<T> & RealFirFilter<T>::resample(RealVector<T> & data, int interpRate, int decimateRate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    int dataStart, filterStart;
    int interpLen, resampLen;
    std::vector<T> scratch;
    std::vector<T> *dataTmp;
    T *savedDataArray = (T *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        int numTaps = (this->size() + interpRate - 1) / interpRate;
        if (numSavedSamples >= numTaps) {
            // First call to interp, have too many "saved" (really just the initial zeros) samples
            numSavedSamples = numTaps - 1;
            phase = (numTaps - 1) * interpRate;
        }

        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        interpLen = (unsigned) dataTmp->size() * interpRate;
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);
        bool keepGoing = true;
        for (resultIndex=0, dataStart=0, filterStart=phase; keepGoing; ++resultIndex) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
            if (dataTmp->size() - dataStart == numSavedSamples) {
                keepGoing = false;
                phase = filterStart;
            }
        }
        data.resize(resultIndex);

        int i;
        for (i=0; dataStart<dataTmp->size(); i++, dataStart++) {
            savedDataArray[i] = (*dataTmp)[dataStart];
        }
        numSavedSamples = i;
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        interpLen = data.size() * interpRate + this->size() - 1 - (interpRate - 1);
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);

        // Initial partial overlap
        for (resultIndex=0, dataStart=0, filterStart=0; resultIndex<((int)this->size()-1+decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=filterStart; filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()*interpRate + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        interpLen = data.size() * interpRate;
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0, dataStart=0, filterStart=initialTrim;
             resultIndex<((int)this->size()-1 - initialTrim + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=filterStart; filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()*interpRate - initialTrim + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }
        break;
    }
    return data;
}

template <class T>
ComplexVector<T> & RealFirFilter<T>::resampleComplex(ComplexVector<T> & data, int interpRate, int decimateRate, bool trimTails) {
    int resultIndex;
    int filterIndex;
    int dataIndex;
    int dataStart, filterStart;
    int interpLen, resampLen;
    std::vector< std::complex<T> > scratch;
    std::vector< std::complex<T> > *dataTmp;
    std::complex<T> *savedDataArray = (std::complex<T> *) VECTOR_TO_ARRAY(savedData);

    if (data.scratchBuf == NULL) {
        dataTmp = &scratch;
    }
    else {
        dataTmp = data.scratchBuf;
    }

    switch (filtOperation) {

    case STREAMING: {
        int numTaps = (this->size() + interpRate - 1) / interpRate;
        if (numSavedSamples >= numTaps) {
            // First call to interp, have too many "saved" (really just the initial zeros) samples
            numSavedSamples = numTaps - 1;
            phase = (numTaps - 1) * interpRate;
        }

        dataTmp->resize(numSavedSamples + data.size());
        for (int i=0; i<numSavedSamples; i++) {
            (*dataTmp)[i] = savedDataArray[i];
        }
        for (int i=0; i<data.size(); i++) {
            (*dataTmp)[i + numSavedSamples] = data[i];
        }

        interpLen = (unsigned) dataTmp->size() * interpRate;
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);
        bool keepGoing = true;
        for (resultIndex=0, dataStart=0, filterStart=phase; keepGoing; ++resultIndex) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
            if (dataTmp->size() - dataStart == numSavedSamples) {
                keepGoing = false;
                phase = filterStart;
            }
        }
        data.resize(resultIndex);

        int i;
        for (i=0; dataStart<dataTmp->size(); i++, dataStart++) {
            savedDataArray[i] = (*dataTmp)[dataStart];
        }
        numSavedSamples = i;
        }
        break;

    case ONE_SHOT_RETURN_ALL_RESULTS:
        *dataTmp = data.vec;
        interpLen = data.size() * interpRate + this->size() - 1 - (interpRate - 1);
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);

        // Initial partial overlap
        for (resultIndex=0, dataStart=0, filterStart=0; resultIndex<((int)this->size()-1+decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=filterStart; filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()*interpRate + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }
        break;

    case ONE_SHOT_TRIM_TAILS:
        *dataTmp = data.vec;
        interpLen = data.size() * interpRate;
        resampLen = (interpLen + decimateRate - 1) / decimateRate;
        data.resize(resampLen);

        // Initial partial overlap
        int initialTrim = (this->size() - 1) / 2;
        for (resultIndex=0, dataStart=0, filterStart=initialTrim;
             resultIndex<((int)this->size()-1 - initialTrim + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=0, filterIndex=filterStart; filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Middle full overlap
        for (; resultIndex<((int)dataTmp->size()*interpRate - initialTrim + decimateRate-1)/decimateRate; resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 filterIndex>=0; dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }

        // Final partial overlap
        for (; resultIndex<(int)data.size(); resultIndex++) {
            data[resultIndex] = 0;
            for (dataIndex=dataStart, filterIndex=filterStart;
                 dataIndex<(int)dataTmp->size(); dataIndex++, filterIndex-=interpRate) {
                data[resultIndex] += (*dataTmp)[dataIndex] * this->vec[filterIndex];
            }
            filterStart += decimateRate;
            while (filterStart >= (int)this->size()) {
                // Filter no longer overlaps with this data sample, so the first overlap sample is the next one.  We thus
                // increment the data index and decrement the filter index.
                filterStart -= interpRate;
                ++dataStart;
            }
        }
        break;
    }
    return data;
}

template <class T>
bool RealFirFilter<T>::firpm(int filterOrder, int numBands, double *freqPoints, double *desiredBandResponse,
                            double *weight, int lGrid) {
    bool converged;

    this->resize(filterOrder + 1);
    std::vector<double> temp(filterOrder + 1);

    // Need to renormalize the frequency points because for us the Nyquist frequency is 1.0, but for the
    // Iowa Hills code it is 0.5.
    for (int i=0; i<numBands*2; i++) {
        freqPoints[i] /= 2;
    }

    // Move the pointers back 1 (i.e. subtract one) because the ParksMcClellan code was ported from Fortran,
    // which apparently uses 1-based arrays, not 0-based arrays.
    converged = ParksMcClellan2(&(temp[0]), filterOrder + 1, PASSBAND_FILTER, numBands, freqPoints-1,
                    desiredBandResponse-1, weight-1, lGrid);
    for (int i=0; i<= filterOrder; i++) {
        (*this)[i] = (T) temp[i];
    }
    return converged;
}

template <class T>
void RealFirFilter<T>::fractionalDelayFilter(int numTaps, double bandwidth, double delay) {
    assert(bandwidth > 0 && bandwidth < 1.0);
    assert(numTaps > 0);

    int index;
    double tapTime;
    double timeIncrement = bandwidth * M_PI;

    if (numTaps % 2) {
        tapTime = (numTaps / 2 + delay) * -timeIncrement;
    }
    else {
        tapTime = (((int) numTaps / 2) - 0.5 + delay) * -timeIncrement;
    }

    this->resize(numTaps);

    // Create the delayed sinc filter
    for (index = 0; index < numTaps; index++, tapTime += timeIncrement) {
        if (tapTime != 0.0) {
            (*this)[index] = (T) (sin(tapTime) / tapTime);
        }
        else {
            (*this)[index] = (T) 1.0;
        }
    }

    // Window the filter
    hamming();
}

template <class T>
void RealFirFilter<T>::hamming() {
    T phase = -M_PI;
    T phaseIncrement = 2 * M_PI / (this->size() - 1);
    T alpha = 0.54;
    T beta = 0.46;
    unsigned start, end;

    for (start=0, end=this->size()-1; start < end; start++, end--, phase += phaseIncrement) {
        double hammingVal = alpha + beta * cos(phase);
        (*this)[start] *= hammingVal;
        (*this)[end] *= hammingVal;
    }
}

template <class T>
RealVector<T> & RealFirFilter<T>::corr(RealVector<T> & data) {
    this->reverse();
    this->conv(data);
    this->reverse();
    return data;
}

/**
 * \brief Correlation function.
 *
 * \param data Buffer to operate on.
 * \param filter The filter that will correlate with "data".
 * \return Reference to "data", which holds the result of the convolution.
 */
template <class T>
inline RealVector<T> & corr(RealVector<T> & data, RealFirFilter<T> & filter) {
    return filter.corr(data);
}

template <class T>
void RealFirFilter<T>::hamming(unsigned len)
{
    generalizedHamming(len, 0.54, 0.46);
}

template <class T>
void RealFirFilter<T>::hann(unsigned len)
{
    generalizedHamming(len, 0.5, 0.5);
}

template <class T>
void RealFirFilter<T>::generalizedHamming(unsigned len, double alpha, double beta)
{
    this->resize(len);
    double N = len - 1;
    for (unsigned index=0; index<len; index++) {
        this->vec[index] = (T) (alpha - beta * cos(2 * M_PI * ((double) index) / N));
    }
}

template <class T>
void RealFirFilter<T>::blackman(unsigned len)
{
    const double alpha[] = {0.42, 0.5, 0.08};

    this->resize(len);
    double N = len - 1;
    for (unsigned index=0; index<len; index++) {
        this->vec[index] = (T) (alpha[0] - alpha[1] * cos(2 * M_PI * ((double) index) / N) +
                alpha[2] * cos(4 * M_PI * ((double) index) / N));
    }
}

template <class T>
void RealFirFilter<T>::blackmanHarris(unsigned len)
{
    const double alpha[] = {0.35875, 0.48829, 0.14128, 0.01168};

    this->resize(len);
    double N = len - 1;
    for (unsigned index=0; index<len; index++) {
        this->vec[index] = (T) (alpha[0] - alpha[1] * cos(2 * M_PI * ((double) index) / N) +
                alpha[2] * cos(4 * M_PI * ((double) index) / N) - alpha[3] * cos(6 * M_PI * ((double) index) / N));
    }
}

};

#endif


text:
.class public abstract Landroid/database/ContentObserver;
.super Ljava/lang/Object;
.source "ContentObserver.java"

# annotations
.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Landroid/database/ContentObserver$Transport;,
        Landroid/database/ContentObserver$NotificationRunnable;
    }
.end annotation

# instance fields
.field private lock:Ljava/lang/Object;

.field mHandler:Landroid/os/Handler;

.field private mTransport:Landroid/database/ContentObserver$Transport;

# direct methods
.method public constructor <init>(Landroid/os/Handler;)V
    .locals 1
    .parameter "handler"

    .prologue
    .line 79
    invoke-direct/range {p0 .. p0}, Ljava/lang/Object;-><init>()V

    .line 30
    new-instance v0, Ljava/lang/Object;

    invoke-direct/range {v0 .. v0}, Ljava/lang/Object;-><init>()V

    iput-object v0, p0, Landroid/database/ContentObserver;->lock:Ljava/lang/Object;

    .line 80
    iput-object p1, p0, Landroid/database/ContentObserver;->mHandler:Landroid/os/Handler;

    .line 81
    return-void
.end method

# virtual methods
.method public deliverSelfNotifications()Z
    .locals 1

    .prologue
    .line 119
    const/4 v0, 0x0

    return v0
.end method

.method public final dispatchChange(Z)V
    .locals 2
    .parameter "selfChange"

    .prologue
    .line 132
    iget-object v0, p0, Landroid/database/ContentObserver;->mHandler:Landroid/os/Handler;

    if-nez v0, :cond_0

    .line 133
    invoke-virtual {p0, p1}, Landroid/database/ContentObserver;->onChange(Z)V

    .line 137
    :goto_0
    return-void

    .line 135
    :cond_0
    iget-object v0, p0, Landroid/database/ContentObserver;->mHandler:Landroid/os/Handler;

    new-instance v1, Landroid/database/ContentObserver$NotificationRunnable;

    invoke-direct {v1, p0, p1}, Landroid/database/ContentObserver$NotificationRunnable;-><init>(Landroid/database/ContentObserver;Z)V

    invoke-virtual {v0, v1}, Landroid/os/Handler;->post(Ljava/lang/Runnable;)Z

    goto :goto_0
.end method

.method public getContentObserver()Landroid/database/IContentObserver;
    .locals 2

    .prologue
    .line 89
    iget-object v1, p0, Landroid/database/ContentObserver;->lock:Ljava/lang/Object;

    monitor-enter v1

    .line 90
    :try_start_0
    iget-object v0, p0, Landroid/database/ContentObserver;->mTransport:Landroid/database/ContentObserver$Transport;

    if-nez v0, :cond_0

    .line 91
    new-instance v0, Landroid/database/ContentObserver$Transport;

    invoke-direct {v0, p0}, Landroid/database/ContentObserver$Transport;-><init>(Landroid/database/ContentObserver;)V

    iput-object v0, p0, Landroid/database/ContentObserver;->mTransport:Landroid/database/ContentObserver$Transport;

    .line 93
    :cond_0
    iget-object v0, p0, Landroid/database/ContentObserver;->mTransport:Landroid/database/ContentObserver$Transport;

    monitor-exit v1

    return-object v0

    .line 94
    :catchall_0
    move-exception v0

    monitor-exit v1
    :try_end_0
    .catchall {:try_start_0 .. :try_end_0} :catchall_0

    throw v0
.end method

.method public onChange(Z)V
    .locals 0
    .parameter "selfChange"

    .prologue
    .line 129
    return-void
.end method

.method public releaseContentObserver()Landroid/database/IContentObserver;
    .locals 3

    .prologue
    .line 104
    iget-object v2, p0, Landroid/database/ContentObserver;->lock:Ljava/lang/Object;

    monitor-enter v2

    .line 105
    :try_start_0
    iget-object v0, p0, Landroid/database/ContentObserver;->mTransport:Landroid/database/ContentObserver$Transport;

    .line 106
    .local v0, oldTransport:Landroid/database/ContentObserver$Transport;
    if-eqz v0, :cond_0

    .line 107
    invoke-virtual {v0}, Landroid/database/ContentObserver$Transport;->releaseContentObserver()V

    .line 108
    const/4 v1, 0x0

    iput-object v1, p0, Landroid/database/ContentObserver;->mTransport:Landroid/database/ContentObserver$Transport;

    .line 110
    :cond_0
    monitor-exit v2

    return-object v0

    .line 111
    .end local v0           #oldTransport:Landroid/database/ContentObserver$Transport;
    :catchall_0
    move-exception v1

    monitor-exit v2
    :try_end_0
    .catchall {:try_start_0 .. :try_end_0} :catchall_0

    throw v1
.end method

redpajama_set_name: RedPajamaGithub


text:
layout: kanji
v4: 1991
v6: 2146
kanji: 虜
keyword: captive
elements: captive, tiger, male, rice field, brains, power, muscle, arnold
strokes: 13
image: E8999C
on-yomi: リョ、ロ
kun-yomi: とりこ、とりく
permalink: /rtk/虜/
prev: 虎
next: 膚
---

1) [Piitaa] 21-7-2006(299): Captive men are thrown to the tigers. I think you can imagine something else is done to captive women...

2) [Katsuo] 2-8-2007(104): Tip: To avoid confusing keyword captive with captured (#1018 囚) note that captive contains "ti" for tiger.

3) [ayoung24] 21-12-2006(64): Captive men are thrown to the tigers. Captive women are thrown to the men. (thanks, Piitaa).

4) [romanrozhok] 24-3-2008(16): The CAPTIVE men in the movie "Gladiator" were forced to fight TIGERS in a Gladiator Arena.

5) [stehr] 29-12-2007(7): A capitive tiger in San Francisco leaps out of his pen and kills a man and attacks two others.


text:
class ChangeTaskStringType < ActiveRecord::Migration
  def change
    change_column :statuses, :task_order_string, :text, :default => "[]", :limit => nil
  end
end


text:
package net.sf.jsqlparser.expression;

import net.sf.jsqlparser.statement.select.SubSelect;

public class AnyComparisonExpression implements Expression {
	private SubSelect subSelect;

	public AnyComparisonExpression(SubSelect subSelect) {
		this.subSelect = subSelect;
	}

	public SubSelect getSubSelect() {
		return subSelect;
	}

	public void accept(ExpressionVisitor expressionVisitor) {
		expressionVisitor.visit(this);
	}
}


text:
package com.android.dx.rop.annotation;

import com.android.dx.rop.cst.CstString;
import com.android.dx.rop.cst.CstType;
import com.android.dx.util.MutabilityControl;
import com.android.dx.util.ToHuman;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.TreeMap;

/**
 * An annotation on an element of a class. Annotations have an
 * associated type and additionally consist of a set of (name, value)
 * pairs, where the names are unique.
 */
public final class Annotation extends MutabilityControl
        implements Comparable<Annotation>, ToHuman {
    /** {@code non-null;} type of the annotation */
    private final CstType type;

    /** {@code non-null;} the visibility of the annotation */
    private final AnnotationVisibility visibility;

    /** {@code non-null;} map from names to {@link NameValuePair} instances */
    private final TreeMap<CstString, NameValuePair> elements;

    /**
     * Construct an instance. It initially contains no elements.
     *
     * @param type {@code non-null;} type of the annotation
     * @param visibility {@code non-null;} the visibility of the annotation
     */
    public Annotation(CstType type, AnnotationVisibility visibility) {
        if (type == null) {
            throw new NullPointerException("type == null");
        }

        if (visibility == null) {
            throw new NullPointerException("visibility == null");
        }

        this.type = type;
        this.visibility = visibility;
        this.elements = new TreeMap<CstString, NameValuePair>();
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object other) {
        if (! (other instanceof Annotation)) {
            return false;
        }

        Annotation otherAnnotation = (Annotation) other;

        if (! (type.equals(otherAnnotation.type)
                        && (visibility == otherAnnotation.visibility))) {
            return false;
        }

        return elements.equals(otherAnnotation.elements);
    }

    /** {@inheritDoc} */
    public int hashCode() {
        int hash = type.hashCode();
        hash = (hash * 31) + elements.hashCode();
        hash = (hash * 31) + visibility.hashCode();
        return hash;
    }

    /** {@inheritDoc} */
    public int compareTo(Annotation other) {
        int result = type.compareTo(other.type);

        if (result != 0) {
            return result;
        }

        result = visibility.compareTo(other.visibility);

        if (result != 0) {
            return result;
        }

        Iterator<NameValuePair> thisIter = elements.values().iterator();
        Iterator<NameValuePair> otherIter = other.elements.values().iterator();

        while (thisIter.hasNext() && otherIter.hasNext()) {
            NameValuePair thisOne = thisIter.next();
            NameValuePair otherOne = otherIter.next();

            result = thisOne.compareTo(otherOne);
            if (result != 0) {
                return result;
            }
        }

        if (thisIter.hasNext()) {
            return 1;
        } else if (otherIter.hasNext()) {
            return -1;
        }

        return 0;
    }

    /** {@inheritDoc} */
    @Override
    public String toString() {
        return toHuman();
    }

    /** {@inheritDoc} */
    public String toHuman() {
        StringBuilder sb = new StringBuilder();

        sb.append(visibility.toHuman());
        sb.append("-annotation ");
        sb.append(type.toHuman());
        sb.append(" {");

        boolean first = true;
        for (NameValuePair pair : elements.values()) {
            if (first) {
                first = false;
            } else {
                sb.append(", ");
            }
            sb.append(pair.getName().toHuman());
            sb.append(": ");
            sb.append(pair.getValue().toHuman());
        }

        sb.append("}");
        return sb.toString();
    }

    /**
     * Gets the type of this instance.
     *
     * @return {@code non-null;} the type
     */
    public CstType getType() {
        return type;
    }

    /**
     * Gets the visibility of this instance.
     *
     * @return {@code non-null;} the visibility
     */
    public AnnotationVisibility getVisibility() {
        return visibility;
    }

    /**
     * Put an element into the set of (name, value) pairs for this instance.
     * If there is a preexisting element with the same name, it will be
     * replaced by this method.
     *
     * @param pair {@code non-null;} the (name, value) pair to place into this instance
     */
    public void put(NameValuePair pair) {
        throwIfImmutable();

        if (pair == null) {
            throw new NullPointerException("pair == null");
        }

        elements.put(pair.getName(), pair);
    }

    /**
     * Add an element to the set of (name, value) pairs for this instance.
     * It is an error to call this method if there is a preexisting element
     * with the same name.
     *
     * @param pair {@code non-null;} the (name, value) pair to add to this instance
     */
    public void add(NameValuePair pair) {
        throwIfImmutable();

        if (pair == null) {
            throw new NullPointerException("pair == null");
        }

        CstString name = pair.getName();

        if (elements.get(name) != null) {
            throw new IllegalArgumentException("name already added: " + name);
        }

        elements.put(name, pair);
    }

    /**
     * Gets the set of name-value pairs contained in this instance. The
     * result is always unmodifiable.
     *
     * @return {@code non-null;} the set of name-value pairs
     */
    public Collection<NameValuePair> getNameValuePairs() {
        return Collections.unmodifiableCollection(elements.values());
    }
}


text:
<?php

namespace Gehaxelt\SyMDWikiBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class GehaxeltSyMDWikiBundle extends Bundle
{
}


text:
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.security;

import com.facebook.presto.metadata.QualifiedObjectName;
import com.facebook.presto.spi.CatalogSchemaName;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.security.AccessControlContext;
import com.facebook.presto.spi.security.Identity;
import com.facebook.presto.spi.security.PrestoPrincipal;
import com.facebook.presto.spi.security.Privilege;
import com.facebook.presto.transaction.TransactionId;

import java.security.Principal;
import java.util.Optional;
import java.util.Set;

public class AllowAllAccessControl
        implements AccessControl
{
    @Override
    public void checkCanSetUser(AccessControlContext context, Optional<Principal> principal, String userName)
    {
    }

    @Override
    public void checkQueryIntegrity(Identity identity, AccessControlContext context, String query)
    {
    }

    @Override
    public Set<String> filterCatalogs(Identity identity, AccessControlContext context, Set<String> catalogs)
    {
        return catalogs;
    }

    @Override
    public void checkCanAccessCatalog(Identity identity, AccessControlContext context, String catalogName)
    {
    }

    @Override
    public void checkCanCreateSchema(TransactionId transactionId, Identity identity, AccessControlContext context, CatalogSchemaName schemaName)
    {
    }

    @Override
    public void checkCanDropSchema(TransactionId transactionId, Identity identity, AccessControlContext context, CatalogSchemaName schemaName)
    {
    }

    @Override
    public void checkCanRenameSchema(TransactionId transactionId, Identity identity, AccessControlContext context, CatalogSchemaName schemaName, String newSchemaName)
    {
    }

    @Override
    public void checkCanShowSchemas(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName)
    {
    }

    @Override
    public Set<String> filterSchemas(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName, Set<String> schemaNames)
    {
        return schemaNames;
    }

    @Override
    public void checkCanCreateTable(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanDropTable(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanRenameTable(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName, QualifiedObjectName newTableName)
    {
    }

    @Override
    public void checkCanShowTablesMetadata(TransactionId transactionId, Identity identity, AccessControlContext context, CatalogSchemaName schema)
    {
    }

    @Override
    public Set<SchemaTableName> filterTables(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName, Set<SchemaTableName> tableNames)
    {
        return tableNames;
    }

    @Override
    public void checkCanAddColumns(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanDropColumn(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanRenameColumn(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanInsertIntoTable(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanDeleteFromTable(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName)
    {
    }

    @Override
    public void checkCanCreateView(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName viewName)
    {
    }

    @Override
    public void checkCanDropView(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName viewName)
    {
    }

    @Override
    public void checkCanCreateViewWithSelectFromColumns(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName, Set<String> columnNames)
    {
    }

    @Override
    public void checkCanGrantTablePrivilege(TransactionId transactionId, Identity identity, AccessControlContext context, Privilege privilege, QualifiedObjectName tableName, PrestoPrincipal grantee, boolean withGrantOption)
    {
    }

    @Override
    public void checkCanRevokeTablePrivilege(TransactionId transactionId, Identity identity, AccessControlContext context, Privilege privilege, QualifiedObjectName tableName, PrestoPrincipal revokee, boolean grantOptionFor)
    {
    }

    @Override
    public void checkCanSetSystemSessionProperty(Identity identity, AccessControlContext context, String propertyName)
    {
    }

    @Override
    public void checkCanSetCatalogSessionProperty(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName, String propertyName)
    {
    }

    @Override
    public void checkCanSelectFromColumns(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName tableName, Set<String> columnNames)
    {
    }

    @Override
    public void checkCanCreateRole(TransactionId transactionId, Identity identity, AccessControlContext context, String role, Optional<PrestoPrincipal> grantor, String catalogName)
    {
    }

    @Override
    public void checkCanDropRole(TransactionId transactionId, Identity identity, AccessControlContext context, String role, String catalogName)
    {
    }

    @Override
    public void checkCanGrantRoles(TransactionId transactionId, Identity identity, AccessControlContext context, Set<String> roles, Set<PrestoPrincipal> grantees, boolean withAdminOption, Optional<PrestoPrincipal> grantor, String catalogName)
    {
    }

    @Override
    public void checkCanRevokeRoles(TransactionId transactionId, Identity identity, AccessControlContext context, Set<String> roles, Set<PrestoPrincipal> grantees, boolean adminOptionFor, Optional<PrestoPrincipal> grantor, String catalogName)
    {
    }

    @Override
    public void checkCanSetRole(TransactionId requiredTransactionId, Identity identity, AccessControlContext context, String role, String catalog)
    {
    }

    @Override
    public void checkCanShowRoles(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName)
    {
    }

    @Override
    public void checkCanShowCurrentRoles(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName)
    {
    }

    @Override
    public void checkCanShowRoleGrants(TransactionId transactionId, Identity identity, AccessControlContext context, String catalogName)
    {
    }
}


text:
from __future__ import unicode_literals
from jinja2 import Template

from moto.core.responses import BaseResponse
from moto.ec2.models import ec2_backend
from moto.ec2.utils import route_table_ids_from_querystring, filters_from_querystring, optional_from_querystring

class RouteTables(BaseResponse):
    def associate_route_table(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        subnet_id = self.querystring.get('SubnetId')[0]
        association_id = ec2_backend.associate_route_table(route_table_id, subnet_id)
        template = Template(ASSOCIATE_ROUTE_TABLE_RESPONSE)
        return template.render(association_id=association_id)

    def create_route(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        destination_cidr_block = self.querystring.get('DestinationCidrBlock')[0]

        internet_gateway_id = optional_from_querystring('GatewayId', self.querystring)
        instance_id = optional_from_querystring('InstanceId', self.querystring)
        interface_id = optional_from_querystring('NetworkInterfaceId', self.querystring)
        pcx_id = optional_from_querystring('VpcPeeringConnectionId', self.querystring)

        route = ec2_backend.create_route(route_table_id, destination_cidr_block,
                                         gateway_id=internet_gateway_id,
                                         instance_id=instance_id,
                                         interface_id=interface_id,
                                         vpc_peering_connection_id=pcx_id)

        template = Template(CREATE_ROUTE_RESPONSE)
        return template.render()

    def create_route_table(self):
        vpc_id = self.querystring.get('VpcId')[0]
        route_table = ec2_backend.create_route_table(vpc_id)
        template = Template(CREATE_ROUTE_TABLE_RESPONSE)
        return template.render(route_table=route_table)

    def delete_route(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        destination_cidr_block = self.querystring.get('DestinationCidrBlock')[0]
        ec2_backend.delete_route(route_table_id, destination_cidr_block)
        template = Template(DELETE_ROUTE_RESPONSE)
        return template.render()

    def delete_route_table(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        ec2_backend.delete_route_table(route_table_id)
        template = Template(DELETE_ROUTE_TABLE_RESPONSE)
        return template.render()

    def describe_route_tables(self):
        route_table_ids = route_table_ids_from_querystring(self.querystring)
        filters = filters_from_querystring(self.querystring)
        route_tables = ec2_backend.get_all_route_tables(route_table_ids, filters)
        template = Template(DESCRIBE_ROUTE_TABLES_RESPONSE)
        return template.render(route_tables=route_tables)

    def disassociate_route_table(self):
        association_id = self.querystring.get('AssociationId')[0]
        ec2_backend.disassociate_route_table(association_id)
        template = Template(DISASSOCIATE_ROUTE_TABLE_RESPONSE)
        return template.render()

    def replace_route(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        destination_cidr_block = self.querystring.get('DestinationCidrBlock')[0]

        internet_gateway_id = optional_from_querystring('GatewayId', self.querystring)
        instance_id = optional_from_querystring('InstanceId', self.querystring)
        interface_id = optional_from_querystring('NetworkInterfaceId', self.querystring)
        pcx_id = optional_from_querystring('VpcPeeringConnectionId', self.querystring)

        route = ec2_backend.replace_route(route_table_id, destination_cidr_block,
                                          gateway_id=internet_gateway_id,
                                          instance_id=instance_id,
                                          interface_id=interface_id,
                                          vpc_peering_connection_id=pcx_id)

        template = Template(REPLACE_ROUTE_RESPONSE)
        return template.render()

    def replace_route_table_association(self):
        route_table_id = self.querystring.get('RouteTableId')[0]
        association_id = self.querystring.get('AssociationId')[0]
        new_association_id = ec2_backend.replace_route_table_association(association_id, route_table_id)
        template = Template(REPLACE_ROUTE_TABLE_ASSOCIATION_RESPONSE)
        return template.render(association_id=new_association_id)

CREATE_ROUTE_RESPONSE = """
<CreateRouteResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <return>true</return>
</CreateRouteResponse>
"""

REPLACE_ROUTE_RESPONSE = """
<ReplaceRouteResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <return>true</return>
</ReplaceRouteResponse>
"""

CREATE_ROUTE_TABLE_RESPONSE = """
<CreateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <routeTable>
      <routeTableId>{{ route_table.id }}</routeTableId>
      <vpcId>{{ route_table.vpc_id }}</vpcId>
      <routeSet>
         {% for route in route_table.routes.values() %}
           {% if route.local %}
           <item>
             <destinationCidrBlock>{{ route.destination_cidr_block }}</destinationCidrBlock>
             <gatewayId>local</gatewayId>
             <state>active</state>
           </item>
           {% endif %}
         {% endfor %}
      </routeSet>
      <associationSet/>
      <tagSet/>
   </routeTable>
</CreateRouteTableResponse>
"""

DESCRIBE_ROUTE_TABLES_RESPONSE = """
<DescribeRouteTablesResponse xmlns="http://ec2.amazonaws.com/doc/2013-08-15/">
   <requestId>6f570b0b-9c18-4b07-bdec-73740dcf861a</requestId>
   <routeTableSet>
     {% for route_table in route_tables %}
       <item>
          <routeTableId>{{ route_table.id }}</routeTableId>
          <vpcId>{{ route_table.vpc_id }}</vpcId>
          <routeSet>
            {% for route in route_table.routes.values() %}
              <item>
                <destinationCidrBlock>{{ route.destination_cidr_block }}</destinationCidrBlock>
                {% if route.local %}
                  <gatewayId>local</gatewayId>
                  <origin>CreateRouteTable</origin>
                  <state>active</state>
                {% endif %}
                {% if route.internet_gateway %}
                  <gatewayId>{{ route.internet_gateway.id }}</gatewayId>
                  <origin>CreateRoute</origin>
                  <state>active</state>
                {% endif %}
                {% if route.instance %}
                  <instanceId>{{ route.instance.id }}</instanceId>
                  <origin>CreateRoute</origin>
                  <state>active</state>
                {% endif %}
                {% if route.vpc_pcx %}
                  <origin>CreateRoute</origin>
                  <state>blackhole</state>
                {% endif %}
              </item>
            {% endfor %}
          </routeSet>
          <associationSet>
            {% for association_id,subnet_id in route_table.associations.items() %}
              <item>
                <routeTableAssociationId>{{ association_id }}</routeTableAssociationId>
                <routeTableId>{{ route_table.id }}</routeTableId>
                <main>false</main>
                <subnetId>{{ subnet_id }}</subnetId>
              </item>
            {% endfor %}
          </associationSet>
         <tagSet/>
       </item>
     {% endfor %}
   </routeTableSet>
</DescribeRouteTablesResponse>
"""

DELETE_ROUTE_RESPONSE = """
<DeleteRouteResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <return>true</return>
</DeleteRouteResponse>
"""

DELETE_ROUTE_TABLE_RESPONSE = """
<DeleteRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <return>true</return>
</DeleteRouteTableResponse>
"""

ASSOCIATE_ROUTE_TABLE_RESPONSE = """
<AssociateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <associationId>{{ association_id }}</associationId>
</AssociateRouteTableResponse>
"""

DISASSOCIATE_ROUTE_TABLE_RESPONSE = """
<DisassociateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <return>true</return>
</DisassociateRouteTableResponse>
"""

REPLACE_ROUTE_TABLE_ASSOCIATION_RESPONSE = """
<ReplaceRouteTableAssociationResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
   <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
   <newAssociationId>{{ association_id }}</newAssociationId>
</ReplaceRouteTableAssociationResponse>
"""


text:
## reject

The opposite of [`filter`](#filter). Removes values that pass an async truth test.

[![](https://img.shields.io/npm/v/apr-reject.svg?style=flat-square)](https://www.npmjs.com/package/apr-reject) [![](https://img.shields.io/npm/l/apr-reject.svg?style=flat-square)](https://www.npmjs.com/package/apr-reject)

**Parameters**

-   `input` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) | Iterable)**
-   `iteratee` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)**

**Examples**

```javascript
import awaitify from 'apr-awaitify';
import reject from 'apr-reject';

const access = awaitify(fs.access);
const files = [
  'file1',
  'file2',
  'file3'
];

var missing = await reject(files, async (file) =>
  await access(file)
);
```

Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**

### series

**Parameters**

-   `input` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) | Iterable)**
-   `iteratee` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)**

Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**

### limit

**Parameters**

-   `input` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) | Iterable)**
-   `limit` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)**
-   `iteratee` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)**

Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**