def _handle_ticklabels(ax, k, x_ticklabels, y_ticklabels):
    """
    Handle and format ticks and ticklabels for use in imsubplot.

    The `imsubplot` function creates a figure showing an abitrary number of
    subplots. The `imsubplot` function allows for custom ticklabels along the
    x- and y-axes. This function handles the formatting of the ticklabels for a
    given subplot.

    Parameters
    ----------
    ax : matplotlib.axes.Axes
        The matplotlib axes (subplot) to format ticklabels for.
    k : int
        The axes index, i.e. the subplot number out of the total number of
        subplots.
    x_ticklabels : list or tuple
        The x_ticklabels (as strings or lists of strings) to use for the
        subplots (the default is None, which implies that no x_ticklabels are
        displayed).
    y_ticklabels : list or tuple
        The y_ticklabels (as strings or lists of strings) to use for the
        subplots (the default is None, which implies that no y_ticklabels are
        displayed).

    """
    if x_ticklabels is not None:
        if isinstance(x_ticklabels[0], (list, tuple)):
            x_t = range(len(x_ticklabels[k]))
            x_tl = x_ticklabels[k]
        else:
            x_t = range(len(x_ticklabels))
            x_tl = x_ticklabels
        ax.set_xticks(x_t)
        ax.set_xticklabels(x_tl, rotation=90)
    if y_ticklabels is not None:
        if isinstance(y_ticklabels[0], (list, tuple)):
            y_t = range(len(y_ticklabels[k]))
            y_tl = y_ticklabels[k]
        else:
            y_t = range(len(y_ticklabels))
            y_tl = y_ticklabels
        ax.set_yticks(y_t)
        ax.set_yticklabels(y_tl)


def count():
    """Return the number of spiders in the queue.

        This method can return a deferred. """


def efficiency(Voc, Isc, FF, A=1):
    """Return the efficiency of a solar cell (units not percentage)given Voc (volts), Isc in (amps) and  FF (units).
    also works for Jsc since area of 1 is assumed
    """
    return 1000 * Voc * Isc * FF / A


def translate_urls(json_home, new_prefix):
    """Given a JSON Home document, sticks new_prefix on each of the urls."""
    for dummy_rel, resource in json_home['resources'].items():
        if 'href' in resource:
            resource['href'] = new_prefix + resource['href']
        elif 'href-template' in resource:
            resource['href-template'] = new_prefix + resource['href-template']


def ok_(expr, msg=None):
    """Shorthand for assert. Saves 3 whole characters!
    """
    if not expr:
        raise AssertionError(msg)


def render_pep440_old(pieces):
    """TAG[.postDISTANCE[.dev0]] .

    The ".dev0" means dirty.

    Eexceptions:
    1: no tags. 0.postDISTANCE[.dev0]
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance'] or pieces['dirty']:
            rendered += '.post%d' % pieces['distance']
            if pieces['dirty']:
                rendered += '.dev0'
    else:
        rendered = '0.post%d' % pieces['distance']
        if pieces['dirty']:
            rendered += '.dev0'
    return rendered


def normalize_pep440(**kwd):
    """ Normalize the version.

        >>> normalize_pep440(**parse_pep440('1.2.3.4.rc5.post.dev'))
        '1.2.3.4rc5'
    """
    normalized = '.'.join(map(str, kwd['release']))
    if 'pre_release' in kwd:
        normalized += '%s%s' % kwd['pre_release']
    if 'post_release' in kwd:
        normalized += '.post' + str(kwd['post_release'])
    if 'dev_release' in kwd:
        normalized += '.dev' + str(kwd['dev_release'])
    if 'epoch' in kwd:
        normalized = '{}!{}'.format(kwd['epoch'], normalized)
    return normalized


def actuator_remove(actuator: str='', object: str=''):
    """Remove an actuator from the active object

    :param actuator: Actuator, Name of the actuator to edit
    :type actuator: str
    :param object: Object, Name of the object the actuator belongs to
    :type object: str
    """
    pass


def add_args(parser, the_arg):
    """Convenience function to add ``the_arg`` to the ``parser``.

    This relies on the argument being structured as a dictionary with the keys
    ``args`` for positional arguments and ``kwargs`` for the keyword
    arguments. The value of doing this is that arguments that are reused
    in several parsers can be referred to by a variable instead of being
    redefined.

    Usage::

        >>> my_arg = {'arg': ['-x'], 'kwargs': {'help': 'help'}}
        >>> this_parser = argparse.ArgumentParser()
        >>> add_args(this_parser, my_arg)

    :param parser: the parser to be modified
    :type parser: :py:class:`argparse.ArgumentParser`
    :param dict the_arg: the argument specified as a dict with keys ``args`` and ``kwargs``
    :return: a modified parser object
    :rtype: :py:class:`argparse.ArgumentParser`
    """
    return parser.add_argument(*the_arg['args'], **the_arg['kwargs'])


def window_close():
    """Close the current Blender window

    """
    pass


def _cache_dir():
    """Hack to prevent circular imports issue with the constants module"""
    from .config import CIDC_WORKING_DIR
    return CIDC_WORKING_DIR


def disable(class_name, var):
    """Set disable_<var> to True in the class class_name."""
    setattr(class_name, 'disable_' + var, True)


def activate(repo, mark):
    """
    Set the given bookmark to be 'active', meaning that this bookmark will
    follow new commits that are made.
    The name is recorded in .hg/bookmarks.current
    """
    repo._bookmarks.active = mark
    repo._bookmarks._writeactive()


@staticmethod
def filter_value(setting, data, *args):
    """Remove values related to setting that are invalid given args."""


def move_speakers_to_own_model(apps, schema_editor):
    """
    Create a list of speaker for every item that exists. Move the speakers over to
    the new list of speakers.
    """
    Item = apps.get_model('agenda', 'Item')
    Speaker = apps.get_model('agenda', 'Speaker')
    ListOfSpeakers = apps.get_model('agenda', 'ListOfSpeakers')
    for item in Item.objects.all():
        los = ListOfSpeakers(content_type=item.content_type, object_id=item
            .object_id, closed=item.speaker_list_closed)
        los.save(skip_autoupdate=True)
    for speaker in Speaker.objects.all():
        speaker.list_of_speakers = ListOfSpeakers.objects.get(object_id=
            speaker.item.object_id, content_type=speaker.item.content_type)
        speaker.save(skip_autoupdate=True)


def normalize_response(response):
    """ Normalize the given response, by always returning a 3-element tuple
    (status, headers, body). The body is not "resolved"; it is safe
    to call this function multiple times on the same response.
    """
    if isinstance(response, tuple):
        if len(response) == 3:
            status, headers, body = response
        elif len(response) == 2:
            status = 200
            headers, body = response
        elif len(response) == 1:
            status, headers, body = 200, {}, response[0]
        else:
            raise ValueError(f'Handler returned {len(response)}-tuple.')
    else:
        status, headers, body = 200, {}, response
    if not isinstance(status, int):
        raise ValueError(f'Status code must be an int, not {type(status)}')
    if not isinstance(headers, dict):
        raise ValueError(f'Headers must be a dict, not {type(headers)}')
    return status, headers, body


def get_source_term_div(heat_fluxes, metric):
    """
    Compute the radiative in the conventional way by taking the divergence of
    the radiative heat flux vector

    Parameters
    ----------
    heat_fluxes: numpy arrays containing heat fluxes in x, y, and projected
    onto the boundaries
    metric: object containing information relative to metric (gradients,
    coordinates, etc.)

    Returns
    source_term: radiative source term
    -------

    """
    q_x = heat_fluxes[0]
    q_y = heat_fluxes[1]
    grad_x = metric.grad_x_csr
    grad_y = metric.grad_y_csr
    radiative_source_term_div = grad_x.dot(q_x) + grad_y.dot(q_y)
    return radiative_source_term_div


def __call__(xCqNck7t, *args, **kwargs):
    """Dict(key=val) creates a new dict with the key:val. That has always been true for
        initializing a new Dict. But now, this pattern also works for an existing Dict.
        For example:
        >>> d1 = Dict(a=1, b=2); d2 = d1(c=3); d1; d2
        {'a': 1, 'b': 2}
        {'a': 1, 'b': 2, 'c': 3}
        >>>
        Note that d1 has not been changed -- this method creates a new dict based
        on the old one without changing the old one.
        """
    d = xCqNck7t.__class__(*args, **xCqNck7t)
    d.update(**kwargs)
    return d


def suppress_exceptions(callables, *exceptions):
    """
    Call each callable in callables, suppressing any exceptions supplied. If
    no exception classes are supplied, all Exceptions will be suppressed.

    >>> import functools
    >>> c1 = functools.partial(int, 'a')
    >>> c2 = functools.partial(int, '10')
    >>> list(suppress_exceptions((c1, c2)))
    [10]
    >>> list(suppress_exceptions((c1, c2), KeyError))
    Traceback (most recent call last):
    ...
    ValueError: invalid literal for int() with base 10: 'a'
    """
    if not exceptions:
        exceptions = Exception,
    for callable in callables:
        try:
            yield callable()
        except exceptions:
            pass


def is_list_of_dec_nums(arg):
    """
    Determines if the argument is a list of decimal numbers

    :param arg: A string to be evaluate as a list of decimal numbers
    :type arg: str

    :return: A boolean indicator True or False
    :rtype:  bool

    :author: Milica Ng
    """
    if not isinstance(arg, list):
        return False
    elif not arg:
        return False
    else:
        for q in arg:
            if not isinstance(q, list):
                return False
    return True


@classmethod
def find(cls, db, name):
    """Find a service by name.

        Returns None if not found.
        """
    return db.query(cls).filter(cls.name == name).first()


def export_net_json(net, net_type, indent='no-indent'):
    """ export json string of dat """
    import json
    from copy import deepcopy
    if net_type == 'dat':
        exp_dict = deepcopy(net.dat)
        if type(exp_dict['mat']) is not list:
            exp_dict['mat'] = exp_dict['mat'].tolist()
            if 'mat_orig' in exp_dict:
                exp_dict['mat_orig'] = exp_dict['mat_orig'].tolist()
    elif net_type == 'viz':
        exp_dict = net.viz
    elif net_type == 'sim_row':
        exp_dict = net.sim['row']
    elif net_type == 'sim_col':
        exp_dict = net.sim['col']
    if indent == 'indent':
        exp_json = json.dumps(exp_dict, indent=2)
    else:
        exp_json = json.dumps(exp_dict)
    return exp_json


def turbulent_Nunner(Re, Pr, fd, fd_smooth):
    """Calculates internal convection Nusselt number for turbulent flows
    in pipe according to [2]_ as shown in [1]_.

    .. math::
        Nu = \\frac{RePr(f/8)}{1 + 1.5Re^{-1/8}Pr^{-1/6}[Pr(f/f_s)-1]}

    Parameters
    ----------
    Re : float
        Reynolds number, [-]
    Pr : float
        Prandtl number, [-]
    fd : float
        Darcy friction factor [-]
    fd_smooth : float
        Darcy friction factor of a smooth pipe [-]

    Returns
    -------
    Nu : float
        Nusselt number, [-]

    Notes
    -----
    Valid for Pr ≅ 0.7; bad results for Pr > 1.

    Examples
    --------
    >>> turbulent_Nunner(Re=1E5, Pr=0.7, fd=0.0185, fd_smooth=0.005)
    101.15841010919947

    References
    ----------
    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat
       Transfer, 3E. New York: McGraw-Hill, 1998.
    .. [2] W. Nunner, "Warmeiibergang und Druckabfall in Rauhen Rohren,"
       VDI-Forschungsheft 445, ser. B,(22): 5-39, 1956
    """
    return Re * Pr * fd / 8.0 / (1 + 1.5 * Re ** -0.125 * Pr ** (-1 / 6.0) *
        (Pr * fd / fd_smooth - 1.0))


def p_step_8(p):
    """Step : AbbreviatedStep"""
    p[0] = p[1]


def update_kwargs_for_key(kwargs: dict, key: str, values: dict):
    """Updates the passed in dictionary for the given key (using the dictionary `update` method of merging).

    If no value exists for the key, the supplied values dict is assigned directly.

    :param kwargs: The kwargs dictionary to modify in-place.
    :param key: The key to set (e.g. kwargs[key]).
    :param values: The values to update (e.g. kwargs[key].update(values)).
    """
    if key in kwargs:
        kwargs[key].update(values)
    else:
        kwargs[key] = values


def customdata_custom_splitnormals_add():
    """Add a custom split normals layer, if none exists yet

    """
    pass


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 render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

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

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


def extrude_move(ARMATURE_OT_extrude=None, TRANSFORM_OT_translate=None):
    """Create new bones from the selected joints and move them

    :param ARMATURE_OT_extrude: Extrude, Create new bones from the selected joints
    :param TRANSFORM_OT_translate: Translate, Translate (move) selected items
    """
    pass


def _is_list(value):
    """
    check if is list
    :param value:
    :type value: str
    :rtype bool
    """
    return value.endswith('_list')


def check_params(module):
    """
    Most modules must have either `name` or `id` specified.
    """
    if module.params.get('name') is None and module.params.get('id') is None:
        module.fail_json(msg='"name" or "id" is required')


@staticmethod
def positional_to_model(value):
    """Converts a positional argument to a model value"""
    return value


@classmethod
def from_hex(cls, hex_str):
    """Instantiate from a hexadecimal string."""
    return cls(bytes.fromhex(hex_str))


@staticmethod
def save(file_path, model):
    """
        Save the model onto the file identified by file_path.

        Parameters
        ----------
        file_path : str
            The path to the filename where the model has to be saved
        model : RTEnsemble
            The model RTEnsemble model to save on file

        Returns
        -------
        status : bool
            Returns true if the save is successful, false otherwise
        """
    raise NotImplementedError('Feature not implemented!')


def isNumber(x):
    """Returns true if x is an int or a float"""
    return isinstance(x, (int, float))


def getById(Id):
    """Returns ICachableItem that matches Id or None if not found"""


def localview_remove_from():
    """Move selected objects out of local view

    """
    pass


def write_data(output, iterable):
    """ Write (index, data) iterable to `output`

    Write some data to `output`. Iterable should return 2-tuples of the form
    index, data such that::

        output[index] = data

    makes sense.

    Examples
    --------
    >>> a=np.zeros((2,2))
    >>> write_data(a, data_generator(np.asarray([[1,2],[3,4]])))
    >>> a
    array([[ 1.,  2.],
           [ 3.,  4.]])
    """
    for index, data in iterable:
        output[index] = data


@classmethod
def _HasProvideGoogFlag(cls, source):
    """Determines whether the @provideGoog flag is in a comment."""
    for comment_content in cls._COMMENT_REGEX.findall(source):
        if '@provideGoog' in comment_content:
            return True
    return False


@classmethod
def is_datasource_for(cls, header):
    """
        Check if class supports data from the given FITS file.

        Parameters
        ----------
        header : `~astropy.io.fits.Header`
            main header of the FITS file
        """
    return header.get('instrume', '').strip() in cls.INSTRUMENTS


@staticmethod
def full_path(dir_name, file_name):
    """ Consturct full file path """
    if dir_name[len(dir_name) - 1:] == '/':
        file_path = '{}{}'.format(dir_name, file_name)
    else:
        file_path = '{}/{}'.format(dir_name, file_name)
    return file_path


def PhaseWtSum(G2frame, histo):
    """
    Calculate sum of phase mass*phase fraction for PWDR data (exclude magnetic phases)

    :param G2frame: GSASII main frame structure
    :param str histo: histogram name
    :returns: sum(scale*mass) for phases in histo
    """
    Histograms, Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
    wtSum = 0.0
    for phase in Phases:
        if Phases[phase]['General']['Type'] != 'magnetic':
            if histo in Phases[phase]['Histograms']:
                if not Phases[phase]['Histograms'][histo]['Use']:
                    continue
                mass = Phases[phase]['General']['Mass']
                phFr = Phases[phase]['Histograms'][histo]['Scale'][0]
                wtSum += mass * phFr
    return wtSum


def action(discriminator, callable=None, args=(), kw=None, **extra):
    """Record a configuration action

        The job of most directives is to compute actions for later
        processing.  The action method is used to record those
        actions.  The discriminator is used to to find actions that
        conflict. Actions conflict if they have the same
        discriminator. The exception to this is the special case of
        the discriminator with the value None. An actions with a
        discriminator of None never conflicts with other actions. This
        is possible to add an order argument to crudely control the
        order of execution.  'info' is optional source line information,
        'includepath' is None (the default) or a tuple of include paths for
        this action.
        """


def psi_K_CO3_OH_HMW84(T, P):
    """c-a-a': potassium carbonate hydroxide [HMW84]."""
    psi = -0.01
    valid = T == 298.15
    return psi, valid


