def summarize_reduced_data(data):
    """
    Take a list of LMT data sets and return summaries of each relevant key
    """
    totals = {'n': 0, 'sum_bytes_read': 0, 'sum_bytes_write': 0, 'oss_ave':
        -0.0, 'oss_max': -0.0, 'mds_ave': -0.0, 'mds_max': -0.0,
        'missing_ost_read': 0, 'missing_ost_write': 0, 'missing_oss_cpu': 0,
        'missing_mds_cpu': 0, 'num_ost_read': 0, 'num_ost_write': 0,
        'num_oss_cpu': 0, 'num_mds_cpu': 0}
    for timestamp in sorted(data.keys()):
        datum = data[timestamp]
        points_in_bin = datum['indexf'] - datum['index0']
        totals['sum_bytes_read'] += datum['sum_ost_read']
        totals['sum_bytes_write'] += datum['sum_ost_write']
        totals['n'] += points_in_bin
        if 'ave_oss_cpu' in datum:
            totals['oss_ave'] += datum['ave_oss_cpu'] * points_in_bin
        if 'ave_mds_cpu' in datum:
            totals['mds_ave'] += datum['ave_mds_cpu'] * points_in_bin
        if 'max_oss_cpu' in datum:
            if datum['max_oss_cpu'] > totals['oss_max']:
                totals['oss_max'] = datum['max_oss_cpu']
            else:
                totals['oss_max'] = totals['oss_max']
        if 'max_mds_cpu' in datum:
            if datum['max_mds_cpu'] > totals['mds_max']:
                totals['mds_max'] = datum['max_mds_cpu']
            else:
                totals['mds_max'] = totals['mds_max']
        totals['missing_ost_read'] += datum.get('missing_ost_read', 0)
        totals['missing_ost_write'] += datum.get('missing_ost_write', 0)
        totals['missing_oss_cpu'] += datum.get('missing_oss_cpu', 0)
        totals['missing_mds_cpu'] += datum.get('missing_mds_cpu', 0)
        totals['num_ost_read'] += datum.get('num_ost_read', 0)
        totals['num_ost_write'] += datum.get('num_ost_write', 0)
        totals['num_oss_cpu'] += datum.get('num_oss_cpu', 0)
        totals['num_mds_cpu'] += datum.get('num_mds_cpu', 0)
    totals['ave_bytes_read_per_dt'] = totals['sum_bytes_read'] / totals['n']
    totals['ave_bytes_write_per_dt'] = totals['sum_bytes_write'] / totals['n']
    totals['sum_kibs_read'] = totals['sum_bytes_read'] / 1024.0
    totals['sum_kibs_write'] = totals['sum_bytes_write'] / 1024.0
    totals['sum_mibs_read'] = totals['sum_kibs_read'] / 1024.0
    totals['sum_mibs_write'] = totals['sum_kibs_write'] / 1024.0
    totals['sum_gibs_read'] = totals['sum_mibs_read'] / 1024.0
    totals['sum_gibs_write'] = totals['sum_mibs_write'] / 1024.0
    totals['sum_tibs_read'] = totals['sum_gibs_read'] / 1024.0
    totals['sum_tibs_write'] = totals['sum_gibs_write'] / 1024.0
    totals['ave_gibs_read_per_dt'] = totals['sum_gibs_read'] / totals['n']
    totals['ave_gibs_write_per_dt'] = totals['sum_gibs_write'] / totals['n']
    totals['oss_ave'] = totals['oss_ave'] / totals['n']
    totals['mds_ave'] = totals['mds_ave'] / totals['n']
    for base in ['ost_read', 'ost_write', 'oss_cpu', 'mds_cpu']:
        if totals['num_%s' % base] > 0:
            totals['frac_missing_%s' % base] = float(totals['missing_%s' %
                base]) / totals['num_%s' % base]
    totals['ave_tibs_read_per_dt'] = totals['sum_gibs_read'] / totals['n']
    totals['ave_tibs_write_per_dt'] = totals['sum_gibs_write'] / totals['n']
    return totals


def __renumber(dictionary, status):
    """Renumber the values of the dictionary from 0 to n
    """
    count = 0
    ret = dictionary.copy()
    new_values = dict([])
    old_com_2_new_com = {}
    for key in dictionary.keys():
        value = dictionary[key]
        new_value = new_values.get(value, -1)
        if new_value == -1:
            new_values[value] = count
            new_value = count
            count += 1
        ret[key] = new_value
        if value not in old_com_2_new_com:
            old_com_2_new_com[value] = new_value
    temp = dict([])
    for k in set(dictionary.values()):
        com_id = old_com_2_new_com[k]
        temp[com_id] = status.com_attr[k]
    status.com_attr = temp
    return ret, status


def material_slot_add():
    """Add a new material slot

    """
    pass


def methods_of(obj):
    """Get all callable methods of an object that don't start with underscore
    returns a list of tuples of the form (method_name, method).
    """
    result = {}
    for i in dir(obj):
        if callable(getattr(obj, i)) and not i.startswith('_'):
            result[i] = getattr(obj, i)
    return result


def try_key(dictionary, key, default):
    """
    Try to get the value at dict[key]
    :param dictionary: A Python dict
    :param key: A key
    :param default: The value to return if the key doesn't exist
    :return: Either dictionary[key] or default if it doesn't exist.
    """
    try:
        return dictionary[key]
    except KeyError:
        return default


def force_prefix_use(modeladmin, request, queryset):
    """ update selected Metaprops to use CURIE form with registered prefix """
    for obj in queryset.all():
        obj.save()


def crud_url_name(model, action, prefix=None):
    """
    Returns url name for given model and action.
    """
    if prefix is None:
        prefix = ''
    app_label = model._meta.app_label
    model_lower = model.__name__.lower()
    return '%s%s_%s_%s' % (prefix, app_label, model_lower, action)


def shebang_to_require(shebang):
    """Convert shebang to the format of requirement."""
    return shebang.split()[0][2:]


def assess_integrity(vault_path, config_path):
    """
        The vault config file contains a salt. The salt is used to unlock the vault along with the master key.
        By default, config files are created automatically. A new config file will not allow to open an existing vault.
        We are ensuring here that a config file exists if a vault exists.
    """
    import os
    import sys
    if not os.path.isfile(config_path) and os.path.isfile(vault_path):
        print()
        print(
            'It looks like you have a vault setup but your config file is missing.'
            )
        print(
            'The vault cannot be unlocked without a critical piece of information from the config file (the salt).'
            )
        print('Please restore the config file before proceeding.')
        print()
        sys.exit()


def _backward_map(scale):
    """ Provide a mapping from plone scale names to collective.documentviewer
    scale names for convenience. This assures that code can use both naming
    conventions.

    :param scale: The name of a scale
    :type scale: A string
    :return: The corresponding name of the scale as understood by c.dv
    :rtype: string
    """
    if scale == 'thumb':
        return 'small'
    elif scale == 'preview':
        return 'normal'
    elif scale == 'large':
        return 'large'
    if scale not in ('large', 'normal', 'small'):
        scale = 'large'
    return scale


def read_gtdb_representative(metadata_file):
    """Parse GTDB representative from GTDB metadata.

    Parameters
    ----------
    metadata_file : str
        Metadata for all genomes.

    Return
    ------
    dict : d[genome_id] -> True or False
    """
    gtdb_reps = {}
    with open(metadata_file) as f:
        headers = f.readline().strip().split('\t')
        genome_index = headers.index('accession')
        gtdb_representative_index = headers.index('gtdb_representative')
        for line in f:
            line_split = line.strip().split('\t')
            genome_id = line_split[genome_index]
            is_rep = line_split[gtdb_representative_index] == 't'
            gtdb_reps[genome_id] = is_rep
    return gtdb_reps


def locale_date(date):
    """
    Render a date in the current locale date.
    """
    return date.strftime('%-d %B %Y')


@staticmethod
def convertData(data):
    """
        convertDate tries to convert data from an older or newer version of the config
        file to the actual needed one.

        :param      data:   config data as dict
        :return:    data:   config data as dict
        """
    return data


def str_time(seconds):
    """
    Format time in seconds to a three-digit + unit format

    :param seconds: time in seconds
    :return: `str` representation in appropriate unit
    """
    if seconds is None:
        return '---  s'
    if seconds == 0:
        return '0.0  s'
    e_power = 18
    for t_power, prefix in enumerate(u'EPTGMk mμnpfa'):
        power = e_power - t_power * 3
        p_num = seconds / 10 ** power
        if 1000.0 > p_num > 1.0:
            if p_num > 100:
                return '%3.0f %ss' % (p_num, prefix)
            if p_num > 10:
                return '%2.0f. %ss' % (p_num, prefix)
            return '%3.1f %ss' % (p_num, prefix)


@classmethod
def length(cls, dataset):
    """
        Returns the length of the multi-tabular dataset making it appear
        like a single array of concatenated subpaths separated by NaN
        values.
        """
    if not dataset.data:
        return 0
    length = 0
    ds = cls._inner_dataset_template(dataset)
    for d in dataset.data:
        ds.data = d
        length += ds.interface.length(ds)
    return length + len(dataset.data) - 1


def check_charges(q, g):
    """Assert q and g are integers, q is positive, g nonnegative."""
    assert isinstance(q, int) and q > 0, 'q must be a positive integer.'
    assert isinstance(g, int) and g >= -1, 'g must be greater than -1.'


def set_diagonal_matrix(matrix, d):
    """Set diagonal matrix."""
    for j, row in enumerate(matrix):
        for i, x in enumerate(row):
            if i == j:
                matrix[j][i] = d[i]
            else:
                matrix[j][i] = x
    return matrix


def get_ns(tag):
    """
        Extract namespace.

        This function is opposite to get_local_name, in that
        it returns the first part of the tag: the namespace.

        Parameters
        ----------
        tag : str
            Tag to process.
    """
    p_open = tag.find('{')
    p_close = tag.find('}')
    if p_open != -1 and p_close != -1:
        return tag[p_open + 1:p_close]
    else:
        return ''


def camstop_com():
    """Stop the cam scan.

    Return a list with parts for the cam command.
    """
    return [('cmd', 'stopcamscan')]


@staticmethod
def add_report_option(add_option):
    """
        Add an option to the test runner to suppress the flaky report.

        :param add_option:
            A function that can add an option to the test runner.
            Its argspec should equal that of argparse.add_option.
        :type add_option:
            `callable`
        """
    add_option('--no-flaky-report', action='store_false', dest=
        'flaky_report', default=True, help=
        'Suppress the report at the end of the run detailing flaky test results.'
        )
    add_option('--no-success-flaky-report', action='store_false', dest=
        'flaky_success_report', default=True, help=
        'Suppress reporting flaky test successesin the report at the end of the run detailing flaky test results.'
        )


def sliding_impl(wrap, size, step, sequence):
    """
    Implementation for sliding_t
    :param wrap: wrap children values with this
    :param size: size of window
    :param step: step size
    :param sequence: sequence to create sliding windows from
    :return: sequence of sliding windows
    """
    i = 0
    n = len(sequence)
    while i + size <= n or step != 1 and i < n:
        yield wrap(sequence[i:i + size])
        i += step


def get_default_arch():
    """helper function to consistently return the default architecture for windows files"""
    return 'amd64'


