docs: public static CurveInterface createIndexCurveWithSeasonality(String name, LocalDate referenceDate, Map<LocalDate, Double> indexFixings, Map<String, Double> seasonalityAdjustments, Integer seasonalAveragingNumberOfYears, Map<LocalDate, Double> annualizedZeroRates, String forwardsFixingLag, String forwardsFixingType) {
  
  		/*
  		 * Create a curve containing past fixings (using picewise constant interpolation)
  		 */
  		double[] fixingTimes = new double[indexFixings.size()];
  		double[] fixingValue = new double[indexFixings.size()];
  		int i = 0;
  		List<LocalDate> fixingDates = new ArrayList<LocalDate>(indexFixings.keySet());
  		Collections.sort(fixingDates);
  		for(LocalDate fixingDate : fixingDates) {
  			fixingTimes[i] = modelDcc.getDaycountFraction(referenceDate, fixingDate);
  			fixingValue[i] = indexFixings.get(fixingDate).doubleValue();
  			i++;
  		}
  		CurveInterface curveOfFixings = new Curve(name, referenceDate, InterpolationMethod.PIECEWISE_CONSTANT_RIGHTPOINT, ExtrapolationMethod.CONSTANT, InterpolationEntity.VALUE, fixingTimes, fixingValue);
  
  		/*
  		 * Create a curve modeling the seasonality
  		 */
  		CurveInterface seasonCurve = null;
  		if(seasonalityAdjustments != null && seasonalityAdjustments.size() > 0 && seasonalAveragingNumberOfYears == null) {
  			String[] monthList = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december" };
  			double[] seasonTimes = new double[12];
  			double[] seasonValue = new double[12];
  			double seasonValueCummulated = 1.0;
  			for(int j=0; j<12; j++) {
  				seasonValueCummulated *= Math.exp(seasonalityAdjustments.get(monthList[j]));
  				seasonTimes[j] = j/12.0;
  				seasonValue[j] = seasonValueCummulated;
  			}
  			seasonCurve = new SeasonalCurve(name + "-seasonal", referenceDate,new Curve(name + "-seasonal-base", referenceDate, InterpolationMethod.PIECEWISE_CONSTANT_LEFTPOINT, ExtrapolationMethod.CONSTANT, InterpolationEntity.VALUE, seasonTimes, seasonValue));
  		}
  		else if(seasonalAveragingNumberOfYears != null && seasonalityAdjustments == null) {
  			seasonCurve = new SeasonalCurve(name + "-seasonal", referenceDate, indexFixings, seasonalAveragingNumberOfYears);
  		}
  		else if(seasonalAveragingNumberOfYears != null && seasonalityAdjustments != null) {
  			throw new IllegalArgumentException("Specified seasonal factors and seasonal averaging at the same time.");
  		}
  
  		/*
  		 * Create the index curve from annualized zero rates.
  		 */
  		double[] times = new double[annualizedZeroRates.size()];
  		double[] givenDiscountFactors = new double[annualizedZeroRates.size()];
  
  
  		int index = 0;
  		List<LocalDate> dates = new ArrayList<LocalDate>(annualizedZeroRates.keySet());
  		Collections.sort(dates);
  		for(LocalDate forwardDate : dates) {
  			LocalDate cpiDate = forwardDate;
  			if(forwardsFixingType != null && forwardsFixingLag != null) {
  				if(forwardsFixingType.equals("endOfMonth")) {
  					cpiDate = cpiDate.withDayOfMonth(1);
  					if(forwardsFixingLag.equals("-2M")) {
  						cpiDate = cpiDate.minusMonths(2);
  					} else if(forwardsFixingLag.equals("-3M")) {
  						cpiDate = cpiDate.minusMonths(3);
  					} else if(forwardsFixingLag.equals("-4M")) {
  						cpiDate = cpiDate.minusMonths(4);
  					} else {
  						throw new IllegalArgumentException("Unsupported fixing type for forward in curve " + name);
  					}
  					cpiDate = cpiDate.withDayOfMonth(cpiDate.lengthOfMonth());
  				}
  				else {
  					throw new IllegalArgumentException("Unsupported fixing type for forward in curve " + name);
  				}
  			}
  			times[index] = modelDcc.getDaycountFraction(referenceDate, cpiDate);
  			double rate = annualizedZeroRates.get(forwardDate).doubleValue();
  			givenDiscountFactors[index] = 1.0/Math.pow(1 + rate, (new DayCountConvention_30E_360()).getDaycountFraction(referenceDate, forwardDate));
  			index++;
  		}
  		DiscountCurveInterface discountCurve = DiscountCurve.createDiscountCurveFromDiscountFactors(name, referenceDate, times, givenDiscountFactors, null, InterpolationMethod.LINEAR, ExtrapolationMethod.CONSTANT, InterpolationEntity.LOG_OF_VALUE);
  
  		LocalDate baseDate = referenceDate;
  		if(forwardsFixingType != null && forwardsFixingType.equals("endOfMonth") && forwardsFixingLag != null) {
  			baseDate = baseDate.withDayOfMonth(1);
  			if(forwardsFixingLag.equals("-2M")) {
  				baseDate = baseDate.minusMonths(2);
  			} else if(forwardsFixingLag.equals("-3M")) {
  				baseDate = baseDate.minusMonths(3);
  			} else if(forwardsFixingLag.equals("-4M")) {
  				baseDate = baseDate.minusMonths(4);
  			} else {
  				throw new IllegalArgumentException("Unsupported fixing type for forward in curve " + name);
  			}
  			baseDate = baseDate.withDayOfMonth(baseDate.lengthOfMonth());
  		}
  
  		/*
  		 * Index base value
  		 */
  		Double baseValue	= indexFixings.get(baseDate);
  		if(baseValue == null) {
  			throw new IllegalArgumentException("Curve " + name + " has missing index value for base date " + baseDate);
  		}
  		double baseTime		= FloatingpointDate.getFloatingPointDateFromDate(referenceDate, baseDate);
  
  		/*
  		 * Combine all three curves.
  		 */
  		double currentProjectedIndexValue = baseValue;
  		if(seasonCurve != null) {
  			// Rescale initial value of with seasonality
  			currentProjectedIndexValue /= seasonCurve.getValue(baseTime);
  
  			CurveInterface indexCurve = new IndexCurveFromDiscountCurve(name, currentProjectedIndexValue, discountCurve);
  			CurveInterface indexCurveWithSeason = new CurveFromProductOfCurves(name, referenceDate, new CurveInterface[] { indexCurve, seasonCurve });
  			PiecewiseCurve indexCurveWithFixing = new PiecewiseCurve(indexCurveWithSeason, curveOfFixings, -Double.MAX_VALUE, fixingTimes[fixingTimes.length-1] + 1.0/365.0);
  			return indexCurveWithFixing;
  		}
  		else {
  			CurveInterface indexCurve = new IndexCurveFromDiscountCurve(name, currentProjectedIndexValue, discountCurve);
  			PiecewiseCurve indexCurveWithFixing = new PiecewiseCurve(indexCurve, curveOfFixings, -Double.MAX_VALUE, fixingTimes[fixingTimes.length-1]);
  			return indexCurveWithFixing;
  		}
  	}