Date
    YoYOptionletVolatilitySurface::baseDate() const {

        // Depends on interpolation, or not, of observed index
        // and observation lag with which it was built.
        // We want this to work even if the index does not
        // have a yoy term structure.
        if (indexIsInterpolated()) {
            return referenceDate() - observationLag();
        } else {
            return inflationPeriod(referenceDate() - observationLag(),
                                   frequency()).first;
        }
    }
    Rate YoYInflationTermStructure::yoyRate(const Date &d, const Period& instObsLag,
                                              bool forceLinearInterpolation,
                                              bool extrapolate) const {

        Period useLag = instObsLag;
        if (instObsLag == Period(-1,Days)) {
            useLag = observationLag();
        }

        Rate yoyRate;
        if (forceLinearInterpolation) {
            std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
            dd.second = dd.second + Period(1,Days);
            Real dp = dd.second - dd.first;
            Real dt = (d-useLag) - dd.first;
            // if we are interpolating we only check the exact point
            // this prevents falling off the end at curve maturity
            InflationTermStructure::checkRange(d, extrapolate);
            Time t1 = timeFromReference(dd.first);
            Time t2 = timeFromReference(dd.second);
            Rate y1 = yoyRateImpl(t1);
            Rate y2 = yoyRateImpl(t2);
            yoyRate = y1 + (y2-y1) * (dt/dp);
        } else {
            if (indexIsInterpolated()) {
                InflationTermStructure::checkRange(d-useLag, extrapolate);
                Time t = timeFromReference(d-useLag);
                yoyRate = yoyRateImpl(t);
            } else {
                std::pair<Date,Date> dd = inflationPeriod(d-useLag, frequency());
                InflationTermStructure::checkRange(dd.first, extrapolate);
                Time t = timeFromReference(dd.first);
                yoyRate = yoyRateImpl(t);
            }
        }

        if (hasSeasonality()) {
            yoyRate = seasonality()->correctYoYRate(d-useLag, yoyRate, *this);
        }
        return yoyRate;
    }
    Volatility
    YoYOptionletVolatilitySurface::volatility(const Date& maturityDate,
                                              Rate strike,
                                              const Period &obsLag,
                                              bool extrapolate) const {

        Period useLag = obsLag;
        if (obsLag==Period(-1,Days)) {
            useLag = observationLag();
        }

        if (indexIsInterpolated()) {
            YoYOptionletVolatilitySurface::checkRange(maturityDate-useLag, strike, extrapolate);
            Time t = timeFromReference(maturityDate-useLag);
            return volatilityImpl(t,strike);
        } else {
            std::pair<Date,Date> dd = inflationPeriod(maturityDate-useLag, frequency());
            YoYOptionletVolatilitySurface::checkRange(dd.first, strike, extrapolate);
            Time t = timeFromReference(dd.first);
            return volatilityImpl(t,strike);
        }
    }
    //! needed for total variance calculations
    Time
    YoYOptionletVolatilitySurface::timeFromBase(const Date &maturityDate,
                                                const Period& obsLag) const {

        Period useLag = obsLag;
        if (obsLag==Period(-1,Days)) {
            useLag = observationLag();
        }

        Date useDate;
        if (indexIsInterpolated()) {
            useDate = maturityDate - useLag;
        } else {
            useDate = inflationPeriod(maturityDate - useLag,
                                      frequency()).first;
        }

        // This assumes that the inflation term structure starts
        // as late as possible given the inflation index definition,
        // which is the usual case.
        return dayCounter().yearFraction(baseDate(), useDate);
    }