<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def start_end(data, num_start=250, num_end=100, full_output=False):
 """ Gate out first and last events. Parameters data : FCSData or numpy array NxD flow cytometry data where N is the number of events and D is the number of parameters (aka channels). num_start, num_end : int, optional Number of events to gate out from beginning and end of `data`. Ignored if less than 0. full_output : bool, optional Flag specifying to return additional outputs. If true, the outputs are given as a namedtuple. Returns ------- gated_data : FCSData or numpy array Gated flow cytometry data of the same format as `data`. mask : numpy array of bool, only if ``full_output==True`` Boolean gate mask used to gate data such that ``gated_data = data[mask]``. Raises ------ ValueError If the number of events to discard is greater than the total number of events in `data`. """


    if num_start < 0:
        num_start = 0
    if num_end < 0:
        num_end = 0

    if data.shape[0] < (num_start + num_end):
        raise ValueError('Number of events to discard greater than total' + 
            ' number of events.')
    
    mask = np.ones(shape=data.shape[0],dtype=bool)
    mask[:num_start] = False
    if num_end > 0:
        # catch the edge case where `num_end=0` causes mask[-num_end:] to mask
        # off all events
        mask[-num_end:] = False
    gated_data = data[mask]

    if full_output:
        StartEndGateOutput = collections.namedtuple(
            'StartEndGateOutput',
            ['gated_data', 'mask'])
        return StartEndGateOutput(gated_data=gated_data, mask=mask)
    else:
        return gated_data