def blocking(indices, block_size, initial_boundary=0):
    """
    Split list of integers into blocks of block_size and return block indices.

    First block element will be located at initial_boundary (default 0).

    >>> blocking([0, -1, -2, -3, -4, -5, -6, -7, -8, -9], 8)
    [0,-1]
    >>> blocking([0], 8)
    [0]
    >>> blocking([0], 8, initial_boundary=32)
    [-4]
    """
    blocks = []
    for idx in indices:
        bl_idx = (idx - initial_boundary) // float(block_size)
        if bl_idx not in blocks:
            blocks.append(bl_idx)
    blocks.sort()
    return blocks


def FlattenTraces(d):
    """
    return list of tuples (key,peak)
    """
    l = []
    for k, v in d.items():
        l.append((k, v))
    return l


@classmethod
def from_file(cls, filepath):
    """Initialize the object from a Netcdf file"""
    return cls(filepath)


def _check_valid(key, val, valid):
    """Helper to check valid options"""
    if val not in valid:
        raise ValueError('%s must be one of %s, not "%s"' % (key, valid, val))


def add(callback):
    """
        Add a listener. The arguments to the callback are determined by whomever calls notify()
        """


def _nih_checkdigit(h):
    """Luhn mod N algorithm in base 16 (hex) according to RFC6920_

    .. _RFC6920: https://www.ietf.org/rfc/rfc6920
    """
    factor = 2
    total = 0
    base = 16
    digits = len(h)
    parity = digits % 2
    for x in range(digits):
        digit = int(h[x], 16)
        if x % 2 != parity:
            digit *= 2
            total += sum(divmod(digit, 16))
        else:
            total += digit
    remainder = (16 - total) % 16
    return '%x' % remainder


def join_weights_and_biases(weights, biases):
    """
    joins two arrays into one
    :param weights: list of numpy arrays.
    :param biases: list of numpy arrays with same length as weights.
    :return: list of list with two numpy arrays for weights and biases, respectively.
        - the first index is defines layer and the second weight (0) or bias (1)
    """
    out = list()
    for i, _ in enumerate(weights):
        out.append([weights[i], biases[i]])
    return out


def select_nth(nth: int=2, skip: int=1, offset: int=0):
    """Deselect every Nth element starting from the active vertex, edge or face

    :param nth: Nth Selection
    :type nth: int
    :param skip: Skip
    :type skip: int
    :param offset: Offset
    :type offset: int
    """
    pass


def memory_statistics():
    """Print memory statistics to the console

    """
    pass


def print_greeting(model, observable):
    """
    Prints some user greeting information
    """
    print('*' * 80)
    print('* MODEL')
    print('*' * 80)
    print(model)
    print('*' * 80)
    print('* OBSERVABLE VARIABLES')
    print('*' * 80)
    print('\n'.join(sorted(observable)))


def load_numpy_f2py___version__(finder, module):
    """the numpy.f2py.__version__ module optionally imports the __svn_version__
       module; ignore the error if the module cannot be found."""
    module.IgnoreName('__svn_version__')


def serial_trails_mask_columns_tag_from_serial_trails_mask_columns(
    serial_trails_mask_columns):
    """Generate a serial_trails_mask_columns tag, to customize phase names based on the number of columns in the charge
    injection region in the trails of the serial clocking direction are masked during the fit,

    This changes the phase name 'phase_name' as follows:

    serial_trails_mask_columns = None -> phase_name
    serial_trails_mask_columns = (0, 10) -> phase_name_serial_trails_mask_columns_(0,10)
    serial_trails_mask_columns = (20, 60) -> phase_name_serial_trails_mask_columns_(20,60)
    """
    if serial_trails_mask_columns == None:
        return ''
    else:
        x0 = str(serial_trails_mask_columns[0])
        x1 = str(serial_trails_mask_columns[1])
        return '_ser_trails_mask_col_(' + x0 + ',' + x1 + ')'


def quaternion_real(quaternion):
    """Return real part of quaternion.

    >>> quaternion_real([3, 0, 1, 2])
    3.0

    """
    return float(quaternion[0])


@classmethod
def get_real_child_model(cls, data):
    """Returns the real base class specified by the discriminator"""
    discriminator_value = data[cls.json_discriminator_key]
    return cls.discriminator_value_class_map.get(discriminator_value)


@classmethod
def all_address_target_pairs(cls, address_families):
    """Implementation of `address_target_pairs_from_address_families()` which does no
        filtering."""
    addr_tgt_pairs = []
    for af in address_families:
        addr_tgt_pairs.extend(af.addressables.items())
    return addr_tgt_pairs


@classmethod
def debug(cls, msg):
    """
        Log provided message with level DEBUG.
        """
    return cls(msg, level='debug')


def add_verbose(parser):
    """
    Add a verbose option (--verbose or -v) to parser.

    Parameters:
    -----------

    parser : `ArgumentParser`

    """
    verbose_help = 'provide more information during processing'
    parser.add_argument('-v', '--verbose', help=verbose_help, action=
        'store_true')


def get_haunted():
    """Return the final target object.
        """


def commentaire_accentues():
    """
    L'aide de cette fonction contient assuréments des accents.

    .. faqref::
        :tag: python
        :title: Python n'accepte pas les accents

        .. index:: accent, accents, utf8, encoding

        Le langage Python a été conçu en langage anglais. Dès qu'on on ajoute un caractère
        qui ne fait pas partie de l'alphabet anglais (ponctuation comprise), il déclenche une erreur :

        ::

            File "faq_cvxopt.py", line 3
            SyntaxError: Non-UTF-8 code starting with 'è' in file faq_cvxopt.py on line 4, but no encoding declared;
                see http://python.org/dev/peps/pep-0263/ for details

        Pour la résoudre, il faut dire à l'interpréteur que des caractères non anglais peuvent apparaître
        et écrire sur la première ligne du programme :

        ::

            # -*- coding: latin-1 -*-

        Ou pour tout caractère y compris chinois :

        ::

            # -*- coding: utf-8 -*-

        Si vous utilisez l'éditeur `SciTE <http://www.scintilla.org/SciTE.html>`_ sous Windows,
        après avoir ajouté cette ligne avec l'encoding `utf-8`,
        il est conseillé de fermer le fichier puis de le réouvrir.
        SciTE le traitera différemment.

        **L'encodage ``utf-8`` est la norme sur Internet.** C'est pourquoi il est préférable d'utiliser celui-ci pour
        partager son code via une page Web.
    """
    pass


@classmethod
def exists(cls, db):
    """
        Check if tables exists in database.

        :param obj db: DatabaseManager.
        :return: True if exists otherwise False.
        """
    return cls.__table__.exists(db.engine)


def save_model(obj, fname):
    """Store model from file. The model is stored using gzip and pickle

    :param obj: object to store
    :type obj: object
    :param fname: filename
    :type fname: str (path)
    """
    import gzip
    import pickle
    with gzip.open(fname, 'w') as fpt:
        pickle.dump(obj, fpt)


def dedup(l, suffix='__', case_sensitive=True):
    """De-duplicates a list of string by suffixing a counter

    Always returns the same number of entries as provided, and always returns
    unique values. Case sensitive comparison by default.

    >>> print(','.join(dedup(['foo', 'bar', 'bar', 'bar', 'Bar'])))
    foo,bar,bar__1,bar__2,Bar
    >>> print(
        ','.join(dedup(['foo', 'bar', 'bar', 'bar', 'Bar'], case_sensitive=False))
    )
    foo,bar,bar__1,bar__2,Bar__3
    """
    new_l = []
    seen = {}
    for s in l:
        s_fixed_case = s if case_sensitive else s.lower()
        if s_fixed_case in seen:
            seen[s_fixed_case] += 1
            s += suffix + str(seen[s_fixed_case])
        else:
            seen[s_fixed_case] = 0
        new_l.append(s)
    return new_l


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


def _set_edge_values_inplace(image, value):
    """Set edge values along all axes to a constant value.

    Parameters
    ----------
    image : ndarray
        The array to modify inplace.
    value : scalar
        The value to use. Should be compatible with `image`'s dtype.

    Examples
    --------
    >>> image = np.zeros((4, 5), dtype=int)
    >>> _set_edge_values_inplace(image, 1)
    >>> image
    array([[1, 1, 1, 1, 1],
           [1, 0, 0, 0, 1],
           [1, 0, 0, 0, 1],
           [1, 1, 1, 1, 1]])
    """
    for axis in range(image.ndim):
        sl = [slice(None)] * image.ndim
        sl[axis] = 0
        image[tuple(sl)] = value
        sl[axis] = -1
        image[tuple(sl)] = value


def _ed_log_get_value_from_rows(rows, key):
    """
    Searches for ``key`` in rows
    If the ``key`` is found, returns the value to the 'right' of the key

    :type rows: list
    :param rows: list of lists of strings
    :type key: str
    :param key:
    :rtype: None, str
    :return: Value corresponding to the key or ``None``
        if the key is not found in ``rows``
    """
    for row in rows:
        if key not in row:
            continue
        i = row.index(key) + 1
        if i >= len(row):
            continue
        return row[i]
    return None


def fil_remove_parent(branchs):
    """Remove status with .. from list"""
    for branch in branchs:
        if not '..' in branch:
            yield branch


@staticmethod
def eval(e, amplitude, e_0, alpha):
    """One dimensional power law model function"""
    xx = e / e_0
    return amplitude * xx ** -alpha


@staticmethod
def _validate_token_fields(token):
    """
            Validates a token
        """
    valid_keys = ['kind', 'localId', 'email', 'displayName', 'idToken',
        'registered', 'refreshToken', 'expiresIn', 'userId']
    for k in valid_keys:
        if k not in token:
            return False
    return True


def schema_import(conn, dbpath):
    """Import profiles from another database.

    This does not overwrite existing profiles in the target database. Profiles
    in the source database that share names with those in the target database
    are ignored.

    :param conn: A connection to an SQLite3 database into which to copy
        profiles.
    :param dbpath: The filesystem path to the source SQLite3 database.
    """
    conn.execute('ATTACH DATABASE ? AS source', (str(dbpath),))
    conn.execute(
        'INSERT OR IGNORE INTO profiles (name, data) SELECT name, data FROM source.profiles WHERE data IS NOT NULL'
        )
    conn.commit()
    conn.execute('DETACH DATABASE source')


def normalize_userinfo(userinfo):
    """Normalize userinfo part of the url.

    Params:
        userinfo : string : url userinfo, e.g., 'user@'

    Returns:
        string : normalized userinfo data.

    """
    if userinfo in ['@', ':@']:
        return ''
    return userinfo


def carmichael_of_ppower(pp):
    """Carmichael function of the given power of the given prime.
  """
    p, a = pp
    if p == 2 and a > 2:
        return 2 ** (a - 2)
    else:
        return (p - 1) * p ** (a - 1)


def is_authorized(request):
    """ Returns true if the given request has the configured auth code. """
    auth = request.match_info.get('auth')
    return auth is not None and auth == request.app.auth


def _Minus(lhs=None, rhs=None, out=None, name=None, **kwargs):
    """Subtracts arguments element-wise.

    The storage type of ``elemwise_sub`` output depends on storage types of inputs

       - elemwise_sub(row_sparse, row_sparse) = row_sparse
       - elemwise_sub(csr, csr) = csr
       - elemwise_sub(default, csr) = default
       - elemwise_sub(csr, default) = default
       - elemwise_sub(default, rsp) = default
       - elemwise_sub(rsp, default) = default
       - otherwise, ``elemwise_sub`` generates output with default storage

    Parameters
    ----------
    lhs : NDArray
        first input
    rhs : NDArray
        second input

    out : NDArray, optional
        The output NDArray to hold the result.

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.
    """
    return 0,


