Join given range groups, collapsing their overlapping ranges. If only one
    group is given, this method will still fix it (sort and collapsing).

    No typecheck is performed, so a valid range group will be any iterable
    (or iterator) containing an (start, end) iterable pair. Result type will
    be defined by group_class parameter (defaults to RangeGroup)

    :param *range_lists: several range groups to join
    :type *range_list: iterable of iterables
    :param group_class: result type, defaults to RangeGroup
    :type group_class: type
    :returns: merged range group
    :rtype: taken from group_class
    :

def merge(*range_lists, **kwargs):
    '''
    Join given range groups, collapsing their overlapping ranges. If only one
    group is given, this method will still fix it (sort and collapsing).

    No typecheck is performed, so a valid range group will be any iterable
    (or iterator) containing an (start, end) iterable pair. Result type will
    be defined by group_class parameter (defaults to RangeGroup)

    :param *range_lists: several range groups to join
    :type *range_list: iterable of iterables
    :param group_class: result type, defaults to RangeGroup
    :type group_class: type
    :returns: merged range group
    :rtype: taken from group_class
    :
    '''
    group_class = kwargs.pop('group_class', RangeGroup)  # FIXME: python2
    range_list = [
        unirange
        for range_list in range_lists
        for unirange in range_list
        ]
    range_list.sort()
    it = iter(range_list)
    slast, elast = last = list(next(it))
    result = [last]
    for start, end in it:
        if start > elast:
            slast, elast = last = [start, end]
            result.append(last)
        elif end > elast:
            last[1] = elast = end
    return group_class(result)