@staticmethod
def _copy_blanks(df, source_column, destination_column):
    """
        Copies all blanks from the source column to the destination column
        """
    df.loc[df.loc[:, (source_column)].isnull(), destination_column] = ''
    if df.dtypes[source_column] == object:
        df.loc[df.loc[:, (source_column)] == '', destination_column] = ''


def actualizar(símismo):
    """
        Esta función actualiza las matrices internas del Simulable para prepararlo para una simulación.
        Se aplica individualmente en todas las subclases de Simulable, que también deben poner símismo.listo = True
        al final.

        """
    raise NotImplementedError


def get_exception_message(ex):
    """Build exception message with details.
    """
    template = '{0}: {1!r}'
    return template.format(type(ex).__name__, ex.args)


def steps(current, target, max_steps):
    """ Steps between two values.

    :param current: Current value (0.0-1.0).
    :param target: Target value (0.0-1.0).
    :param max_steps: Maximum number of steps.
    """
    if current < 0 or current > 1.0:
        raise ValueError('current value %s is out of bounds (0.0-1.0)', current
            )
    if target < 0 or target > 1.0:
        raise ValueError('target value %s is out of bounds (0.0-1.0)', target)
    return int(abs(current * max_steps - target * max_steps))


def del_com():
    """Delete the cam list.

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


def strip_suffix(name, split='_'):
    """
    Returns the portion of name minus the last element separated by the splitter character
    :param name: str, name to strip the suffix from
    :param split: str, split character
    :return: str
    """
    if not name.count(split):
        return name
    return name.replace(split + name.split(split)[-1], '')


def symbolic(func):
    """Dummy decorator used in TensorFlow 2.0 to enter the Keras graph."""
    return func


def load_smt_data(model, xt, yt, dyt_dxt=None):
    """
    Utility function to load SMT data more easily

    :param model: SurrogateModel object for which to load training data
    :param xt: smt data points at which response is evaluated
    :param yt: response at xt
    :param dyt_dxt: gradient at xt
    """
    if len(xt.shape) == 1:
        n_x = 1
        m = xt.size
    else:
        m, n_x = xt.shape
    if len(yt.shape) == 1:
        n_y = 1
    else:
        n_y = yt.shape[1]
    xt = xt.reshape((m, n_x))
    yt = yt.reshape((m, n_y))
    model.set_training_values(xt, yt)
    if dyt_dxt is not None:
        dyt_dxt = dyt_dxt.reshape((m, n_x))
        for i in range(n_x):
            model.set_training_derivatives(xt, dyt_dxt[:, (i)].reshape((m,
                1)), i)


def _format_field_name(attr):
    """Format an object attribute in a human-friendly way."""
    parts = attr.rsplit(':', 1)
    name = parts[-1].replace('_', ' ')
    if name.isupper() or name.islower():
        name = name.title()
    parts[-1] = name
    return ': '.join(parts)


def preprocess_scan(scan_file):
    """Preprocess the scan file to a form that chooch will accept."""
    try:
        with open(scan_file, 'r') as fh:
            i = int(fh.readlines()[1])
        return scan_file
    except Exception:
        data = open(scan_file, 'r').readlines()
        more_data = []
        for d in data:
            if not '#' in d and d.strip():
                more_data.append(d)
        data = more_data
        count = len(data)
        out = open('xia2-chooch.raw', 'w')
        out.write('Chooch Scan File from xia2\n%d\n' % count)
        for d in data:
            out.write('%f %f\n' % tuple(map(float, d.split(',')[:2])))
        out.close()
        return 'xia2-chooch.raw'


def _(x):
    """Identity function for string extraction."""
    return x


def as_bytes(value):
    """
    Returns value as bytes
    """
    if not isinstance(value, bytes):
        return value.encode('UTF-8')
    return value


@staticmethod
def _get_scheduler_hints(filter_properties, request_spec=None):
    """Helper method to get scheduler hints.

        This method prefers to get the hints out of the request spec, but that
        might not be provided. Conductor will pass request_spec down to the
        first compute chosen for a build but older computes will not pass
        the request_spec to conductor's build_instances method for a
        a reschedule, so if we're on a host via a retry, request_spec may not
        be provided so we need to fallback to use the filter_properties
        to get scheduler hints.
        """
    hints = {}
    if request_spec is not None and 'scheduler_hints' in request_spec:
        hints = request_spec.scheduler_hints
    if not hints:
        hints = filter_properties.get('scheduler_hints') or {}
    return hints


def get_all_storage_nodes(session, cloud_name, return_type=None, **kwargs):
    """
    Get all Storage Nodes

    :type session: zadarapy.session.Session
    :param session: A valid zadarapy.session.Session object.  Required.

    :type cloud_name: str
    :param cloud_name: Cloud Name: i.e: zadaraqa9

    :type return_type: str
    :param return_type: If this is set to the string 'json', this function
        will return a JSON string.  Otherwise, it will return a Python
        dictionary.  Optional (will return a Python dictionary by default).

    :rtype: dict, str
    :returns: A dictionary or JSON data set as a string depending on
        return_type parameter.
    """
    path = '/api/clouds/{0}/nodes.json'.format(cloud_name)
    return session.get_api(path=path, return_type=return_type, **kwargs)


def setupScoreboard(players, score, gamesPlayed, total, wins):
    """Initialise the scoreboard on the UI. Not required for console."""
    pass


def quality_mime_sort_key(qmt):
    """
    Media ranges can be overridden by more    specific media ranges or specific media    types. If more than one media range    applies to a given type, the most    specific reference has precedence.

    Example::

        1. text/plain;format=flowed
        2. text/plain
        3. text/*
        4. */*

    :param qmt:
    :return: Factor as tuple(quality,    type_factor, subtype_factor,    len_of_params)
    """
    value, params = qmt
    type_, subtype = value
    if type_ != '*':
        type_factor = 1
    else:
        type_factor = 0
    if subtype != '*':
        subtype_factor = 1
    else:
        subtype_factor = 0
    return params['q'] * -1, type_factor * -1, subtype_factor * -1, len(params
        ) * -1


def whitespace_tokenize(text):
    """Runs basic whitespace cleaning and splitting on a piece of text."""
    text = text.strip()
    if not text:
        return []
    tokens = text.split()
    return tokens


@classmethod
def is_windows(cls):
    """
        Checks if the current platform is in our windows list.

        :rtype: bool
        """
    return cls.get() in cls.WINDOWS


def _embedding_aggregator(output_queue, n_worker):
    """ Process that aggregates the results of the workers.
        This should be the main/original process.

    Parameters
    ----------
    output_queue: Queue
        This queue is the output queue of the workers.
    n_worker: int
        The number of worker processes.

    Returns
    -------
    Aggregated embedding dictionary.
    """
    embedding = {}
    num_done = 0
    while num_done < n_worker:
        new_embedding = output_queue.get()
        if new_embedding == 'DONE':
            num_done += 1
        else:
            embedding.update(new_embedding)
    return embedding


def convert_by_vocab(vocab, items):
    """Converts a sequence of [tokens|ids] using the vocab."""
    output = []
    for item in items:
        output.append(vocab[item])
    return output


def dfmeta_to_htmlfile(styled_df, filename, head=''):
    """
    styled_df should be <class 'IPython.core.display.HTML'>
    """
    r = f'
{head}
\n' + '\n' + styled_df.data + '\n'
    with open(filename, 'w') as f:
        f.write(r)
    return f'{filename} saved'


def weighted_avg(df, col, weight_col='vol', epsilon=0):
    """find weighted_avg of col values based on weights from weight_col
    Args:
        df: (pd.DataFrame) data that has col and weight_col
        col: (str) name of the column which will be averaged
        weight_col: (str) name of the column which will be used as weights
        epsilon: (float) value to add to weights to ensure not zero
    """
    df[weight_col] += epsilon
    return (df[col] * df[weight_col]).sum() / df[weight_col].sum()


def _df_meta_to_arr(df):
    """Check what kind of data exists in pandas columns or index. If string return as numpy array 'S' type, otherwise regular numpy array. Used when saving Brain_Data objects to hdf5.
    """
    if len(df.columns):
        if isinstance(df.columns[0], str):
            columns = df.columns.values.astype('S')
        else:
            columns = df.columns.values
    else:
        columns = []
    if len(df.index):
        if isinstance(df.index[0], str):
            index = df.index.values.astype('S')
        else:
            index = df.index.values
    else:
        index = []
    return columns, index


def deslugify(string):
    """
    Convert a string to a feature name and its parameters.

    Parameters
    ----------
        string : str
            The slug string to extract values from.

    Returns
    -------
        name : str
            The name of the class corresponding to the string.

        final_params : dict
            A dictionary of the feature parameters.
    """
    parts = string.split('__')
    name = parts[0]
    params = parts[1:]
    swap = {'None': None, 'True': True, 'False': False}
    final_params = dict()
    for param in params:
        arg, value = param.split('=')
        try:
            value = int(value)
        except ValueError:
            try:
                value = float(value)
            except ValueError:
                pass
        if value in swap:
            value = swap[value]
        final_params[arg] = value
    return name, final_params


def pulse_magnitude(time, magnitude, start, repeat_time=0):
    """ Implements xmile's PULSE function

    PULSE:             Generate a one-DT wide pulse at the given time
       Parameters:     2 or 3:  (magnitude, first time[, interval])
                       Without interval or when interval = 0, the PULSE is generated only once
       Example:        PULSE(20, 12, 5) generates a pulse value of 20/DT at time 12, 17, 22, etc.

    In rage [-inf, start) returns 0
    In range [start + n * repeat_time, start + n * repeat_time + dt) return magnitude/dt
    In rage [start + n * repeat_time + dt, start + (n + 1) * repeat_time) return 0
    """
    t = time()
    small = 1e-06
    if repeat_time <= small:
        if abs(t - start) < time.step():
            return magnitude * time.step()
        else:
            return 0
    elif abs((t - start) % repeat_time) < time.step():
        return magnitude * time.step()
    else:
        return 0


def amend_simple(line, filename, user, timestamp_length):
    """Given a line from a log file, insert its filename and return it"""
    return '{} - {} - {}{}'.format(line[:timestamp_length], filename, user,
        line[timestamp_length:])


def print_phylip(source_dict):
    """Print phylip-formatted string from {taxon: seq} dict."""
    taxa_list = list(source_dict.keys())
    no_taxa = len(taxa_list)
    pad_longest_name = len(max(taxa_list, key=len)) + 3
    seq_length = len(next(iter(source_dict.values())))
    header = str(len(source_dict)) + ' ' + str(seq_length)
    phylip_string = header + '\n'
    for taxon, seq in sorted(source_dict.items()):
        taxon = taxon.replace(' ', '_').strip("'")
        phylip_string += taxon.ljust(pad_longest_name, ' ') + seq + '\n'
    return phylip_string


def which_one(iterable):
    """Index of the first True value in an iterable."""
    it = enumerate(iterable)
    i, x = next(it)
    while not x:
        i, x = next(it)
    return i


def can_paginate(operation_name=None):
    """
    Check if an operation can be paginated.

    :type operation_name: string
    :param operation_name: The operation name. This is the same name
            as the method name on the client. For example, if the
            method name is create_foo, and you'd normally invoke the
            operation as client.create_foo(**kwargs), if the
            create_foo operation can be paginated, you can use the
            call client.get_paginator('create_foo').

    """
    pass


def rules_stats(rules, itemsets, n_examples):
    """
    Generate additional stats for rules generated by :obj:`association_rules()`.

    Parameters
    ----------
    rules: iterable
        Rules as output by `association_rules()`.
    itemsets: dict
        The itemsets as obtained by `dict(frequent_itemsets(...))`.
    n_examples: int
        The total number of instances (for calculating coverage, lift,
        and leverage).

    Yields
    ------
    atecedent: frozenset
        The LHS of the association rule.
    consequent: frozenset
        The RHS of the association rule.
    support: int
        Support as an absolute number of instances.
    confidence: float
        The confidence percent, calculated as: ``total_support / lhs_rupport``.
    coverage: float
        Calculated as: ``lhs_support / n_examples``
    strength: float
        Calculated as: ``rhs_support / lhs_examples``
    lift: float
        Calculated as: ``n_examples * total_support / lhs_support / rhs_support``
    leverage: float
        Calculated as: ``(total_support * n_examples - lhs_support * rhs_support) / n_examples**2``

    Examples
    --------
    >>> N = 30
    >>> X = np.random.random((N, 50)) > .9
    >>> itemsets = dict(frequent_itemsets(X, .1))
    >>> rules = association_rules(itemsets, .6)
    >>> list(rules_stats(rules, itemsets, N))
    [(frozenset({15}), frozenset({0}), 3, 0.75, 0.13..., 1.5, 3.75, 0.073...),
     (frozenset({47}), frozenset({22}), 3, 0.6, 0.16..., 1.4, 2.57..., 0.061...),
     (frozenset({27}), frozenset({22}), 4, 0.66..., 0.2, 1.16..., 2.85..., 0.086...),
     (frozenset({19}), frozenset({22}), 3, 0.6, 0.16..., 1.4, 2.57..., 0.061...)]

    """
    assert isinstance(itemsets, dict) and isinstance(next(iter(itemsets),
        frozenset()), frozenset)
    assert n_examples > 0
    for left, right, support, confidence in rules:
        l_support, r_support = itemsets[left], itemsets[right]
        coverage = l_support / n_examples
        strength = r_support / l_support
        lift = n_examples * confidence / r_support
        leverage = (support * n_examples - l_support * r_support
            ) / n_examples ** 2
        yield left, right, support, confidence, coverage, strength, lift, leverage


def face_make_planar(factor: float=1.0, repeat: int=1):
    """Flatten selected faces

    :param factor: Factor
    :type factor: float
    :param repeat: Iterations
    :type repeat: int
    """
    pass


def psi_H_MgOH_OH_HMW84(T, P):
    """c-c'-a: hydrogen magnesium-hydroxide hydroxide [HMW84]."""
    psi = 0
    valid = T == 298.15
    return psi, valid