def _make_split(X, y, valid_ds, **kwargs):
    """Used by ``predefined_split`` to allow for pickling"""
    return X, valid_ds


@classmethod
def validate_params(cls, parser, params):
    """Проверка параметров."""
    if params.backend is None:
        parser.error('the following arguments are required: Back-end')


def inch2cm(inches):
    """Inches to centimeters"""
    return inches / 0.393701


def fly():
    """Interactively fly around the scene

    """
    pass


def _apply_scalar_cards(model, model2_renumber):
    """apply cards from model2 to model if they don't exist in model"""
    if model.aero is None and model2_renumber.aero:
        model.aero = model2_renumber.aero
    if model.aeros is None and model2_renumber.aeros:
        model.aeros = model2_renumber.aeros
    model.mkaeros += model2_renumber.mkaeros
    for key, param in model2_renumber.params.items():
        if key not in model.params:
            model.params[key] = param


def get_object(state, obj):
    """Get an object from the given state.

        The ``obj`` is the JSONB document of which the created object is part
        of.
        """


@classmethod
def export_members_report(cls, val):
    """
        Create an instance of this class set to the ``export_members_report``
        tag with value ``val``.

        :param ExportMembersReportType val:
        :rtype: EventType
        """
    return cls('export_members_report', val)


def usual_language_name(language):
    """Return the usual language name (one that may be found in _SCRIPT_EXTENSIONS above)"""
    language = language.lower()
    if language == 'r':
        return 'R'
    if language.startswith('c++'):
        return 'c++'
    if language == 'octave':
        return 'matlab'
    if language in ['cs', 'c#']:
        return 'csharp'
    if language in ['fs', 'f#']:
        return 'fsharp'
    return language


def get_datatype_metranet(datatype):
    """
    maps de config file radar data type name into the corresponding metranet
    data type  name and Py-ART field name

    Parameters
    ----------
    datatype : str
        config file radar data type name

    Returns
    -------
    metranet type : dict
        dictionary containing the metranet data type name and its
        corresponding Py-ART field name

    """
    if datatype == 'dBZ':
        datatype_metranet = 'ZH'
        field_name = 'reflectivity'
    elif datatype == 'dBZv':
        datatype_metranet = 'ZV'
        field_name = 'reflectivity_vv'
    elif datatype == 'ZDR':
        datatype_metranet = 'ZDR'
        field_name = 'differential_reflectivity'
    elif datatype == 'uRhoHV':
        datatype_metranet = 'RHO'
        field_name = 'uncorrected_cross_correlation_ratio'
    elif datatype == 'uPhiDP':
        datatype_metranet = 'PHI'
        field_name = 'uncorrected_differential_phase'
    elif datatype == 'V':
        datatype_metranet = 'VEL'
        field_name = 'velocity'
    elif datatype == 'W':
        datatype_metranet = 'WID'
        field_name = 'spectrum_width'
    elif datatype == 'CLT':
        datatype_metranet = 'CLT'
        field_name = 'clutter_exit_code'
    elif datatype == 'ST1':
        datatype_metranet = 'ST1'
        field_name = 'stat_test_lag1'
    elif datatype == 'ST2':
        datatype_metranet = 'ST2'
        field_name = 'stat_test_lag2'
    elif datatype == 'WBN':
        datatype_metranet = 'WBN'
        field_name = 'wide_band_noise'
    elif datatype == 'MPH':
        datatype_metranet = 'MPH'
        field_name = 'mean_phase'
    else:
        raise ValueError('ERROR: Metranet fields do not contain datatype ' +
            datatype)
    return {datatype_metranet: field_name}


def formatAustralianPhoneNumber(n):
    """Formats a string of numbers (no spaces) into an Australian mobile or landline."""
    if len(n) != 10:
        return n
    if n[1] == '4':
        return u'{0} {1} {2}'.format(n[0:4], n[4:7], n[7:10])
    return u'({0}) {1} {2}'.format(n[0:2], n[2:6], n[6:10])


def is_number(word):
    """ Function that returns 'NUM' if a shipo word is a number or False if not

        :param word: a word to be evaluated
        :type word: str
        :returns: 'NUM' if a shipo word is a number or False if not
        :rtype: str

        :Example:

        >>> import chana.ner
        >>> chana.ner.is_number('kimisha')
        'NUM'

    """
    numbers = ['westiora', 'rabé', 'kimisha', 'chosko', 'pichika', 'sokota',
        'kanchis', 'posaka', 'iskon', 'chonka', 'pacha', 'waranka']
    if word.lower() in numbers:
        return 'NUM'
    else:
        return False


@classmethod
def from_arguments(cls, argstring):
    """
        Initializes command object from unparsed args string.
        """
    obj = object.__new__(cls)
    obj.parse(argstring)
    return obj


def get_undone(single_list):
    """
    Returns the number of undone tasks in a list.
    Takes:
        - a single todo list
    Returns:
        the number of undone tasks from that list
    """
    undone = 0
    for task_id in single_list:
        if not single_list[task_id][1]:
            undone += 1
    return undone


def read_healpix_hdf5(hdf5_filename):
    """
    Read hdf5 healpix files using h5py and get a healpix map, indices and frequencies.

    Parameters
    ----------
    hdf5_filename : str
        Path and name of the hdf5 file to read.

    Returns
    -------
    hpmap : array_like of float
        Stokes-I surface brightness in K, for a set of pixels
        Shape (Ncomponents, Nfreqs)
    indices : array_like, int
        Corresponding HEALPix indices for hpmap.
    freqs : array_like, float
        Frequencies in Hz. Shape (Nfreqs)
    """
    import h5py
    with h5py.File(hdf5_filename, 'r') as file:
        hpmap = file['data'][0, ...]
        indices = file['indices'][()]
        freqs = file['freqs'][()]
    return hpmap, indices, freqs


def get_trace_attribute_values(log, attribute_key, parameters=None):
    """
    Get the attribute values of the log for the specified attribute along with their count

    Parameters
    ------------
    log
        Log
    attribute_key
        Attribute for which we wish to get the values along with their count
    parameters
        Possible parameters of the algorithm

    Returns
    ------------
    attributes
        Dictionary of attributes associated with their count
    """
    if parameters is None:
        parameters = {}
    attributes = {}
    for trace in log:
        if attribute_key in trace.attributes:
            attribute = trace.attributes[attribute_key]
            if attribute not in attributes:
                attributes[attribute] = 0
            attributes[attribute] = attributes[attribute] + 1
    return attributes


def get_months_apart(d1, d2):
    """
    Get amount of months between dates
    http://stackoverflow.com/a/4040338
    """
    return (d1.year - d2.year) * 12 + d1.month - d2.month


@staticmethod
def sort_key(person):
    """ Get a key to sort a person

        Args:
            person (:obj:`Person`): person

        Returns:
            :obj:`tuple`
        """
    return person.last_name, person.first_name, person.middle_name


def _remove_single_element_groups(hierarchy):
    """
    Flatten sub-lists of length 1.

    Parameters
    ----------
    hierarchy : list of lists

    Returns
    -------
    hierarchy : list of el / lists

    Examples
    --------
    >>> hierarchy = [[0], [1, 2]]
    >>> _remove_single_element_groups(hierarchy)
    [0, [1, 2]]
    """
    h_new = []
    for el in hierarchy:
        if len(el) > 1:
            h_new.append(el)
        else:
            h_new.append(el[0])
    return h_new


def change_spacing(delta: int=1):
    """Change font spacing

    :param delta: Delta, Amount to decrease or increase character spacing with
    :type delta: int
    """
    pass


def read_torrent_file(filepath):
    """Reads torrent file from filesystem and returns its contents."""
    f = open(filepath, 'rb')
    contents = f.read()
    f.close()
    return contents


@classmethod
def database_close(cls):
    """Close the database connection."""
    if not cls._meta.database.is_closed():
        cls._meta.database.close()


def set_initialized(initialized):
    """
    set the initialization state of the local node
    @param initialized: True if node initialized
    @type  initialized: bool
    """
    global _client_ready
    _client_ready = initialized


def plus_or_dot(pieces):
    """Return a + if we don't already have one, else return a ."""
    if '+' in pieces.get('closest-tag', ''):
        return '.'
    return '+'


def clear_db_env():
    """
    Unset global configuration variables for database.
    """
    global _FACADE
    _FACADE = None


def set_language(series, language):
    """
  Set the language to use.

  :param series: the series created with :func:`~thetvdb_api.api.set_series`
  :type series: :mod:`thetvdb_api.theTVDB` object
  :param str language: a language accepted by theTVDB.com (see :doc:`languages`)
  """
    return series.set_language(language)


def write_header(target, softwareversion, osversion, radioversion):
    """
    Write header for file.

    :param target: File to write to.
    :type target: file

    :param softwareversion: Software release version.
    :type softwareversion: str

    :param osversion: OS version.
    :type osversion: str

    :param radioversion: Radio version.
    :type radioversion: str
    """
    target.write('OS VERSION: {0}\n'.format(osversion))
    target.write('RADIO VERSION: {0}\n'.format(radioversion))
    target.write('SOFTWARE RELEASE: {0}\n'.format(softwareversion))


@staticmethod
def p_variant_coding_optional_list_optional(p):
    """variant_coding_optional_list_optional : empty
                                                 | variant_coding_optional_list"""
    p[0] = tuple() if p[1] is None else p[1]


def p_sub_channel_mode(t):
    """sub_channel_mode : RW
                        | RW_RAW"""
    t[0] = t[1]


@classmethod
def shared_link_change_visibility(cls, val):
    """
        Create an instance of this class set to the
        ``shared_link_change_visibility`` tag with value ``val``.

        :param SharedLinkChangeVisibilityType val:
        :rtype: EventType
        """
    return cls('shared_link_change_visibility', val)


def p_for_expr(p):
    """for_expr : empty
                | non_empty_for_expr"""
    p[0] = p[1]


def get_all_addables(require=None):
    """Get a list of all content that could be added in the
        adapted container (they can be added to the site).

        If require is not None, it is an interface that the all the
        returned addable must implement.
        """


def sort_ranking(replicas, location):
    """
    Return a list of replicas sorted by ranking metric.
    :param replicas : A dict with RSEs as values and replicas as keys (URIs).
    :param location: Location dictionary containing {'ip', 'fqdn', 'site'}
    """
    return replicas


