def client_detect(self, client, starttime, endtime, threshold,<EOL>threshold_type, trig_int, plotvar, min_gap=None,<EOL>daylong=False, parallel_process=True, xcorr_func=None,<EOL>concurrency=None, cores=None, ignore_length=False,<EOL>group_size=None, debug=<NUM_LIT:0>, return_stream=False,<EOL>full_peaks=False, save_progress=False,<EOL>process_cores=None, retries=<NUM_LIT:3>, **kwargs):
party = Party()<EOL>buff = <NUM_LIT><EOL>data_length = max([t.process_length for t in self.templates])<EOL>pad = <NUM_LIT:0><EOL>for template in self.templates:<EOL><INDENT>max_delay = (template.st.sort(['<STR_LIT>'])[-<NUM_LIT:1>].stats.starttime -<EOL>template.st.sort(['<STR_LIT>'])[<NUM_LIT:0>].stats.starttime)<EOL>if max_delay > pad:<EOL><INDENT>pad = max_delay<EOL><DEDENT><DEDENT>download_groups = int(endtime - starttime) / data_length<EOL>template_channel_ids = []<EOL>for template in self.templates:<EOL><INDENT>for tr in template.st:<EOL><INDENT>if tr.stats.network not in [None, '<STR_LIT>']:<EOL><INDENT>chan_id = (tr.stats.network,)<EOL><DEDENT>else:<EOL><INDENT>chan_id = ('<STR_LIT:*>',)<EOL><DEDENT>if tr.stats.station not in [None, '<STR_LIT>']:<EOL><INDENT>chan_id += (tr.stats.station,)<EOL><DEDENT>else:<EOL><INDENT>chan_id += ('<STR_LIT:*>',)<EOL><DEDENT>if tr.stats.location not in [None, '<STR_LIT>']:<EOL><INDENT>chan_id += (tr.stats.location,)<EOL><DEDENT>else:<EOL><INDENT>chan_id += ('<STR_LIT:*>',)<EOL><DEDENT>if tr.stats.channel not in [None, '<STR_LIT>']:<EOL><INDENT>if len(tr.stats.channel) == <NUM_LIT:2>:<EOL><INDENT>chan_id += (tr.stats.channel[<NUM_LIT:0>] + '<STR_LIT:?>' +<EOL>tr.stats.channel[-<NUM_LIT:1>],)<EOL><DEDENT>else:<EOL><INDENT>chan_id += (tr.stats.channel,)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>chan_id += ('<STR_LIT:*>',)<EOL><DEDENT>template_channel_ids.append(chan_id)<EOL><DEDENT><DEDENT>template_channel_ids = list(set(template_channel_ids))<EOL>if return_stream:<EOL><INDENT>stream = Stream()<EOL><DEDENT>if int(download_groups) < download_groups:<EOL><INDENT>download_groups = int(download_groups) + <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>download_groups = int(download_groups)<EOL><DEDENT>for i in range(download_groups):<EOL><INDENT>bulk_info = []<EOL>for chan_id in template_channel_ids:<EOL><INDENT>bulk_info.append((<EOL>chan_id[<NUM_LIT:0>], chan_id[<NUM_LIT:1>], chan_id[<NUM_LIT:2>], chan_id[<NUM_LIT:3>],<EOL>starttime + (i * data_length) - (pad + buff),<EOL>starttime + ((i + <NUM_LIT:1>) * data_length) + (pad + buff)))<EOL><DEDENT>for retry_attempt in range(retries):<EOL><INDENT>try:<EOL><INDENT>st = client.get_waveforms_bulk(bulk_info)<EOL>break<EOL><DEDENT>except Exception as e:<EOL><INDENT>print(e)<EOL>continue<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise MatchFilterError(<EOL>"<STR_LIT>".format(<EOL>retries))<EOL><DEDENT>if min_gap:<EOL><INDENT>gaps = st.get_gaps(min_gap=min_gap)<EOL>if len(gaps) > <NUM_LIT:0>:<EOL><INDENT>print("<STR_LIT>")<EOL>st.merge()<EOL>gappy_channels = list(<EOL>set([(gap[<NUM_LIT:0>], gap[<NUM_LIT:1>], gap[<NUM_LIT:2>], gap[<NUM_LIT:3>])<EOL>for gap in gaps]))<EOL>_st = Stream()<EOL>for tr in st:<EOL><INDENT>tr_stats = (tr.stats.network, tr.stats.station,<EOL>tr.stats.location, tr.stats.channel)<EOL>if tr_stats in gappy_channels:<EOL><INDENT>print("<STR_LIT>" % str(tr))<EOL><DEDENT>else:<EOL><INDENT>_st += tr<EOL><DEDENT><DEDENT>st = _st<EOL>st.split()<EOL><DEDENT><DEDENT>st.merge()<EOL>st.trim(starttime=starttime + (i * data_length) - pad,<EOL>endtime=starttime + ((i + <NUM_LIT:1>) * data_length) + pad)<EOL>for tr in st:<EOL><INDENT>if not _check_daylong(tr):<EOL><INDENT>st.remove(tr)<EOL>print("<STR_LIT>"<EOL>"<STR_LIT>".format(tr.id))<EOL><DEDENT><DEDENT>for tr in st:<EOL><INDENT>if tr.stats.endtime - tr.stats.starttime <<NUM_LIT> * data_length:<EOL><INDENT>st.remove(tr)<EOL>print("<STR_LIT>"<EOL>"<STR_LIT>".format(tr.id))<EOL><DEDENT><DEDENT>if return_stream:<EOL><INDENT>stream += st<EOL><DEDENT>try:<EOL><INDENT>party += self.detect(<EOL>stream=st, threshold=threshold,<EOL>threshold_type=threshold_type, trig_int=trig_int,<EOL>plotvar=plotvar, daylong=daylong,<EOL>parallel_process=parallel_process, xcorr_func=xcorr_func,<EOL>concurrency=concurrency, cores=cores,<EOL>ignore_length=ignore_length, group_size=group_size,<EOL>overlap=None, debug=debug, full_peaks=full_peaks,<EOL>process_cores=process_cores, **kwargs)<EOL>if save_progress:<EOL><INDENT>party.write("<STR_LIT>")<EOL><DEDENT><DEDENT>except Exception as e:<EOL><INDENT>print('<STR_LIT>')<EOL>print('<STR_LIT>' % str(e))<EOL>if return_stream:<EOL><INDENT>return party, stream<EOL><DEDENT>else:<EOL><INDENT>return party<EOL><DEDENT><DEDENT><DEDENT>for family in party:<EOL><INDENT>if family is not None:<EOL><INDENT>family.detections = family._uniq().detections<EOL><DEDENT><DEDENT>if return_stream:<EOL><INDENT>return party, stream<EOL><DEDENT>else:<EOL><INDENT>return party<EOL><DEDENT>
Detect using a Tribe of templates within a continuous stream.

