(skeleton_id, tree, reviews, max_gap)
return epochs
Split the arbor into one or more review epochs.
    An epoch is defined as a continuous range of time containing gaps
    of up to max_gap (e.g. 3 days) and fully reviewed by the same reviewer.
    Treenodes reviewed within an epoch may not form a coherent subset of the arbor,
    given that different subsets of the arbor may have been joined at a later time.
Split the arbor into one or more review epochs.
    An epoch is defined as a continuous range of time containing gaps
    of up to max_gap (e.g. 3 days) and fully reviewed by the same reviewer.
    Treenodes reviewed within an epoch may not form a coherent subset of the arbor,
    given that different subsets of the arbor may have been joined at a later time.
Split the arbor into one or more review epochs . An epoch is defined as a continuous range of time containing gaps of up to max_gap ( e . g . 3 days ) and fully reviewed by the same reviewer . Treenodes reviewed within an epoch may not form a coherent subset of the arbor given that different subsets of the arbor may have been joined at a later time .
def _split_into_epochs(skeleton_id, tree, reviews, max_gap) -> List:
    """ Split the arbor into one or more review epochs.
    An epoch is defined as a continuous range of time containing gaps
    of up to max_gap (e.g. 3 days) and fully reviewed by the same reviewer.
    Treenodes reviewed within an epoch may not form a coherent subset of the arbor,
    given that different subsets of the arbor may have been joined at a later time. """

    # Sort nodes by date of most recent review (first in list)
    def get_review_time(e):
        return reviews[e[0]][0].review_time
    nodes = sorted(tree.nodes(data=True), key=get_review_time)

    # Grab the oldest node
    oldest = nodes[0]
    last_id = oldest[0] # id of first node
    last = oldest[1] # props of first node

    # First epoch contains the oldest node
    epoch = [last_id]

    # Most recent review of first node
    last_review = reviews[last_id][0]

    # Collect epochs
    epochs = [(last_review.reviewer_id, epoch)]

    # Iterate from second-oldest node forward in time
    for node, props in nodes:
        # Most recent review of current node
        node_review = reviews[node][0]
        # Add to current epoch if same reviewer and we are within max_gap
        if node_review.reviewer_id == last_review.reviewer_id and \
                node_review.review_time - last_review.review_time < max_gap:
            epoch.append(node)
        else:
            # Start new epoch
            epoch = [node]
            epochs.append((node_review.reviewer_id, epoch))

        last_review = reviews[node][0]

    return epochs
def _split_into_epochs ( skeleton_id , tree , reviews , max_gap ) -> List : # Sort nodes by date of most recent review (first in list) def get_review_time ( e ) : return reviews [ e [ 0 ] ] [ 0 ] . review_time nodes = sorted ( tree . nodes ( data = True ) , key = get_review_time ) # Grab the oldest node oldest = nodes [ 0 ] last_id = oldest [ 0 ] # id of first node last = oldest [ 1 ] # props of first node # First epoch contains the oldest node epoch = [ last_id ] # Most recent review of first node last_review = reviews [ last_id ] [ 0 ] # Collect epochs epochs = [ ( last_review . reviewer_id , epoch ) ] # Iterate from second-oldest node forward in time for node , props in nodes : # Most recent review of current node node_review = reviews [ node ] [ 0 ] # Add to current epoch if same reviewer and we are within max_gap if node_review . reviewer_id == last_review . reviewer_id and node_review . review_time - last_review . review_time < max_gap : epoch . append ( node ) else : # Start new epoch epoch = [ node ] epochs . append ( ( node_review . reviewer_id , epoch ) ) last_review = reviews [ node ] [ 0 ] return epochs