def render_git_describe_long(pieces):
    """TAG-DISTANCE-gHEX[-dirty].

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


@classmethod
def jsonschema_type_checker(cls, checker, instance):
    """Type checker for use with jsonschema >= 3.0.0.

        Args:
            checker (jsonschema.TypeChecker): Type checker class.
            instance (object): Object being checked.

        Returns:
            bool: True if instance could be of this type, False otherwise.

        """
    return cls.validate(instance)


def site_url():
    """Return the URL of the site."""


def get_missing_elements(match, dmrs):
    """ Returns a list of elements of dmrs for which no match was found.:
        :param match A Match object.
        :param dmrs A DMRS object for which the match was searched.
        :return A list of nodeids and links.
    """
    matched_nodeids = list(zip(*match.nodeid_pairs))[1]
    matched_links = list(zip(*match.link_pairs))[1]
    not_matched = []
    for nodeid in dmrs:
        if nodeid not in matched_nodeids:
            not_matched.append(nodeid)
    for link in dmrs.iter_links():
        if link not in matched_links:
            not_matched.append(link)
    return not_matched


def get_completer_delims():
    """An empty implementation of readline.get_completer_delims."""


def usage_percent(used, total, round_=None):
    """Calculate percentage usage of 'used' against 'total'."""
    try:
        ret = float(used) / total * 100
    except ZeroDivisionError:
        return 0.0
    else:
        if round_ is not None:
            ret = round(ret, round_)
        return ret


def remove_distortion_keywords(hdr):
    """
    Remove WCS distortion related keywords from the input header
    """
    distortion_kws = ['TDDALPHA', 'TDDBETA', 'D2IMEXT', 'D2IMERR',
        'DGEOEXT', 'NPOLEXT']
    for kw in distortion_kws:
        if kw in hdr:
            try:
                del hdr[kw]
            except KeyError:
                pass
    if 'ctype1' in hdr and hdr['ctype1'].find('SIP') > -1:
        hdr['ctype1'] = hdr['ctype1'][:-4]
        hdr['ctype2'] = hdr['ctype2'][:-4]
    for k in list(hdr.items()):
        if k[0][:2] in ['A_', 'B_'] or k[0][:3] in ['IDC', 'SCD'] and k[0
            ] != 'IDCTAB' or k[0][:6] in ['SCTYPE', 'SCRVAL', 'SNAXIS',
            'SCRPIX']:
            try:
                del hdr[k[0]]
            except KeyError:
                pass
    for k in list(hdr.items()):
        if k[0][:2] == 'DP':
            try:
                del hdr[k[0] + '*']
                del hdr[k[0] + '.*']
                del hdr[k[0] + '.*.*']
            except:
                print(
                    "ERROR (bleandheaders.remove_distortion_keywords) trying to delete '{:s}' in the header."
                    .format(k[0] + '*'))
                pass
        if k[0][:2] == 'CP':
            try:
                del hdr[k[0]]
            except KeyError:
                pass


def enable_warning_messages():
    """
    Enable warning message printing.
    """
    global warning_enabled
    warning_enabled = True


def clean_whitespaces(df, *cols):
    """
    Removes all whitespaces from items in one or more pd.Dataframe columns.
    :param df: the Dataframe
    :param cols: the columns to remove whitespaces
    """
    for col in cols:
        df[col] = df[col].str.replace(' ', '')


def check_required_networks(networks, required_networks):
    """Verifies required networks are present."""
    if required_networks:
        msg = 'Networks (%s) required but missing'
        msg_networks = ','.join(required_networks)
        if required_networks.intersection(networks) != required_networks:
            return msg % msg_networks
    return ''


def read_td_job(job_id, engine, index_col=None, parse_dates=None):
    """Read Treasure Data job result into a DataFrame.

    Returns a DataFrame corresponding to the result set of the job.
    This method waits for job completion if the specified job is still running.
    Optionally provide an index_col parameter to use one of the columns as
    the index, otherwise default integer index will be used.

    Parameters
    ----------
    job_id : integer
        Job ID.
    engine : QueryEngine
        Handler returned by create_engine.
    index_col : string, optional
        Column name to use as index for the returned DataFrame object.
    parse_dates : list or dict, optional
        - List of column names to parse as dates
        - Dict of {column_name: format string} where format string is strftime
          compatible in case of parsing string times or is one of (D, s, ns, ms, us)
          in case of parsing integer timestamps

    Returns
    -------
    DataFrame
    """
    job = engine.connection.client.job(job_id)
    r = engine.get_result(job, wait=True)
    return r.to_dataframe(index_col=index_col, parse_dates=parse_dates)


def strict_str(smth) ->str:
    """Converts not str objects to empty string"""
    return smth if smth and isinstance(smth, str) else ''


def extract_deb(archive, compression, cmd, verbosity, interactive, outdir):
    """Extract a DEB archive."""
    cmdlist = [cmd]
    if verbosity > 1:
        cmdlist.append('--vextract')
    else:
        cmdlist.append('--extract')
    cmdlist.extend(['--', archive, outdir])
    return cmdlist


def intersperse_r(delimiter, iterable):
    """put the delimiter on the right of every element of iterable"""
    it = iter(iterable)
    for x in it:
        yield x
        yield delimiter


@staticmethod
def cpu_id_to_string(idx):
    """ Get a displayable form to cpu index. """
    return idx - 1 if idx > 0 else 'all'


@staticmethod
def tabulate(link):
    """Make a given a href link parsed on bs4 printable."""
    return link.parent.find(class_='detName').text, link.parent.find(class_
        ='detDesc').text, link['href']


def delete_open_id_connect_provider(OpenIDConnectProviderArn=None):
    """
    Deletes an OpenID Connect identity provider (IdP) resource object in IAM.
    Deleting an IAM OIDC provider resource does not update any roles that reference the provider as a principal in their trust policies. Any attempt to assume a role that references a deleted provider fails.
    This action is idempotent; it does not fail or return an error if you call the action for a provider that does not exist.
    See also: AWS API Documentation

    :example: response = client.delete_open_id_connect_provider(
        OpenIDConnectProviderArn='string'
    )

    :type OpenIDConnectProviderArn: string
    :param OpenIDConnectProviderArn: [REQUIRED]
            The Amazon Resource Name (ARN) of the IAM OpenID Connect provider resource object to delete. You can get a list of OpenID Connect provider resource ARNs by using the ListOpenIDConnectProviders action.

    """
    pass


@staticmethod
def build_columns(choice):
    """Default column building method

        Overwrite this method when initializing this widget or using
        self.fields[name].widget.build_columns in a parent form initialization
        to customize the behavior (see above for details)

        :param choice:
        :return:
        """
    return choice


def _constant_time_compare(first, second):
    """Return True if both string or binary inputs are equal, otherwise False.

    This function should take a constant amount of time regardless of
    how many characters in the strings match. This function uses an
    approach designed to prevent timing analysis by avoiding
    content-based short circuiting behaviour, making it appropriate
    for cryptography.
    """
    first = str(first)
    second = str(second)
    if len(first) != len(second):
        return False
    result = 0
    for x, y in zip(first, second):
        result |= ord(x) ^ ord(y)
    return result == 0


def retransmit_timeout(group_state: 'GroupState'):
    """
    retransmit timer associated with group GroupState object has expired
    """
    group_state.group_state_logger.debug(
        'NonQuerier MembersPresent: retransmit_timeout')
    return


def render_git_describe_long(pieces):
    """TAG-DISTANCE-gHEX[-dirty].

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


def validate_format(*_arg):
    """
    This method can be overridden with format validation logic.
    """
    return True


@classmethod
def get_exchange_name(cls):
    """
        Get exchange name
        :return: Exchange name string
        """
    return 'Template'


def get_display(choices, label):
    """Returns the display value of a choices tuple for label.
    """
    for choice in choices:
        store_value, display_value = choice
        if label == store_value:
            return display_value
    return None


def _no_slots_copy(dct):
    """Internal helper: copy class __dict__ and clean slots class variables.
    (They will be re-created if necessary by normal class machinery.)
    """
    dict_copy = dict(dct)
    if '__slots__' in dict_copy:
        for slot in dict_copy['__slots__']:
            dict_copy.pop(slot, None)
    return dict_copy


def list_addable_policies(container):
    """List all available policies that can be used on the given
        container.
        """


@staticmethod
def _get_default_field_kwargs(property_class):
    """
        Return default kwargs used to initialize
        the Serializer field with.
        :param property_class: Neomodel property class
        """
    defaults = property_class.__dict__.copy()
    delete_attrs = ['db_property', 'choices', 'has_default', 'index',
        'unique_index']
    for attr in delete_attrs:
        if attr in defaults:
            del defaults[attr]
    return defaults


def check_letters(str1, str2) ->bool:
    """
    检查两个字符串是否由相同字母的不同顺序组成
    :param str1:
    :param str2:
    :return:
    """
    from collections import Counter
    resbool = Counter(str1) == Counter(str2)
    return resbool


def should_dict_attr_be_excluded(map_option_name, option_key, exclude_list):
    """An entry for the Exclude list for excluding a map's key is specifed as a dict with the map option name as the
    key, and the value as a list of keys to be excluded within that map. For example, if the keys "k1" and "k2" of a map
    option named "m1" needs to be excluded, the exclude list must have an entry {'m1': ['k1','k2']} """
    for exclude_item in exclude_list:
        if isinstance(exclude_item, dict):
            if map_option_name in exclude_item:
                if option_key in exclude_item[map_option_name]:
                    return True
    return False


def _set_coords(ds):
    """Turn all variables without `time` dimensions into coordinates."""
    coords = set()
    for vname in ds.variables:
        if 'time' not in ds[vname].dims or ds[vname].dims == ('time',):
            coords.add(vname)
    return ds.set_coords(list(coords))


def extract_ironic_uuid(node):
    """Function to extract the uuid associated to Ironic resource

    :param node:  Dict from Ironic node
    :returns The uuid for the Ironic resource
    """
    return node.__dict__['uuid']


def background(url):
    """This action will run an addon in the background for the provided URL.

    See 'RunPlugin()' at
    http://kodi.wiki/view/List_of_built-in_functions

    Args:
        url (str): Full path must be specified.
            Does not work for folder plugins.

    Returns:
        str: String of the builtin command
    """
    return 'RunPlugin(%s)' % url


def _glibc_version_string_ctypes():
    """
    Fallback implementation of glibc_version_string using ctypes.
    """
    try:
        import ctypes
    except ImportError:
        return None
    process_namespace = ctypes.CDLL(None)
    try:
        gnu_get_libc_version = process_namespace.gnu_get_libc_version
    except AttributeError:
        return None
    gnu_get_libc_version.restype = ctypes.c_char_p
    version_str = gnu_get_libc_version()
    if not isinstance(version_str, str):
        version_str = version_str.decode('ascii')
    return version_str


def align_down(value, multiple):
    """! @brief Return value aligned down to multiple."""
    return value // multiple * multiple


def cz2z(cz, e):
    """Transform from *z* index value to *z* index value, using the
    *e.css('cd')* (column depth) as column measure."""
    if cz is None:
        z = 0
    else:
        z = e.parent.pzf + cz * (e.css('cd', 0) + e.gd)
    return z


def get_remote_ip(request):
    """
    Find the IP address of the current request.
    This may require reading a different request header depending on the server setup.
    However, we recommend using wsgiunproxy instead,
    so all packages can read the same header consistently.
    """
    return request.META.get('REMOTE_ADDR', None)


