Returns a list of repeating dates from the inputted start date based on the
    given mode.  If an repeatUntil date is supplied, then the results will be
    capped once the last date is reached, otherwise, the maximum number of
    results will be returned.
    
    :param      first       | <datetime.date>
                mode        | <RepeatMode>
                step        | <int> | value must be greater than 1
                flags       | <RepeatFlags>
                startAt     | <datetime.date> || None
                repeatUntil | <datetime.date> || None
                maximum     | <int> || None
    
    :return     [<datetime.date>, ..]

def repeating(first,
              mode=RepeatMode.Weekly,
              step=1,
              flags=0,
              startAt=None,
              repeatUntil=None,
              maximum=None):
    """
    Returns a list of repeating dates from the inputted start date based on the
    given mode.  If an repeatUntil date is supplied, then the results will be
    capped once the last date is reached, otherwise, the maximum number of
    results will be returned.
    
    :param      first       | <datetime.date>
                mode        | <RepeatMode>
                step        | <int> | value must be greater than 1
                flags       | <RepeatFlags>
                startAt     | <datetime.date> || None
                repeatUntil | <datetime.date> || None
                maximum     | <int> || None
    
    :return     [<datetime.date>, ..]
    """
    if repeatUntil is None and maximum is None:
        maximum = 100

    # calculate the dates
    step = max(1, step)
    output = []

    # create the start at information
    if startAt is not None and first < startAt:
        if mode == RepeatMode.Monthly:
            curr = datetime.date(startAt.year, startAt.month, first.day)
        elif mode == RepeatMode.Yearly:
            curr = datetime.date(startAt.year, first.month, first.day)
        else:
            curr = first
    else:
        curr = first

    if curr < first:
        curr = first

    # determine if any days are flagged
    any_days = 0
    for value in DaysOfWeek.values():
        any_days |= value

    # repeat on a daily basis
    while True:
        # increment daily
        if mode == RepeatMode.Weekly:
            # repeat for specific days
            if flags & any_days:
                start = curr + datetime.timedelta(days=1 - curr.isoweekday())
                exit_loop = False

                for i in range(7):
                    day = start + datetime.timedelta(days=i)

                    if day < first:
                        continue

                    elif repeatUntil is not None and repeatUntil < day:
                        exit_loop = True
                        break

                    flag = DaysOfWeek[day.isoweekday()]

                    # skip this day of the week when repeating
                    if not (flags & flag):
                        continue

                    if startAt is None or startAt <= day:
                        output.append(day)

                if exit_loop:
                    break

            else:
                if repeatUntil is not None and repeatUntil < curr:
                    break

                if startAt is None or startAt <= curr:
                    output.append(curr)

            curr = curr + datetime.timedelta(days=7 * step)

        # break when the end first is hit
        if repeatUntil is not None and repeatUntil < curr:
            break

        # break when the maximum is hit
        elif maximum is not None and len(output) == maximum:
            break

        # increment weekly
        elif mode == RepeatMode.Weekly:
            if startAt is None or startAt <= curr:
                output.append(curr)

            curr = curr + datetime.timedelta(days=step * 7)

        # increment monthly
        elif mode == RepeatMode.Monthly:
            if startAt is None or startAt <= curr:
                output.append(curr)

            # approximate the delta
            curr = addMonths(curr, step)

            # check to see if we're repeating on the day of the week in
            # the month, or the actual day of the month
            if (flags & RepeatFlags.DayOfTheWeek) != 0:
                shift = curr.isodayofweek() - first.isoweekday()
                curr = curr + datetime.timedelta(days=shift)

        # increment yearly
        elif mode == RepeatMode.Yearly:
            if startAt is None or startAt <= curr:
                output.append(curr)

            curr = addYears(curr, step)

    return output