<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def generate_stimfunction(onsets, event_durations, total_time, weights=[1], timing_file=None, temporal_resolution=100.0, ):
 """Return the function for the timecourse events When do stimuli onset, how long for and to what extent should you resolve the fMRI time course. There are two ways to create this, either by supplying onset, duration and weight information or by supplying a timing file (in the three column format used by FSL). Parameters onsets : list, int What are the timestamps (in s) for when an event you want to generate onsets? event_durations : list, int What are the durations (in s) of the events you want to generate? If there is only one value then this will be assigned to all onsets total_time : int How long (in s) is the experiment in total. weights : list, float What is the weight for each event (how high is the box car)? If there is only one value then this will be assigned to all onsets timing_file : string The filename (with path) to a three column timing file (FSL) to make the events. Still requires total_time to work temporal_resolution : float How many elements per second are you modeling for the timecourse. This is useful when you want to model the HRF at an arbitrarily high resolution (and then downsample to your TR later). Returns stim_function : 1 by timepoint array, float The time course of stimulus evoked activation. This has a temporal resolution of temporal resolution / 1.0 elements per second """


    # If the timing file is supplied then use this to acquire the
    if timing_file is not None:

        # Read in text file line by line
        with open(timing_file) as f:
            text = f.readlines()  # Pull out file as a an array

        # Preset
        onsets = list()
        event_durations = list()
        weights = list()

        # Pull out the onsets, weights and durations, set as a float
        for line in text:
            onset, duration, weight = line.strip().split()

            # Check if the onset is more precise than the temporal resolution
            upsampled_onset = float(onset) * temporal_resolution

            # Because of float precision, the upsampled values might
            # not round as expected .
            # E.g. float('1.001') * 1000 = 1000.99
            if np.allclose(upsampled_onset, np.round(upsampled_onset)) == 0:
                warning = 'Your onset: ' + str(onset) + ' has more decimal ' \
                                                        'points than the ' \
                                                        'specified temporal ' \
                                                        'resolution can ' \
                                                        'resolve. This means' \
                                                        ' that events might' \
                                                        ' be missed. ' \
                                                        'Consider increasing' \
                                                        ' the temporal ' \
                                                        'resolution.'
                logger.warning(warning)

            onsets.append(float(onset))
            event_durations.append(float(duration))
            weights.append(float(weight))

    # If only one duration is supplied then duplicate it for the length of
    # the onset variable
    if len(event_durations) == 1:
        event_durations = event_durations * len(onsets)

    if len(weights) == 1:
        weights = weights * len(onsets)

    # Check files
    if np.max(onsets) > total_time:
        raise ValueError('Onsets outside of range of total time.')

    # Generate the time course as empty, each element is a millisecond by
    # default
    stimfunction = np.zeros((int(round(total_time * temporal_resolution)), 1))

    # Cycle through the onsets
    for onset_counter in list(range(len(onsets))):
        # Adjust for the resolution
        onset_idx = int(np.floor(onsets[onset_counter] * temporal_resolution))

        # Adjust for the resolution
        offset_idx = int(np.floor((onsets[onset_counter] + event_durations[
            onset_counter]) * temporal_resolution))

        # Store the weights
        stimfunction[onset_idx:offset_idx, 0] = [weights[onset_counter]]

    return stimfunction