def modify_load_balancer_attributes(LoadBalancerName=None,
    LoadBalancerAttributes=None):
    """
    Modifies the attributes of the specified load balancer.
    You can modify the load balancer attributes, such as AccessLogs , ConnectionDraining , and CrossZoneLoadBalancing by either enabling or disabling them. Or, you can modify the load balancer attribute ConnectionSettings by specifying an idle connection timeout value for your load balancer.
    For more information, see the following in the Classic Load Balancer Guide :
    See also: AWS API Documentation

    Examples
    This example enables cross-zone load balancing for the specified load balancer.
    Expected Output:
    This example enables connection draining for the specified load balancer.
    Expected Output:

    :example: response = client.modify_load_balancer_attributes(
        LoadBalancerName='string',
        LoadBalancerAttributes={
            'CrossZoneLoadBalancing': {
                'Enabled': True|False
            },
            'AccessLog': {
                'Enabled': True|False,
                'S3BucketName': 'string',
                'EmitInterval': 123,
                'S3BucketPrefix': 'string'
            },
            'ConnectionDraining': {
                'Enabled': True|False,
                'Timeout': 123
            },
            'ConnectionSettings': {
                'IdleTimeout': 123
            },
            'AdditionalAttributes': [
                {
                    'Key': 'string',
                    'Value': 'string'
                },
            ]
        }
    )

    :type LoadBalancerName: string
    :param LoadBalancerName: [REQUIRED]
            The name of the load balancer.

    :type LoadBalancerAttributes: dict
    :param LoadBalancerAttributes: [REQUIRED]
            The attributes for the load balancer.
            CrossZoneLoadBalancing (dict) --If enabled, the load balancer routes the request traffic evenly across all instances regardless of the Availability Zones.
            For more information, see Configure Cross-Zone Load Balancing in the Classic Load Balancer Guide .
            Enabled (boolean) -- [REQUIRED]Specifies whether cross-zone load balancing is enabled for the load balancer.
            AccessLog (dict) --If enabled, the load balancer captures detailed information of all requests and delivers the information to the Amazon S3 bucket that you specify.
            For more information, see Enable Access Logs in the Classic Load Balancer Guide .
            Enabled (boolean) -- [REQUIRED]Specifies whether access logs are enabled for the load balancer.
            S3BucketName (string) --The name of the Amazon S3 bucket where the access logs are stored.
            EmitInterval (integer) --The interval for publishing the access logs. You can specify an interval of either 5 minutes or 60 minutes.
            Default: 60 minutes
            S3BucketPrefix (string) --The logical hierarchy you created for your Amazon S3 bucket, for example my-bucket-prefix/prod . If the prefix is not provided, the log is placed at the root level of the bucket.
            ConnectionDraining (dict) --If enabled, the load balancer allows existing requests to complete before the load balancer shifts traffic away from a deregistered or unhealthy instance.
            For more information, see Configure Connection Draining in the Classic Load Balancer Guide .
            Enabled (boolean) -- [REQUIRED]Specifies whether connection draining is enabled for the load balancer.
            Timeout (integer) --The maximum time, in seconds, to keep the existing connections open before deregistering the instances.
            ConnectionSettings (dict) --If enabled, the load balancer allows the connections to remain idle (no data is sent over the connection) for the specified duration.
            By default, Elastic Load Balancing maintains a 60-second idle connection timeout for both front-end and back-end connections of your load balancer. For more information, see Configure Idle Connection Timeout in the Classic Load Balancer Guide .
            IdleTimeout (integer) -- [REQUIRED]The time, in seconds, that the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer.
            AdditionalAttributes (list) --This parameter is reserved.
            (dict) --This data type is reserved.
            Key (string) --This parameter is reserved.
            Value (string) --This parameter is reserved.

    :rtype: dict
    :return: {
        'LoadBalancerName': 'string',
        'LoadBalancerAttributes': {
            'CrossZoneLoadBalancing': {
                'Enabled': True|False
            },
            'AccessLog': {
                'Enabled': True|False,
                'S3BucketName': 'string',
                'EmitInterval': 123,
                'S3BucketPrefix': 'string'
            },
            'ConnectionDraining': {
                'Enabled': True|False,
                'Timeout': 123
            },
            'ConnectionSettings': {
                'IdleTimeout': 123
            },
            'AdditionalAttributes': [
                {
                    'Key': 'string',
                    'Value': 'string'
                },
            ]
        }
    }

    :returns:
    LoadBalancerName (string) -- [REQUIRED]
    The name of the load balancer.

    LoadBalancerAttributes (dict) -- [REQUIRED]
    The attributes for the load balancer.

    CrossZoneLoadBalancing (dict) --If enabled, the load balancer routes the request traffic evenly across all instances regardless of the Availability Zones.
    For more information, see Configure Cross-Zone Load Balancing in the Classic Load Balancer Guide .

    Enabled (boolean) -- [REQUIRED]Specifies whether cross-zone load balancing is enabled for the load balancer.

    AccessLog (dict) --If enabled, the load balancer captures detailed information of all requests and delivers the information to the Amazon S3 bucket that you specify.
    For more information, see Enable Access Logs in the Classic Load Balancer Guide .

    Enabled (boolean) -- [REQUIRED]Specifies whether access logs are enabled for the load balancer.

    S3BucketName (string) --The name of the Amazon S3 bucket where the access logs are stored.

    EmitInterval (integer) --The interval for publishing the access logs. You can specify an interval of either 5 minutes or 60 minutes.
    Default: 60 minutes

    S3BucketPrefix (string) --The logical hierarchy you created for your Amazon S3 bucket, for example my-bucket-prefix/prod . If the prefix is not provided, the log is placed at the root level of the bucket.

    ConnectionDraining (dict) --If enabled, the load balancer allows existing requests to complete before the load balancer shifts traffic away from a deregistered or unhealthy instance.
    For more information, see Configure Connection Draining in the Classic Load Balancer Guide .

    Enabled (boolean) -- [REQUIRED]Specifies whether connection draining is enabled for the load balancer.

    Timeout (integer) --The maximum time, in seconds, to keep the existing connections open before deregistering the instances.

    ConnectionSettings (dict) --If enabled, the load balancer allows the connections to remain idle (no data is sent over the connection) for the specified duration.
    By default, Elastic Load Balancing maintains a 60-second idle connection timeout for both front-end and back-end connections of your load balancer. For more information, see Configure Idle Connection Timeout in the Classic Load Balancer Guide .

    IdleTimeout (integer) -- [REQUIRED]The time, in seconds, that the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer.

    AdditionalAttributes (list) --This parameter is reserved.

    (dict) --This data type is reserved.

    Key (string) --This parameter is reserved.

    Value (string) --This parameter is reserved.

    """
    pass


def str_to_bytes(input_str):
    """Convert string to bytes.
  """
    return input_str.encode()


def render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

    Like 'git describe --tags --dirty --always'.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


@classmethod
def show(cls, theta):
    """Create a window that with a ThetaView inside."""
    tv = cls(theta=theta)
    tv.edit_traits()


def _get_compiler_list(cmd):
    """ Return the compiler command as a list of strings. Distutils provides a
    wildly inconsistent API here:
      - UnixCCompiler returns a list
      - MSVCCompiler intentionally doesn't set this variable
      - CygwinCompiler returns a string

    As we are focused on identifying gcc vs clang right now, we ignore MSVC's
    bad result and convert all results into lists of strings
    """
    compiler = getattr(cmd.compiler, 'compiler', '')
    if isinstance(compiler, str):
        compiler = compiler.split()
    return compiler


def getAllProperties():
    """
        Return iterable of all IDAVProperty objects defined for the
        current context.
        """


def _is_bin_op(func):
    """Try to guess if function is a binary operator"""
    return 'value' in func.__doc__


def set_workspace_path(path: str):
    """
    sets the path to the global variable
    """
    global workspace_path
    workspace_path = path


def lsumdiffsquared(x, y):
    """
Takes pairwise differences of the values in lists x and y, squares
these differences, and returns the sum of these squares.

Usage:   lsumdiffsquared(x,y)
Returns: sum[(x[i]-y[i])**2]
"""
    sds = 0
    for i in range(len(x)):
        sds = sds + (x[i] - y[i]) ** 2
    return sds


def _write_two_arrays(file_name, id_values, bound_id_code=None):
    """Write two arrays: cell_id-value pairs and bound_id-bound_code pairs
    Inputs:
        file_name :  the full file name including path
        id_values: valid cell ID - value pair
        bound_id_code: boundary cell ID - codes pair. If bound_id_code is not
            given, then the second part of the file won't be written (only
            the case for precipitatin_mask.dat)
    """
    if not file_name.endswith('.dat'):
        file_name = file_name + '.dat'
    if id_values.shape[1] == 3:
        fmt = ['%d %g %g']
    elif id_values.shape[1] == 2:
        fmt = ['%d %g']
    else:
        raise ValueError('Please check the shape of the 1st array: id_values')
    fmt = '\n'.join(fmt * id_values.shape[0])
    id_values_str = fmt % tuple(id_values.ravel())
    if bound_id_code is not None:
        fmt = ['%-12d %2d %2d %2d']
        fmt = '\n'.join(fmt * bound_id_code.shape[0])
        bound_id_code_str = fmt % tuple(bound_id_code.ravel())
    with open(file_name, 'w') as file2write:
        file2write.write('$Element Number\n')
        file2write.write('%d\n' % id_values.shape[0])
        file2write.write('$Element_id  Value\n')
        file2write.write(id_values_str)
        if bound_id_code is not None:
            file2write.write('\n$Boundary Numbers\n')
            file2write.write('%d\n' % bound_id_code.shape[0])
            file2write.write('$Element_id  Value\n')
            file2write.write(bound_id_code_str)


def is_forking(argv):
    """
    Return whether commandline indicates we are forking
    """
    if len(argv) >= 2 and argv[1] == '--billiard-fork':
        return True
    else:
        return False


@staticmethod
def _remove_strings_in_metadata_keys(gdal_metadata, rm_strings):
    """Remove unwanted metadata"""
    new_meta = {}
    for key, value in gdal_metadata.items():
        for rms in rm_strings:
            if rms in key:
                key = key.replace(rms, '')
        new_meta[key] = value
    return new_meta


def GetCentredTextExtent(dc, text_list, xpos=0, ypos=0, width=0, height=0):
    """
    Get the centred text extend

    :param `dc`: the :class:`wx.MemoryDC`
    :param `text_list`: a list of text lines
    :param `xpos`: unused
    :param `ypos`: unused
    :param `width`: unused
    :param `height`: unused

    :returns: maximum width and the height

    """
    if not text_list:
        return 0, 0
    max_width = 0
    for line in text_list:
        current_width, char_height = dc.GetTextExtent(line.GetText())
        if current_width > max_width:
            max_width = current_width
    return max_width, len(text_list) * char_height


def is_clone(g):
    """
    Return True if the generator `g` is a clone of another generator, otherwise return False.
    """
    return g.parent is not None


@classmethod
def get_selection(cls, strings, title='Select an option', subtitle=None,
    show_exit_option=True, _menu=None):
    """
        Single-method way of getting a selection out of a list of strings.

        Args:
            strings (:obj:`list` of :obj:`str`):  The list of strings this menu should be built from.
            title (str): The title of the menu.
            subtitle (str): The subtitle of the menu.
            show_exit_option (bool): Specifies whether this menu should show an exit item by default. Defaults to True.
            _menu: Should probably only be used for testing, pass in a list and the created menu used internally by
                the method will be appended to it

        Returns:
            int: The index of the selected option.

        """
    menu = cls(strings, title, subtitle, show_exit_option=show_exit_option)
    if _menu is not None:
        _menu.append(menu)
    menu.show()
    menu.join()
    return menu.selected_option