def default_send(*args):
    """对于参数数量确定的，有且只有一个的情况，可以使用默认发送函数"""
    return args[0], b''


def listAllowedRights(content=None, content_type=None):
    """ List the allowed values of the 'Rights' DCMI element.

        o The 'Rights' element describes copyright or other IP declarations
          pertaining to a resource.

        o Return only values appropriate for content's type, or all values if
          both 'content' and 'content_type' are None.
        """


def deg2dms(x):
    """Transform degrees to *degrees:arcminutes:arcseconds* strings.

    Parameters
    ----------
    x : float
        The degree value to be converted.

    Returns
    -------
    out : str
        The input angle as a string, written as degrees:minutes:seconds.

    """
    from astropy.coordinates import Angle
    ac = Angle(x, unit='degree')
    dms = ac.to_string(unit='degree', sep=':', pad=True)
    return str(dms)


def compute_knee_frequency(knee, exponent):
    """Compute the frequency value of the knee given the aperiodic parameter values.

    Parameters
    ----------
    knee : float
        Knee parameter value.
    exponent : float
        Exponent parameter value.

    Returns
    -------
    float
        Frequency value, in Hz, of the knee occurs.
    """
    return knee ** (1.0 / exponent)


def unalias(aliased_key):
    """Return the key belonging to aliased_key.
        """


def get_inheritance_map(class_to_process):
    """
    Return the inheritance mapping of the given class
    :param class_to_process: class
    """
    import inspect
    return inspect.getmro(class_to_process)


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

        :param NoExpirationLinkGenReportFailedType val:
        :rtype: EventType
        """
    return cls('no_expiration_link_gen_report_failed', val)


def empty(value):
    """test if a value is empty

    >>> empty('')
    True

    >>> empty(' ')
    True

    >>> empty('\\n')
    True

    >>> empty('x')
    False

    >>> empty(1)
    False
    """
    try:
        return not value or value.isspace()
    except AttributeError:
        return False


def jac_shortage(x, cf, *args):
    """Function defining Jacobian of inequality constraint on
    RES production shortage, when production from RES is not able
    to meet fraction of demand not met by conventional components.

    :param x: State vector(not used).
    :param cf: Time-dependent capacity factors.
    :type x: :py:class:`numpy.array`
    :type cf: :py:class:`numpy.array`

    :returns: Value of Jacobian of constraint.
    :rtype: :py:class:`numpy.array`
    """
    return cf


def vet_perms(user, observation):
    """
    This context flag will determine if vet buttons appears for the observation.
    That includes observer, station owner involved, moderators, admins.
    see: https://wiki.satnogs.org/Operation#Network_permissions_matrix
    """
    if user.is_authenticated():
        if user.ground_stations.filter(status=2).exists():
            return True
        try:
            if observation.author == user:
                return True
        except AttributeError:
            pass
        try:
            if observation.ground_station.owner == user:
                return True
        except AttributeError:
            pass
        if user.groups.filter(name='Moderators').exists():
            return True
        if user.is_superuser:
            return True
    return False


@classmethod
def create(cls):
    """
        Convenience function that creates a new instance of this class, with
        all fields initialized to empty sequences.
        """
    return cls([], [], [], [])


def entries(daterange=None, human_resource=None, costunit=None):
    """ Returns a list of non repeating time entries to cover the provided date range,
            optionally only for a given human resource or cost unit
        """


def str2port(s):
    """Convert a string to a network port number.

    :param str s: the string to convert
    :return: port number
    :rtype: int
    :raises ValueError: if ``s`` cannot be converted to a number in [0..65535]

    .. versionadded:: 0.5.0
    """
    port = int(s)
    if 0 <= port <= 65535:
        return port
    raise ValueError('not a valid port number: %d' % port)


def atomic_add(API):
    """
    Return the atomic_add for the given API.
    Overcome the missing atomic_add_float for OpenCL-1.2.
    """
    ocl_add = """
    // #pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
    KERNEL void atomic_add_float(
            GLOBAL_MEM float *ptr,
            const float temp)
    {
    // The work-around of AtomicAdd for float
    // lockless add *source += operand
    // Caution!!!!!!! Use with care! You have been warned!
    // http://simpleopencl.blogspot.com/2013/05/atomic-operations-and-floats-in-opencl.html
    // Source: https://github.com/clMathLibraries/clSPARSE/blob/master/src/library/kernels/csrmv_adaptive.cl
        union {
            unsigned int intVal;
            float floatVal;
        } newVal;

        union {
            unsigned int intVal;
            float floatVal;
        } prevVal;

        do {
            prevVal.floatVal = *ptr;
            newVal.floatVal = prevVal.floatVal + temp;
        } while (atomic_cmpxchg((volatile GLOBAL_MEM unsigned int *)ptr, prevVal.intVal, newVal.intVal) != prevVal.intVal);
    };
    """
    cuda_add = """

    __device__ void atomic_add_float(
            GLOBAL_MEM float *ptr,
            const float temp)
    { // Wrapper around CUDA atomicAdd();
    atomicAdd(ptr, temp);
    };

    """
    if API == 'cuda':
        code_text = cuda_add
    elif API == 'ocl':
        code_text = ocl_add
    return code_text


def get_client_ip(request):
    """
    Get the client IP address from the *request* object.

    Looks up the IP address that sent the *request* by checking the
    `HTTP_X_FORWARDED_FOR` header or `REMOTE_ADDR` in the request's metadata.

    Args:
        request: a Django request.

    Returns:
        An IP address as a string or an empty string if no IP could be found.
    """
    client_ip = request.META.get('HTTP_X_FORWARDED_FOR', '')
    try:
        client_ip = client_ip.split(',')[0]
    except IndexError:
        pass
    if not client_ip:
        client_ip = request.META.get('REMOTE_ADDR', '')
    return client_ip.strip()


def create_yubikey_validationservice(app_config, **kwargs):
    """
    Make sure at least one ValidationService exists.
    """
    from otp_yubikey.models import ValidationService
    if app_config.label == 'otp_yubikey' and ValidationService.objects.all(
        ).count() == 0:
        ValidationService.objects.get_or_create(defaults={'name':
            'YubiCloud', 'use_ssl': True, 'param_sl': '', 'param_timeout': ''})


def convert_by_vocab(vocab, items):
    """Converts a sequence of [tokens|ids] using the vocab."""
    output = []
    for item in items:
        output.append(vocab[item])
    return output


@classmethod
def choose(cls, *types):
    """Decorator to force `Maybe` values constraining to expecting types.

        For example, a function that return a collection (tuple or list) if
        valid or False if not, if not decorated could be ambiguous for an
        empty collection::

            >>> @Just.choose(tuple, list)
            ... def check_range(values, min, max):
            ...     if isinstance(values, (tuple, list)):
            ...         return [v for v in values if min <= v <= max]
            ...     else:
            ...         return False

            >>> check_range(range(10), 7, 17)
            [7, 8, 9]

            >>> check_range(range(10), 17, 27)
            Just([])

            >>> check_range(set(range(10)), 7, 17)
            False

        """
    pass


@staticmethod
def _genTopBottom(text, symbol):
    """
        Generate the top or bottom of the header
        :param text: Text
        :param symbol: Symbol
        :return: String for top + bottom header
        """
    neededLength = len(text) + 8
    return str(symbol * neededLength)


@staticmethod
def to_jwk(key_obj):
    """
        Serializes a given RSA key into a JWK
        """
    raise NotImplementedError


@classmethod
def identity(cls, dim):
    """Returns a dim x dim identity matrix."""
    if dim < 1:
        raise ValueError(
            'Identity matrix must have positive size, %d not allowed.' % dim)
    return cls._matrix_alloc_identity(dim)


def stringdisplay(s):
    """convert "d.d.d.d,d.d.d.d" to ["d.d.d.d","d.d.d.d"].
       also handle u'd.d.d.d d.d.d.d', as reporting on SF
    """
    import re
    return map(str, re.split('[ ,]', s))


def generic_args(t):
    """
    Generic's arg-types
    >>> generic_args(list) is None
    True
    >>> generic_args(Dict) is None
    True
    >>> generic_args(List[str])
    (<class 'str'>,)
    >>> generic_args(Union[str, int, None])
    (<class 'str'>, <class 'int'>, <class 'NoneType'>)
    >>> generic_args(Union[int, str, None])
    (<class 'int'>, <class 'str'>, <class 'NoneType'>)
    """
    if hasattr(t, '__origin__') and hasattr(t, '__args__'):
        return getattr(t, '__args__')
    else:
        return None


def get_tables():
    """Returns hardcoded list of tables which have ``tenant_id`` column.

    The list is hard-coded to match the state of the schema when this upgrade
    script is run.
    """
    tables = ['bgpvpn_router_associations', 'bgpvpns',
        'bgpvpn_network_associations']
    return tables


def is_a_reload():
    """Returns flag indicating whether reloading mechanics is used.

    :rtype: bool
    """
    return False


def scan_setup_py():
    """Validate the contents of setup.py against Versioneer's expectations."""
    found = set()
    setters = False
    errors = 0
    with open('setup.py', 'r') as f:
        for line in f.readlines():
            if 'import versioneer' in line:
                found.add('import')
            if 'versioneer.get_cmdclass()' in line:
                found.add('cmdclass')
            if 'versioneer.get_version()' in line:
                found.add('get_version')
            if 'versioneer.VCS' in line:
                setters = True
            if 'versioneer.versionfile_source' in line:
                setters = True
    if len(found) != 3:
        print('')
        print('Your setup.py appears to be missing some important items')
        print('(but I might be wrong). Please make sure it has something')
        print('roughly like the following:')
        print('')
        print(' import versioneer')
        print(' setup( version=versioneer.get_version(),')
        print('        cmdclass=versioneer.get_cmdclass(),  ...)')
        print('')
        errors += 1
    if setters:
        print("You should remove lines like 'versioneer.VCS = ' and")
        print("'versioneer.versionfile_source = ' . This configuration")
        print('now lives in setup.cfg, and should be removed from setup.py')
        print('')
        errors += 1
    return errors


