<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def compute_followup_snr_series(data_reader, htilde, trig_time, duration=0.095, check_state=True, coinc_window=0.05):
 """Given a StrainBuffer, a template frequency series and a trigger time, compute a portion of the SNR time series centered on the trigger for its rapid sky localization and followup. If the trigger time is too close to the boundary of the valid data segment the SNR series is calculated anyway and might be slightly contaminated by filter and wrap-around effects. For reasonable durations this will only affect a small fraction of the triggers and probably in a negligible way. Parameters data_reader : StrainBuffer The StrainBuffer object to read strain data from. htilde : FrequencySeries The frequency series containing the template waveform. trig_time : {float, lal.LIGOTimeGPS} The trigger time. duration : float (optional) Duration of the computed SNR series in seconds. If omitted, it defaults to twice the Earth light travel time plus 10 ms of timing uncertainty. check_state : boolean If True, and the detector was offline or flagged for bad data quality at any point during the inspiral, then return (None, None) instead. coinc_window : float (optional) Maximum possible time between coincident triggers at different detectors. This is needed to properly determine data padding. Returns ------- snr : TimeSeries The portion of SNR around the trigger. None if the detector is offline or has bad data quality, and check_state is True. """

    if check_state:
        # was the detector observing for the full amount of involved data?
        state_start_time = trig_time - duration / 2 - htilde.length_in_time
        state_end_time = trig_time + duration / 2
        state_duration = state_end_time - state_start_time
        if data_reader.state is not None:
            if not data_reader.state.is_extent_valid(state_start_time,
                                                     state_duration):
                return None

        # was the data quality ok for the full amount of involved data?
        dq_start_time = state_start_time - data_reader.dq_padding
        dq_duration = state_duration + 2 * data_reader.dq_padding
        if data_reader.dq is not None:
            if not data_reader.dq.is_extent_valid(dq_start_time, dq_duration):
                return None

    stilde = data_reader.overwhitened_data(htilde.delta_f)
    snr, _, norm = matched_filter_core(htilde, stilde,
                                          h_norm=htilde.sigmasq(stilde.psd))

    valid_end = int(len(snr) - data_reader.trim_padding)
    valid_start = int(valid_end - data_reader.blocksize * snr.sample_rate)

    half_dur_samples = int(snr.sample_rate * duration / 2)
    coinc_samples = int(snr.sample_rate * coinc_window)
    valid_start -= half_dur_samples + coinc_samples
    valid_end += half_dur_samples
    if valid_start < 0 or valid_end > len(snr)-1:
        raise ValueError(('Requested SNR duration ({0} s)'
                          ' too long').format(duration))

    # Onsource slice for Bayestar followup
    onsource_idx = float(trig_time - snr.start_time) * snr.sample_rate
    onsource_idx = int(round(onsource_idx))
    onsource_slice = slice(onsource_idx - half_dur_samples,
                           onsource_idx + half_dur_samples + 1)
    return snr[onsource_slice] * norm