def twos_comp(val, bits):
    """compute the 2's complement of val.

    :param int val:
        the value to compute the two's complement for

    :param int bits:
        size of val in bits
    """
    if val & 1 << bits - 1 != 0:
        val = val - (1 << bits)
    return val


def provider_parser(subparser):
    """Configure provider parser for NSOne"""
    subparser.add_argument('--auth-token', help=
        'specify token for authentication')


@classmethod
def success(cls, val):
    """
        Create an instance of this class set to the ``success`` tag with value
        ``val``.

        :param FileMetadata val:
        :rtype: UploadSessionFinishBatchResultEntry
        """
    return cls('success', val)


def row2dict(columns, row):
    """Convert rows to dictionaries with column keys from description"""
    robj = {}
    for k, v in zip(columns, row):
        robj.setdefault(k, v)
    return robj


def remove_www(hostname):
    """
    Removes www. from the beginning of the address. Only for
    routing purposes. www.test.com/login/ and test.com/login/ should
    find the same tenant.
    """
    if hostname.startswith('www.'):
        return hostname[4:]
    return hostname


def get_sort_params(input_params, default_key='created_at', default_dir='desc'
    ):
    """Retrieves sort keys/directions parameters.

    Processes the parameters to create a list of sort keys and sort directions
    that correspond to the 'sort_key' and 'sort_dir' parameter values. These
    sorting parameters can be specified multiple times in order to generate
    the list of sort keys and directions.

    The input parameters are not modified.

    :param input_params: webob.multidict of request parameters (from
                         masakari.wsgi.Request.params)
    :param default_key: default sort key value, added to the list if no
                        'sort_key' parameters are supplied
    :param default_dir: default sort dir value, added to the list if no
                        'sort_dir' parameters are supplied
    :returns: list of sort keys, list of sort dirs
    """
    params = input_params.copy()
    sort_keys = []
    sort_dirs = []
    while 'sort_key' in params:
        sort_keys.append(params.pop('sort_key').strip())
    while 'sort_dir' in params:
        sort_dirs.append(params.pop('sort_dir').strip())
    if len(sort_keys) == 0 and default_key:
        sort_keys.append(default_key)
    if len(sort_dirs) == 0 and default_dir:
        sort_dirs.append(default_dir)
    return sort_keys, sort_dirs


def clean_serie(serie, err_max=10):
    """
    Funcion que limpia las mediciones dentro de una serie de tiempo
    con un error mayor al predefinido
    """
    serie_limpia = []
    for i, med in enumerate(serie):
        err_e = serie[i][4]
        err_n = serie[i][5]
        err_z = serie[i][6]
        if err_e < err_max and err_n < err_max and err_z < err_max:
            serie_limpia.append(serie[i])
    return serie_limpia


def legacy_html_escape(s):
    """legacy HTML escape for non-unicode mode."""
    s = s.replace('&', '&')
    s = s.replace('>', '>')
    s = s.replace('<', '<')
    s = s.replace('"', '"')
    s = s.replace("'", ''')
    return s


def _parse_index_file(filename):
    """Parse index file."""
    index = []
    for line in open(filename):
        index.append(int(line.strip()))
    return index


def escape_html(text):
    """Escape &, <, > as well as single and double quotes for HTML."""
    return text.replace('&', '&').replace('<', '<').replace('>', '>'
        ).replace('"', '"').replace("'", ''')


def _distill_params(multiparams, params):
    """Given arguments from the calling form *multiparams, **params,
    return a list of bind parameter structures, usually a list of
    dictionaries.

    In the case of 'raw' execution which accepts positional parameters,
    it may be a list of tuples or lists.

    """
    if not multiparams:
        if params:
            return [params]
        else:
            return []
    elif len(multiparams) == 1:
        zero = multiparams[0]
        if isinstance(zero, (list, tuple)):
            if not zero or hasattr(zero[0], '__iter__') and not hasattr(zero
                [0], 'strip'):
                return zero
            else:
                return [zero]
        elif hasattr(zero, 'keys'):
            return [zero]
        else:
            return [[zero]]
    elif hasattr(multiparams[0], '__iter__') and not hasattr(multiparams[0],
        'strip'):
        return multiparams
    else:
        return [multiparams]


def _add_doc(func, doc):
    """Add documentation to a function."""
    func.__doc__ = doc


@staticmethod
def clear(queue):
    """ Only undocumented methods. """
    with queue.mutex:
        queue.queue.clear()
        queue.all_tasks_done.notify_all()
        queue.unfinished_tasks = 0


@classmethod
def command(cls, name):
    """ Get command class for name """
    return cls.commands().get(name)


def write_key(key, value):
    """Return a string with the key, value in the WOK RIS format
    """
    if isinstance(value, list):
        lines = [key + ' ' + value[0].strip()]
        for val in value[1:]:
            lines.append('   ' + val.strip())
        return lines
    else:
        return [key + ' ' + value.strip()]


def writable(name):
    """Return boolean indicating whether a file at path is writable

        Note that a true value should be returned if the file doesn't
        exist but it's directory is writable.

        """


def capitalize(string):
    """
    Returns same string but with first letter capitalized
    Parameters
    ----------
    string: (str)

    Returns
    -------
    str
    """
    return string.capitalize()[0] + string[1:]


def detuplify(x):
    """If `x` is a tuple with one thing, extract it"""
    return None if len(x) == 0 else x[0] if len(x) == 1 and getattr(x,
        'ndim', 1) == 1 else x


def get_left(stereo_samp):
    """Return StereoSample stereo_samp's left value."""
    return stereo_samp.get_left()


def drop_nan_columns(data, ratio=1.0):
    """
    The ratio parameter (0.0<=ratio<1.0) lets you drop columns which has 'ratio'% of nans. (i.e if ratio is 0.8 then all columns with 80% or more entries being nan get dropped)
    Returns a new dataframe
    """
    col_list = []
    na_df = data.isna()
    total_size = na_df.shape[0]
    for col in na_df:
        a = na_df[col].value_counts()
        if False not in a.keys():
            col_list.append(col)
        elif True not in a.keys():
            pass
        elif a[True] / total_size >= ratio:
            col_list.append(col)
    print(f'{len(col_list)} columns dropped- {col_list}')
    return data.drop(col_list, axis=1)


@classmethod
def get_transcript(cls, video_id, languages=('en',), proxies=None, cookies=None
    ):
    """
        Retrieves the transcript for a single video. This is just a shortcut for calling::

            YouTubeTranscriptApi.list_transcripts(video_id, proxies).find_transcript(languages).fetch()

        :param video_id: the youtube video id
        :type video_id: str
        :param languages: A list of language codes in a descending priority. For example, if this is set to ['de', 'en']
        it will first try to fetch the german transcript (de) and then fetch the english transcript (en) if it fails to
        do so.
        :type languages: list[str]
        :param proxies: a dictionary mapping of http and https proxies to be used for the network requests
        :type proxies: {'http': str, 'https': str} - http://docs.python-requests.org/en/master/user/advanced/#proxies
        :param cookies: a string of the path to a text file containing youtube authorization cookies
        :type cookies: str
        :return: a list of dictionaries containing the 'text', 'start' and 'duration' keys
        :rtype [{'text': str, 'start': float, 'end': float}]:
        """
    return cls.list_transcripts(video_id, proxies, cookies).find_transcript(
        languages).fetch()


def ensure_project():
    """Ensure current directory is under a pentoy project."""
    pass


def set_wireframe(actor):
    """
    set an actor's look to wireframe

    :param actor:

    """
    actor.wireframe(value=True)


def is_flagging_threshold(proportion: float) ->bool:
    """Does the given proportion correspond to a board solved with 'flagging'?"""
    return proportion > 0.1


@classmethod
def member_change_external_id_details(cls, val):
    """
        Create an instance of this class set to the
        ``member_change_external_id_details`` tag with value ``val``.

        :param MemberChangeExternalIdDetails val:
        :rtype: EventDetails
        """
    return cls('member_change_external_id_details', val)


def removeContext(anExecutableObject):
    """Remove an ExecutableObject from the current security context.

        o Remove all objects from the top of the stack "down" to the
          supplied object.

        o If the top object on the stack declares a custom security policy,
          make that policy "current".

        o If the stack is empty, or if the top declares no custom security
          policy, restore the 'default" security policy as current.
        """


def fill(array, value, start=0, end=None):
    """Fills elements of array with value from `start` up to, but not
    including, `end`.

    Args:
        array (list): List to fill.
        value (mixed): Value to fill with.
        start (int, optional): Index to start filling. Defaults to ``0``.
        end (int, optional): Index to end filling. Defaults to ``len(array)``.

    Returns:
        list: Filled `array`.

    Example:

        >>> fill([1, 2, 3, 4, 5], 0)
        [0, 0, 0, 0, 0]
        >>> fill([1, 2, 3, 4, 5], 0, 1, 3)
        [1, 0, 0, 4, 5]
        >>> fill([1, 2, 3, 4, 5], 0, 0, 100)
        [0, 0, 0, 0, 0]

    Warning:
        `array` is modified in place.

    .. versionadded:: 3.1.0
    """
    if end is None:
        end = len(array)
    else:
        end = min(end, len(array))
    array[:] = array[:start] + [value] * len(array[start:end]) + array[end:]
    return array


def trigonalP(cp):
    """ a=b=c, alpha=beta=gamma """
    a, b, c, al, be, ga = cp
    anew = (a + b + c) / 3.0
    alnew = (al + be + ga) / 3.0
    return [anew, anew, anew, alnew, alnew, alnew]


def rotate(v, n=1):
    """Rotates the elements of a sequence by (n) places.
    Returns a new list.
    """
    n %= len(v)
    return v[n:] + v[:n]


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


def font_parse_string(font):
    """
    Convert from font string/tyuple into a Qt style sheet string
    :param font: "Arial 10 Bold" or ('Arial', 10, 'Bold)
    :return: style string that can be combined with other style strings
    """
    if font is None:
        return ''
    if type(font) is str:
        _font = font.split(' ')
    else:
        _font = font
    family = _font[0]
    point_size = int(_font[1])
    style = _font[2:] if len(_font) > 1 else None
    return family, point_size, style


def findIndices(bounds, data):
    """Look for boundary indices of array based on desired value range.
    """
    start = 0
    stop = len(data) - 1
    if bounds is not None:
        if bounds[0] is not None:
            while start < len(data) and data[start] < bounds[0]:
                start += 1
        if bounds[1] is not None:
            while stop >= 0 and data[stop] > bounds[1]:
                stop -= 1
        if start > 0 and start < len(data):
            start -= 1
        if stop < len(data) - 1 and stop >= 0:
            stop += 1
    return start, stop


def fill_empties(abstract):
    """Fill empty cells in the abstraction

    The way the row patterns are constructed assumes that empty cells are
    marked by the letter `C` as well. This function fill those in. The function
    also removes duplicate occurrances of ``CC`` and replaces these  with
    ``C``.

    Parameters
    ----------
    abstract : str
        The abstract representation of the file.

    Returns
    -------
    abstraction : str
        The abstract representation with empties filled.

    """
    while 'DD' in abstract:
        abstract = abstract.replace('DD', 'DCD')
    while 'DR' in abstract:
        abstract = abstract.replace('DR', 'DCR')
    while 'RD' in abstract:
        abstract = abstract.replace('RD', 'RCD')
    while 'CC' in abstract:
        abstract = abstract.replace('CC', 'C')
    if abstract.startswith('D'):
        abstract = 'C' + abstract
    if abstract.endswith('D'):
        abstract += 'C'
    return abstract