:type client: `obspy.clients.*.Client`
:param client: Any obspy client with a dataselect service.
:type starttime: :class:`obspy.core.UTCDateTime`
:param starttime: Start-time for detections.
:type endtime: :class:`obspy.core.UTCDateTime`
:param endtime: End-time for detections
:type threshold: float
:param threshold:
    Threshold level, if using `threshold_type='MAD'` then this will be
    the multiple of the median absolute deviation.
:type threshold_type: str
:param threshold_type:
    The type of threshold to be used, can be MAD, absolute or
    av_chan_corr.  See Note on thresholding below.
:type trig_int: float
:param trig_int:
    Minimum gap between detections in seconds. If multiple detections
    occur within trig_int of one-another, the one with the highest
    cross-correlation sum will be selected.
:type plotvar: bool
:param plotvar:
    Turn plotting on or off, see warning about plotting below
:type min_gap: float
:param min_gap:
    Minimum gap allowed in data - use to remove traces with known
    issues
:type daylong: bool
:param daylong:
    Set to True to use the
    :func:`eqcorrscan.utils.pre_processing.dayproc` routine, which
    preforms additional checks and is more efficient for day-long data
    over other methods.
:type parallel_process: bool
:param parallel_process:
:type xcorr_func: str or callable
:param xcorr_func:
    A str of a registered xcorr function or a callable for implementing
    a custom xcorr function. For more information see:
    :func:`eqcorrscan.utils.correlate.register_array_xcorr`
:type concurrency: str
:param concurrency:
    The type of concurrency to apply to the xcorr function. Options are
    'multithread', 'multiprocess', 'concurrent'. For more details see
    :func:`eqcorrscan.utils.correlate.get_stream_xcorr`
:type cores: int
:param cores: Number of workers for processing and detection.
:type ignore_length: bool
:param ignore_length:
    If using daylong=True, then dayproc will try check that the data
    are there for at least 80% of the day, if you don't want this check
    (which will raise an error if too much data are missing) then set
    ignore_length=True.  This is not recommended!
:type group_size: int
:param group_size:
    Maximum number of templates to run at once, use to reduce memory
    consumption, if unset will use all templates.
:type full_peaks: bool
:param full_peaks: See `eqcorrscan.utils.findpeaks.find_peaks2_short`
:type save_progress: bool
:param save_progress:
    Whether to save the resulting party at every data step or not.
    Useful for long-running processes.
:type process_cores: int
:param process_cores:
    Number of processes to use for pre-processing (if different to
    `cores`).
:type debug: int
:param debug:
    Debug level from 0-5 where five is more output, for debug levels
    4 and 5, detections will not be computed in parallel.
:type return_stream: bool
:param return_stream:
    Whether to also output the stream downloaded, useful if you plan
    to use the stream for something else, e.g. lag_calc.
:type retries: int
:param retries:
    Number of attempts allowed for downloading - allows for transient
    server issues.

:return:
    :class:`eqcorrscan.core.match_filter.Party` of Families of
    detections.

.. Note::
    Detections are not corrected for `pre-pick`, the
    detection.detect_time corresponds to the beginning of the earliest
    template channel at detection.

.. warning::
    Picks included in the output Party.get_catalog() will not be
    corrected for pre-picks in the template.

.. Note::
    Ensures that data overlap between loops, which will lead to no
    missed detections at data start-stop points (see note for
    :meth:`eqcorrscan.core.match_filter.Tribe.detect` method).
    This will result in end-time not being strictly
    honoured, so detections may occur after the end-time set.  This is
    because data must be run in the correct process-length.

.. warning::
    Plotting within the match-filter routine uses the Agg backend
    with interactive plotting turned off.  This is because the function
    is designed to work in bulk.  If you wish to turn interactive
    plotting on you must import matplotlib in your script first,
    when you then import match_filter you will get the warning that
    this call to matplotlib has no effect, which will mean that
    match_filter has not changed the plotting behaviour.

.. note::
    **Thresholding:**

    **MAD** threshold is calculated as the:

    .. math::

        threshold {\\times} (median(abs(cccsum)))

    where :math:`cccsum` is the cross-correlation sum for a given
    template.

    **absolute** threshold is a true absolute threshold based on the
    cccsum value.

    **av_chan_corr** is based on the mean values of single-channel
    cross-correlations assuming all data are present as required for
    the template, e.g:

    .. math::

        av\_chan\_corr\_thresh=threshold \\times (cccsum /
        len(template))

    where :math:`template` is a single template from the input and the
    length is the number of channels within this template.