def __ne__(A, other):
    """Returns true if both objects are not equal"""
    return not A == other


def ppv_converter(sensitivity, specificity, prevalence):
    """Generates the positive predictive value from designated sensitivity, specificity, and prevalence.

    Positive predictive value is calculated using

    .. math::

        PPV = \\frac{Se \\times P}{Se \\times P + (1-Sp) (1-P)}

    Parameters
    -------------
    sensitivity : float
        Sensitivity of the testing criteria
    specificity : float
        Specificity of the testing criteria
    prevalence : float
        Prevalence of the outcome in the population

    Returns
    ------------
    float
        Positive predictive value

    Examples
    --------
    Calculate the positivity predictive value

    >>> from zepid.calc import ppv_converter
    >>> ppv_converter(0.9, 0.88, 0.15)
    """
    if sensitivity > 1 or specificity > 1 or prevalence > 1:
        raise ValueError(
            'sensitivity/specificity/prevalence cannot be greater than 1')
    if sensitivity < 0 or specificity < 0 or prevalence < 0:
        raise ValueError(
            'sensitivity/specificity/prevalence cannot be less than 0')
    sens_prev = sensitivity * prevalence
    nspec_nprev = (1 - specificity) * (1 - prevalence)
    ppv = sens_prev / (sens_prev + nspec_nprev)
    return ppv


def _comp_suffix(s):
    """
    Returns the comparison operator suffix given a search field.
    This does not include the `__` (double underscore).

    If no suffix is present, then `eq` is returned.
    """
    suffixes = ['eq', 'ne', 'lt', 'le', 'gt', 'ge']
    for suffix in suffixes:
        if s.endswith(suffix):
            return suffix
    return 'eq'


def mixed_reclassifier(original_classifier, probability, m_player):
    """Function to reclassify the strategy"""
    if isinstance(probability, float) or isinstance(probability, int):
        m_player = [m_player]
        probability = [probability]
    if min(probability) == max(probability) == 0:
        return original_classifier
    if 1 in probability:
        player = m_player[probability.index(1)]
        original_classifier['stochastic'] = player.classifier['stochastic']
        return original_classifier
    original_classifier['stochastic'] = True
    return original_classifier


def p_proper_slice(p):
    """proper_slice : short_slice
                    | long_slice """
    p[0] = [p[1]]


@staticmethod
def is_diagnostic(obj):
    """Determine if the object is a diagnostic test."""
    return hasattr(obj, '_DIAGNOSTIC')


def enhance_intraday_data(df):
    """Add columns to the intraday dataframe.

    Parameters
    ----------
    df : pandas.DataFrame
        The intraday dataframe.

    Returns
    -------
    df : pandas.DataFrame
        The dataframe with bar number and end-of-day columns.

    """
    df['date'] = df.index.strftime('%Y-%m-%d')
    date_group = df.groupby('date')
    df['bar_number'] = date_group.cumcount()
    df['end_of_day'] = False
    df.loc[date_group.tail(1).index, 'end_of_day'] = True
    del df['date']
    return df


@classmethod
def has_core_in_register(cls, blok, core):
    """ Return True if One Class exist in this blok for this core

        :param blok: name of the blok
        :param core: is the existing core name
        """
    return len(cls.loaded_bloks[blok]['Core'][core]) > 0


def _add_var_to_assignment(partial_assignt, ass_vars, new_var, new_value):
    """
    Add a value for a variable in an assignment.
    The given partial assignment is not modified and a new assignement is
    returned, augmented with the value for the new variable, in the right
    position according to `ass_vars`.

    :param partial_assignt: a partial assignment represented as a list of
    values, the order of the values maps the order of the corresponding
    variables in `ass_vars`
    :param ass_vars: a list of variables corresponding to the list to the
    variables whose values are given by `partial_assignt`, augmented with one
    extra variable 'new_var' whose value is given by `new_value`.
    :param new_var: variable that must be added in the assignment
    :param new_value: value to add in the assignement for the new variable

    """
    if len(partial_assignt) + 1 != len(ass_vars):
        raise ValueError(
            'Length of partial assignment and variables do not match.')
    full_assignment = partial_assignt[:]
    for i in range(len(ass_vars)):
        if ass_vars[i] == new_var:
            full_assignment.insert(i, new_value)
    return full_assignment


def num_descents(perm):
    """Returns the number of descents of the permutation

    >>> Permutation(42561873).num_descents()
    4
    """
    return len(perm.descent_set())


def _print(*_args, **_kargs):
    """
    Isolate this for Python 2.6.  We need to exclude this to avoid errors
    on install.
    """


@classmethod
def hook(cls, **kwargs):
    """
        A hook which is called everytime when attributes are about to change.

        You should override this method if you want to enable pre-processing
        or monitoring of your attributes. For example, one could use this
        to react to attribute changes::

            >>> from pycraf.utils import MultiState

            >>> class MyState(MultiState):
            ...
            ...     _attributes = ('foo', 'bar')
            ...     foo = 1
            ...     bar = "guido"
            ...
            ...     @classmethod
            ...     def hook(cls, **kwargs):
            ...         if 'bar' in kwargs:
            ...             if kwargs['bar'] != cls.bar:
            ...                 print('{} about to change: {} --> {}'.format(
            ...                     'bar', kwargs['bar'], cls.bar
            ...                     ))
            ...                 # do stuff ...

            >>> _ = MyState.set(bar="david")
            bar about to change: david --> guido
            >>> _ = MyState.set(bar="david")
            >>> _ = MyState.set(bar="guido")
            bar about to change: guido --> david

            >>> with MyState.set(bar="david"):
            ...     pass
            bar about to change: david --> guido
            bar about to change: guido --> david
        """
    pass


@classmethod
def _get_log_request_file_path(cls, directory, transact_id, ext='txt'):
    """creates the final file path for request logs"""
    return cls._format_log_file_path.format(directory=directory,
        transaction_id=transact_id, ext=ext)


def CurrentControlledCurrentSource(G):
    """symbolic current controlled current source
    @param G string current gain
    @return list of list of string s-parameter matrix
    containing LaTeX or ASCII strings for each element.
    @note strings can be any valid LaTeX
    @note this is the symbolic version of
    SignalIntegrity.Lib.Devices.CurrentControlledCurrentSource.CurrentControlledCurrentSource
    """
    return [['0', '1', '0', '0'], ['1', '0', '0', '0'], ['-' + G, G, '1',
        '0'], [G, '-' + G, '0', '1']]


@classmethod
def _from_dict(cls, _dict):
    """Initialize a Timeslice object from a json dictionary."""
    args = {}
    if 'field' in _dict:
        args['field'] = _dict.get('field')
    if 'interval' in _dict:
        args['interval'] = _dict.get('interval')
    if 'anomaly' in _dict:
        args['anomaly'] = _dict.get('anomaly')
    return cls(**args)


@classmethod
def with_quotes(cls, string):
    """Return the rendered template between quotes"""
    return ''.join(('"""', string, '"""'))


def getHistory(history_id, countPurged=True, substitute=True):
    """Return the history of an object by the given history id.

        If ``countPurged`` is ``True`` purged versions are returned also.
        If ``False`` purged versions aren't returned.

        If ``substitute`` is ``True`` a substitute is returned in case
        the requested version was purged before.

        Return a ``IHistory`` object.
        """


def add_time_offset(offset):
    """Adds specified number of microseconds to the offset applied to time() function result."""
    global _time_offset
    _time_offset += int(offset)


def describe_option_group_options(EngineName=None, MajorEngineVersion=None,
    Filters=None, MaxRecords=None, Marker=None):
    """
    Describes all available options.
    See also: AWS API Documentation

    Examples
    This example lists information for all option group options for the specified DB engine.
    Expected Output:

    :example: response = client.describe_option_group_options(
        EngineName='string',
        MajorEngineVersion='string',
        Filters=[
            {
                'Name': 'string',
                'Values': [
                    'string',
                ]
            },
        ],
        MaxRecords=123,
        Marker='string'
    )

    :type EngineName: string
    :param EngineName: [REQUIRED]
            A required parameter. Options available for the given engine name will be described.

    :type MajorEngineVersion: string
    :param MajorEngineVersion: If specified, filters the results to include only options for the specified major engine version.

    :type Filters: list
    :param Filters: This parameter is not currently supported.
            (dict) --This type is not currently supported.
            Name (string) -- [REQUIRED]This parameter is not currently supported.
            Values (list) -- [REQUIRED]This parameter is not currently supported.
            (string) --

    :type MaxRecords: integer
    :param MaxRecords: The maximum number of records to include in the response. If more records exist than the specified MaxRecords value, a pagination token called a marker is included in the response so that the remaining results can be retrieved.
            Default: 100
            Constraints: Minimum 20, maximum 100.

    :type Marker: string
    :param Marker: An optional pagination token provided by a previous request. If this parameter is specified, the response includes only records beyond the marker, up to the value specified by MaxRecords .

    :rtype: dict
    :return: {
        'OptionGroupOptions': [
            {
                'Name': 'string',
                'Description': 'string',
                'EngineName': 'string',
                'MajorEngineVersion': 'string',
                'MinimumRequiredMinorEngineVersion': 'string',
                'PortRequired': True|False,
                'DefaultPort': 123,
                'OptionsDependedOn': [
                    'string',
                ],
                'OptionsConflictsWith': [
                    'string',
                ],
                'Persistent': True|False,
                'Permanent': True|False,
                'OptionGroupOptionSettings': [
                    {
                        'SettingName': 'string',
                        'SettingDescription': 'string',
                        'DefaultValue': 'string',
                        'ApplyType': 'string',
                        'AllowedValues': 'string',
                        'IsModifiable': True|False
                    },
                ],
                'OptionGroupOptionVersions': [
                    {
                        'Version': 'string',
                        'IsDefault': True|False
                    },
                ]
            },
        ],
        'Marker': 'string'
    }

    :returns:
    (string) --

    """
    pass