def sanitizer(unit):
    """
    Sanitizes a unit string. That is, it is de-blanked, and mu and µ symbols
    are changed to u for micro.

    :param unit: The unit that needs to be sanitized.

    :returns: the sanitized unit.
    :rtype: str
    """
    micro = 'µ'
    mugr = 'μ'
    return unit.replace(' ', '').replace('mu', 'u').replace(micro, 'u'
        ).replace(mugr, 'u')


def fixation_detection(x, y, time, missing=0.0, maxdist=25, mindur=50):
    """Detects fixations, defined as consecutive samples with an inter-sample distance of less than a set amount of pixels (disregarding missing data)

	Parameters
	----------
	x : array
		Gaze x positions
	y :	array
		Gaze y positions
	time : array
		Timestamps
	missing	: float
		Value to be used for missing data (default = 0.0)
	maxdist : int
		Maximal inter sample distance in pixels (default = 25)
	mindur : int
		Minimal duration of a fixation in milliseconds; detected fixation cadidates will be disregarded if they are below this duration (default = 100)

	Returns
	-------
	Sfix : list of lists
		Each containing [starttime]
	Efix : list of lists
		Each containing [starttime, endtime, duration, endx, endy]

	"""
    Sfix = []
    Efix = []
    si = 0
    fixstart = False
    for i in range(1, len(x)):
        dist = ((x[si] - x[i]) ** 2 + (y[si] - y[i]) ** 2) ** 0.5
        if dist <= maxdist and not fixstart:
            si = 0 + i
            fixstart = True
            Sfix.append([time[i]])
        elif dist > maxdist and fixstart:
            fixstart = False
            if time[i - 1] - Sfix[-1][0] >= mindur:
                Efix.append([Sfix[-1][0], time[i - 1], time[i - 1] - Sfix[-
                    1][0], x[si], y[si]])
            else:
                Sfix.pop(-1)
            si = 0 + i
        elif not fixstart:
            si += 1
    return Sfix, Efix


def remove_kwarg(argument: str) ->str:
    """Removes `**` in kwargs so those can be assigned in dynamic `__init__` creation"""
    return argument.split('**')[1]


@classmethod
def check_summary(cls, a, aidx, b, bidx):
    """Determine if two summary structures are equivalent,
        printing differences in the error if they are not.

        Args:
            a (dict): Summary information for an element type defintion.
            aidx (int): Index of element summarized by a that is used
                in the error message.
            b (dict): Summary information for an element type defintion.
            bidx (int): Index of element summarized by b that is used
                in the error message.

        Raises:
            AssertionError: If a and b are not equivalent.

        """
    if a == b:
        return
    assert len(a) == len(b)
    err_msg = []
    for k in a.keys():
        if a[k] != b[k]:
            err_msg.append(
                "The %s of element %d (%s) dosn't match element %d (%s=%s)" %
                (k, aidx, a[k], bidx, k, b[k]))
    raise AssertionError('\n'.join(err_msg))


def getpathfrombrowser(context):
    """
    returns path from filebrowser
    """
    for a in context.window.screen.areas:
        if a.type == 'FILE_BROWSER':
            params = a.spaces[0].params
            break
    try:
        params
    except UnboundLocalError:
        return {'CANCELLED'}
    path = params.directory
    return path


@staticmethod
def write_reqs_dep(filed, filename):
    """Writes out the dependency to all requirements."""
    filed.write('%s: ${REQS}\n\t${CALL_RMTOO}\n' % filename)


def progress_message(gen_all):
    """Decide progress bar message based on gen_all flag"""
    if gen_all:
        return 'Generating Transforms'
    else:
        return 'Stabilizing'


def pytest_register_ast_transformer(ast_manager, config):
    """ Register new ast transformers via `ast_manager.add_transformer`.

        Example:
            ast_manager.add_transformer(AssertTransformer())
    """


def resource_exists(resource):
    """Check whether the given `resource` exists physically.

        :rtype: bool

        Attempting to retrieve the model object for a non-existing
        resource should raise a `ResourceNotFound` exception.
        (''since 0.11.8'')
        """


def unflatten_people(em, people):
    """ Unflatten a list of IbisPerson objects (done in place). """
    if people:
        for idx, person in enumerate(people):
            people[idx] = person.unflatten(em)


def load(savename, loaddir='saved_interrogations'):
    """
    Load saved data into memory:

        >>> loaded = load('interro')

    will load ``./saved_interrogations/interro.p`` as loaded

    :param savename: Filename with or without extension
    :type savename: str

    :param loaddir: Relative path to the directory containg *savename*
    :type loaddir: str

    :param only_concs: Set to True if loading concordance lines
    :type only_concs: bool

    :returns: loaded data
    """
    try:
        import cPickle as pickle
    except ImportError:
        import pickle as pickle
    import os
    if not savename.endswith('.p'):
        savename = savename + '.p'
    if loaddir:
        if '/' not in savename:
            fullpath = os.path.join(loaddir, savename)
        else:
            fullpath = savename
    else:
        fullpath = savename
    with open(fullpath, 'rb') as fo:
        data = pickle.load(fo)
    return data


@classmethod
def unwrap(cls, value):
    """ Unwrap the value if it's wrapped with a marker """
    return value.key if isinstance(value, cls) else value


def view_selected():
    """Reset viewable area to show selected strips range

    """
    pass


def verify_build(build):
    """Verify the build section of the configuration file."""
    if not isinstance(build, dict):
        yield 'The "build" section has to be a dictionary.'
        return
    if 'image' not in build:
        yield '"image" is required in the build section.'
    if 'script' not in build:
        yield '"script" is required in the build section.'


def finddives2(depths, min_dive_thresh=10):
    """Find dives in depth data below a minimum dive threshold

    Args
    ----
    depths: ndarray
        Datalogger depth measurements
    min_dive_thresh: float
        Minimum depth threshold for which to classify a dive

    Returns
    -------
    dives: ndarray
        Dive summary information in a numpy record array

        *Columns*:

        * dive_id
        * start_idx
        * stop_idx
        * dive_dur
        * depth_max
        * depth_max_i
        * depth_min
        * depth_min_i
        * depth_mean
        * comp_mean

    dive_mask: ndarray
        Boolean mask array over depth data. Cells with `True` are dives and
        cells with `False` are not.
    """
    import numpy
    import pandas
    from . import utils
    condition = depths > min_dive_thresh
    ind_start, ind_end = utils.contiguous_regions(condition)
    n_dives = len(ind_start)
    dive_mask = numpy.zeros(len(depths), dtype=bool)
    dtypes = numpy.dtype([('dive_id', int), ('start_idx', int), ('stop_idx',
        int), ('dive_dur', int), ('depth_max', float), ('depth_max_idx',
        float), ('depth_min', float), ('depth_min_idx', float), (
        'depth_mean', float), ('comp_mean', float)])
    dive_data = numpy.zeros(n_dives, dtype=dtypes)
    for i in range(n_dives):
        dive_mask[ind_start[i]:ind_end[i]] = True
        dive_depths = depths[ind_start[i]:ind_end[i]]
        dive_data['dive_id'][i] = i
        dive_data['start_idx'][i] = ind_start[i]
        dive_data['stop_idx'][i] = ind_end[i]
        dive_data['dive_dur'][i] = ind_end[i] - ind_start[i]
        dive_data['depth_max'][i] = dive_depths.max()
        dive_data['depth_max_idx'][i] = numpy.argmax(dive_depths)
        dive_data['depth_min'][i] = dive_depths.min()
        dive_data['depth_min_idx'][i] = numpy.argmin(dive_depths)
        dive_data['depth_mean'][i] = numpy.mean(dive_depths)
        dive_data['comp_mean'][i] = numpy.mean(1 + 1 / (0.1 * dive_depths))
    dive_data = dive_data[dive_data['stop_idx'] < len(depths)]
    dives = pandas.DataFrame(dive_data)
    return dives, dive_mask


def get_subsite_folder():
    """
        Return the parent folder marked as "Subsite", for retrieve some infos
        like a color and the image pin
        """


def move_density_to_bdry(x, phi, P):
    """
    P tells us how much should be removed, by multiplying phi*P
    Take that density and instead of deleting it, move straight to boundary
    P - stores how much denstity from each grid point should be moved to diagonal
    """
    for ii in range(len(x)):
        for jj in range(len(x)):
            if P[ii, jj] == 0:
                continue
            else:
                amnt = P[ii, jj]
                s = ii + jj
                if ii == 1 and jj == len(x) - 3:
                    phi[ii + 1, jj] += phi[ii, jj] * amnt / 4.0 * 2
                    phi[ii, jj + 1] += phi[ii, jj] * amnt / 4.0 * 2
                    phi[ii - 1, jj] += phi[ii, jj] * amnt / 2 * 2
                    phi[ii, jj] *= 1 - amnt
                elif ii == len(x) - 3 and jj == 1:
                    phi[ii + 1, jj] += phi[ii, jj] * amnt / 4.0 * 2
                    phi[ii, jj + 1] += phi[ii, jj] * amnt / 4.0 * 2
                    phi[ii, jj - 1] += phi[ii, jj] * amnt / 2 * 2
                    phi[ii, jj] *= 1 - amnt
                elif (len(x) - 1 - s) % 2 == 1:
                    dist = (len(x) - 1 - s) // 2
                    phi[ii + dist + 1, jj + dist] += phi[ii, jj
                        ] * amnt / 2.0 * 2
                    phi[ii + dist, jj + dist + 1] += phi[ii, jj
                        ] * amnt / 2.0 * 2
                    phi[ii, jj] *= 1 - amnt
                else:
                    dist = (len(x) - 1 - s) // 2
                    phi[ii + dist, jj + dist] += phi[ii, jj] * amnt * 2
                    phi[ii, jj] *= 1 - amnt
    return phi


def is_motorcycle(df):
    """Return if vehicle is a motorcycle, per NHTSA convention."""
    yr = df['YEAR']
    body = df['BODY_TYP']
    return yr.between(1975, 1981) & body.between(15, 18) | yr.between(1982,
        1990) & body.between(20, 29) | (1991 <= yr) & body.between(80, 89)


def _node_value(G, node_attr):
    """Returns a function that returns a value from G.nodes[u].

    We return a function expecting a node as its sole argument. Then, in the
    simplest scenario, the returned function will return G.nodes[u][node_attr].
    However, we also handle the case when `node_attr` is None or when it is a
    function itself.

    Parameters
    ----------
    G : graph
        A NetworkX graph

    node_attr : {None, str, callable}
        Specification of how the value of the node attribute should be obtained
        from the node attribute dictionary.

    Returns
    -------
    value : function
        A function expecting a node as its sole argument. The function will
        returns a value from G.nodes[u] that depends on `edge_attr`.

    """
    if node_attr is None:

        def value(u):
            return u
    elif not hasattr(node_attr, '__call__'):

        def value(u):
            return G.nodes[u][node_attr]
    else:
        value = node_attr
    return value


@classmethod
def remove_ptable(cls, options=None):
    """
        Removes partitioning table from OS.
        """
    cls.command_sub = 'remove-ptable '
    result = cls.execute(cls._construct_command(options))
    return result


