docs: public static Schedule createScheduleFromConventions(
  			LocalDate referenceDate,
  			LocalDate startDate,
  			LocalDate maturityDate,
  			Frequency frequency,
  			DaycountConvention daycountConvention,
  			ShortPeriodConvention shortPeriodConvention,
  			DateRollConvention dateRollConvention,
  			BusinessdayCalendar businessdayCalendar,
  			int	fixingOffsetDays,
  			int	paymentOffsetDays,
  			boolean isUseEndOfMonth
  			)
  	{
  		/*
  		 * Generate periods - note: we do not use any date roll convention
  		 */
  		ArrayList<Period> periods = new ArrayList<>();
  
  		DayCountConvention daycountConventionObject = null;
  		switch (daycountConvention) {
  		case E30_360_ISDA:
  			daycountConventionObject = new DayCountConvention_30E_360_ISDA();
  			break;
  		case E30_360:
  			daycountConventionObject = new DayCountConvention_30E_360();
  			break;
  		case U30_360:
  			daycountConventionObject = new DayCountConvention_30U_360();
  			break;
  		case ACT_360:
  			daycountConventionObject = new DayCountConvention_ACT_360();
  			break;
  		case ACT_365:
  			daycountConventionObject = new DayCountConvention_ACT_365();
  			break;
  		case ACT_ACT_ISDA:
  		case ACT_ACT:
  		default:
  			daycountConventionObject = new DayCountConvention_ACT_ACT_ISDA();
  			break;
  		}
  
  		int periodLengthDays	= 0;
  		int periodLengthWeeks	= 0;
  		int periodLengthMonth	= 0;
  		switch(frequency) {
  		case DAILY:
  			periodLengthDays	= 1;
  			break;
  		case WEEKLY:
  			periodLengthWeeks	= 1;
  			break;
  		case MONTHLY:
  			periodLengthMonth	= 1;
  			break;
  		case QUARTERLY:
  			periodLengthMonth	= 3;
  			break;
  		case SEMIANNUAL:
  			periodLengthMonth	= 6;
  			break;
  		case ANNUAL:
  		default:
  			periodLengthMonth	= 12;
  			break;
  		case TENOR:
  			periodLengthMonth	= 100000;
  			break;
  		}
  
  		// This should not happen.
  		if(periodLengthDays == 0 && periodLengthWeeks == 0 && periodLengthMonth == 0) {
  			throw new IllegalArgumentException("ScheduleFromPeriods generation requires positive period length.");
  		}
  		if(shortPeriodConvention == ShortPeriodConvention.LAST) {
  			/*
  			 * Going forward on periodStartDate, starting with startDate as periodStartDate
  			 */
  			LocalDate periodStartDateUnadjusted	= startDate;
  			LocalDate periodEndDateUnadjusted	= startDate;
  			LocalDate periodStartDate			= businessdayCalendar.getAdjustedDate(periodStartDateUnadjusted, dateRollConvention);
  
  			int periodIndex = 0;
  			while(periodStartDateUnadjusted.isBefore(maturityDate)) {
  				periodIndex++;
  				// The following code only makes calculations on periodEndXxx while the periodStartXxx is only copied and used to check if we terminate
  				// Determine period end
  				if(isUseEndOfMonth && startDate.getDayOfMonth() == startDate.lengthOfMonth()) {
  					periodEndDateUnadjusted = startDate
  							.plusDays(1)
  							.plusDays(periodLengthDays*periodIndex)
  							.plusWeeks(periodLengthWeeks*periodIndex)
  							.plusMonths(periodLengthMonth*periodIndex)
  							.minusDays(1);
  				}
  				else {
  					periodEndDateUnadjusted = startDate
  							.plusDays(periodLengthDays*periodIndex)
  							.plusWeeks(periodLengthWeeks*periodIndex)
  							.plusMonths(periodLengthMonth*periodIndex);
  				}
  				if(periodEndDateUnadjusted.isAfter(maturityDate)) {
  					periodEndDateUnadjusted 	= maturityDate;
  					periodStartDateUnadjusted 	= maturityDate;	// Terminate loop (next periodEndDateUnadjusted)
  				}
  
  				// Adjust period
  				LocalDate periodEndDate		= businessdayCalendar.getAdjustedDate(periodEndDateUnadjusted, dateRollConvention);
  
  				// Skip empty periods
  				if(periodStartDate.compareTo(periodEndDate) == 0) {
  					continue;
  				}
  
  				// Roll fixing date
  				LocalDate fixingDate = businessdayCalendar.getRolledDate(periodStartDate, fixingOffsetDays);
  				// TODO: There might be an additional calendar adjustment of the fixingDate, if the index has its own businessdayCalendar.
  
  				// Roll payment date
  				LocalDate paymentDate = businessdayCalendar.getRolledDate(periodEndDate, paymentOffsetDays);
  				// TODO: There might be an additional calendar adjustment of the paymentDate, if the index has its own businessdayCalendar.
  
  				// Create period
  				periods.add(new Period(fixingDate, paymentDate, periodStartDate, periodEndDate));
  
  				periodStartDate				= periodEndDate;
  				periodStartDateUnadjusted	= periodEndDateUnadjusted;
  			}
  		} else {
  			/*
  			 * Going backward on periodEndDate, starting with maturity as periodEndDate
  			 */
  			LocalDate periodStartDateUnadjusted	= maturityDate;
  			LocalDate periodEndDateUnadjusted	= maturityDate;
  			LocalDate periodEndDate				= businessdayCalendar.getAdjustedDate(periodEndDateUnadjusted, dateRollConvention);
  
  			int periodIndex = 0;
  			while(periodEndDateUnadjusted.isAfter(startDate)) {
  				periodIndex++;
  				// The following code only makes calculations on periodStartXxx while the periodEndXxx is only copied and used to check if we terminate
  				// Determine period start
  				if(isUseEndOfMonth && maturityDate.getDayOfMonth() == maturityDate.lengthOfMonth()) {
  					periodStartDateUnadjusted = maturityDate
  							.plusDays(1)
  							.minusDays(periodLengthDays*periodIndex)
  							.minusWeeks(periodLengthWeeks*periodIndex)
  							.minusMonths(periodLengthMonth*periodIndex)
  							.minusDays(1);
  				}
  				else {
  					periodStartDateUnadjusted = maturityDate
  							.minusDays(periodLengthDays*periodIndex)
  							.minusWeeks(periodLengthWeeks*periodIndex)
  							.minusMonths(periodLengthMonth*periodIndex);
  				}
  
  				if(periodStartDateUnadjusted.isBefore(startDate))	{
  					periodStartDateUnadjusted	= startDate;
  					periodEndDateUnadjusted 	= startDate;	// Terminate loop (next periodEndDateUnadjusted)
  				}
  
  				// Adjust period
  				LocalDate periodStartDate	= businessdayCalendar.getAdjustedDate(periodStartDateUnadjusted, dateRollConvention);
  
  				// Skip empty periods
  				if(periodStartDate.compareTo(periodEndDate) == 0) {
  					continue;
  				}
  
  				// Roll fixing date
  				LocalDate fixingDate = businessdayCalendar.getRolledDate(periodStartDate, fixingOffsetDays);
  				// TODO: There might be an additional calendar adjustment of the fixingDate, if the index has its own businessdayCalendar.
  
  				// Roll payment date
  				LocalDate paymentDate = businessdayCalendar.getRolledDate(periodEndDate, paymentOffsetDays);
  				// TODO: There might be an additional calendar adjustment of the paymentDate, if the index has its own businessdayCalendar.
  
  				// Create period
  				periods.add(0, new Period(fixingDate, paymentDate, periodStartDate, periodEndDate));
  
  				periodEndDate			= periodStartDate;
  				periodEndDateUnadjusted	= periodStartDateUnadjusted;
  			}
  		}
  
  		return new ScheduleFromPeriods(referenceDate, periods, daycountConventionObject);
  	}