def run_interval(mfts, partitioner, train_data, test_data, window_key=None,
    **kwargs):
    """
    Run the interval forecasting benchmarks

    :param mfts: FTS model
    :param partitioner: Universe of Discourse partitioner
    :param train_data: data used to train the model
    :param test_data: ata used to test the model
    :param window_key: id of the sliding window
    :param transformation: data transformation
    :param indexer: seasonal indexer
    :return: a dictionary with the benchmark results
    """
    import time
    from pyFTS.models import hofts, ifts, pwfts
    from pyFTS.partitioners import Grid, Entropy, FCM
    from pyFTS.benchmarks import Measures, arima, quantreg
    tmp = [hofts.HighOrderFTS, ifts.IntervalFTS, pwfts.ProbabilisticWeightedFTS
        ]
    tmp2 = [Grid.GridPartitioner, Entropy.EntropyPartitioner, FCM.
        FCMPartitioner]
    tmp4 = [arima.ARIMA, quantreg.QuantileRegression]
    tmp3 = [Measures.get_interval_statistics]
    steps_ahead = kwargs.get('steps_ahead', 1)
    method = kwargs.get('method', None)
    if mfts.benchmark_only:
        _key = mfts.shortname + str(mfts.order if mfts.order is not None else
            '') + str(mfts.alpha)
    else:
        pttr = str(partitioner.__module__).split('.')[-1]
        _key = mfts.shortname + ' n = ' + str(mfts.order
            ) + ' ' + pttr + ' q = ' + str(partitioner.partitions)
        mfts.partitioner = partitioner
        mfts.append_transformation(partitioner.transformation)
    _key += str(steps_ahead)
    _key += str(method) if method is not None else ''
    _start = time.time()
    mfts.fit(train_data, **kwargs)
    _end = time.time()
    times = _end - _start
    _start = time.time()
    metrics = Measures.get_interval_statistics(test_data, mfts, **kwargs)
    _end = time.time()
    times += _end - _start
    ret = {'key': _key, 'obj': mfts, 'sharpness': metrics[0], 'resolution':
        metrics[1], 'coverage': metrics[2], 'time': times, 'Q05': metrics[3
        ], 'Q25': metrics[4], 'Q75': metrics[5], 'Q95': metrics[6],
        'winkler05': metrics[7], 'winkler25': metrics[8], 'window':
        window_key, 'steps': steps_ahead, 'method': method}
    return ret


def message(text):
    """Wrapper for the `print` function"""
    print(text)
    return text


def bdecode(data, alphabet='0123456789'):
    """Decode a base-N encoded string ( N = len(alphabet) )"""
    num = 0
    base = len(alphabet)
    for c in data:
        num *= base
        num += alphabet.index(c)
    return num


def identity(attrs, inputs, proto_obj):
    """Returns the identity function of the input."""
    return 'identity', attrs, inputs


def getURLsToPurge(path, proxies):
    """Yield full purge URLs for a given path, taking the caching proxies
    listed in the registry into account.
    """
    if not path.startswith('/'):
        path = '/' + path
    for proxy in proxies:
        if proxy.endswith('/'):
            proxy = proxy[:-1]
        yield proxy + path


def trignometric_clamp(x):
    """ Clamp *x* in the range [-1.,1]. """
    if x > 1.0:
        return 1.0
    elif x < -1.0:
        return -1.0
    else:
        return x


def getSelectionRows(grid):
    """Indices of the rows that have any cell selected.
    """
    rows = grid.GetNumberRows()
    rset = set()
    if grid.GetSelectedCols():
        rset.update(range(rows))
    rset.update(grid.GetSelectedRows())
    for r, c in grid.GetSelectedCells():
        rset.add(r)
    blocks = zip(grid.GetSelectionBlockTopLeft(), grid.
        GetSelectionBlockBottomRight())
    for tl, br in blocks:
        rset.update(range(tl[0], br[0] + 1))
    rv = sorted(rset)
    return rv


def operator_eq(ref_value, values):
    """
    Compare if the field values is in the condition values.
    """
    if isinstance(ref_value, list):
        for v in values:
            if v in ref_value:
                return True
    return ref_value == values[0]


def collect_main_title(lines, index):
    """Collect a main title"""
    output = '\n'.join([lines[index], lines[index + 1], lines[index + 2]])
    return output, index + 3


@staticmethod
def join_comps(*comps):
    """Comps must be strings
        Replacement for os path join as that discards empty string instead of putting a forward slash there"""
    _ = []
    for idx, comp in enumerate(comps):
        assert isinstance(comp, str), f'Provided type {type(comp)}'
        while comp.endswith(('/', '\\')):
            comp = comp[:-1]
        if idx > 0:
            while comp.startswith(('/', '\\')):
                comp = comp[1:]
        if idx not in (0, len(comps) - 1):
            if comp == '':
                continue
        _.append(comp)
    return '/'.join(_)


def config_option_update(context, data_dict):
    """Update the runtime-editable configuration options

       Only sysdmins can do it
    """
    return {'success': False}


def include_package(config):
    """Pyramid package include"""
    config.add_translation_dirs('pyams_file:locales')
    config.scan()


def count_kmers(seq, k=3):
    """Returns the Count or Frequency of Kmers generated in a sequence"""
    counts = {}
    num_kmers = len(str(seq)) - k + 1
    for i in range(num_kmers):
        kmer = str(seq)[i:i + k]
        if kmer not in counts:
            counts[kmer] = 0
        counts[kmer] += 1
    return counts


@classmethod
def add_as_argument_for(cls, command):
    """Add this flag to the command line parser."""
    command.cmd_parser.add_argument('--{}'.format(cls.restic_name()),
        action='store_true', default=False)


def duplicate_move(CURVE_OT_duplicate=None, TRANSFORM_OT_translate=None):
    """Duplicate curve and move

    :param CURVE_OT_duplicate: Duplicate Curve, Duplicate selected control points
    :param TRANSFORM_OT_translate: Move, Move selected items
    """
    pass


def cross_product(p1, p2):
    """ Returns the cross product of two ``XYPoints``."""
    return p1.x * p2.y - p1.y * p2.x


def get_contacts(filename):
    """
    Return two lists names, emails containing names and email addresses
    read from a file specified by filename.
    """
    names = []
    emails = []
    with open(filename, mode='r', encoding='utf-8') as contacts_file:
        for a_contact in contacts_file:
            names.append(a_contact.split()[0])
            emails.append(a_contact.split()[1])
    return names, emails


def parse_host_files(filename):
    """
    Transform the hostfile into a format of
    <IP address> or <host name>:<Number of GPUs>
    :param filename: Should be in <IP address> or <host name> slots=<number of GPUs>
    :return: Comma separated string of <IP address> or <host name>:<Number of GPUs>
    """
    hosts = []
    with open(filename, 'r') as f:
        for line in f.readlines():
            line = line.rstrip()
            hostname = line.split()[0]
            slots = line.split('=')[1]
            hosts.append('{name}:{slots}'.format(name=hostname, slots=slots))
    return ','.join(hosts)


def iscensored(rev):
    """Return whether a revision's content has been censored."""


def and_filter_f_args(fArgs):
    """
    This is for when we change and filter from [[fArg ...]] to _f(fArg)
    """
    return fArgs[0]


def total():
    """Return the length of the list (not the batch)."""


def set_t_colorbar_label(colorbar, scale, extra=''):
    """
    Function sets label of the colorbar for effective temperature surface function.
    """
    if scale == 'linear':
        colorbar.set_label(extra + ' $T_{eff}/[K]$')
    elif scale == 'log':
        colorbar.set_label(extra + ' $log(T_{eff})$')


def str_swap(str_raw, replace_dict):
    """
    Goes through a str using the replacement dictionary and looks for the
    keys in brackets and replaces them with the values

    Args:
        str_raw: Original string to replace keywords in using the replace_dictionary
        replace_dict: dictionary containing keywords to replace with full strings from the values

    Returns:
        info: string with keywords that are populated with values
    """
    info = str_raw
    for k, v in replace_dict.items():
        search_str = '[{}]'.format(k)
        info = info.replace(search_str, v)
    return info


def _ri2ro(obj):
    """ Dummy function for ri2ro.

    This function will convert rpy2.rinterface (ri) low-level objects
    into rpy2.robjects (ro) higher-level objects.
    """
    raise NotImplementedError(
        "Conversion 'ri2ro' not defined for objects of type '%s'" % str(
        type(obj)))


def has_resource(resource_name):
    """Does the package contain the named resource?"""


def _ADDS_extended_register(cpu, res_op, reg_op1, reg_op2):
    """
        ADDS (extended register).

        :param res_op: destination register.
        :param reg_op1: source register.
        :param reg_op2: source register.
        """
    cpu._adds_subs_extended_register(res_op, reg_op1, reg_op2, mnem='adds')


def get_object(state):
    """Convert the state to an object."""


@staticmethod
def min_and(a, b, c, d, w):
    """
        Lower bound of result of ANDing 2-intervals.

        :param a: Lower bound of first interval
        :param b: Upper bound of first interval
        :param c: Lower bound of second interval
        :param d: Upper bound of second interval
        :param w: bit width
        :return: Lower bound of ANDing 2-intervals
        """
    m = 1 << w - 1
    while m != 0:
        if ~a & ~c & m != 0:
            temp = (a | m) & -m
            if temp <= b:
                a = temp
                break
            temp = (c | m) & -m
            if temp <= d:
                c = temp
                break
        m >>= 1
    return a & c


def _add_alert_node(nx_graph, alert):
    """Add alert node to the graph."""
    nx_graph.add_node(alert['AlertType'] + '(R)', name=alert['AlertType'],
        time=str(alert['StartTimeUtc']), displayname=alert[
        'AlertDisplayName'], color='red', count=0, node_type='alert')