@staticmethod
def is_in_interval(n, l, r, border='included'):
    """
        Checks whether a number is inside the interval l, r.
        """
    if 'included' == border:
        return n >= l and n <= r
    elif 'excluded' == border:
        return n > l and n < r
    else:
        raise ValueError("borders must be either 'included' or 'excluded'")


@staticmethod
def supportedViews():
    """Overrides :meth:`.ControlMixin.supportedViews`. The
        ``OrthoEditSettingsPanel`` is only intended to be added to
        :class:`.OrthoPanel` views.
        """
    from fsleyes.views.orthopanel import OrthoPanel
    return [OrthoPanel]


def render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

    Like 'git describe --tags --dirty --always'.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


def pdb(stmt):
    """Run the statement under the PDB debugger."""
    import pdb
    pdb.set_trace()
    exec(stmt)


def _scale_size(size, scale):
    """Rescale a size by a ratio.

    Args:
        size (tuple[int]): (w, h).
        scale (float): Scaling factor.

    Returns:
        tuple[int]: scaled size.
    """
    w, h = size
    return int(w * float(scale) + 0.5), int(h * float(scale) + 0.5)


@staticmethod
def _split_line(line: str) ->list:
    """Every message in the file is timestamped in the following format:
          1585817817.5626152:{"type":"RECORD","value":{"col_1":"value_1"}}

        This method split the original message to timestamp and the real message
        componets and returns as list of two items.
        """
    return line.split(':', 1)


@staticmethod
def _valid_packet(raw_packet):
    """Validate incoming packet."""
    if raw_packet[0:1] != b'\xcc':
        return False
    if len(raw_packet) != 19:
        return False
    checksum = 0
    for i in range(1, 17):
        checksum += raw_packet[i]
    if checksum != raw_packet[18]:
        return False
    return True


def doStop():
    """
        Called every time this is unconnected from a Port or Connector.
        """


def baseId(resource_id, version=False):
    """Calculates base id (assetId?)."""
    v = 0
    if resource_id > 1358954496:
        resource_id -= 1342177280
        v += 1
    if resource_id > 67108864:
        resource_id -= 50331648
        v += 1
    while resource_id > 16777216:
        resource_id -= 16777216
        v += 1
    if version:
        return resource_id, v
    return resource_id


def _gmm(profiles, n_groups, threshold, init='random', n_init=100):
    """Apply the classic Gaussian Mixture Model (GMM) to discover
    resource groups [1]_.

    Parameters
    ----------
    profiles : DataFrame
        Constructed resource profiles.
    n_groups : int
        Expected number of resource groups.
    threshold : float
        A given threshold value in range [0, 1.0] for producing
        determined clustering from the fuzzy clustering results from GMM.
    init : {'random', 'mja', 'ahc', 'kmeans', 'plain'}, optional,         default 'random'
        Options for deciding the strategy for initialization. Could be
        one of the following:

            - ``'random'``, use random initialization.
            - ``'mja'``, use the mining method Metric based on Joint
              Activities as initialization method.
            - ``'ahc'``, use the hierarchical method of Agglomerative
              Hierarchical Clustering as initialization method.
            - ``'kmeans'``, use the classic clustering algorithm kMeans
              as initialization method.
            - ``'plain'``, simply put resources into groups by in the
              order of their ids.

        Note that if an option other than ``'random'`` is specified, then
        the initialization is performed once only.
    n_init : int, optional, default 100
        Number of times of random initialization (if specified) performs
        before training the clustering model.

    Returns
    -------
    list of frozensets
        Discovered resource groups.

    Raises
    ------
    ValueError
        If the specified option for initialization is invalid.

    See Also
    --------
    sklearn.mixture.GaussianMixture
    orgminer.OrganizationalModelMiner.community.graph_partitioning.mja
    orgminer.OrganizationalModelMiner.clustering.hierarchical.ahc
    sklearn.cluster.KMeans

    References
    ----------
    .. [1] Yang, J., Ouyang, C., Pan, M., Yu, Y., & ter Hofstede, A.
       (2018). Finding the Liberos: Discover Organizational Models with
       Overlaps. In *Proceedings of the 16th International Conference on
       Business Process Management*, pp. 339-355. Springer, Cham.
       `<https://doi.org/10.1007/978-3-319-98648-7_20>`_
    """
    print('Applying overlapping clustering -based GMM:')
    if init in ['mja', 'ahc', 'kmeans', 'plain']:
        warm_start = True
        if init == 'mja':
            from orgminer.OrganizationalModelMiner.community.graph_partitioning import _mja
            init_groups = _mja(profiles, n_groups)
        elif init == 'ahc':
            from .hierarchical import _ahc
            init_groups, _ = _ahc(profiles, n_groups)
        elif init == 'kmeans':
            init_groups = list(set() for i in range(n_groups))
            from sklearn.cluster import KMeans
            labels = KMeans(n_clusters=n_groups, random_state=0).fit_predict(
                profiles)
            for i, r in enumerate(sorted(profiles.index)):
                init_groups[labels[i]].add(r)
        else:
            init_groups = list(set() for i in range(n_groups))
            for i, r in enumerate(sorted(profiles.index)):
                init_groups[i % n_groups].add(r)
        print('Initialization done using {}:'.format(init))
    elif init == 'random':
        warm_start = False
    else:
        raise ValueError('Invalid value for parameter `{}`: {}'.format(
            'init', init))
    from sklearn.mixture import GaussianMixture
    if warm_start:
        from numpy import mean
        init_means = list()
        for g in init_groups:
            init_means.append(mean(profiles.loc[list(g)].values, axis=0))
        gmm_model = GaussianMixture(n_components=n_groups, covariance_type=
            'tied', tol=1e-09, max_iter=1000, n_init=1, random_state=0,
            means_init=init_means).fit(profiles.values)
    else:
        gmm_model = GaussianMixture(n_components=n_groups, covariance_type=
            'tied', tol=1e-09, max_iter=1000, n_init=n_init, init_params=
            'random').fit(profiles.values)
    posterior_pr = gmm_model.predict_proba(profiles.values)
    from numpy import nonzero, median, unique, count_nonzero, amin, percentile
    """
    threshold_ub = 0
    for pr in sorted(unique(posterior_pr), reverse=True):
        mbr_mat = posterior_pr >= pr
        if count_nonzero(mbr_mat.any(axis=1)) < len(profiles):
            pass
        else:
            if count_nonzero(mbr_mat.any(axis=0)) == n_groups:
                threshold_ub = pr
                break

    if threshold_ub != 0.0:
        threshold = amin([percentile(posterior_pr, 75), threshold_ub])
        membership_total = posterior_pr >= threshold
    else:
        membership_total = posterior_pr > 0.0
    """
    membership_total = posterior_pr >= threshold
    from collections import defaultdict
    groups = defaultdict(set)
    for i, membership in enumerate(membership_total):
        for j in nonzero(membership)[0]:
            groups[j].add(profiles.index[i])
    return [frozenset(g) for g in groups.values()]


def dpad_down_pressed(controller):
    """
    Callback function that is triggered, when the dpad down button was pressed

    :param controller:              the controller that triggered the action
    :type controller:               steuer.Controller
    """
    print('ACTION:' + str(controller.number) + ':' + controller.name +
        ':DPAD Down pressed')


def get_pixel(x, x0, width):
    """returns the pixel number for a coordinate value."""
    return int((x - x0) // width)


def _hexprints(n):
    """
    Returns a hex sting of length 2 that represents the number n
    :raises ValueError if 0 > n or n > 255
    :param n: int
    :return: string
    """
    if isinstance(n, str):
        n = ord(n)
    if 0 > n or n > 255:
        raise ValueError('n(' + str(n) + ") doesn't fit for _hexprints")
    if n > 15:
        return hex(n)[2:]
    else:
        return '0' + hex(n)[2:]


def generic_find_fk_constraint_names(table, columns, referenced, insp):
    """Utility to find foreign-key constraint names in alembic migrations"""
    names = set()
    for fk in insp.get_foreign_keys(table):
        if fk['referred_table'] == referenced and set(fk['referred_columns']
            ) == columns:
            names.add(fk['name'])
    return names


def pixel2img(xy, ax=None):
    """
    Plot create by SPM.show can be either in pixels or real unit.
    This function return the input in case the plot is in pixels
    or calculate and return the real unit coordinate of the corresponding pixel.
    """
    import matplotlib.pyplot as plt
    if ax is None:
        ax = plt.gca()
    if hasattr(ax, 'isPixel'):
        if not ax.isPixel:
            pixel_shape = ax.images[0].get_array().shape
            extent = ax.images[0].get_extent()
            eW = extent[1] - extent[0]
            eH = extent[3] - extent[2]
            return xy[0] * eW / pixel_shape[1], xy[1] * eH / pixel_shape[0]
    return xy


def project_community(index, start, end):
    """Compute the metrics for the project community section of the enriched
    github issues index.

    Returns a dictionary containing "author_metrics", "people_top_metrics"
    and "orgs_top_metrics" as the keys and the related Metrics as the values.

    :param index: index object
    :param start: start date to get the data from
    :param end: end date to get the data upto
    :return: dictionary with the value of the metrics
    """
    results = {'author_metrics': [], 'people_top_metrics': [],
        'orgs_top_metrics': []}
    return results


def render_git_describe_long(pieces):
    """TAG-DISTANCE-gHEX[-dirty].

    Like 'git describe --tags --dirty --always -long'.
    The distance/hash is unconditional.

    Exceptions:
    1: no tags. HEX[-dirty]  (note: no 'g' prefix)
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        rendered += '-%d-g%s' % (pieces['distance'], pieces['short'])
    else:
        rendered = pieces['short']
    if pieces['dirty']:
        rendered += '-dirty'
    return rendered


def _node_merge_dict(primary_label, primary_key, nodes):
    """ Convert a set of :class:`.Node` objects into a dictionary of
    :class:`.Node` lists, keyed by a 3-tuple of
    (primary_label, primary_key, frozenset(labels)).

    :param primary_label:
    :param primary_key:
    :param nodes:
    :return: dict of (p_label, p_key, frozenset(labels)) to list(nodes)
    """
    d = {}
    for node in nodes:
        p_label = getattr(node, '__primarylabel__', None) or primary_label
        p_key = getattr(node, '__primarykey__', None) or primary_key
        key = p_label, p_key, frozenset(node.labels)
        d.setdefault(key, []).append(node)
    return d


def default_pylogger_config(name='ctl'):
    """
    The defauly python logging setup to use when no `log` config
    is provided via the ctl config file
    """
    return {'version': 1, 'formatters': {'default': {'format':
        '[%(asctime)s] %(message)s'}}, 'handlers': {'console': {'level':
        'INFO', 'class': 'logging.StreamHandler', 'formatter': 'default',
        'stream': 'ext://sys.stdout'}}, 'loggers': {name: {'level': 'INFO',
        'handlers': ['console']}, 'usage': {'level': 'INFO', 'handlers': [
        'console']}}}


def _ctypes_dtype(parameter):
    """Determines the ISO_C data type to use for describing the specified parameter.
    """
    ctype = parameter.ctype
    if ctype is None:
        if parameter.kind is not None:
            return '{}({})'.format(parameter.dtype, parameter.kind)
        else:
            return parameter.dtype
    else:
        return '{}({})'.format(parameter.dtype, ctype)


def matches(match):
    """
        return files in the dirstate (in whatever state) filtered by match
        """