def parse_controls(control_path, control_ids, relationship_ids, framework_id):
    """parse the NIST800-53 revision 4 controls and return a STIX bundle
    :param control_path: the filepath to the controls TSV file
    :param control_ids: is a dict of format {control_name: stixID} which maps
                        control names (e.g AC-1) to desired STIX IDs
    :param relationship_ids: is a dict of format {relationship-source-id---relationship-target-id: relationship-id},
                        same general purpose as control_ids
    :param framework_id: the framework id - e.g., "NIST 800-53 Revision 4".
    """

    tqdmformat = "{desc}: {percentage:3.0f}% |{bar}| {elapsed}<{remaining}{postfix}"

    # controls_df = pd.read_csv(control_path, sep="\t", keep_default_na=False, header=0)
    with open(control_path, "r") as controlsfile:
        controls_data = controlsfile.read().split("\n")
    columns = controls_data[0].split("\t")
    controls_data = controls_data[1:]
    controls = []

    current_control = []
    for row in tqdm(controls_data, desc="parsing NIST 800-53 revision 5", bar_format=tqdmformat):
        row = row.strip('"')  # remove leading and trailing quotation marks
        returned_type = row_type(row)
        if returned_type == "control" or returned_type == "control_enhancement":
            if current_control:  # otherwise first row creates an empty control
                controls.append(Control("\n".join(current_control), columns, control_ids))  # finish previous control
            current_control = [row]  # start a new control
        else:
            current_control.append(row)  # append line to current control

    # finish last control
    controls.append(Control("\n".join(current_control), columns, control_ids))

    # parse controls into stix
    stix_controls = []
    for control in tqdm(controls, desc="creating controls", bar_format=tqdmformat):
        stix_controls.append(control.to_stix(framework_id))

    # parse control relationships into stix
    relationships = []
    for control in tqdm(list(filter(lambda c: control.parent_id or len(control.related) > 0, controls)),
                        desc="creating control relationships",
                        bar_format=tqdmformat):
        if control.parent_id:
            # build subcontrol-of relationships
            target_id = control_ids[control.parent_id]
            source_id = control.stix_id
            joined_id = f"{source_id}---{target_id}"
            rel_type = "subcontrol-of"
            subcontrols_refs = relationship_ids.get(rel_type, {})

            relationships.append(Relationship(
                id=subcontrols_refs[joined_id] if joined_id in subcontrols_refs else None,
                source_ref=source_id,
                target_ref=target_id,
                relationship_type=rel_type
            ))

        if len(control.related) > 0:
            # build related-to relationships
            for related_id in control.related:
                if related_id not in control_ids:
                    continue  # sometimes related doesn't refer to a control but rather an appendix section
                source_id = control.stix_id
                target_id = control_ids[related_id]
                joined_id = f"{source_id}---{target_id}"
                rel_type = "related-to"
                related_refs = relationship_ids.get(rel_type, {})

                relationships.append(Relationship(
                    id=related_refs[joined_id] if joined_id in related_refs else None,
                    source_ref=source_id,
                    target_ref=target_id,
                    relationship_type=rel_type
                ))

    return Bundle(*itertools.chain(stix_controls, relationships))
parse the NIST800-53 revision 4 controls and return a STIX bundle
    :param control_path: the filepath to the controls TSV file
    :param control_ids: is a dict of format {control_name: stixID} which maps
                        control names (e.g AC-1) to desired STIX IDs
    :param relationship_ids: is a dict of format {relationship-source-id---relationship-target-id: relationship-id},
                        same general purpose as control_ids
    :param framework_id: the framework id - e.g., "NIST 800-53 Revision 4".
    
src/parse_r5_controls.py