def tex_tableau(cor, div0, div1, u, nblist, chf_unite):
    """tableau de conversion pour les unités simples : L, g ou m"""
    if len(u) == 6:
        cor.append('\\begin{tabular}{c|c|c|c|c|c}')
        cor.append('h%s & da%s & %s & d%s & c%s & m%s \\\\ \\hline' % u)
        delta = 1
        div0 = div0 - 1
        div1 = div1 - 1
    else:
        cor.append('\\begin{tabular}{c|c|c|c|c|c|c}')
        cor.append('k%s & h%s & da%s & %s & d%s & c%s & m%s \\\\ \\hline' % u)
        delta = 0
    for dummy in range(-div0 + chf_unite):
        tmp = nblist.pop(0)
        nblist[0] = tmp + nblist[0]
    for dummy in range(div0 - chf_unite):
        nblist.insert(0, '0')
    for dummy in range(-len(u) + len(nblist)):
        tmp = nblist.pop(7)
        nblist[6] = nblist[6] + tmp
    for dummy in range(len(u) - len(nblist)):
        nblist.append('0')
    nblist[div0] = '%s\\Rnode{virg0}{\\ }' % nblist[div0]
    nblist[div1] = '{%s\\Rnode{virg1}{\\textcolor{red}{ \\LARGE ,}}}' % nblist[
        div1]
    cor.append(('%s ' + '& %s' * (6 - delta)) % tuple(nblist))


@classmethod
def fromcache(cls, cache, iterable=()):
    """Initialize deque using `cache`.

        >>> cache = Cache('/tmp/diskcache/index')
        >>> _ = cache.clear()
        >>> deque = Deque.fromcache(cache, [5, 6, 7, 8])
        >>> len(deque)
        4
        >>> 7 in deque
        True
        >>> deque.popleft()
        5

        :param Cache cache: cache to use
        :param iterable: iterable of items
        :return: initialized Deque

        """
    self = cls.__new__(cls)
    self._cache = cache
    self.extend(iterable)
    return self


def robot_update_mobility(api, exp_id, name, nodes_list=()):
    """Update robot mobility on nodes_list.

    :param api: API Rest api object
    :param exp_id: Target experiment id
    :param name: mobility name
    :param nodes_list: List of nodes where to run command.
                       Empty list runs on all nodes
    """
    result = api.robot_update_mobility(exp_id, name, nodes_list)
    return result


def parse_source_file(source_file):
    """Parses a source file thing and returns the file name

    Example:

    >>> parse_file('hg:hg.mozilla.org/releases/mozilla-esr52:js/src/jit/MIR.h:755067c14b06')
    'js/src/jit/MIR.h'

    :arg str source_file: the source file ("file") from a stack frame

    :returns: the filename or ``None`` if it couldn't determine one

    """
    if not source_file:
        return None
    vcsinfo = source_file.split(':')
    if len(vcsinfo) == 4:
        vcstype, root, vcs_source_file, revision = vcsinfo
        return vcs_source_file
    if len(vcsinfo) == 2:
        vcstype, vcs_source_file = vcsinfo
        return vcs_source_file
    if source_file.startswith('/'):
        return source_file
    return None


@staticmethod
def in_bbox(point, a, b):
    """Return True if `point` is in the bounding box defined by `a`
        and `b`.

        >>> bmin = (0, 0)
        >>> bmax = (100, 100)
        >>> Vector.in_bbox((50, 50), bmin, bmax)
        True
        >>> Vector.in_bbox((647, -10), bmin, bmax)
        False

        """
    return (point[0] <= a[0] and point[0] >= b[0] or point[0] <= b[0] and
        point[0] >= a[0]) and (point[1] <= a[1] and point[1] >= b[1] or
        point[1] <= b[1] and point[1] >= a[1])


def Gp_Gm_vectors(ssalb, kestar, g, mu):
    """return Gp and Gm vectors at one wavelength

    :param ssalb: single scattering albedo of each layer (no unit)
    :type ssalb: array
    :param kestar: delta-eddington AFEC (no unit)
    :type kestar: array
    :param g: asymmetry factor  of each layer (no unit)
    :type g: array
    :param mu: cosine of the incident angle

    :returns: Gp and Gm
"""
    g_star = g / (1 + g)
    ssalb_star = ssalb * (1 - g ** 2) / (1 - g ** 2 * ssalb)
    gamma1 = 0.25 * (7 - ssalb_star * (4 + 3 * g_star))
    gamma2 = -0.25 * (1 - ssalb_star * (4 - 3 * g_star))
    gamma3 = 0.25 * (2 - 3 * g_star * mu)
    gamma4 = 0.25 * (2 + 3 * g_star * mu)
    G = mu ** 2 * ssalb_star / ((kestar * mu) ** 2 - 1)
    Gp = G * ((gamma1 - 1 / mu) * gamma3 + gamma2 * gamma4)
    Gm = G * ((gamma1 + 1 / mu) * gamma4 + gamma2 * gamma3)
    return Gp, Gm


def strip_modifier_remove(name: str='Name'):
    """Remove a modifier from the strip

    :param name: Name, Name of modifier to remove
    :type name: str
    """
    pass