def P_stagnation(P, T, Tst, k):
    """Calculates stagnation flow pressure `Pst` for a fluid with the
    given isentropic coefficient and specified stagnation temperature and
    normal temperature. Normally used with converging/diverging nozzles.

    .. math::
        \\frac{P_0}{P}=\\left(\\frac{T_0}{T}\\right)^{\\frac{k}{k-1}}

    Parameters
    ----------
    P : float
        Normal pressure of a fluid [Pa]
    T : float
        Normal temperature of a fluid [K]
    Tst : float
        Stagnation temperature of a fluid moving at a certain velocity [K]
    k : float
        Isentropic coefficient []

    Returns
    -------
    Pst : float
        Stagnation pressure of a fluid moving at a certain velocity [Pa]

    Notes
    -----
    Assumes isentropic flow.

    Examples
    --------
    Example 12-1 in [1]_.

    >>> P_stagnation(54050., 255.7, 286.8, 1.4)
    80772.80495900588

    References
    ----------
    .. [1] Cengel, Yunus, and John Cimbala. Fluid Mechanics: Fundamentals and
       Applications. Boston: McGraw Hill Higher Education, 2006.
    """
    return P * (Tst / T) ** (k / (k - 1.0))


@staticmethod
def _get_data_format_5(raw):
    """
        Validate that data is from RuuviTag and is Data Format 5

        Returns:
            string: Sensor data
        """
    try:
        if 'FF990405' not in raw:
            return None
        payload_start = raw.index('FF990405') + 6
        return raw[payload_start:]
    except:
        return None


def set(key, item, set_creationtime=True):
    """Store an item with key to cache.

        XXX: get rid of ``set_creationtime``
        """


@classmethod
def from_row(cls, row, **kwargs):
    """Create an image from a row of images. See Image.from_array for passthrough parameters."""
    return cls.from_array([row], **kwargs)


def pyvar(string):
    """Transform a string into a valid Python variable

    :param string: Input string
    :return: Python variable-compatible string
    """
    for ch in string:
        if ch.isalpha() or ch.isdigit():
            pass
        else:
            string = string.replace(ch, '_')
    return string


def public():
    """Allow public access.

    - anyone can read anything
    - authenticated users can comment, tag and compare
    - only admins may delete datasets
    """
    return {'collection': ['__unauthenticated__', '__authenticated__'],
        'comment': ['__authenticated__'], 'compare': ['__authenticated__'],
        'delete': ['admin'], 'detail': ['__unauthenticated__',
        '__authenticated__'], 'file_list': ['__unauthenticated__',
        '__authenticated__'], 'get_partial_url': ['__unauthenticated__',
        '__authenticated__'], 'get_stream_url': ['__unauthenticated__',
        '__authenticated__'], 'rpcs': ['__authenticated__'], 'stream': [
        '__unauthenticated__'], 'tag': ['__authenticated__']}


def edit_margin_len(row, read_cigar):
    """
    The function is used to edit the margin length in the original realign_ss.
    Margin length is called margin_length in the old file.
    One insertion 'I' or 'D' will +1 or -1 in the margin length.
    """
    cigar_slice = read_cigar.cslice(start_ci=row['realign_start_ci'],
        end_ci=row['realign_end_ci'])
    new_margin_len = row['margin_len']
    for n, c in cigar_slice:
        if c == 'D':
            new_margin_len -= n
        elif c == 'I':
            new_margin_len += n
    return new_margin_len


@staticmethod
def _calculate_checksum(data, number_of_bytes):
    """5.7 CRC Checksum using the polynomial given in the datasheet
		Credits: https://github.com/jaques/sht21_python/blob/master/sht21.py
		"""
    POLYNOMIAL = 305
    crc = 0
    for byteCtr in range(number_of_bytes):
        crc ^= data[byteCtr]
        for bit in range(8, 0, -1):
            if crc & 128:
                crc = crc << 1 ^ POLYNOMIAL
            else:
                crc = crc << 1
    return crc


def write_file(filename, contents):
    """Create a file with the specified name and write 'contents' (a
    sequence of strings without line terminators) to it.
    """
    contents = '\n'.join(contents)
    contents = contents.encode('utf-8')
    with open(filename, 'wb') as f:
        f.write(contents)


@staticmethod
def __analyze_neighbors(neighbors, excluded_nodes, weight):
    """
        Analyzes a node dict for the frequency of nodes and gives them
        a weight. An upper bound of the weights is set.

        :param neighbors: list of node_pub_keys
        :param excluded_nodes: excluded node_pub_keys for analysis
        :param weight: float, weight for each individual appearance of a node
        :return: dict, keys: node_pub_keys, values: node weights
        """
    node_weights = {}
    for n in neighbors:
        if n not in excluded_nodes:
            if n in node_weights.keys():
                node_weights[n] = min(node_weights[n] + weight, 1.0)
            else:
                node_weights[n] = weight
    return node_weights


def multiunion(seq):
    """Return union of (zero or more) integer sets, as an integer set.

        seq is a sequence of objects each convertible to an integer set.
        These objects are convertible to an integer set:

        + An integer, which is added to the union.

        + A Set or TreeSet from the same module (for example, an
          :class:`BTrees.IIBTree.TreeSet` for :meth:`BTrees.IIBTree.multiunion`).  The elements of the
          set are added to the union.

        + A Bucket or BTree from the same module (for example, an
          :class:`BTrees.IOBTree.IOBTree` for :meth:`BTrees.IOBTree.multiunion`).  The keys of the
          mapping are added to the union.

        The union is returned as a Set from the same module (for example,
        :meth:`BTrees.IIBTree.multiunion` returns an :class:`BTrees.IIBTree.IISet`).

        The point to this method is that it can run much faster than
        doing a sequence of two-input :meth:`~BTrees.Interfaces.IMerge.union` calls.  Under the covers,
        all the integers in all the inputs are sorted via a single
        linear-time radix sort, then duplicates are removed in a second
        linear-time pass.
        """


def linalg_potri(A=None, name=None, attr=None, out=None, **kwargs):
    """Performs matrix inversion from a Cholesky factorization.
    Input is a tensor *A* of dimension *n >= 2*.

    If *n=2*, *A* is a triangular matrix (entries of upper or lower triangle are all zero)
    with positive diagonal. We compute:

      *out* = *A*\\ :sup:`-T` \\* *A*\\ :sup:`-1` if *lower* = *true*
      *out* = *A*\\ :sup:`-1` \\* *A*\\ :sup:`-T` if *lower* = *false*

    In other words, if *A* is the Cholesky factor of a symmetric positive definite matrix
    *B* (obtained by *potrf*), then

      *out* = *B*\\ :sup:`-1`

    If *n>2*, *potri* is performed separately on the trailing two dimensions for all inputs
    (batch mode).

    .. note:: The operator supports float32 and float64 data types only.

    .. note:: Use this operator only if you are certain you need the inverse of *B*, and
              cannot use the Cholesky factor *A* (*potrf*), together with backsubstitution
              (*trsm*). The latter is numerically much safer, and also cheaper.

    Examples::

       Single matrix inverse
       A = [[2.0, 0], [0.5, 2.0]]
       potri(A) = [[0.26563, -0.0625], [-0.0625, 0.25]]

       Batch matrix inverse
       A = [[[2.0, 0], [0.5, 2.0]], [[4.0, 0], [1.0, 4.0]]]
       potri(A) = [[[0.26563, -0.0625], [-0.0625, 0.25]],
                   [[0.06641, -0.01562], [-0.01562, 0,0625]]]

    Defined in src/operator/tensor/la_op.cc:L275

    Parameters
    ----------
    A : Symbol
        Tensor of lower triangular matrices

    name : string, optional.
        Name of the resulting symbol.

    Returns
    -------
    Symbol
        The result symbol.
    """
    return 0,


def _get_column_info_keystring():
    """
    Define the special key name within the table_meta_data dictionary for columns.

    Define the special key name within the table_meta_data dictionary that is used to hold information on all columns (parsed from the '# TableCol' lines). Could be any string, as long as it does not clash with other meta data entries in the stats file.
    """
    return 'column_info_'


def hypot2(x, y):
    """Compute the norm, I{squared} M{x**2 + y**2}.

       @arg x: Argument (C{scalar}).
       @arg y: Argument (C{scalar}).

       @return: B{C{x}}C{**2 + }B{C{y}}C{**2} (C{float}).
    """
    x, y = x ** 2, y ** 2
    if x < y:
        x, y = y, x
    if y:
        x *= 1 + y / x
    return x


def _applySpecial_MeshOpts_vertexSet(args, overlayList, displayCtx, target):
    """Applies the :attr:`.MeshOpts.vertexSet` option. """
    import fsleyes.actions.loadvertexdata as loadvertexdata
    last = len(args.vertexSet) - 1
    for i, vd in enumerate(args.vertexSet):
        loadvertexdata.loadVertices(target.overlay, displayCtx, vd, select=
            i == last)


def get_assign_groups(line, ops=ops):
    """ Split a line into groups by assignment (including
        augmented assignment)
    """
    group = []
    for item in line:
        group.append(item)
        if item in ops:
            yield group
            group = []
    yield group


def set_column_name(df, name):
    """
    Helper function to associate dataframe with a name. This is done with the
    columns-axis name, as pd.DataFrame do not have a name attribute.
    """
    df.columns.name = name
    return df


@staticmethod
def write_int(value, file):
    """
        Writes an integer as a field to a CSV file.

        :param int value: The integer.
        :param T file: The file.
        """
    file.write(str(value))


def _join(s, tail):
    """
    Return the concatenation of s + ' ' + tail if s is a truthy string, or tail
    only otherwise.
    """
    return ' '.join((s, tail)) if s else tail


def _get_next(request):
    """
    The part that's the least straightforward about views in this module is
    how they determine their redirects after they have finished computation.

    In short, they will try and determine the next place to go in the
    following order:

    1. If there is a variable named ``next`` in the *POST* parameters, the
       view will redirect to that variable's value.
    2. If there is a variable named ``next`` in the *GET* parameters,
       the view will redirect to that variable's value.
    3. If Django can determine the previous page from the HTTP headers,
       the view will redirect to that previous page.
    """
    next = request.POST.get('next', request.GET.get('next', request.META.
        get('HTTP_REFERER', None)))
    if not next:
        next = request.path
    return next


def unlink():
    """Remove Pose Library from active Object

    """
    pass


def RKOCstr2code(ocstr):
    """
        Converts output of runge_kutta_order_conditions() to
        numpy-executable code.
    """
    factors = ocstr.split(',')
    occode = 'np.dot(b,'
    for factor in factors[0:len(factors) - 1]:
        occode = occode + 'np.dot(' + factor + ','
    occode = occode + factors[len(factors) - 1]
    occode = occode.replace(']', ',:]')
    occode = occode + ')' * len(factors)
    return occode


@staticmethod
def _set_collapse_interval(data, interval):
    """
        间隔折叠节点，当节点过多时可以解决节点显示过杂间隔。

        :param data: 节点数据
        :param interval: 指定间隔
        """
    if interval <= 0:
        return data
    if data and isinstance(data, list):
        for d in data:
            children = d.get('children', None)
            if children and interval > 0:
                for index, value in enumerate(children):
                    if index % interval == 0:
                        value.update(collapsed='false')
        return data


