def METHOD_NAME(protocol, pipette, well, heights,
                      aspirate=None, dispense=None,
                      on_pre_submerge=None, on_post_emerge=None,
                      inspect=False, retract=0.0, full_dispense=True):
    assert (aspirate is not None or dispense is not None),\
        'must either aspirate or dispense'
    assert (aspirate is None or dispense is None),\
        'cannot both aspirate and dispense'
    if inspect:
        input('Ready to inspect positions. Press ENTER when ready')
    pipette.move_to(well.top(retract))
    if inspect:
        input('Move to the TOP of the well')
    if aspirate:
        # NOTE: this MUST happen before the .move_to()
        #       because the API automatically moves the pipette
        #       to well.top() before beginning the .aspirate()
        pipette.aspirate(pipette.min_volume)
        pipette.dispense()
    if callable(on_pre_submerge):
        on_pre_submerge()
    if aspirate:
        pipette.aspirate(SUBMERGED_AIR_GAP_VOL[pipette.max_volume])
    # in case (start.above < end.below)
    start_above = max(heights.start.above, heights.end.below)
    pipette.move_to(well.bottom(start_above),
                    force_direct=False)
    if inspect:
        input('Move above START liquid-height')
    submerged_loc = well.bottom(heights.end.below)
    pipette.move_to(submerged_loc, force_direct=True, speed=SUBMERGED_SPEED)
    if inspect:
        input('Move below END liquid-height')
    if aspirate:
        pipette.aspirate(aspirate)
    else:
        pipette.dispense(dispense)
        if full_dispense and pipette.current_volume > 0:
            # temporarily change the dispense volume
            pipette.flow_rate.dispense = SUBMERGED_AIR_GAP_FLOW_RATE[pipette.max_volume]
            pipette.dispense()
            apply_pipette_speeds(pipette)  # back to defaults
    if inspect:
        input('Aspirate/Dispense below END liquid-height')
    protocol.delay(seconds=1)
    pipette.move_to(well.bottom(heights.end.above),
                    force_direct=True, speed=SUBMERGED_SPEED)
    if dispense and full_dispense:
        pipette.blow_out()  # nothing to loose
    if inspect:
        input('Move above END liquid-height')
    pipette.move_to(well.top(retract), force_direct=True)
    if callable(on_post_emerge):
        on_post_emerge()