@classmethod
def from_struct_time(cls, t):
    """Constructs a :py:class:`Date` from a struct_time, such as
        might be returned from time.gmtime() and related functions."""
    return cls(century=t[0] // 100, year=t[0] % 100, month=t[1], day=t[2])


def update_keyword_es(es, hit):
    """
    Update keywords of a news entry in ElasticSearch

    :param es: ElasticSearch connection
    :param hit: news entry to update
    """
    es.update(index='sitemaps', id=hit['_id'], body={'doc': {
        'news:keywords': hit['_source']['news:keywords']}})


def text_length_validator(value, values):
    """ Provides a validator function that a valid string for the display
    commands of the Keithley. Raises a TypeError if value is not a string.
    If the string is too long, it is truncated to the correct length.

    :param value: A value to test
    :param values: The allowed length of the text
    """
    if not isinstance(value, str):
        raise TypeError('Value is not a string.')
    return value[:values]


def _format_float(arg):
    """Formats a float value to be as short as possible.

    Trims extraneous trailing zeros and period to give API
    args the best possible chance of fitting within 2000 char
    URL length restrictions.

    For example:

    format_float(40) -> "40"
    format_float(40.0) -> "40"
    format_float(40.1) -> "40.1"
    format_float(40.001) -> "40.001"
    format_float(40.0010) -> "40.001"

    :param arg: The lat or lng float.
    :type arg: float

    :rtype: string
    """
    return '{}'.format(round(float(arg), 6)).rstrip('0').rstrip('.')


def parse_fasta(filename):
    """
	Imports specified .fasta file
	"""
    f = open(filename)
    sequences = {}
    for line in f:
        if line.startswith('>'):
            name = line[1:].strip()
            sequences[name] = ''
        else:
            sequences[name] = sequences[name] + line.strip()
    f.close()
    return sequences


@staticmethod
def to_rankine(celsius):
    """ Convert celsius to rankie """
    return (celsius + 273.15) * 9 / 5


def var(x, *args, **kwargs):
    """Variance between cells."""
    if x.ndim > 2:
        x = x.mean(axis=2)
    return x.var(axis=1)


def render_pep440_old(pieces):
    """TAG[.postDISTANCE[.dev0]] .

    The ".dev0" means dirty.

    Eexceptions:
    1: no tags. 0.postDISTANCE[.dev0]
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance'] or pieces['dirty']:
            rendered += '.post%d' % pieces['distance']
            if pieces['dirty']:
                rendered += '.dev0'
    else:
        rendered = '0.post%d' % pieces['distance']
        if pieces['dirty']:
            rendered += '.dev0'
    return rendered


def node_text_equality(left, right):
    """Do these two nodes have the same text fields? Accounts for Nones"""
    return (left and right and left.text == right.text and left.title ==
        right.title and left.tagged_text == right.tagged_text)


def resiliency_upstream(graph, edgelist, event):
    """
    This function computes the resiliency of all upstream sections,
    mainly looking out for generators
    :param edgelist: All upstream sections of the feeder, from persective of a feeder being analyzed
    :return:
    """
    print('Heat your ', edgelist)
    pass


@classmethod
def walk_fast(cls, level):
    """Walk along a Hilbert curve at the given level.

        This function does not exist in the SWIG bindings of the original C++
        library. It provides a more Pythonic way to iterate over cells.

        Use with caution: this repeatedly mutates a single instance with a
        changing ``id``. If you save the object, it will change out from
        underneath you.

        :returns:
            Iterator over ids in the same instance of :class:`CellId`.
        """
    instance = cls.begin(level)
    cellid_int = instance.id()
    endid_int = cls.end(level).id()
    increment = instance.lsb() << 1
    while cellid_int != endid_int:
        instance.__id = cellid_int
        yield instance
        cellid_int += increment


def get_str(track, tag):
    """Get tag from Mutagen file as a string.

    Return the first value of a multivalued tag.  Return '' if the tag is
    missing or empty.
    """
    try:
        values = track[tag]
        return values[0]
    except (IndexError, KeyError):
        return ''


def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]


def create_config_dir_name(pkg_name):
    """Return name of pkg's config directory."""
    return pkg_name + '_config'


def set_verbosity(value):
    """Set the logging verbosity level.

    :param value: verbosity level to set, e.g. VERBOSE_VERY.
    """
    global VERBOSE
    VERBOSE = int(value)


@staticmethod
def prepare_target_to_reset(target_id, available_devices):
    """
        prepare target to reset
        """
    targets_to_reset = []
    if isinstance(target_id, list):
        for target in target_id:
            for device in available_devices:
                if target == device['target_id'
                    ] and device not in targets_to_reset:
                    targets_to_reset.append(device)
    elif target_id == 'all':
        targets_to_reset = available_devices
    elif len(target_id) <= 48:
        for device in available_devices:
            if (target_id == device['target_id'] or device['target_id'].
                startswith(target_id)) and device not in targets_to_reset:
                targets_to_reset.append(device)
    return targets_to_reset


def get_formatted_mass(mass):
    """
    This helps with looking up masses in a dictionary by mass by ensuring the values 0.3 and 0.30 are represented
    the same
    :param mass:
    :return:
    """
    return float('{0:0.6f}'.format(float(mass)))


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 userAuthSuccessHtml(user, conf):
    """
  user auth success, would see this html from browser
  if you only have bot app, it is not needed
  """
    return (
        '
You have authorized the bot to access your RingCentral data! Please close this page and get back to Glip
'
        )


def repeat(x, n=None):
    """
    Returns a generator that indefinitly yields ``x`` (or ``n`` times if ``n``
    is supplied).
    """
    if n is None:
        n = -1
    elif n < 0:
        n = 0
    while n != 0:
        yield x
        n -= 1


def handle_exception(exc, msg='SOMETHING WENT WRONG', xit=SystemExit):
    """
    Print msg, then text of exception exc, then raise exception xit.

    :param exc: Exception to handle.
    :type exc: Exception

    :param msg: Message to raise, "SOMETHING WENT WRONG" by default.
    :type msg: str

    :param xit: Exception to raise upon exit, SystemExit by default.
    :type xit: Exception
    """
    print(msg)
    print(exc)
    if xit is not None:
        raise xit


@classmethod
def init_artifact(cls, context, values):
    """Initialize an empty versioned object with values.

        Initialize vo object with default values and values specified by user.
        Also reset all changes of initialized object so user can track own
        changes.

        :param context: user context
        :param values: values needs to be set
        :return: artifact with initialized values
        """
    af = cls(context)
    default_fields = []
    for field in af.fields:
        if field not in values:
            default_fields.append(field)
    if default_fields:
        af.obj_set_defaults(*default_fields)
    for name, value in values.items():
        setattr(af, name, value)
    return af


@classmethod
def topic(cls, **kwargs) ->str:
    """Get MQTT topic for this message."""
    return 'rhasspy/g2p/phonemes'


def validate_boolean(setting, value, option_parser, config_parser=None,
    config_section=None):
    """Check/normalize boolean settings:
         True:  '1', 'on', 'yes', 'true'
         False: '0', 'off', 'no','false', ''
    """
    if isinstance(value, bool):
        return value
    try:
        return option_parser.booleans[value.strip().lower()]
    except KeyError:
        raise LookupError('unknown boolean value: "%s"' % value)


def update_build(BuildId=None, Name=None, Version=None):
    """
    Updates metadata in a build record, including the build name and version. To update the metadata, specify the build ID to update and provide the new values. If successful, a build object containing the updated metadata is returned.
    See also: AWS API Documentation

    :example: response = client.update_build(
        BuildId='string',
        Name='string',
        Version='string'
    )

    :type BuildId: string
    :param BuildId: [REQUIRED]
            Unique identifier for a build to update.

    :type Name: string
    :param Name: Descriptive label that is associated with a build. Build names do not need to be unique.

    :type Version: string
    :param Version: Version that is associated with this build. Version strings do not need to be unique.

    :rtype: dict
    :return: {
        'Build': {
            'BuildId': 'string',
            'Name': 'string',
            'Version': 'string',
            'Status': 'INITIALIZED'|'READY'|'FAILED',
            'SizeOnDisk': 123,
            'OperatingSystem': 'WINDOWS_2012'|'AMAZON_LINUX',
            'CreationTime': datetime(2015, 1, 1)
        }
    }

    :returns:
    INITIALIZED  A new build has been defined, but no files have been uploaded. You cannot create fleets for builds that are in this status. When a build is successfully created, the build status is set to this value.
    READY  The game build has been successfully uploaded. You can now create new fleets for this build.
    FAILED  The game build upload failed. You cannot create new fleets for this build.

    """
    pass


def escape_cdata(cdata):
    """Escape XML CDATA content"""
    return cdata.replace(']]>', ']]>]]><![CDATA[')


@classmethod
def adapt_emulated_to_native(cls, impl, **kw):
    """Produce a MySQL native :class:`.mysql.ENUM` from plain
        :class:`.Enum`.

        """
    kw.setdefault('validate_strings', impl.validate_strings)
    kw.setdefault('values_callable', impl.values_callable)
    return cls(**kw)


@staticmethod
def format_expire_date(expiry_month, expiry_year):
    """
        Convert the given month and year in the format MMYY.
        :param int expiry_month: The month.
        :param int expiry_year: The year.
        :return str: The expiry date in the format MMYY.
        """
    return '%02d' % expiry_month + '%02d' % expiry_year


def get_attributes_config(obj, refresh=False):
    """Experimental function. Not part of the official API"""
    return obj._helper.get_attr_cache(refresh=refresh)


def replace_grid(old_grid, new_grid, topology_grid):
    """Replaces old hyperparameter search grid with one supplied by YAML."""
    for k in new_grid.keys():
        if k != 'topology_grid':
            old_grid['--{}'.format(k)] = new_grid[k]
    if 'topology_grid' in new_grid:
        topology_grid = new_grid.pop('topology_grid')
    return old_grid, topology_grid


def partition(cond, seq, parts=2):
    """
    Partition function from Erik Wilsher on Ned's blog at
    http://nedbatchelder.com/blog/200607/partition_for_python.html
    but with cond first, to match filter, map, etc.
    """
    res = [[] for i in range(parts)]
    for e in seq:
        res[int(cond(e))].append(e)
    return res


def read_load():
    """Reads server load stats."""
    with open('/proc/loadavg') as f:
        line = f.read()
        loadavg_1min = line.split()[0]
        loadavg_5min = line.split()[1]
        return loadavg_1min, loadavg_5min


@classmethod
def _fromEventProxy(cls, event_proxy):
    """
        Internal Constructor to wrap around JAVA class Event
        :param event_proxy:
        :return:
        """
    if event_proxy is None:
        return None
    instance = cls.__new__(cls)
    instance._event_proxy = event_proxy
    return instance


def _parse_args(p):
    """Command line arguments - all optional with [reasonable] defaults"""
    p.add_argument('--version', action='store_true', help=
        'show version information and exit')
    p.add_argument('-v', action='count', help='raise verbosity', default=0)
    g = p.add_mutually_exclusive_group()
    g.add_argument('--watch', action='store_true', help=
        'watch and build in foreground', default=False)
    g.add_argument('--daemon', action='store_true', help=
        'watch and build as daemon', default=False)
    g.add_argument('--kill', action='store_true', default=False, help=
        'exorcise daemon if running')
    p.add_argument('--i3-refresh-msg', action='store', default='reload',
        choices=['restart', 'reload', 'nop'], help='i3-msg to send after build'
        )
    p.add_argument('--notify', action='store_true', default=False, help=
        'show build notification via notify-send')
    p.add_argument('--log', action='store', default=None, help=
        'i3configgerPath to where log should be stored')
    p.add_argument('message', help='message to send to i3configger', nargs='*')
    return p.parse_args()


def is_stage_validated(stage: dict) ->bool:
    """
    Check if stage has special validation key
    and is validated.
    """
    for key in stage.keys():
        if key == 'validation' and stage['validation']['validation'
            ] == 'valid':
            return True
    return False


def test_Map():
    """ Build a map, then try matches.
    >>> m = RouteMap([{'pattern': '^/$'}])
    >>> m.match('') == None
    True
    >>> m.match('/') == {}
    True
    """


@classmethod
def options(cls):
    """Return dictionary of all included options."""
    return cls.OPTIONS


def decode_keys(doc, field):
    """Decode encoded field keys.

    :param doc: doc
    :param field: doc field
    """
    if not doc.get(field):
        return
    decoded = {}
    for key, val in doc.get(field).items():
        decoded[key.replace(';', '.')] = val
    doc[field] = decoded


def forward(input, layers):
    """ perform a forward path in the layers given an input

    utility function

    Parameters
    ----------

    input: Tensor
        the tensor to be forwarded across the given layers

    layers: list of layers
        the layers to forward the input in a consecutive manner
    """
    outputs = [layers[0].forward(input)]
    for layer in layers[1:]:
        outputs.append(layer.forward(outputs[-1]))
    return outputs


@classmethod
def render_regions(cls, view, **kwargs):
    """
        This is mostly helpful when using ``{% region %}`` template tags. It
        returns all regions when rendering the detail page of the passed
        view. Those regions still have to be filtered using ``changed_regions``
        if you do not want to exchange all snippets.

        When editing data which is used to render a detail page of the same
        or of a different, related model instance, rendering the detail page
        and extracting (potentially) changed parts is necessary for
        live-updating the affected HTML snippets in the frontend.

        This class method achieves exactly that.

        Usage examples::

            # When editing the same model as is on display
            regions = DetailView.render_regions(self)

            # When using towel.resources.inlines
            regions = DetailView.render_regions(self,
                model=self.get_parent_class(),
                object=self.parent,
                )
        """
    self = cls()
    self.request = view.request
    self.model = view.model
    self.object = view.object
    for key, value in kwargs.items():
        setattr(self, key, value)
    regions = {}
    context = self.get_context_data(object=self.object, regions=regions)
    self.render_to_response(context).render()
    return regions


@staticmethod
def clearAllCircularDependency(stringDef):
    """ Replaces cp.dynamic(x,y,z) , pp.dynamic(x,y,z) and dynamic(x,y,z) for 0
        """
    response = stringDef
    initialIndex = -1
    startIndex = -1
    finalIndex = -1
    toReplace = ''
    dynLen = len('cp.dynamic(')
    initialIndex = stringDef.find('cp.dynamic(')
    if initialIndex == -1:
        initialIndex = stringDef.find('pp.dynamic(')
    if initialIndex == -1:
        initialIndex = stringDef.find('dynamic(')
        dynLen = len('dynamic(')
    if initialIndex != -1:
        startIndex = initialIndex
        initialIndex = initialIndex + dynLen
        if len(stringDef) > initialIndex:
            finalIndex = stringDef[initialIndex + 1:].find(')')
    if initialIndex != -1 and finalIndex != -1:
        toReplace = stringDef[startIndex:initialIndex + finalIndex + 2]
        response = stringDef.replace(toReplace, '0')
    return response


def format_table_row(values, widths=None, sep=' | '):
    """Format a row with `values` of a table."""
    if widths:
        _values = []
        for value, width in zip(values, widths):
            if value is None:
                value = ''
            _values.append('{0:>{1}s}'.format(value, width))
    return sep.join(_values)


@classmethod
def delete_cookie(cls, message, key, path='/', domain=None):
    """
        Deletes a cookie in a response.
        """
    return cls.set_cookie(message, key, max_age=0, path=path, domain=domain,
        expires='Thu, 01-Jan-1970 00:00:00 GMT')


@staticmethod
def load_from_namespace(module_name):
    """
        Load a py3status bundled module.
        """
    class_inst = None
    name = 'py3status.modules.{}'.format(module_name)
    py_mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        py_mod = getattr(py_mod, comp)
    class_inst = py_mod.Py3status()
    return class_inst


def writeFile(path, data):
    """Write a file at the specified path.

        Parent directories will be added if necessary. The final path component
        gives the filename. If the file already exists, it will be overwritten.

        ``data`` may be a string or file-like object.
        """


@classmethod
def view_key(cls, key):
    """
        Wrapper for KVSClient view
        """
    return cls.client.view(key)


@classmethod
def has_archiving(cls):
    """Returns whether it supports archiving items on the fetch process.

        :returns: this backend supports items archive
        """
    return True


def write_output(imputed_gwas, output, append=False):
    """
    Write GWAS data to file in tab-delimited format

    :param imputed_gwas: pandas.DataFrame object containing GWAS data
    :param output: file-object or path to write file to
    :param append: bool indicated whether or not to append to the file

    :return: None
    """
    imputed_gwas.to_csv(output, sep='\t', mode='a' if append else 'w',
        header=not append, index=False, float_format='%.3g')
    return


def Morrison(Re):
    """Calculates drag coefficient of a smooth sphere using the method in
    [1]_ as described in [2]_.

    .. math::
        C_D = \\frac{24}{Re} + \\frac{2.6Re/5}{1 + \\left(\\frac{Re}{5}\\right)^{1.52}}
        + \\frac{0.411 \\left(\\frac{Re}{263000}\\right)^{-7.94}}{1
        + \\left(\\frac{Re}{263000}\\right)^{-8}} + \\frac{Re^{0.8}}{461000}

    Parameters
    ----------
    Re : float
        Reynolds number of the sphere, [-]

    Returns
    -------
    Cd : float
        Drag coefficient [-]

    Notes
    -----
    Range is Re <= 1E6.

    Examples
    --------
    >>> Morrison(200.)
    0.767731559965325

    References
    ----------
    .. [1] Morrison, Faith A. An Introduction to Fluid Mechanics.
       Cambridge University Press, 2013.
    .. [2] Barati, Reza, Seyed Ali Akbar Salehi Neyshabouri, and Goodarz
       Ahmadi. "Development of Empirical Models with High Accuracy for
       Estimation of Drag Coefficient of Flow around a Smooth Sphere: An
       Evolutionary Approach." Powder Technology 257 (May 2014): 11-19.
       doi:10.1016/j.powtec.2014.02.045.
    """
    Cd = 24.0 / Re + 2.6 * Re / 5.0 / (1 + (Re / 5.0) ** 1.52) + 0.411 * (Re /
        263000.0) ** -7.94 / (1 + (Re / 263000.0) ** -8) + Re ** 0.8 / 461000.0
    return Cd


def process_bib_entry(cid, bibdatabase, bibnums, fallback_fmt=
    '[{author_abbrev}, {year}]'):
    """work out the best way to represent the bib entry """
    entry = bibdatabase[cid]
    if cid not in bibnums:
        bibnums[cid] = len(bibnums) + 1
    if 'doi' in entry:
        return '{text}'.format(doi=
            entry['doi'], text=bibnums[cid])
    elif 'url' in entry:
        return '{text}'.format(url=entry['url'], text=
            bibnums[cid])
    elif 'link' in entry:
        return '{text}'.format(url=entry['link'], text=
            bibnums[cid])
    else:
        return bibnums[cid]


@staticmethod
def p_word(symbols):
    """word : CHARACTER word_next
                | COMMA word_next
                | EQUAL word_next
        """
    symbols[0] = symbols[1] + symbols[2]


def engine_map_modelfunc(coeff_values, X):
    """
    The function that models the engine-map.
    """
    a = coeff_values['a']
    b = coeff_values['b']
    c = coeff_values['c']
    a2 = coeff_values['a2']
    b2 = coeff_values['b2']
    loss0 = coeff_values['loss0']
    loss2 = coeff_values['loss2']
    pmf = X['pmf']
    cm = X['cm']
    bmep = (a + b * cm + c * cm ** 2) * pmf + (a2 + b2 * cm
        ) * pmf ** 2 + loss0 + loss2 * cm ** 2
    return bmep


def release_gh_metadata_handler(release, ex):
    """Handler for CustomGithubMetadataError."""
    release.model.errors = {'errors': ex.message}


def skip(overwrite, on_server, update):
    """
    Determine if object should be skipped or overwritten by comparing the state on the server
    with the state as submitted
    :param overwrite: if it should be overwritten regardless of congruent state
    :param on_server: the existing object on the server to assess
    :param update: ObjectSharing object sourced from arguments
    :return: True if skip, False if overwrite
    """
    if overwrite:
        return False
    else:
        return on_server == update


@staticmethod
def concat_url(endpoint, url):
    """Concatenate endpoint and final URL.

        E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
        "http://keystone/v2.0/tokens".

        :param endpoint: the base URL
        :param url: the final URL
        """
    return '%s/%s' % (endpoint.rstrip('/'), url.strip('/'))


def get_auth_type_from_header(header):
    """
    Given a WWW-Authenticate or Proxy-Authenticate header, returns the
    authentication type to use. We prefer NTLM over Negotiate if the server
    suppports it.
    """
    if 'ntlm' in header:
        return 'NTLM'
    elif 'negotiate' in header:
        return 'Negotiate'
    return None


def list_users_in_group(UserPoolId=None, GroupName=None, Limit=None,
    NextToken=None):
    """
    Lists the users in the specified group.
    Requires developer credentials.
    See also: AWS API Documentation

    :example: response = client.list_users_in_group(
        UserPoolId='string',
        GroupName='string',
        Limit=123,
        NextToken='string'
    )

    :type UserPoolId: string
    :param UserPoolId: [REQUIRED]
            The user pool ID for the user pool.

    :type GroupName: string
    :param GroupName: [REQUIRED]
            The name of the group.

    :type Limit: integer
    :param Limit: The limit of the request to list users.

    :type NextToken: string
    :param NextToken: An identifier that was returned from the previous call to this operation, which can be used to return the next set of items in the list.

    :rtype: dict
    :return: {
        'Users': [
            {
                'Username': 'string',
                'Attributes': [
                    {
                        'Name': 'string',
                        'Value': 'string'
                    },
                ],
                'UserCreateDate': datetime(2015, 1, 1),
                'UserLastModifiedDate': datetime(2015, 1, 1),
                'Enabled': True|False,
                'UserStatus': 'UNCONFIRMED'|'CONFIRMED'|'ARCHIVED'|'COMPROMISED'|'UNKNOWN'|'RESET_REQUIRED'|'FORCE_CHANGE_PASSWORD',
                'MFAOptions': [
                    {
                        'DeliveryMedium': 'SMS'|'EMAIL',
                        'AttributeName': 'string'
                    },
                ]
            },
        ],
        'NextToken': 'string'
    }

    :returns:
    UNCONFIRMED - User has been created but not confirmed.
    CONFIRMED - User has been confirmed.
    ARCHIVED - User is no longer active.
    COMPROMISED - User is disabled due to a potential security threat.
    UNKNOWN - User status is not known.

    """
    pass


def dslice_ex(dict_, keys, strict=True):
    """Returns a new dictionary with only the specified keys removed"""
    ret = dict_.copy()
    for key in keys:
        if strict or key in ret:
            del ret[key]
    return ret


def b2h(num, suffix='B'):
    """Format file sizes as human readable.

    https://stackoverflow.com/a/1094933

    Parameters
    ----------
    num : int
        The number of bytes.
    suffix : str, optional
        (default: 'B')

    Returns
    -------
    str
        The human readable file size string.

    Examples
    --------
    >>> b2h(2048)
    '2.0kB'
    """
    try:
        for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']:
            if abs(num) < 1024.0:
                return '{0:3.1f}{1}{2}'.format(num, unit, suffix)
            num /= 1024.0
        return '{0:.1f}{1}{2}'.format(num, 'Y', suffix)
    except:
        return '-'


def zoom_fft_visualize(zoom_fft_spectrum, antenna_idx, range_bin_idx):
    """to be implemented"""
    pass


@staticmethod
def always(src, dst, fn):
    """Always overwrite files on conflict."""
    return True


def lower_case_underscore_to_camel_case(text):
    """
    Converts string or unicdoe from lower case underscore to camel case
    :param text: str, string to convert
    :return: str
    """
    split_string = text.split('_')
    class_ = text.__class__
    return split_string[0] + class_.join('', map(class_.capitalize,
        split_string[1:]))


def object_add_grid_scale(context):
    """Return scale which should be applied on object data to align it to grid scale

    """
    pass


@classmethod
def from_stat(cls, obj, filename=None):
    """
        Create an `.SFTPAttributes` object from an existing ``stat`` object (an
        object returned by `os.stat`).

        :param object obj: an object returned by `os.stat` (or equivalent).
        :param str filename: the filename associated with this file.
        :return: new `.SFTPAttributes` object with the same attribute fields.
        """
    attr = cls()
    attr.st_size = obj.st_size
    attr.st_uid = obj.st_uid
    attr.st_gid = obj.st_gid
    attr.st_mode = obj.st_mode
    attr.st_atime = obj.st_atime
    attr.st_mtime = obj.st_mtime
    if filename is not None:
        attr.filename = filename
    return attr


def notify_objects(interface):
    """ Notify object events of objects implementing the given interface
        """


def repeatedly(f, n=None):
    """
    Takes a function of no args, presumably with side effects, and returns an
    infinite (or length ``n`` if supplied) lazy sequence of calls to it.
    """
    if callable(n) and isinstance(f, int):
        f, n = n, f
    if n is None:
        n = -1
    while n != 0:
        yield f()
        n -= 1


def make_result(df, filename):
    """ write output result in filename
    """
    df.drop(['datetime', 'timestamp', 'score_value'], axis=1, inplace=True)
    df['player'] = df.player.str.upper()
    df.to_csv(filename)
    print('  {} Made')


def critical(__self, __message, *args, **kwargs):
    """Log ``message.format(*args, **kwargs)`` with severity ``'CRITICAL'``."""
    __self._log('CRITICAL', None, False, __self._options, __message, args,
        kwargs)


def update(*args, **kwds):
    """od.update(E, **F) -> None.  Update od from dict/iterable E and F.

        If E is a dict instance, does:           for k in E: od[k] = E[k]
        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
        In either case, this is followed by:     for k, v in F.items(): od[k] = v

        """
    if len(args) > 2:
        raise TypeError(
            'update() takes at most 2 positional arguments (%d given)' % (
            len(args),))
    elif not args:
        raise TypeError('update() takes at least 1 argument (0 given)')
    self = args[0]
    other = ()
    if len(args) == 2:
        other = args[1]
    if isinstance(other, dict):
        for key in other:
            self[key] = other[key]
    elif hasattr(other, 'keys'):
        for key in other.keys():
            self[key] = other[key]
    else:
        for key, value in other:
            self[key] = value
    for key, value in kwds.items():
        self[key] = value


def should_build_with_cython(previous_cython_version, is_release):
    """
    Returns the previously used Cython version (or 'unknown' if not
    previously built) if Cython should be used to build extension modules from
    pyx files.
    """
    have_cython = False
    try:
        from Cython import __version__ as cython_version
        have_cython = True
    except ImportError:
        pass
    if have_cython and (not is_release or previous_cython_version == 'unknown'
        ):
        return cython_version
    else:
        return False


@staticmethod
def get_configure_command(config_options=None):
    """
        Get the command to configure the package

        Parameters
        ----------
        config_options : dict
            Configuration options to use with `./configure`.
            The configuration options will be converted to `--key=val` during
            runtime

        Returns
        -------
        config_str : str
            The configuration command
        """
    options = ''
    if config_options is not None:
        for key, val in config_options.items():
            if val is not None:
                options += f' --{key}={val}'
            else:
                options += f' --{key}'
    config_str = f'./configure{options}'
    return config_str


@classmethod
def where_user_id(cls, user_id):
    """ Easy way to query by user id """
    return cls.query.filter_by(user_id=user_id).first()


@staticmethod
def _from_db_object(test, db):
    """Converts a database entity to a formal object."""
    for field in test.fields:
        test[field] = db[field]
    test.obj_reset_changes()
    return test


def pack_padded_tensor(input, lengths):
    """Packs a tensor containing padded sequence of variable length.

    Parameters
    ----------
    input : Tensor
        The input tensor with shape :math:`(B, L, *)`, where :math:`B` is
        the batch size and :math:`L` is the maximum length of the batch.
    lengths : list or tensor
        The array of tensor lengths (of the first dimension) :math:`L`.
        :math:`\\max_i(L_i)` should equal :math:`L`.

    Returns
    -------
    Tensor
        The obtained tensor with shape :math:`(N, *)` where
        :math:`N = \\sum_{i=1}^{B}L_i`
    """
    pass


def post_upgrade():
    """Post-upgrade checks."""
    pass


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

        :param LoginSuccessDetails val:
        :rtype: EventDetails
        """
    return cls('login_success_details', val)


def getActiveCurrencies():
    """returns a list of the active currencies"""


def enable_all_features():
    """
    Enables all features in an organization. This enables the use of organization policies that can restrict the services and actions that can be called in each account. Until you enable all features, you have access only to consolidated billing, and you can't use any of the advanced account administration features that AWS Organizations supports. For more information, see Enabling All Features in Your Organization in the AWS Organizations User Guide .
    After all invited member accounts accept the handshake, you finalize the feature set change by accepting the handshake that contains "Action": "ENABLE_ALL_FEATURES" . This completes the change.
    After you enable all features in your organization, the master account in the organization can apply policies on all member accounts. These policies can restrict what users and even administrators in those accounts can do. The master account can apply policies that prevent accounts from leaving the organization. Ensure that your account administrators are aware of this.
    This operation can be called only from the organization's master account.
    See also: AWS API Documentation

    :example: response = client.enable_all_features()

    :rtype: dict
    :return: {
        'Handshake': {
            'Id': 'string',
            'Arn': 'string',
            'Parties': [
                {
                    'Id': 'string',
                    'Type': 'ACCOUNT'|'ORGANIZATION'|'EMAIL'
                },
            ],
            'State': 'REQUESTED'|'OPEN'|'CANCELED'|'ACCEPTED'|'DECLINED'|'EXPIRED',
            'RequestedTimestamp': datetime(2015, 1, 1),
            'ExpirationTimestamp': datetime(2015, 1, 1),
            'Action': 'INVITE'|'ENABLE_ALL_FEATURES'|'APPROVE_ALL_FEATURES',
            'Resources': [
                {
                    'Value': 'string',
                    'Type': 'ACCOUNT'|'ORGANIZATION'|'ORGANIZATION_FEATURE_SET'|'EMAIL'|'MASTER_EMAIL'|'MASTER_NAME'|'NOTES'|'PARENT_HANDSHAKE',
                    'Resources': {'... recursive ...'}
                },
            ]
        }
    }

    :returns:
    ACCOUNT - Specifies an AWS account ID number.
    ORGANIZATION - Specifies an organization ID number.
    EMAIL - Specifies the email address that is associated with the account that receives the handshake.
    OWNER_EMAIL - Specifies the email address associated with the master account. Included as information about an organization.
    OWNER_NAME - Specifies the name associated with the master account. Included as information about an organization.
    NOTES - Additional text provided by the handshake initiator and intended for the recipient to read.

    """
    pass


def from_float_to_int(val):
    """Convert float to int

    :param val: value to convert
    :type val: float
    :return: int(val)
    :rtype: int
    """
    val = int(val)
    return val


def deg(x):
    """
    Convert string of radians to degrees helper function
    """
    from math import degrees
    return degrees(float(x))


def populate_metadata():
    """
    Generates the metadata needed for the output summary page
    """
    metadata = {'Type': 'ValSummary', 'Title': 'Validation', 'TableTitle':
        'Perturbation growth test', 'Headers': ['Test status',
        'Null hypothesis', 'T test (t, p)', 'Ensembles']}
    return metadata


def initTooltips():
    """Sets some parameters controlling tooltip display. """
    import wx
    wx.ToolTip.Enable(True)
    wx.ToolTip.SetDelay(1500)
    wx.ToolTip.SetMaxWidth(300)
    wx.ToolTip.SetReshow(3000)
    wx.ToolTip.SetAutoPop(5000)


@classmethod
def is_following(cls, follower_id, object_id):
    """Return True if follower_id is currently following object_id, False
        otherwise.

        """
    return cls.get(follower_id, object_id) is not None


def compose(*args, iterable=None):
    """
    Compose a full bytestring command from individual pieces.

    Args:
        *args: Variable list of command parts to combine. Arguments may be
            a bytes object, bytearay object, or an integer (which will be
            cast to a single byte).
        iterable: Any iterable object that yields objects compatible with the
            rules for `*args`

    Returns:
        bytearray: The fully composed command ready to be written to
        the output buffer.
    """
    buffer = bytearray()
    for obj in (iterable or args):
        if isinstance(obj, (bytes, bytearray)):
            buffer.extend(obj)
        elif isinstance(obj, (bool, int)):
            buffer.append(obj)
        elif obj is None:
            continue
        else:
            raise RuntimeError(f'Invalid object of type {type(obj)}')
    return buffer


@classmethod
def clear_config_singleton(cls):
    """Delete the current configuration singleton to allow the
        initialization of a new one. This method is predominantly used
        during test.
        """
    cls._config = None


def guess_file_type(file_name, file_type=None):
    """
    Guess the type of a file name
    """
    file_extensions = {'svg': ['svg'], 'pdf': ['pdf'], 'png': ['png'],
        'jpeg': ['jpg', 'jpeg'], 'gif': ['gif']}
    if file_type is None:
        try:
            ext = file_name.lower().split('.')[-1]
            for file_type in file_extensions:
                if ext in file_extensions[file_type]:
                    break
        except TypeError:
            print('Unknown file type for file name: ' + file_name + '.')
    return file_type


def summary_sentences(talker):
    """
  returns summary as a list of sentences,
  each a list of words
  """
    return talker.summary_sentences()


@classmethod
def str_to_bool(cls, s: str) ->bool:
    """
        TODO: may refactor in standalone util
        :param s:
        :return:
        """
    return s is not None and s.lower() == 'true'


def rekey_db():
    """
        Change the db encryption key
    """
    print('Change the db encryption key: not implemented!')
    return None


def add_route(evlp: 'jina_pb2.Envelope', name: str, identity: str) ->None:
    """Add a route to the envelope

    :param evlp: the envelope to modify
    :param name: the name of the pod service
    :param identity: the identity of the pod service
    """
    r = evlp.routes.add()
    r.pod = name
    r.start_time.GetCurrentTime()
    r.pod_id = identity


def __iter__():
    """ Iterator over the available notifications of the
            current user
        """


def in_slots(obj, key, default=False):
    """
    Returns true if key exists in obj.__slots__; false if not in.
    If obj.__slots__ is absent, return default
    """
    return key in obj.__slots__ if getattr(obj, '__slots__', None) else default


def dict_as_tuple_list(d, as_list=False):
    """
    Format a dict to a list of tuples
    :param d: the dictionary
    :param as_list: return a list of lists rather than a list of tuples
    :return: formatted dictionary list
    """
    dd = list()
    for k, v in d.items():
        dd.append([k, v] if as_list else (k, v))
    return dd


def get_dayobs(fits_dict: dict):
    """
    Get dayobs from a fits_dict
    :param fits_dict: Fits dictionary with required header keywords
    :return: Date in DAY-OBS YYYYMMDD format
    """
    day_obs = fits_dict.get('DAY-OBS')
    if not day_obs:
        date_obs = fits_dict.get('DATE-OBS')
        day_obs = date_obs.split('T')[0].replace('-', '')
    return day_obs


def set_default_jvm_stdout(enable, parallel_flush=True):
    """
    This is useful utility method to get the output of the driver JVM from within a Jupyter notebook

    Parameters
    ----------
    enable: boolean
        Should flush the stdout by default when mlcontext.execute is invoked

    parallel_flush: boolean
        Should flush the stdout in parallel
    """
    global default_jvm_stdout, default_jvm_stdout_parallel_flush
    default_jvm_stdout = enable
    default_jvm_stdout_parallel_flush = parallel_flush


def create_fifo_queue(env, queue_name, content_based_deduplication=False,
    message_retention_period=None, visibility_timeout=None, redrive_policy=None
    ):
    """
    Create a new FIFO queue. Note that queue name has to end with ".fifo"

    - "content_based_deduplication" turns on automatic content-based
      deduplication of messages in the queue

    - redrive_policy can be None or an object, generated with
      redrive_policy() method of SQS. In the latter case if defines the
      way failed messages are processed.
    """
    attrs = {'FifoQueue': 'true'}
    kwargs = {'QueueName': env.get_sqs_queue_name(queue_name), 'Attributes':
        attrs}
    if content_based_deduplication:
        attrs['ContentBasedDeduplication'] = 'true'
    if message_retention_period is not None:
        attrs['MessageRetentionPeriod'] = str(message_retention_period)
    if visibility_timeout is not None:
        attrs['VisibilityTimeout'] = str(visibility_timeout)
    if redrive_policy is not None:
        attrs['RedrivePolicy'] = redrive_policy.__json__()
    ret = env.sqs_client.create_queue(**kwargs)
    return ret['QueueUrl']


@classmethod
def from_skeleton_factory(cls, skeleton, head=None, tail=None):
    """
        A factory method taking the simplest possible input: just a skeleton.
        Assumes 0th point is head, n-1th point is tail. No contour.

        Parameters
        ----------
        skeleton : list of ndarray or ndarray
            If ndarray, we are in the simpler "homocardinal" case
            If list of ndarray, each frame can have a varying number of points
        head: ndarray containing the position of the head.
        tail: ndarray containing the position of the tail.

        """
    uow = cls()
    uow.skeleton = skeleton
    if tail is None:
        uow.tail = skeleton[(0), :, :]
    else:
        uow.tail = tail
    if head is None:
        uow.head = skeleton[(-1), :, :]
    else:
        uow.head = head
    return uow


def get_active_rulesets(rulesengine_db, query_start, query_end):
    """gets all active rulesets and paths"""
    from src.praxxis.sqlite import connection
    conn = connection.create_connection(rulesengine_db)
    cur = conn.cursor()
    get_active_rulesets = (
        'SELECT * FROM "RulesEngine" WHERE ACTIVE = 1 ORDER BY ID')
    cur.execute(get_active_rulesets)
    conn.commit()
    rows = cur.fetchall()
    conn.close()
    return rows


def decode_pp_table(rawdata, c_struct):
    """
    De-serializes PowerPlay binary data into a ctypes structure
    """
    return c_struct.from_buffer(rawdata)


def setHook(hook):
    """ set the hook for the transaction manager;  this hook must be
            called whenever an indexing operation is added to the queue """


def color_delete():
    """Remove active color from palette

    """
    pass


@classmethod
def _add_message_type(cls, data, _type):
    """Helper method to add meta info for message

        :param data:
        :param _type:
        """
    data.update(__type=cls.MESSAGE_TYPES[_type])


@staticmethod
def _handle_report(method, body):
    """Reports don't use the same structure as other actifio commands so normalize their method and body

        :param method: The method that will be set as the act_method
        :param body: The body which will have the action and operation params derived from it
        :return: normalized method, normalized body
        """
    if method.startswith('report'):
        action = method
        body = action + ' ' + body
    return method, body


def bC_H_CO3_HMW84(T, P):
    """c-a: hydrogen carbonate [HMW84]."""
    b0 = 0.0
    b1 = 0.0
    b2 = 0.0
    C0 = 0
    C1 = 0
    alph1 = 2
    alph2 = -9
    omega = -9
    valid = T == 298.15
    return b0, b1, b2, C0, C1, alph1, alph2, omega, valid


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 render_git_describe(pieces):
    """TAG[-DISTANCE-gHEX][-dirty].

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

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


def helper_cmp_numbers(n1, n2):
    """Helper to compare two numbers and return `1` if the first number is larger,
    `0` if the numbers are equal, and `-1` otherwise.
    """
    if n1 > n2:
        return 1
    elif n1 < n2:
        return -1
    else:
        return 0


@staticmethod
def getsizeof(value):
    """Return the size of a cache element's value."""
    return 1


def undo():
    """Undo previous action

    """
    pass


def renderCell(item, column, colspan=0):
    """Render a single table body cell."""


def deleteCriterion(criterion_id):
    """Delete selected criterion.
        """


def pp(i, base=1024):
    """
    Pretty-print the integer `i` as a human-readable size representation.
    """
    degree = 0
    pattern = '%4d     %s'
    while i > base:
        pattern = '%7.2f %s'
        i = i / float(base)
        degree += 1
    scales = ['B', 'KB', 'MB', 'GB', 'TB', 'EB']
    return pattern % (i, scales[degree])


def coverage(seq, seq_len):
    """
    Return coverage of the sequence in the alignment.

    >>> coverage("AAAA----", 8)
    50.0
    """
    res = len(seq.replace('-', ''))
    return 100.0 * res / seq_len


@staticmethod
def _return_item_dictionary(param_dict, fast_access, copy):
    """Returns a dictionary containing either all parameters, all explored parameters,
        all config, all derived parameters, or all results.

        :param param_dict: The dictionary which is about to be returned
        :param fast_access: Whether to use fast access
        :param copy: If the original dict should be returned or a shallow copy

        :return: The dictionary

        :raises: ValueError if `copy=False` and fast_access=True`

        """
    if not copy and fast_access:
        raise ValueError(
            'You cannot access the original dictionary and use fast access at the same time!'
            )
    if not fast_access:
        if copy:
            return param_dict.copy()
        else:
            return param_dict
    else:
        resdict = {}
        for key in param_dict:
            param = param_dict[key]
            val = param.f_get()
            resdict[key] = val
        return resdict


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

        :param DeleteBatchResult val:
        :rtype: DeleteBatchLaunch
        """
    return cls('complete', val)


def ratio_from_percent(percent: int) ->float:
    """Convert percent to ratio."""
    return percent / 100


def _user(tsi):
    """ Fetch user information from the ToolShed API for given
    key.
    """
    response = tsi.make_get_request(tsi.url + '/users')
    return response.json()[0]


def get_file_name(file_name):
    """
    converts name of file with directory path
    to file name alone
    /dir/dir2/file_name.ext => file_name.ext
    :param file_name:
    :return:
    """
    by_dir = file_name.split('/')
    file_name = by_dir[len(by_dir) - 1]
    return file_name


def reset():
    """Reset the datamanager for the next transaction."""


def is_linear(cigar_tuple):
    """
    Whether end of alignment segment is a linear end

    Parameters
    -----
    cigar_tuple : tuple of cigar

    Returns
    -----
    int
        1 for linear end, 0 for ambiguous end

    """
    if cigar_tuple[0] == 0 and cigar_tuple[1] >= 5:
        return 1
    else:
        return 0


def readable_join(items, conjunction='or'):
    """
    Returns an oxford-comma-joined string with "or."

    E.g., ['thing1', 'thing2', 'thing3'] becomes "thing1, thing2, or thing3".
    """
    if not items:
        return None
    count = len(items)
    if count == 1:
        s = items[0]
    elif count == 2:
        template = u' {} '.format(conjunction)
        s = template.join(items)
    else:
        s = u'{}, {} {}'.format(u', '.join(items[:-1]), conjunction, items[-1])
    return s


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 function_path(func):
    """
    This will return the path to the calling function
    :param func:
    :return:
    """
    if getattr(func, 'func_code', None):
        return func.__code__.co_filename.replace('\\', '/')
    else:
        return func.__code__.co_filename.replace('\\', '/')


def elgamal_dec(params, d, c):
    """ decrypts the message (h^m) """
    G, o, g1, hs, g2, e = params
    a, b = c
    return b - d * a


@classmethod
def createBlocksFromHTML(cls, html, encoding='utf-8'):
    """
            createBlocksFromHTML - Returns the root level node (unless multiple nodes), and
                a list of "blocks" added (text and nodes).

            @return list< str/AdvancedTag > - List of blocks created. May be strings (text nodes) or AdvancedTag (tags)

            NOTE:
                Results may be checked by:

                    issubclass(block.__class__, AdvancedTag)

                If True, block is a tag, otherwise, it is a text node
        """
    parser = cls(encoding=encoding)
    parser.parseStr(html)
    rootNode = parser.getRoot()
    rootNode.remove()
    return rootNode.blocks


@classmethod
def get(cls, *args, **kwargs):
    """Get an Association instance"""
    raise NotImplementedError('Implement in subclass')


def set_document_loader(load_document):
    """
    Sets the default JSON-LD document loader.

    :param load_document(url): the document loader to use.
    """
    global _default_document_loader
    _default_document_loader = load_document


@classmethod
def tetragonal(cls, a, c, lattice_type='P'):
    """Factory for tetragonal lattices

        :param a: unit cell length
        :param c: unit cell length
        """
    a = float(a)
    self = cls(a, a, float(c), 90, 90, 90, lattice='tetragonal',
        lattice_type=lattice_type)
    return self


def fuzzy_not(v):
    """
    Not in fuzzy logic

    Return None if `v` is None else `not v`.

    Examples
    ========

    >>> fuzzy_not(True)
    False
    >>> fuzzy_not(None)
    >>> fuzzy_not(False)
    True

    """
    if v is None:
        return v
    else:
        return not v


def sort_1d(input):
    """Sort a 1D tensor (in ascending order) and also return the original index.

    Parameters
    ----------
    input : Tensor
        The tensor to be sorted.

    Returns
    -------
    Tensor
        Sorted tensor.
    Tensor
        Index tensor of the elements in the original input.
    """
    pass


def dict_from_cookiejar(cj):
    """Returns a key/value dictionary from a CookieJar.

    :param cj: CookieJar object to extract cookies from.
    :rtype: dict
    """
    cookie_dict = {}
    for cookie in cj:
        cookie_dict[cookie.name] = cookie.value
    return cookie_dict


def can_access_board_backend(request):
    """Whether the given user can access the given board backend."""
    user, board = request.user, request.board
    if board.owner == user:
        return True
    elif user.is_superuser:
        return True
    return False


def lambd_NH3_S_CB89(T, P):
    """n-a: ammonia sulfide [CB89]."""
    lambd = 0.174
    valid = T == 298.15
    return lambd, valid


@classmethod
def count(cls):
    """Returns the number of items in the enumeration."""
    return len(cls.__members__)


def _checkBitsPerPixel(value):
    """
    Raise a ValueError if the bitsPerPixel value isn't 4 or 8.
    """
    if value not in [4, 8]:
        raise ValueError(
            f'bitsPerPixel is only allowed to be 4 or 8, not {value}!')


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

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

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


def coverage_shortest(seq_query, seq_target, seq_len):
    """
    Return coverage of the shortest sequence in the alignment.

    >>> coverage_shortest("AAAA----", "AAAAAAAA", 8)
    50.0
    """
    res_query = len(seq_query.replace('-', ''))
    res_target = len(seq_target.replace('-', ''))
    return 100.0 * min(res_query, res_target) / seq_len


def java_step_properties(jar, main_class, arguments=None):
    """
    Create java step properties

    :param jar: the path of .jar file
    :type jar: string

    :param main_class: the package path for main class
    :type main_class: string

    :param arguments: arguments for the step
    :type arguments: string

    :return:
    :rtype map
    """
    java_step = {'jar': jar, 'mainClass': main_class}
    if arguments is not None:
        java_step['arguments'] = arguments
    return java_step


@classmethod
def get_time(cls, time):
    """returns time in miliseconds
           from '0:00:00.00' """
    sl = cls.time_pattern.search(time)
    return 10 * (int(sl.group(4)) + 100 * (int(sl.group(3)) + 60 * (int(sl.
        group(2)) + 60 * int(sl.group(1)))))


def pollute(names, objects):
    """Pollute the global namespace with symbols -> objects mapping."""
    from inspect import currentframe
    frame = currentframe().f_back.f_back
    try:
        for name, obj in zip(names, objects):
            frame.f_globals[name] = obj
    finally:
        del frame
    return objects


@classmethod
def _get_apic_classes(cls):
    """
        Get the APIC classes used by this acitoolkit class.

        :returns: list of strings containing APIC class names
        """
    return ['fvIp', 'fvStIp']


def roles():
    """ Returns a list of role names
        """


def _update_function(oldfunc, newfunc):
    """Update a function object."""
    oldfunc.__doc__ = newfunc.__doc__
    oldfunc.__dict__.update(newfunc.__dict__)
    oldfunc.__code__ = newfunc.__code__
    oldfunc.__defaults__ = newfunc.__defaults__
    return oldfunc


@classmethod
def _get_file(cls, fp, close=None):
    """
            Returns a three-tuple:
            if fp is a filename:
            filename, filename, close
            or if fp is file-like object:
            filename, file, close
            where filename can be None
            Opening of the file is left to the actual parser class if a filename
            was passed. If a file is passed, care must be taken to ensure it is
            opened in the correct mode (the __file_mode__ attribute on the
            actual parsers class called). Therefore, it is safer to pass
            filenames to a BaseGroupParser sub-class than it is to pass a
            file-like object.
        """
    if isinstance(fp, str):
        return fp, fp, True if close is None else close
    else:
        return getattr(fp, 'name', None), fp, False if close is None else close


@classmethod
def get(cls):
    """
        Get an instance of this Config class with all the configuration loaded
        from default locations. The locations are determined by
        Meta.filename_list attribute.

        :returns: fresh :class:`Config` instance

        """
    self = cls()
    self.read(cls.Meta.filename_list)
    return self


def dupli_extrude_cursor(rotate_source: bool=True):
    """Duplicate and extrude selected vertices, edges or faces towards the mouse cursor

    :param rotate_source: Rotate Source, Rotate initial selection giving better shape
    :type rotate_source: bool
    """
    pass


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

        :param FilePreviewDetails val:
        :rtype: EventDetails
        """
    return cls('file_preview_details', val)


def frame_results_to_events(frame_results, frame_times=None):
    """
    Converting frame-by-frame results into a list of events for each label. If the classifier predicts the same label in a sequence it is considers as an event. (Filtering too short events, or merge close-by events is not included here.)

    Arguments:
        frame_results (list or numpy array): list of frame class labels in an temporal order (sequential). It can contain numeric or string values e.g. ``[1, 1, 0, ...]`` or ``['class_1', 'class_1', 'class_0', ...]``
        frame_times (list or numpy array): list of timestamps (preferably as numeric values e.g. posix time) for each frame.

    Returns:
        dictionary: list of events (tuple of start and end times/indexes) for each unique label found in the frame_results. Event start value is the first occurence of the label, event end is the time or index of the next frame after the event (also the start of the next event).
    """
    if len(frame_results) < 2:
        raise ValueError('frame_results has to contain at least 2 items.')
    if frame_times is not None and len(frame_results) != len(frame_times):
        raise ValueError(
            'Length of frame_results and frame_times has to be equal.')
    unique_labels = set(frame_results)
    results = {}
    for l in unique_labels:
        results[str(l)] = []
    event_label = frame_results[0]
    event_start_index = 0
    for index in range(1, len(frame_results)):
        if frame_results[index] != event_label:
            if frame_times is None:
                results[str(event_label)].append((event_start_index, index))
            else:
                results[str(event_label)].append((frame_times[
                    event_start_index], frame_times[index]))
            event_label = frame_results[index]
            event_start_index = index
    if frame_times is None:
        results[str(event_label)].append((event_start_index, index + 1))
    else:
        results[str(event_label)].append((frame_times[event_start_index],
            frame_times[-1] + float(frame_times[-1] - frame_times[0]) / (
            len(frame_times) - 1)))
    return results


def check_deregister_present(module):
    """Check for deregister method in module.

    :param module:
    :return: True if present.
    """
    if hasattr(module, 'deregister'):
        return True


def freq(T):
    """
Convert array of periods in days to frequencies in Hz.
    """
    return 1.0 / T / 86400.0


def post_install(context):
    """Post install script"""


def true_vs_pred(y_true, y_pred, train_test_ID, scale='linear', color=
    'dodgerblue', rect=(0, 0, 1, 1)):
    """
    plot y_true vs. y_pred as a scatter plot

    Arguments:
    ----------
        y_true, y_pred: true & pred values
        train_test_ID: string. label to be appended to axis labels 'y_true' & 'y_pred'
        scale: 'linear' or 'log' scale to be used in the plot
        color: color to be used for the data points in the plot
        rect = tight_layout(rect=...) coordinates for plot size
    """
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(1, 1)
    ax.plot(y_true, y_pred, 'o', color=color)
    ax.set_xlabel('y_true ' + train_test_ID)
    ax.set_ylabel('y_pred ' + train_test_ID)
    ax.set_xscale(scale)
    ax.set_yscale(scale)
    fig.tight_layout(rect=rect)
    plt.show()


def get(isdsAppliance, uuid, check_mode=False, force=False):
    """
    Retrieving a single interface
    """
    return isdsAppliance.invoke_get('Retrieving a single interface',
        '/application_interfaces/' + uuid + '/addresses/1')


def describe_voices(LanguageCode=None, NextToken=None):
    """
    Returns the list of voices that are available for use when requesting speech synthesis. Each voice speaks a specified language, is either male or female, and is identified by an ID, which is the ASCII version of the voice name.
    When synthesizing speech ( SynthesizeSpeech ), you provide the voice ID for the voice you want from the list of voices returned by DescribeVoices .
    For example, you want your news reader application to read news in a specific language, but giving a user the option to choose the voice. Using the DescribeVoices operation you can provide the user with a list of available voices to select from.
    You can optionally specify a language code to filter the available voices. For example, if you specify en-US , the operation returns a list of all available US English voices.
    This operation requires permissions to perform the polly:DescribeVoices action.
    See also: AWS API Documentation

    Examples
    Returns the list of voices that are available for use when requesting speech synthesis. Displayed languages are those within the specified language code. If no language code is specified, voices for all available languages are displayed.
    Expected Output:

    :example: response = client.describe_voices(
        LanguageCode='cy-GB'|'da-DK'|'de-DE'|'en-AU'|'en-GB'|'en-GB-WLS'|'en-IN'|'en-US'|'es-ES'|'es-US'|'fr-CA'|'fr-FR'|'is-IS'|'it-IT'|'ja-JP'|'nb-NO'|'nl-NL'|'pl-PL'|'pt-BR'|'pt-PT'|'ro-RO'|'ru-RU'|'sv-SE'|'tr-TR',
        NextToken='string'
    )

    :type LanguageCode: string
    :param LanguageCode: The language identification tag (ISO 639 code for the language name-ISO 3166 country code) for filtering the list of voices returned. If you don't specify this optional parameter, all available voices are returned.

    :type NextToken: string
    :param NextToken: An opaque pagination token returned from the previous DescribeVoices operation. If present, this indicates where to continue the listing.

    :rtype: dict
    :return: {
        'Voices': [
            {
                'Gender': 'Female'|'Male',
                'Id': 'Geraint'|'Gwyneth'|'Mads'|'Naja'|'Hans'|'Marlene'|'Nicole'|'Russell'|'Amy'|'Brian'|'Emma'|'Raveena'|'Ivy'|'Joanna'|'Joey'|'Justin'|'Kendra'|'Kimberly'|'Salli'|'Conchita'|'Enrique'|'Miguel'|'Penelope'|'Chantal'|'Celine'|'Mathieu'|'Dora'|'Karl'|'Carla'|'Giorgio'|'Mizuki'|'Liv'|'Lotte'|'Ruben'|'Ewa'|'Jacek'|'Jan'|'Maja'|'Ricardo'|'Vitoria'|'Cristiano'|'Ines'|'Carmen'|'Maxim'|'Tatyana'|'Astrid'|'Filiz'|'Vicki',
                'LanguageCode': 'cy-GB'|'da-DK'|'de-DE'|'en-AU'|'en-GB'|'en-GB-WLS'|'en-IN'|'en-US'|'es-ES'|'es-US'|'fr-CA'|'fr-FR'|'is-IS'|'it-IT'|'ja-JP'|'nb-NO'|'nl-NL'|'pl-PL'|'pt-BR'|'pt-PT'|'ro-RO'|'ru-RU'|'sv-SE'|'tr-TR',
                'LanguageName': 'string',
                'Name': 'string'
            },
        ],
        'NextToken': 'string'
    }

    """
    pass


@classmethod
def load(cls, fileName: str):
    """
        This is a convenience method to generate a ModelDescription object
        from a standard Imfit configuration file.

        Parameters
        ----------
        fileName : string
            Path to the Imfit configuration file.

        Returns
        -------
        model : :class:`ModelDescription`
            The model description.

        See also
        --------
        parse_config_file
        """
    from .config import parse_config_file
    return parse_config_file(fileName)


def boxlist(s):
    """Boxes, row, and columns to scan."""
    boxlist = []
    for b in range(9):
        begin = [0, 3, 6, 27, 30, 33, 54, 57, 60][b]
        bo = []
        for i in (0, 1, 2, 9, 10, 11, 18, 19, 20):
            if s[begin + i] == 0:
                bo.append(begin + i)
        boxlist.append(bo)
    for i in range(9):
        line = []
        for j in range(9):
            if s[i * 9 + j] == 0:
                line.append(i * 9 + j)
        boxlist.append(line)
    for j in range(9):
        line = []
        for i in range(9):
            if s[i * 9 + j] == 0:
                line.append(i * 9 + j)
        boxlist.append(line)
    return boxlist


def read_sequences_from_fasta_string(fasta_string):
    """reads the sequences contained in a FASTA string"""
    lines = fasta_string.split('\n')
    sequences = []
    seqbuffer = ''
    seqname = None
    for line in lines:
        line = line.strip()
        if line.startswith('>'):
            if len(seqbuffer) > 0:
                sequences.append((seqname, seqbuffer))
                seqbuffer = ''
            seqname = line[1:]
        elif line and len(line) > 0:
            seqbuffer += line
    if len(seqbuffer) > 0:
        sequences.append((seqname, seqbuffer))
    return sequences


def isnumber(obj):
    """
    Test if the argument is a number (complex, float or integer).

    :param obj: Object
    :type  obj: any

    :rtype: boolean
    """
    return obj is not None and not isinstance(obj, bool) and isinstance(obj,
        (int, float, complex))


def fixra(ra0):
    """
    fixra: module to fix the notation of the ra string
    ra0: input ra notation from a skycoords query
    returns: the fixed notation for the ra
    """
    R = ''
    s = 0
    for i in ra0:
        if i == ':':
            if s == 0:
                R += 'h'
                s += 1
            else:
                R += 'm'
        else:
            R += i
    return R


def is_text():
    """Return True if the file content is text based.
        """


def yield_from_bed(bedfile):
    """Yield chrom, start, stop tuples from a bed file.

    :param bedfile: str, filepath.
    :yields: (str chrom, int start, int stop).

    """
    with open(bedfile) as fh:
        for line in fh:
            split_line = line.split()
            if split_line[0] in {'browser', 'track'} or len(split_line) < 3:
                continue
            chrom = split_line[0]
            start = int(split_line[1])
            stop = int(split_line[2])
            yield chrom, start, stop


def macroDefinitionString(cmdLineArgS):
    """Given a list of command line arguments of the form n<=d> where n is the
    macro name and d the optional definition this returns a same ordered multi-line
    string where each line is of the form '#define n d' or '#define n' if d is
    not present."""
    retMacros = []
    for d in cmdLineArgS:
        _tup = d.split('=')
        if len(_tup) == 2:
            retMacros.append('#define %s %s' % (_tup[0], _tup[1]))
        elif len(_tup) == 1:
            retMacros.append('#define %s' % _tup[0])
        else:
            raise ValueError(
                'macroDefinitionString(): Macro definition: "%s" has multiple "=" characters.'
                 % d)
    retMacros.append('')
    return '\n'.join(retMacros)


def __iter__():
    """Iterate the keys"""


@staticmethod
def in_out_cubic(progress):
    """.. image:: images/anim_in_out_cubic.png
        """
    p = progress * 2
    if p < 1:
        return 0.5 * p * p * p
    p -= 2
    return 0.5 * (p * p * p + 2.0)


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

        :param MemberSpaceLimitsAddCustomQuotaType val:
        :rtype: EventType
        """
    return cls('member_space_limits_add_custom_quota', val)


def reboot_cache_cluster(CacheClusterId=None, CacheNodeIdsToReboot=None):
    """
    Reboots some, or all, of the cache nodes within a provisioned cache cluster. This operation applies any modified cache parameter groups to the cache cluster. The reboot operation takes place as soon as possible, and results in a momentary outage to the cache cluster. During the reboot, the cache cluster status is set to REBOOTING.
    The reboot causes the contents of the cache (for each cache node being rebooted) to be lost.
    When the reboot is complete, a cache cluster event is created.
    See also: AWS API Documentation

    :example: response = client.reboot_cache_cluster(
        CacheClusterId='string',
        CacheNodeIdsToReboot=[
            'string',
        ]
    )

    :type CacheClusterId: string
    :param CacheClusterId: [REQUIRED]
            The cache cluster identifier. This parameter is stored as a lowercase string.

    :type CacheNodeIdsToReboot: list
    :param CacheNodeIdsToReboot: [REQUIRED]
            A list of cache node IDs to reboot. A node ID is a numeric identifier (0001, 0002, etc.). To reboot an entire cache cluster, specify all of the cache node IDs.
            (string) --

    :rtype: dict
    :return: {
        'CacheCluster': {
            'CacheClusterId': 'string',
            'ConfigurationEndpoint': {
                'Address': 'string',
                'Port': 123
            },
            'ClientDownloadLandingPage': 'string',
            'CacheNodeType': 'string',
            'Engine': 'string',
            'EngineVersion': 'string',
            'CacheClusterStatus': 'string',
            'NumCacheNodes': 123,
            'PreferredAvailabilityZone': 'string',
            'CacheClusterCreateTime': datetime(2015, 1, 1),
            'PreferredMaintenanceWindow': 'string',
            'PendingModifiedValues': {
                'NumCacheNodes': 123,
                'CacheNodeIdsToRemove': [
                    'string',
                ],
                'EngineVersion': 'string',
                'CacheNodeType': 'string'
            },
            'NotificationConfiguration': {
                'TopicArn': 'string',
                'TopicStatus': 'string'
            },
            'CacheSecurityGroups': [
                {
                    'CacheSecurityGroupName': 'string',
                    'Status': 'string'
                },
            ],
            'CacheParameterGroup': {
                'CacheParameterGroupName': 'string',
                'ParameterApplyStatus': 'string',
                'CacheNodeIdsToReboot': [
                    'string',
                ]
            },
            'CacheSubnetGroupName': 'string',
            'CacheNodes': [
                {
                    'CacheNodeId': 'string',
                    'CacheNodeStatus': 'string',
                    'CacheNodeCreateTime': datetime(2015, 1, 1),
                    'Endpoint': {
                        'Address': 'string',
                        'Port': 123
                    },
                    'ParameterGroupStatus': 'string',
                    'SourceCacheNodeId': 'string',
                    'CustomerAvailabilityZone': 'string'
                },
            ],
            'AutoMinorVersionUpgrade': True|False,
            'SecurityGroups': [
                {
                    'SecurityGroupId': 'string',
                    'Status': 'string'
                },
            ],
            'ReplicationGroupId': 'string',
            'SnapshotRetentionLimit': 123,
            'SnapshotWindow': 'string'
        }
    }

    :returns:
    General purpose:
    Current generation: cache.t2.micro , cache.t2.small , cache.t2.medium , cache.m3.medium , cache.m3.large , cache.m3.xlarge , cache.m3.2xlarge , cache.m4.large , cache.m4.xlarge , cache.m4.2xlarge , cache.m4.4xlarge , cache.m4.10xlarge
    Previous generation: cache.t1.micro , cache.m1.small , cache.m1.medium , cache.m1.large , cache.m1.xlarge

    Compute optimized: cache.c1.xlarge
    Memory optimized:
    Current generation: cache.r3.large , cache.r3.xlarge , cache.r3.2xlarge , cache.r3.4xlarge , cache.r3.8xlarge
    Previous generation: cache.m2.xlarge , cache.m2.2xlarge , cache.m2.4xlarge

    """
    pass


def _leading_space_count(line):
    """Return number of leading spaces in line."""
    i = 0
    while i < len(line) and line[i] == ' ':
        i += 1
    return i


@classmethod
def import_repo(cls, assignment, path, sid_pattern='(?P<id>.*)'):
    """Imports a submission from a git repository

        :param str assignment: Assignment associated with this submission

        :param str repo_url: URL to a clone-able git repository.

        :param str sid: The submission ID for the new submission. If
            None, the name of the repository (sans ``.git``) will be
            used.

        :param str sid_pattern: An optional pattern to use to convert
            the name of a submission to a submission id

        :return: the new submission
        :rtype: Submission

        """
    raise NotImplementedError("Git import isn't implemented yet :/")


def build_alloc_info(data):
    """
    Use the __cuda_array_interface__ to extract cpointer
    information for passing into cython.
    :param data:
    :return:
    """
    dev, gpu_matrix, _ = data
    return gpu_matrix.__cuda_array_interface__


def by_published(queryset, published_string='true'):
    """ Filter queryset by publish status """
    if published_string == 'true':
        queryset = queryset.filter(published=1)
    elif published_string == 'false':
        queryset = queryset.filter(published=0)
    return queryset


def _make_section_map(aut):
    """Return `dict` of `Automaton` attributes."""
    sections = dict(env_init=aut.init['env'], env_action=aut.action['env'],
        sys_init=aut.init['sys'], sys_action=aut.action['sys'])
    sections['<>[]'] = aut.win['<>[]']
    sections['[]<>'] = aut.win['[]<>']
    return sections


def assess_species(value):
    """ some table finish with 'Parameter Type'  'Species',
    Species can be either:

    - 0 for 'Energy shift'
    - blank (for global variables)
    - <i> <j> for species specific

    """
    if value.startswith('Energy shift'):
        return value[:12]
    return value


def update_periodic_dcoords(sheet):
    """ Updates the coordinates for periodic boundary conditions.

    """
    for u, boundary in sheet.settings['boundaries'].items():
        period = boundary[1] - boundary[0]
        shift = period * (-(sheet.vert_df[u] > boundary[1]).astype(float) +
            (sheet.vert_df[u] <= boundary[0]).astype(float))
        sheet.vert_df[u] = sheet.vert_df[u] + shift
    srce_pos = sheet.upcast_srce(sheet.vert_df[sheet.coords])
    trgt_pos = sheet.upcast_trgt(sheet.vert_df[sheet.coords])
    sheet.edge_df[[('s' + u) for u in sheet.coords]] = srce_pos
    sheet.edge_df[[('t' + u) for u in sheet.coords]] = trgt_pos
    sheet.edge_df[sheet.dcoords] = trgt_pos - srce_pos
    for u, boundary in sheet.settings['boundaries'].items():
        period = boundary[1] - boundary[0]
        center = boundary[1] - period / 2
        shift = period * (-(sheet.edge_df['d' + u] >= period / 2).astype(
            float) + (sheet.edge_df['d' + u] < -period / 2).astype(float))
        sheet.edge_df['d' + u] = sheet.edge_df['d' + u] + shift
        sheet.edge_df[f'at_{u}_boundary'] = shift != 0
        sheet.face_df[f'at_{u}_boundary'] = sheet.edge_df.groupby('face')[
            f'at_{u}_boundary'].apply(any)
        f_at_boundary = sheet.upcast_face(sheet.face_df[f'at_{u}_boundary']
            ).astype(int)
        period = boundary[1] - boundary[0]
        srce_shift = f_at_boundary * (sheet.edge_df['s' + u] < center) * period
        trgt_shift = f_at_boundary * (sheet.edge_df['t' + u] < center) * period
        sheet.edge_df['s' + u] += srce_shift
        sheet.edge_df['t' + u] += trgt_shift


@staticmethod
def get_tags(instance):
    """
        Return a dictionary of tags
        """
    if 'tags' in instance:
        return dict.fromkeys(instance['tags'])
    return {}


def p_parameter_list_empty(p):
    """parameter_list : empty"""
    p[0] = []


def is_valid_trajectory(ext):
    """ Checks if trajectory format is compatible with GROMACS """
    formats = ['xtc', 'trr', 'cpt', 'gro', 'g96', 'pdb', 'tng']
    return ext in formats


def extract_data(image, i, lut):
    """
    Extract and return image data for given measurement point.
    """
    crop = image.crop(lut.cell_center(i, 6))
    data = list(crop.getdata())
    return data


def ignore_global_phase(statevec):
    """Multiple e^-iθ to `statevec` where θ is a phase of first non-zero element.

    Args:
        statevec np.array: Statevector.

    Returns:
        np.array: `statevec` is returned.
    """
    for q in statevec:
        if abs(q) > 1e-07:
            ang = abs(q) / q
            statevec *= ang
            break
    return statevec


def strict_get(obj, path: str):
    """
    Strict get dot prop.
    If some level doesn't exist, it raises the apropriate exception.
    """
    value = obj
    for key in path.split('.'):
        if isinstance(value, list):
            value = value[int(key)]
        elif isinstance(value, dict):
            value = value[key]
        else:
            value = getattr(value, key)
    return value