def merge_scc_dags(l_scc):
    """
    Merge every other streams into the first one, we assume there's no connection between them
    and that links aren't constructed yet
    :param l_scc
    :return:
    """
    scc1 = l_scc[0]
    if scc1.times:
        min_t, max_t = scc1.times[0], scc1.times[1]
    for scc in l_scc[1:]:
        scc1.c_nodes += scc.c_nodes
        if scc.times:
            min_t = min(min_t, scc.times[0])
            max_t = max(max_t, scc.times[1])
    if scc1.times:
        scc1.times = [min_t, max_t]
    return scc1


@classmethod
def isspace(cls, nextchar):
    """ Whether the next character is whitespace """
    return nextchar.isspace()


def cartesian_to_keplerian(pos, vel, kep):
    """Given observables XYZ position and velocity, compute orbital elements.  Position must be in
       au and velocity in km/s.  Returns astropy unit objects for all orbital elements.
        Inputs:
            pos (3xN arr) [au]: position in xyz coords in au, with
                        x = pos[0], y = pos[1], z = pos[2] for each of N orbits
                        +x = +Dec, +y = +RA, +z = towards observer
            vel (3xN arr) [km/s]: velocity in xyz plane.
        Returns:
            sma (1xN arr flt) [au]: semi-major axis in au, must be an astropy units object
            ecc (1xN arr flt) [unitless]: eccentricity
            inc (1xN arr flt) [deg]: inclination
            argp (1xN arr flt) [deg]: argument of periastron
            lon (1xN arr flt) [deg]: longitude of ascending node
            meananom (1xN arr flt) [radians]: mean anomaly
        Written by Logan Pearce, 2019, inspired by Sarah Blunt
    """
    import numpy as np
    import astropy.units as u
    rcrossv = np.cross(pos, vel) * u.au * (u.km / u.s)
    h = np.sqrt(rcrossv[0] ** 2 + rcrossv[1] ** 2 + rcrossv[2] ** 2)
    n = rcrossv / h
    inc = np.arccos(n[2])
    lon = np.arctan2(n[0], -n[1])
    r = np.sqrt(pos[0] ** 2 + pos[1] ** 2 + pos[2] ** 2)
    v = np.sqrt(vel[0] ** 2 + vel[1] ** 2 + vel[2] ** 2)
    sma = 1 / (2.0 / r - v ** 2 / kep)
    rdotv = pos[0] * vel[0] + pos[1] * vel[1] + pos[2] * vel[2]
    rdot = rdotv / r
    parameter = h ** 2 / kep
    ecosf = parameter / r - 1
    esinf = h * rdot / kep.to(u.m ** 3 / u.s ** 2)
    ecc = np.sqrt(ecosf ** 2 + esinf ** 2)
    f = np.arctan2(esinf, ecosf)
    f = f.value % (2.0 * np.pi)
    E = 2.0 * np.arctan(np.sqrt((1 - ecc.value) / (1 + ecc.value)) * np.tan
        (f / 2.0))
    M = E - ecc * np.sin(E)
    rcosu = pos[0] * np.cos(lon) + pos[1] * np.sin(lon)
    rsinu = (-pos[0] * np.sin(lon) + pos[1] * np.cos(lon)) / np.cos(inc)
    uangle = np.arctan2(rsinu, rcosu)
    argp = uangle.value - f
    return sma.to(u.au), ecc, np.degrees(inc), np.degrees(argp
        ) % 360.0 * u.deg, np.degrees(lon.value) % 360.0 * u.deg, M


def zr_b(mu):
    """Assuming a rainfall parameter relationship of Z=AR^b,
    Compute the b exponent using gamma distribution.

    Ulbrich and Atlas (JAMC 2007), Eqn T5
    Parameters
    ----------
    mu: float
        Shape parameter of gamma DSD model [unitless]

    Returns
    -------
    b: float
        Z-R prefactor (see description)
    """
    b = (7 + mu) / (4.67 + mu)
    return b


def step_function_core(x, step_x=0, flip=False):
    """ Implement a perfect step function f(x) with step at `step_x`:

            / 0   if x < step_x
            |
    f(x) = {  0.5 if x = step_x
            |
            \\ 1   if x > step_x

    *Parameters*
    ============================================================================
    x       array; x domain of function
    step_x  float; position of the step
    flip    boolean; Flip the > and < signs in the definition
    ============================================================================
    """
    sign = -1 if flip else 1
    if sign * x < sign * step_x:
        result = 0
    elif x == step_x:
        result = 0.5
    elif sign * x > sign * step_x:
        result = 1
    return result


@classmethod
def _get_object_command_name(cls, object_name: str):
    """
        Constructs API command for existing Custodian object
        :param obj:
        :return:
        """
    return '/'.join([cls._base_command_name, object_name])


@classmethod
def get_raw_args(cls, q, request=None):
    """
        Return a Query object's SQL augmented with params from cls.get_extras.
        """
    sql, params = q.sql, q.params
    extra_sql, extra_params = cls.get_extras(q, request)
    if extra_sql:
        if "'%s'" in extra_sql:
            raise ValueError(
                'Dangerous use of quotes around place holder. Please see https://docs.djangoproject.com/en/2.2/ref/models/querysets/#extra for more details.'
                )
        sql = sql.rstrip(';') + extra_sql + ';'
        params += extra_params
    return sql, params


def multi_sum_sq(*data, **kwargs):
    """Compute the sums of squares of multiple arrays

    Defined in src/operator/contrib/multi_sum_sq.cc:L36

    Parameters
    ----------
    data : Symbol[]
        Arrays
    num_arrays : int, required
        number of input arrays.

    name : string, optional.
        Name of the resulting symbol.

    Returns
    -------
    Symbol
        The result symbol.
    """
    return 0,


def dict_to_attrs(d):
    """Filter to convert a python dictionary into a HTML attributes.

    For each (key, value) pair inside the dict, a ``key=value`` string will
    be created.

    Parameters
    ----------
    d : dict
        Dictionary containing the key value attributes.

    Returns
    -------
    str
        String containing all the attributes of the dictionary separated with spaces.
    """
    attrs = []
    for k, v in d.items():
        attrs.append(f'{k}="{v}"')
    attrs = ' '.join(attrs)
    return attrs


def hasunfilteredcache(repo, name):
    """check if a repo has an unfilteredpropertycache value for <name>"""
    return name in vars(repo.unfiltered())


@classmethod
def new(cls, tree, data=None):
    """Create a new |ExperimentSection|.

        Parameters
        ----------
        tree : |DesignTree|
            Describes the design of the experiment hierarchy.
        data : |ChainMap|
            All data to be associated with the |ExperimentSection|,
            including the values of independent variables,
            the section numbers indicating the section's location in the experiment,
            and any results associated with this section,
            arising from either the run callback of the |Experiment| or from the method |ExperimentSection.add_data|.
            `data` should be a  |collections.ChainMap|,
            which behaves like a dictionary but has a hierarchical organization such that
            children can access values from the parent but not vice-versa.

        """
    self = cls(tree, data)
    if not self.is_bottom_level:
        self.append_design_tree(self.get_next_tree(), _renumber=False)
        self._number_children()
    return self


def ispow2(n):
    """
    True if n is a power of 2, False otherwise

    >>> ispow2(5)
    False
    >>> ispow2(4)
    True
    """
    return n & n - 1 == 0


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


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

        :param ChangedEnterpriseConnectedTeamStatusType val:
        :rtype: EventType
        """
    return cls('changed_enterprise_connected_team_status', val)


@classmethod
def process(cls, *, context=None, parameter=None):
    """ Evaluate the SLIDE command. """
    value = context.stack.pop()
    for index in range(0, int(parameter['param'], 2)):
        context.stack.pop()
    context.stack.append(value)


def define_correlation_window(params_acquisition: dict):
    """Define the window over which the correlation is calculated inside the frame"""
    params_window = dict({'Elevational size mm': 1, 'Lateral size mm': 1,
        'Axial size mm': 1, 'Start of depth range mm': 6,
        'End of depth range mm': 8, 'Depth step mm': 0.25})
    return params_window


@classmethod
def detect_fields(cls, ds):
    """
        Called once to setup the fields of this type

        It should set the following static variables:
        * parameters: dictionary
           Dictionary containing the variables. The keys should match
           those of `cls.attrs`
        * field_list: list of (ftype, fname)
           The list of the field present in the file
        """
    raise NotImplementedError


@staticmethod
def add_opts(parser):
    """Populate and return the parser with the options for this plugin.

        If the plugin does not need any options, it should return the same
        parser untouched.
        """
    return parser


def subscribe(subscriber, type_name=None):
    """
        Makes 'subscriber' a subscriber of the list.  'subscriber' can be
        any of the supported subscription types.
        """


@classmethod
def from_parameters(cls, parameters, **kwargs):
    """Create model from parameter list

        Parameters
        ----------
        parameters : `Parameters`
            Parameters for init

        Returns
        -------
        model : `Model`
            Model instance
        """
    for par in parameters:
        kwargs[par.name] = par
    return cls(**kwargs)


def fold(fun, start, sequence):
    """
    Fold over a sequence.
    """
    for value in sequence:
        start = fun(start, value)
    return start


def RepairNodeStorageUnits(r, node, storage_type, name):
    """
    Repairs a storage unit on the node.

    @type node: str
    @param node: node whose storage units to repair
    @type storage_type: str
    @param storage_type: storage type to repair
    @type name: str
    @param name: name of the storage unit to repair

    @rtype: int
    @return: job id
    """
    query = {'storage_type': storage_type, 'name': name}
    return r.request('put', '/2/nodes/%s/storage/repair' % node, query=query)


def joinGroup(addr, interface=''):
    """
        Join a multicast group. Returns L{Deferred} of success or failure.

        If an error occurs, the returned L{Deferred} will fail with
        L{error.MulticastJoinError}.
        """


def ReserveHospRsrvEnd(t):
    """Hospitalization reserve: End of period"""
    return 0


def __ne__(ref):
    """KeyReferences must be totally orderable."""


def txt2alt(txt):
    """Convert text to altitude in ft: also FL300 => 30000. as float"""
    try:
        if txt.upper()[:2] == 'FL' and len(txt) >= 4:
            return 100.0 * int(txt[2:])
        else:
            return float(txt)
    except ValueError:
        return -1000000000.0


def get_vocabs(datasets):
    """Build vocabulary from an iterable of datasets objects

    Args:
        datasets: a list of dataset objects

    Returns:
        a set of all the words in the dataset

    """
    print('Building vocab...')
    vocab_words = set()
    vocab_tags = set()
    for dataset in datasets:
        for words, tags in dataset:
            vocab_words.update(words)
            vocab_tags.update(tags)
    print('- done. {} tokens'.format(len(vocab_words)))
    return vocab_words, vocab_tags


@staticmethod
def convert_to_n15hsqc_peaks(csdata):
    """
        Converts the output from get_entry into hsqc peak positions
        :param csdata: output from get_entry
        :return: easy to plot hsqc peak positions
        """
    sidechainres = ['ARG', 'GLN', 'ASN', 'HIS', 'TRP', 'LYS']
    sidechains = {'ARG-HH11': ['HH11NH1'], 'ARG-HH12': ['HH12', 'NH1'],
        'ARG-HH21': ['HH21', 'NH2'], 'ARG-HH22': ['HH22', 'NH2'], 'ARG-HE':
        ['HE', 'NE'], 'GLN-HE21': ['HE21', 'NE2'], 'GLN-HE22': ['HE22',
        'NE2'], 'ASN-HD21': ['HD21', 'ND2'], 'ASN-HD22': ['HD22', 'ND2'],
        'HIS-HD1': ['HD1ND1'], 'HIS-HE2': ['HE2', 'NE2'], 'TRP-HE1': ['HE1',
        'NE1'], 'LYS-HZ': ['HZ', 'NZ'], 'LYS-HZ1': ['HZ1', 'NZ'], 'LYS-HZ2':
        ['HZ2', 'NZ'], 'LYS-HZ3': ['HZ3', 'NZ']}
    outdata = [[], [], [], [], []]
    for i in range(len(csdata[0])):
        atomid = '{}-{}-{}-{}-{}'.format(csdata[0][i], csdata[1][i], csdata
            [2][i], csdata[5][i], csdata[7][i])
        if csdata[3][i] == 'H':
            if atomid not in outdata[0]:
                outdata[0].append(atomid)
                outdata[1].append(csdata[6][i])
                outdata[2].append(None)
                outdata[3].append(csdata[3][i])
                outdata[4].append(None)
            else:
                outdata[1][outdata[0].index(atomid)] = csdata[6][i]
                outdata[3][outdata[0].index(atomid)] = csdata[3][i]
        if csdata[3][i] == 'N':
            if atomid not in outdata[0]:
                outdata[0].append(atomid)
                outdata[2].append(csdata[6][i])
                outdata[1].append(None)
                outdata[4].append(csdata[3][i])
                outdata[3].append(None)
            else:
                outdata[2][outdata[0].index(atomid)] = csdata[6][i]
                outdata[4][outdata[0].index(atomid)] = csdata[3][i]
        if csdata[2][i] in sidechainres:
            for k in sidechains.keys():
                if k.split('-')[0] == csdata[2][i]:
                    atomid = '{}-{}-{}-{}-{}'.format(csdata[0][i], csdata[1
                        ][i], k, csdata[5][i], csdata[7][i])
                    if csdata[3][i] in sidechains[k] and csdata[4][i] == 'H':
                        if atomid not in outdata[0]:
                            outdata[0].append(atomid)
                            outdata[1].append(csdata[6][i])
                            outdata[2].append(None)
                            outdata[3].append(csdata[3][i])
                            outdata[4].append(None)
                        else:
                            outdata[1][outdata[0].index(atomid)] = csdata[6][i]
                            outdata[3][outdata[0].index(atomid)] = csdata[3][i]
                    if csdata[3][i] in sidechains[k] and csdata[4][i] == 'N':
                        if atomid not in outdata[0]:
                            outdata[0].append(atomid)
                            outdata[2].append(csdata[6][i])
                            outdata[1].append(None)
                            outdata[4].append(csdata[3][i])
                            outdata[3].append(None)
                        else:
                            outdata[2][outdata[0].index(atomid)] = csdata[6][i]
                            outdata[4][outdata[0].index(atomid)] = csdata[3][i]
    return outdata


def CollectionProperty(type=None, name: str='', description: str='',
    options: set={'ANIMATABLE'}):
    """Returns a new collection property definition.

    :param type: A subclass of bpy.types.PropertyGroup or bpy.types.ID.
    :param name: Name used in the user interface.
    :type name: str
    :param description: Text used for the tooltip and api documentation.
    :type description: str
    :param options: Enumerator in [‘HIDDEN’, ‘SKIP_SAVE’, ‘ANIMATABLE’, ‘LIBRARY_EDITABLE’, ‘PROPORTIONAL’,’TEXTEDIT_UPDATE’].
    :type options: set
    """
    pass


@classmethod
def where_object_id(cls, object_id):
    """ Get db model by object id """
    return cls.query.filter_by(object_id=object_id).first()


@staticmethod
def int_to_hex(intval):
    """A convenience function, use format to convert int to hex"""
    if type(intval) == 'string':
        intval = int(intval)
    return '{:02}'.format(intval, 'x')


def is_stmt(c):
    """Check if a cursor is a statement
    """
    return c.kind.is_declaration()


def asint(value):
    """Coerce to integer."""
    if value is None:
        return value
    return int(value)


def __as_number(asn, fail=True):
    """ Autonomous System Number validation. """
    if str(asn).isdigit() and 0 <= int(asn) < 2 ** 32:
        return asn
    if fail:
        raise ValueError('Bad AS number')


def bson_ts_to_long(timestamp):
    """Convert BSON timestamp into integer.

    Conversion rule is based from the specs
    (http://bsonspec.org/#/specification).
    """
    return (timestamp.time << 32) + timestamp.inc


def is_valid_pre_6_2_version(xml):
    """Returns whether the given XML object corresponds to an XML output file of Quantum ESPRESSO pw.x pre v6.2.

    :param xml: a parsed XML output file
    :return: boolean, True when the XML was produced by Quantum ESPRESSO with the old XML format
    """
    element_header = xml.find('HEADER')
    if element_header is None:
        return False
    element_format = element_header.find('FORMAT')
    if element_format is None:
        return False
    try:
        name = element_format.attrib['NAME']
    except KeyError:
        return False
    if name != 'QEXML':
        return False
    return True


def teardown_paste_factories():
    """Reverse the effect of setup_paste_factories()."""
    global app_factory, filter_factory
    del app_factory
    del filter_factory


def GetGroupTags(r, group):
    """
    Gets tags for a node group.

    @type group: string
    @param group: Node group whose tags to return

    @rtype: list of strings
    @return: tags for the group
    """
    return r.request('get', '/2/groups/%s/tags' % group)


@classmethod
def creating(cls, callback):
    """
        Register a creating model event with the dispatcher.

        :type callback: callable
        """
    cls._register_model_event('creating', callback)


def skin_root_mark():
    """Mark selected vertices as roots

    """
    pass


def escape_xml_text(data):
    """
    Fix some XML errors in bugzilla xml, which confuse proper XML parser.
    """
    data = data.replace('\x08', '^H')
    data = data.replace('\x13', '^S')
    data = data.replace('\x01', '^A')
    data = data.replace('\x07', '^G')
    return data


def move_to_layer(layers: bool=(False, False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False)):
    """Move the object to different layers

    :param layers: Layer
    :type layers: bool
    """
    pass


def read_bearer_token_file(filename):
    """
    Read a token file and return the oauth2 bearer token.
    """
    f = open(filename)
    bearer_token = f.readline().strip()
    f.close()
    return bearer_token


def unenumerate(value, _type):
    """Returns the value of a specific item"""
    return value[_type]


def chi2_expval(nu):
    """
    Expected value of Chi-squared distribution.
    """
    return nu


def translate_attach_remove_on_cancel(TRANSFORM_OT_translate=None,
    NODE_OT_attach=None, NODE_OT_insert_offset=None):
    """Move nodes and attach to frame

    :param TRANSFORM_OT_translate: Move, Move selected items
    :param NODE_OT_attach: Attach Nodes, Attach active node to a frame
    :param NODE_OT_insert_offset: Insert Offset, Automatically offset nodes on insertion
    """
    pass


def indent(text, num=4):
    """Indet the given string"""
    str_indent = ' ' * num
    return str_indent + ('\n' + str_indent).join(text.splitlines())


def string_cleaner(s):
    """Function for cleaning raw string values.

    :param str s: string to clean.
    :returns: string, lowercased with spaces replaced with "_".
    """
    return s.strip().lower().replace(' ', '_')


def phase_increment(f_out, phase_bits, f_clk):
    """
    Calculate the phase increment required to produce the desired frequency.

    :param f_out:
    :param phase_bits:
    :param f_clk:
    :return:
    """
    return int(f_out * 2 ** phase_bits / f_clk)


def text_file(filename):
    """
    >>> text_file('test/foo.txt')
    'foo\\nbar\\n'
    """
    with open(filename) as file:
        return file.read()


def ConvertListToStr(values, sep=', ', textMarker='', keepType=False):
    """
    converts a python list to string. .
    the list items are seperated by ",". list items are converted to string
    """
    if not values:
        return ''
    if isinstance(values, str):
        return '%s%s%s' % (textMarker, values, textMarker)
    s = []
    for v in values:
        if textMarker != '':
            tm = textMarker
            if keepType:
                if isinstance(v, (int, float)):
                    tm = ''
            s.append('%s%s%s' % (textMarker, str(v), textMarker))
        else:
            s.append(str(v))
    return sep.join(s)


@classmethod
def assert_value(cls, condition=False, message='error'):
    """
        Checks condition and raises ValueError if it is wrong

        :param bool condition: condition to check;
        :param string message: message for `ValueError(message)`
        :raises ValueError: if `condition` is wrong.
        """
    cls._assert(condition, ValueError(message))


def RefreshGuiPartNumber(*args, **kwargs):
    """ Stub Anduin function."""
    print('RefreshGuiPartNumber', args, kwargs)


def interleave(seqs, pass_exceptions=()):
    """
    Interleave a sequence of sequences

    >>> list(interleave([[1, 2], [3, 4]]))
    [1, 3, 2, 4]

    >>> ''.join(interleave(('ABC', 'XY')))
    'AXBYC'

    Both the individual sequences and the sequence of sequences may be infinite

    Returns a lazy iterator
    """
    iters = map(iter, seqs)
    while iters:
        newiters = []
        for itr in iters:
            try:
                yield next(itr)
                newiters.append(itr)
            except ((StopIteration,) + tuple(pass_exceptions)):
                pass
        iters = newiters


def ray_convex_intersection_image_filter(*args, **kwargs):
    """Procedural interface for RayConvexIntersectionImageFilter"""
    import itk
    instance = itk.RayConvexIntersectionImageFilter.New(*args, **kwargs)
    return instance.__internal_call__()


def _np_roll(a, shift, axis=None):
    """
    Roll array elements along a given axis.

    Elements that roll beyond the last position are re-introduced at
    the first.

    Parameters
    ----------
    a : ndarray
        Input array.
    shift : int or tuple of ints
        The number of places by which elements are shifted.  If a tuple,
        then `axis` must be a tuple of the same size, and each of the
        given axes is shifted by the corresponding number.  If an int
        while `axis` is a tuple of ints, then the same value is used for
        all given axes.
    axis : int or tuple of ints, optional
        Axis or axes along which elements are shifted.  By default, the
        array is flattened before shifting, after which the original
        shape is restored.

    Returns
    -------
    res : ndarray
        Output array, with the same shape as `a`.

    Notes
    -----
    Supports rolling over multiple dimensions simultaneously.

    Examples
    --------
    >>> x = np.arange(10)
    >>> np.roll(x, 2)
    array([8., 9., 0., 1., 2., 3., 4., 5., 6., 7.])
    >>> np.roll(x, -2)
    array([2., 3., 4., 5., 6., 7., 8., 9., 0., 1.])

    >>> x2 = np.reshape(x, (2,5))
    >>> x2
    array([[0., 1., 2., 3., 4.],
           [5., 6., 7., 8., 9.]])
    >>> np.roll(x2, 1)
    array([[9., 0., 1., 2., 3.],
           [4., 5., 6., 7., 8.]])
    >>> np.roll(x2, -1)
    array([[1., 2., 3., 4., 5.],
           [6., 7., 8., 9., 0.]])
    >>> np.roll(x2, 1, axis=0)
    array([[5., 6., 7., 8., 9.],
           [0., 1., 2., 3., 4.]])
    >>> np.roll(x2, -1, axis=0)
    array([[5., 6., 7., 8., 9.],
           [0., 1., 2., 3., 4.]])
    >>> np.roll(x2, 1, axis=1)
    array([[4., 0., 1., 2., 3.],
           [9., 5., 6., 7., 8.]])
    >>> np.roll(x2, -1, axis=1)
    array([[1., 2., 3., 4., 0.],
           [6., 7., 8., 9., 5.]])
   """


def split_model_kwargs(kw):
    """
    django_any birds language parser
    """
    from collections import defaultdict
    model_fields = {}
    fields_agrs = defaultdict(lambda : {})
    for key in kw.keys():
        if '__' in key:
            field, _, subfield = key.partition('__')
            fields_agrs[field][subfield] = kw[key]
        else:
            model_fields[key] = kw[key]
    return model_fields, fields_agrs


@classmethod
def bad_syntax(cls, syntax, resource_name, ex=None):
    """Exception used when the resource name cannot be parsed.
        """
    if ex:
        msg = "The syntax is '%s' (%s)." % (syntax, ex)
    else:
        msg = "The syntax is '%s'." % syntax
    msg = "Could not parse '%s'. %s" % (resource_name, msg)
    return cls(msg)


def p_non_empty_for_expr(p):
    """non_empty_for_expr : non_empty_for_expr COMMA expr
                          | expr"""
    if len(p) == 4:
        p[0] = p[1] + [p[3]]
    else:
        p[0] = [p[1]]


@staticmethod
def _verify_decrypt_result(result):
    """Check for successful decryption and a trusted signature."""
    if not result.ok:
        raise Exception(result.status)
    if result.trust_level is None:
        raise Exception('Unsigned data.')
    if result.trust_level < result.TRUST_FULLY:
        raise Exception('Untrusted signature.')


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 _get_colorbar_axes(axes):
    """
    Helper function which returns all axes of colorbars linked to artists.

    Parameters
    ----------
    axes : list
        A list of matplotlib Axes.

    Returns
    -------
    cb_axes : set
    """
    cb_axes = []
    for ax in axes:
        for artist_type in ['images', 'collections']:
            for artist in getattr(ax, artist_type):
                if artist.colorbar is not None:
                    cb_axes.append(artist.colorbar.ax)
    return cb_axes


def bytelen(a):
    """Determine the length of a in bytes."""
    if hasattr(a, 'nbytes'):
        return a.nbytes
    elif isinstance(a, (bytearray, bytes)):
        return len(a)
    else:
        raise ValueError(a, 'cannot determine nbytes')


@classmethod
def concatenate(cls, objects, **kwargs):
    """Concatenate objects to get object that would be recieved if
        the concatenated serialization were deserialized.

        Args:
            objects (list): Objects to be concatenated.
            **kwargs: Additional keyword arguments are ignored.

        Returns:
            list: Set of objects that results from concatenating those provided.

        """
    return objects


def process_samples(lims_process):
    """Retrieve LIMS input samples from a process."""
    for artifact in lims_process.all_inputs():
        for lims_sample in artifact.samples:
            yield {'sample': lims_sample, 'artifact': artifact}


def onRequest(request, theme, settings, dependenciesSettings):
    """Called upon traversal into the site when a theme is enabled
        """


def transformIterable(result, encoding):
    """Called to allow the transformer to modify the result if the result
        is an iterable of strings (as per the WSGI specification).

        Return a new six.text_type string, encoded string or iterable.

        Return None to indicate that the response should not be modified.
        """


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 max_object_id(objects):
    """Return maximum identifier for a list of identifiable objects.

    Parameters
    ----------
    object: list
        List of dataset columns or rows

    Returns
    -------
    int
    """
    max_id = -1
    for obj in objects:
        if obj.identifier > max_id:
            max_id = obj.identifier
    return max_id


def from_toml(value):
    """
    Returns a data structure from the TOML string given.
    Examples:
    >>> from_toml('[table]\\nkey = "value"\\n') == {'table': {'key': 'value'}}
    True
    """
    from toml import loads
    return loads(value)


def is_moderator(user):
    """Check if the user is having moderator rights"""
    if user.groups.filter(name='moderator').exists():
        return True


def get_hh(xtime):
    """
	说明：根据传入的时间 ，返回小时部分（整型）
	参数：xtime，是字符串，格式必须为 hh:mm:ss
	返回值：整型 hh
	"""
    time_str = None
    time_arr = xtime.split(':')
    if len(time_arr) >= 1:
        time_str = int(time_arr[0])
    return time_str


@classmethod
def forget_client(mcs, attr_name_or_client):
    """
        Forget a `Client`.

        Args:
            attr_name_or_client: The client or the attr_name bound to forget.
        """
    if isinstance(attr_name_or_client, str):
        mcs._class_clients.pop(attr_name_or_client)
    else:
        mcs._class_clients.pop(attr_name_or_client.attr_name)


def l1_distance_matrix(X, Y):
    """Fast L1 distance matrix between two sets of columns vectors."""
    pass


def add_folder_counts_recursive(c):
    """Aggregate subfolder counts from folder_x_folder."""
    sql = """
        WITH RECURSIVE descendants AS
            (
                SELECT parent_id, child_id, 1 as level
                FROM folder_x_folder
            UNION ALL
                SELECT d.parent_id, s.child_id, d.level + 1
                FROM descendants AS d
                JOIN folder_x_folder s
                ON d.child_id = s.parent_id
            )
        SELECT count(child_id) as count, parent_id
        FROM descendants
        INNER JOIN folders ON descendants.parent_id = folders.folder_id
        GROUP BY parent_id
    """
    c.execute(sql)
    data = c.fetchall()
    sql = """
        UPDATE folders
        SET subfolder_count_r = ?
        WHERE folder_id = ?
    """
    c.executemany(sql, data)


def isLink():
    """
        True if node is link.
        """


def get_paths_from_log(log, attribute_key='concept:name'):
    """
    Get the paths of the log along with their count

    Parameters
    ----------
    log
        Log
    attribute_key
        Attribute key (must be specified if different from concept:name)

    Returns
    ----------
    paths
        Dictionary of paths associated with their count
    """
    paths = {}
    for trace in log:
        for i in range(0, len(trace) - 1):
            if attribute_key in trace[i] and attribute_key in trace[i + 1]:
                path = trace[i][attribute_key] + ',' + trace[i + 1][
                    attribute_key]
                if path not in paths:
                    paths[path] = 0
                paths[path] = paths[path] + 1
    return paths


def cancel_bundle_task(DryRun=None, BundleId=None):
    """
    Cancels a bundling operation for an instance store-backed Windows instance.
    See also: AWS API Documentation

    :example: response = client.cancel_bundle_task(
        DryRun=True|False,
        BundleId='string'
    )

    :type DryRun: boolean
    :param DryRun: Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation . Otherwise, it is UnauthorizedOperation .

    :type BundleId: string
    :param BundleId: [REQUIRED]
            The ID of the bundle task.

    :rtype: dict
    :return: {
        'BundleTask': {
            'InstanceId': 'string',
            'BundleId': 'string',
            'State': 'pending'|'waiting-for-shutdown'|'bundling'|'storing'|'cancelling'|'complete'|'failed',
            'StartTime': datetime(2015, 1, 1),
            'UpdateTime': datetime(2015, 1, 1),
            'Storage': {
                'S3': {
                    'Bucket': 'string',
                    'Prefix': 'string',
                    'AWSAccessKeyId': 'string',
                    'UploadPolicy': b'bytes',
                    'UploadPolicySignature': 'string'
                }
            },
            'Progress': 'string',
            'BundleTaskError': {
                'Code': 'string',
                'Message': 'string'
            }
        }
    }

    """
    pass


def offset_clear():
    """Clear strip offsets from the start and end frames

    """
    pass


@classmethod
def make_empty(cls, **kw):
    """TODO doc: must call :meth:`check_structure` in the end"""
    data = {'states': {}}
    data.update(kw)
    return cls(data, False)


def replace_quotes(item: str) ->str:
    """
    Replaces the quotes in a string, but only if they are un-escaped.

    .. code-block:: python3

        some_weird_string = r'"this is quoted and removed" but " that was kept and this isn't \\"'
        replace_quotes(some_weird_string)  # 'this is quoted and removed but " that was kept but
        this isnt \\'

    :param item: The string to scan.
    :return: The string, with quotes replaced.
    """
    final_str_arr = []
    for n, char in enumerate(item):
        if n - 1 < 0:
            if char != '"':
                final_str_arr.append(char)
            continue
        if char == '\\':
            if item[n - 1] == '\\':
                final_str_arr.append(char)
            continue
        if char == '"':
            if item[n - 1] == '\\':
                if len(final_str_arr) > 0 and final_str_arr[-1] != '\\':
                    final_str_arr.append('"')
            continue
        final_str_arr.append(char)
    return ''.join(final_str_arr)


def _missing_co2_params(params, *args, _not=False):
    """
    Checks if all co2_params are not defined.

    :param params:
        CO2 emission model parameters (a2, b2, a, b, c, l, l2, t, trg).
    :type params: dict | lmfit.Parameters

    :param _not:
        If True the function checks if not all co2_params are defined.
    :type _not: bool

    :return:
        If is missing some parameter.
    :rtype: bool
    """
    s = {'a', 'b', 'c', 'a2', 'b2', 'l', 'l2', 't0', 'dt', 'trg'}
    if _not:
        return set(params).issuperset(s)
    return not set(params).issuperset(s)


@classmethod
def validate(cls, policy):
    """Validate subscription policy value."""
    return policy in [cls.OPEN, cls.APPROVAL, cls.CLOSED]


def read_file(fpath):
    """ Return all rows of file as string"""
    with open(fpath, 'r', encoding='utf8') as f:
        data = f.read()
    return data


def try_divide(x, y, val=0.0):
    """
    try to divide two numbers
    """
    if y != 0.0:
        val = float(x) / y
    return val


def html(text, env={}):
    """Generate HTML for any object with a string representation

    Parameters
    ----------
    text : any
        Object to be converted to HTML. If the object has a ``.get_html()``
        method the result of this method is returned, otherwise ``str(text)``.
    env : dict
        Environment for HTML.
    """
    if hasattr(text, 'get_html'):
        return text.get_html(env)
    else:
        return str(text)


def sample_var_var(std, n):
    """
    The variance of the sample variance of a distribution.

    Assumes the samples are normally distributed.

    From: //math.stackexchange.com/q/72975

    `std`: Distribution's standard deviation
    `n`: Number of samples
    """
    return 2.0 * std ** 4 / (n - 1.0)