def get_dimensions_encoding(n_bins, batchsize):
    """
    Returns a dimensions tuple for 2,3 and 4 dimensional data.
    :param int batchsize: Batchsize that is used in hdf5_batch_generator().
    :param tuple n_bins: Declares the number of bins for each dimension (x,y,z).
                        If a dimension is equal to 1, it means that the dimension should be left out.
    :return: tuple dimensions: 2D, 3D or 4D dimensions tuple (integers).
    """
    n_bins_x, n_bins_y, n_bins_z, n_bins_t = n_bins[0], n_bins[1], n_bins[2
        ], n_bins[3]
    if n_bins_x == 1:
        if n_bins_y == 1:
            print('Using 2D projected data without dimensions x and y')
            dimensions = batchsize, n_bins_z, n_bins_t, 1
        elif n_bins_z == 1:
            print('Using 2D projected data without dimensions x and z')
            dimensions = batchsize, n_bins_y, n_bins_t, 1
        elif n_bins_t == 1:
            print('Using 2D projected data without dimensions x and t')
            dimensions = batchsize, n_bins_y, n_bins_z, 1
        else:
            print('Using 3D projected data without dimension x')
            dimensions = batchsize, n_bins_y, n_bins_z, n_bins_t, 1
    elif n_bins_y == 1:
        if n_bins_z == 1:
            print('Using 2D projected data without dimensions y and z')
            dimensions = batchsize, n_bins_x, n_bins_t, 1
        elif n_bins_t == 1:
            print('Using 2D projected data without dimensions y and t')
            dimensions = batchsize, n_bins_x, n_bins_z, 1
        else:
            print('Using 3D projected data without dimension y')
            dimensions = batchsize, n_bins_x, n_bins_z, n_bins_t, 1
    elif n_bins_z == 1:
        if n_bins_t == 1:
            print('Using 2D projected data without dimensions z and t')
            dimensions = batchsize, n_bins_x, n_bins_y, 1
        else:
            print('Using 3D projected data without dimension z')
            dimensions = batchsize, n_bins_x, n_bins_y, n_bins_t, 1
    elif n_bins_t == 1:
        print('Using 3D projected data without dimension t')
        dimensions = batchsize, n_bins_x, n_bins_y, n_bins_z, 1
    else:
        dimensions = batchsize, n_bins_x, n_bins_y, n_bins_z, n_bins_t
    return dimensions


def find_match_characters(string, pattern):
    """Find match match pattern string.
    Args:
        params: string
                pattern
    Returns:
    Raises:
    """
    matched = []
    last_index = 0
    if not string or not pattern:
        return matched
    if string[0] != pattern[0]:
        return matched
    for c in pattern:
        index = string.find(c, last_index)
        if index < 0:
            return []
        matched.append((c, index))
        last_index = index + 1
    return matched


def rangize_supp(spans, lngth):
    """
        spans = [(0, 3), (4, 7), (8, 10), (11, 12), (13, 16), (17, 20)]
        rangize_supplement(spans,24)

    """
    rslt = []
    si = 0
    ei = spans[0][0]
    if si == ei:
        pass
    else:
        rslt.append((si, ei))
    prev_ei = spans[0][1]
    for i in range(1, spans.__len__()):
        si = prev_ei
        ei = spans[i][0]
        rslt.append((si, ei))
        prev_ei = spans[i][1]
    if prev_ei < lngth:
        rslt.append((prev_ei, lngth))
    else:
        pass
    return rslt


def decode_params(encoded_data: str) ->str:
    """ Decode Parameter data from Spreader Interop """
    return encoded_data.replace('|', '|').replace('
', '\r\n')


def get_schema_as_json(SchemaArn=None):
    """
    Retrieves a JSON representation of the schema. See JSON Schema Format for more information.
    See also: AWS API Documentation

    :example: response = client.get_schema_as_json(
        SchemaArn='string'
    )

    :type SchemaArn: string
    :param SchemaArn: [REQUIRED]
            The ARN of the schema to retrieve.

    :rtype: dict
    :return: {
        'Name': 'string',
        'Document': 'string'
    }

    """
    pass


def getBlogRoot(context):
    """Returns the blog root of the current context. If the context is
        not within a blog, `None` is returned.
        """


def classes():
    """ Returns a list of CSS classes to be set on the row
        """


def explode(df, column, sep='|', keep=False):
    """
    Split the values of a column and expand so the new DataFrame has one split
    value per row. Filters rows where the column is missing.

    Params
    ------
    df : pandas.DataFrame
        dataframe with the column to split and expand
    column : str
        the column to split and expand
    sep : str
        the string used to split the column's values
    keep : bool
        whether to retain the presplit value as it's own row

    Returns
    -------
    pandas.DataFrame
        Returns a dataframe with the same columns as `df`.
    """
    indexes = list()
    new_values = list()
    df = df.dropna(subset=[column])
    for i, presplit in enumerate(df[column].astype(str)):
        values = presplit.split(sep)
        if keep and len(values) > 1:
            indexes.append(i)
            new_values.append(presplit)
        for value in values:
            indexes.append(i)
            new_values.append(value)
    new_df = df.iloc[(indexes), :].copy()
    new_df[column] = new_values
    return new_df


@staticmethod
def percentage(part, whole):
    """
        Calculate percentage
        """
    if whole == 0:
        return 0
    return 100 * float(part) / float(whole)


@classmethod
def setInstance(cls, inst):
    """Set/override the singleton instance. """
    setattr(cls, '_{}_singleton'.format(cls.__name__), inst)


def dopplerFunction(dim=1024, normalize=True, fq=0):
    """
    Generate the Doppler function in a range of 0 to 1, with dim points.

    Parameters
    ----------
    dim: int
        Dimension of the signal.

    normalize: bool, optional
        It is True by default. This parameter normalize the data values
        in a range of 0 to 1 with a function present in
        ``statsWaveletFilt.miscellaneous``.

    fq: int or float, optional
        It is 0 by default. With this default value the original doppler,
        shown by Donoho [1] will be used.

    Returns
    -------
    tuple:
        [0] 1-D array-like, coordinates in X axis and [1] 1-D array-like,
        coordinates in Y axis

    References
    ----------
    .. [1] DONOHO, D. L.; JOHNSTONE, I. M. Ideal spatial adaptation via
           wavelet shrinkage. Biometrika, v. 81, p. 425–455, 1994.
    """
    import numpy as np
    import statsWaveletFilt.miscellaneous as misc
    linspace = np.linspace
    sin = np.sin
    pi = np.pi
    sqrt = np.sqrt
    x = linspace(0, 1, dim)
    e = 0.05
    if fq == 0:
        y = sqrt(x * (1 - x)) * sin(2 * pi * (1 + e) / (x + e))
    else:
        y = sqrt(x * (1 - x)) * sin(2 * fq * pi * (1 + e) / (x + e))
    if normalize:
        y_nor = misc.normalizeData(y)
    else:
        y_nor = y
    return x, y_nor


@classmethod
def from_dict(cls, d):
    """
        Instances the object from a dictionary representation.

        :param d: Dictionary containing a serialised object.
        :return: An object instance.
        """
    if not cls.is_compatible(d):
        raise ValueError(
            'The dictionary does not contain a serialised string class.')
    c = cls(value=d['value'], description=d['description'])
    return c


def rotc(ebit, debt, equity):
    """Computes return on total capital.

    @params
    -------
    ebit: earnins before interest and taxes
    debt: short- and long-term debt
    equity: equity

    returns
    -------
    Return on total capital, int or float

    explanation
    -----------

    """
    return ebit / (debt - equity)


def rename_app_parameters(app, model):
    """Rename all parameters for a given app."""
    qset = model.objects.filter(name__startswith=app[0])
    for param in qset:
        param.name = param.name.replace('{}.'.format(app[0]), '{}.'.format(
            app[1]))
        param.save()


def _make_version(major, minor, micro, level, serial):
    """Generate version string from tuple (almost entirely from coveragepy)."""
    level_dict = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}
    if level not in level_dict:
        raise RuntimeError('Invalid release level')
    version = '{0:d}.{1:d}'.format(major, minor)
    if micro:
        version += '.{0:d}'.format(micro)
    if level != 'final':
        version += '{0}{1:d}'.format(level_dict[level], serial)
    return version


def dump(obj, path):
    """
    from baiji.pod.util import yaml
    obj = {'foo': 123}
    yaml.dump(obj, 'foo.yml')
    """
    import yaml
    with open(path, 'w') as f:
        yaml.dump(obj, f, default_flow_style=False)


def tls_params(mqtt_config):
    """Return the TLS configuration parameters from a :class:`.MQTTConfig`
    object.

    Args:
        mqtt_config (:class:`.MQTTConfig`): The MQTT connection settings.

    Returns:
        dict: A dict {'ca_certs': ca_certs, 'certfile': certfile,
        'keyfile': keyfile} with the TLS configuration parameters, or None if
        no TLS connection is used.

    .. versionadded:: 0.6.0
    """
    if mqtt_config.tls.hostname:
        return {'ca_certs': mqtt_config.tls.ca_file, 'certfile':
            mqtt_config.tls.client_cert, 'keyfile': mqtt_config.tls.client_key}
    else:
        return None


def _extra_fields(record, restkey):
    """
    Accepts a record from a csv.DictReader object and determines if any extra
    fields are present in the column named after the 'restkey' passed to the
    csv.DictReader constructor.

    Returns the list of extra fields or False if no extra fields are present.
    """
    extra_fields = False
    for key in record:
        if key == restkey:
            extra_fields = record[key]
    return extra_fields


def poly_fd(data):
    """
    Polynomial frequency domain baseline correction - Not Implemented
    """
    raise NotImplementedError


@staticmethod
def p_protocol_layer_optional_list_optional(p):
    """protocol_layer_optional_list_optional : empty
                                                 | protocol_layer_optional_list"""
    p[0] = tuple() if p[1] is None else p[1]


def get_grouped_by_powers(bases, powers):
    """
    Groups the powers and bases in the given
    `~astropy.units.CompositeUnit` into positive powers and
    negative powers for easy display on either side of a solidus.

    Parameters
    ----------
    bases : list of `astropy.units.UnitBase` instances

    powers : list of ints

    Returns
    -------
    positives, negatives : tuple of lists
       Each element in each list is tuple of the form (*base*,
       *power*).  The negatives have the sign of their power reversed
       (i.e. the powers are all positive).
    """
    positive = []
    negative = []
    for base, power in zip(bases, powers):
        if power < 0:
            negative.append((base, -power))
        elif power > 0:
            positive.append((base, power))
        else:
            raise ValueError('Unit with 0 power')
    return positive, negative


def set_normals_from_faces(keep_sharp: bool=False):
    """Set the custom normals from the selected faces ones

    :param keep_sharp: Keep Sharp Edges, Do not set sharp edges to face
    :type keep_sharp: bool
    """
    pass


def verticality_coefficient(pca):
    """Verticality score aiming at evaluating how vertical a 3D-point cloud is,
    by considering its decomposition through a PCA.

    See:
    - Martin Weinmann, Boris Jutzi, Stefan Hinz, Clément Mallet,
    2015. Semantic point cloud interpretation based on optimal neighborhoods,
    relevant features and efficient classifiers. ISPRS Journal of
    Photogrammetry and Remote Sensing, vol 105, pp 286-304.
    - Jerome Demantke, Bruno Vallet, Nicolas Paparotidis, 2012. Streamed
    Vertical Rectangle Detection in Terrestrial Laser Scans for Facade Database
    Productions. In ISPRS Annals of the Photogrammetry, Remote Sensing and
    Spatial Information Sciences, Volume 1-3, pp99-104.

    Parameters
    ----------
    pca : sklearn.decomposition.PCA
        Principle Component Analysis output; must have a `.components_`
    attribute that contains decomposition axes in 3D space

    Returns
    -------
    float
        Verticality coefficient, as defined in (Demantke et al, 2012) and
    (Weinmann et al, 2015)
    """
    decomposition_axes = pca.components_
    assert decomposition_axes.shape[1] == 3
    return 1 - abs(decomposition_axes[2, 2])


def load_ftplib(finder, module):
    """the ftplib module attempts to import the SOCKS module; ignore this
       module if it cannot be found"""
    module.IgnoreName('SOCKS')


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 get_func_definition(sourcelines):
    """Given a block of source lines for a method or function,
    get the lines for the function block.
    """
    count = 1
    for line in sourcelines:
        if line.rstrip().endswith(':'):
            break
        count += 1
    return sourcelines[:count], sourcelines[count:]


def grid_to_rect_coord(grid, die_size, grid_center):
    """
    Convert a die's grid value to the origin point of the rectangle to draw.

    Adjusts for the fact that the grid falls on the center of a die by
    subtracting die_size/2 from the coordinate.

    Adjusts for the fact that Grid +y is down while panel +y is up by
    taking ``grid_center - grid`` rather than ``grid - grid_center`` as is
    done in the X case.
    """
    _x = die_size[0] * (grid[0] - grid_center[0] - 0.5)
    _y = die_size[1] * (grid_center[1] - grid[1] - 0.5)
    return _x, _y


@classmethod
def get_locals(cls, session, **kwargs):
    """
        Get all local users.

        :param session: SQLAlchemy session
        :type session: :class:`sqlalchemy.Session`

        :return: local users
        :rtype: generator of :class:`pyshop.models.User`
        """
    return cls.find(session, where=(cls.local == True,), order_by=cls.login,
        **kwargs)


def fill_object_refs(conn, cursor, get_references):
    """Update the object_refs table by analyzing new transactions.
        """


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

        :param SecondaryEmailVerifiedDetails val:
        :rtype: EventDetails
        """
    return cls('secondary_email_verified_details', val)


@classmethod
def red(cls):
    """A factory method that returns a :class:`Colour` with a value of ``0xe74c3c``."""
    return cls(15158332)


def split_args(args):
    """Split command line args in 3 groups:
    - head, containing the initial options
    - body, containing everything after head, up to the first option
    - tail, containing everything after body
    """
    head = []
    body = []
    tail = []
    for arg in args:
        if arg.startswith('-'):
            if body:
                tail.append(arg)
            else:
                head.append(arg)
        elif tail:
            tail.append(arg)
        else:
            body.append(arg)
    return head, body, tail


def is_validated(user):
    """Is this user record validated?"""
    return user.get('validated', True)


@staticmethod
def _slicespec2boundsspec(slicespec, scs):
    """
        Convert an iterable slicespec (supplying r1,r2,c1,c2 of a
        Slice) into a BoundingRegion specification.

        Exact inverse of _boundsspec2slicespec().
        """
    r1, r2, c1, c2 = slicespec
    left, bottom = scs.matrix2sheet(r2, c1)
    right, top = scs.matrix2sheet(r1, c2)
    return (left, bottom), (right, top)


def have_loops(nodes):
    """
    Checks to see whether there are any Loops in the list of nodes and
    their sub-trees.

    :param nodes: list of PSyIR nodes to check for Loops.
    :type nodes: list of :py:class:`psyclone.psyGen.Node`
    :returns: True if a Loop is found, False otherwise.
    :rtype: bool

    """
    from psyclone.nemo import NemoLoop
    for node in nodes:
        if node.walk(NemoLoop):
            return True
    return False


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

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


def removeWriter(writer):
    """
        Removes an object previously added with L{addWriter}.

        @return: C{None}.
        """


def merge_bases_attribute(cls, attr_name, init, default, merge_func=lambda
    a, b: a + b):
    """
    Merge all values of attribute defined in all bases classes (using `__mro__`).
    Return resulting value. Use default every time a class does not have given attribute.

    Be careful, `merge_func` must be a pure function.
    """
    value = init
    for base in cls.__mro__:
        value = merge_func(value, getattr(base, attr_name, default))
    return value


def get_from_file(path):
    """Get the SHA from the deployment git_sha file."""
    try:
        with open(path, 'r') as f:
            return f.read().strip()
    except IOError:
        pass


def get_single_key_value_pair(d):
    """
    Returns the key and value of a one element dictionary, checking that it actually has only one element

    Parameters
    ----------
    d : dict

    Returns
    -------
    tuple

    """
    assert isinstance(d, dict), f'{d}'
    assert len(d) == 1, f'{d}'
    return list(d.keys())[0], list(d.values())[0]


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


def format_date(value, iso=False):
    """
    Try to get a suitable date out of the value.
    """
    if len(value) == 4 and value.isnumeric():
        if iso:
            return '{}-01-01T00:00:00Z'.format(value)
        else:
            return '{}-01-01'.format(value)
    raise ValueError('could not handle: %s', value)


def strip_from_end(text, suffix):
    """
    Strip a substring from the end of a string

    Parameters
    ----------
    text : str
        The string to be evaluated

    suffix : str
        The suffix or substring to remove from the end of the text string

    Returns
    -------
    str
        A string with the substring removed if it was found at the end of the
        string.
    """
    if not text.endswith(suffix):
        return text
    return text[:len(text) - len(suffix)]


def read_file(filename, mode='r', readlines=True):
    """write_file will open a file, "filename" and write content, "content"
       and properly close the file
    """
    with open(filename, mode) as filey:
        if readlines is True:
            content = filey.readlines()
        else:
            content = filey.read()
    return content


def PIG2Stream(fname, beam=0, time_unit=0.5, fixtempo=0):
    """
    Convert a PIG text file to a music21 Stream object.

    time_unit must be multiple of 2.
    beam = 0, right hand
    beam = 1, left hand.
    """
    from music21 import stream, note, chord
    from music21.articulations import Fingering
    import numpy as np
    f = open(fname, 'r')
    lines = f.readlines()
    f.close()
    durations = []
    firstonset = 0
    blines = []
    for l in lines:
        if l.startswith('//'):
            continue
        _, onset, offset, name, _, _, channel, _ = l.split()
        onset, offset = float(onset), float(offset)
        if beam != int(channel):
            continue
        if not firstonset:
            firstonset = onset
        if offset - onset < 0.0001:
            continue
        durations.append(offset - onset)
        blines.append(l)
    durations = np.array(durations)
    logdurs = -np.log2(durations)
    mindur = np.min(logdurs)
    expos = (logdurs - mindur).astype(int)
    if np.max(expos) > 3:
        mindur = mindur + 1
    sf = stream.Part()
    sf.id = beam
    if not fixtempo and firstonset:
        r = note.Rest()
        logdur = -np.log2(firstonset)
        r.duration.quarterLength = 1.0 / time_unit / pow(2, int(logdur -
            mindur))
        sf.append(r)
    n = len(blines)
    for i in range(n):
        if blines[i].startswith('//'):
            continue
        _, onset, offset, name, _, _, _, finger = blines[i].split()
        onset, offset = float(onset), float(offset)
        name = name.replace('b', '-')
        chordnotes = [name]
        for j in range(1, 5):
            if i + j < n:
                noteid1, onset1, offset1, name1, _, _, _, finger1 = blines[
                    i + j].split()
                onset1 = float(onset1)
                if onset1 == onset:
                    name1 = name1.replace('b', '-')
                    chordnotes.append(name1)
        if len(chordnotes) > 1:
            an = chord.Chord(chordnotes)
        else:
            an = note.Note(name)
            if '_' not in finger:
                x = Fingering(abs(int(finger)))
                x.style.absoluteY = 20
            an.articulations.append(x)
        if fixtempo:
            an.duration.quarterLength = fixtempo
        else:
            logdur = -np.log2(offset - onset)
            an.duration.quarterLength = 1.0 / time_unit / pow(2, int(logdur -
                mindur))
        sf.append(an)
        if i + 1 < n:
            _, onset1, _, _, _, _, _, _ = blines[i + 1].split()
            onset1 = float(onset1)
            if onset1 - offset > 0:
                r = note.Rest()
                if fixtempo:
                    r.duration.quarterLength = fixtempo
                logdur = -np.log2(onset1 - offset)
                d = int(logdur - mindur)
                if d < 4:
                    r.duration.quarterLength = 1.0 / time_unit / pow(2, d)
                    sf.append(r)
    return sf


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 untransform_record_data(data):
    """Return untransformed data
        """


def duplicate_move(ACTION_OT_duplicate=None, TRANSFORM_OT_transform=None):
    """Make a copy of all selected keyframes and move them

    :param ACTION_OT_duplicate: Duplicate Keyframes, Make a copy of all selected keyframes
    :param TRANSFORM_OT_transform: Transform, Transform selected items by mode type
    """
    pass


def filter_adjlist(adjlist, focal_col='focal', neighbor_col='neighbor'):
    """
    This dedupes an adjacency list by examining both (a,b) and (b,a) when (a,b) is enountered.
    The removal is done in order of the iteration order of the input adjacency list. So, if a
    special order of removal is desired, you need to sort the list before this function.

    Parameters
    ----------
    adjlist     :   pandas DataFrame
                    a dataframe that contains focal and neighbor columns
    focal_col   :   string
                    the name of the column with the focal observation id
    neighbor_col:   string
                    the name of the column with the neighbor observation id

    Returns
    -------
    an adjacency table with reversible entries removed.
    """
    directed = set(map(tuple, adjlist[[focal_col, neighbor_col]].values))
    undirected = set()
    for tupe in directed:
        if tupe in undirected:
            to_drop_mask = (adjlist[focal_col] == tupe[0]) & (adjlist[
                neighbor_col] == tupe[-1])
            to_drop = adjlist[to_drop_mask]
        elif tuple(reversed(tupe)) in undirected:
            to_drop_mask = (adjlist[focal_col] == tupe[-1]) & (adjlist[
                neighbor_col] == tupe[0])
            to_drop = adjlist[to_drop_mask]
        else:
            undirected.update((tupe,))
            undirected.update(tuple(reversed(tupe)))
            continue
        adjlist = adjlist.drop(to_drop.index)
    return adjlist


def count_of_data_points_for_each_id(df):
    """Returns dict with IDs as keys and total number (int) of observations of data as values, based on the DataFrame (df) passed as an argument.

    Args:
        df (pandas DataFrame): DataFrame as created by **history** module.

    Returns:
        counts_by_id (dict): Dict of key-value pairs, in which IDs are keys.
     """
    return df.groupby(level=0).count().to_dict()


@staticmethod
def _set_boolean(target, data, bitarray):
    """ set given value to target bit in bitarray """
    bitarray[int(target['offset'])] = data
    return bitarray


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

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


def properties():
    """Toggle the properties region visibility

    """
    pass


def _big_huge_pos_tag_for_wordnet_pos_tag(pos_tag):
    """Convert the given WordNet style PoS Tag into a Big Huge Thesaurus Style PoS Tag

		Keyword arguments:

		- `pos_tag` -- The WordNet style PoS Tag (**mandatory**, *no default*)
	"""
    tag = 'noun'
    if pos_tag == 'v':
        tag = 'verb'
    elif pos_tag == 'a' or pos_tag == 'r' or pos_tag == 's':
        tag = 'adjective'
    return tag


def event_message(iden, event):
    """Return an event message."""
    return {'id': iden, 'type': 'event', 'event': event}


def prepare_df(df):
    """
    This function converts the df header into string format
    for the gui to be able to plot

    Args:
        df --> pandas dataframe: df needs to be cleaned
    Return:
        df --> pandas dataframe: cleaned df
    """
    columns = list(df.columns.values)
    for num, item in enumerate(columns):
        if not isinstance(item, str):
            columns[num] = '{}'.format(item)
    df.columns = columns
    return df


def ebc_to_srm(ebc):
    """
    Convert the EBC value to SRM
    https://en.wikipedia.org/wiki/Standard_Reference_Method
    """
    return ebc * 0.508


@staticmethod
def turn_to_time(time):
    """ Takes miliseconds
        and returns "hours:minutes:seconds,miliseconds"
        with padding (:03 means pad with 0s if it's less than 3 digits)"""
    b = time // 1000 // 60
    return f'{b // 60:02}:{b % 60:02}:{time // 1000 % 60:02},{time % 1000:03}'


def mean(l):
    """mean(...) --> float

	Return the Mean (Average) of a list of numbers"""
    return sum(l) / len(l)


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

        :param PaperChangeMemberLinkPolicyDetails val:
        :rtype: EventDetails
        """
    return cls('paper_change_member_link_policy_details', val)


def decimal_str_to_int(decimal_string):
    """
    Helper to decimal currency string into integers (cents).
    WARNING: DO NOT TRY TO DO THIS BY CONVERSION AND MULTIPLICATION,
    FLOATING POINT ERRORS ARE NO FUN IN FINANCIAL SYSTEMS.
    @param string The amount in currency with full stop decimal separator
    @return integer The amount in cents
    """
    int_string = decimal_string.replace('.', '')
    int_string = int_string.lstrip('0')
    return int(int_string)


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


def edges(ax, **kw):
    """
    Plot regular edges and rays (edges whose one endpoint is at infinity)
    """
    verts = kw['vertices']
    edges = kw['edges']
    for beg, end in edges:
        x0, y0 = verts[(beg), :]
        x1, y1 = verts[(end), :]
        ax.fill([x0, x1], [y0, y1], facecolor='none', edgecolor='k',
            linewidth=0.5)
    if 'ray_origins' not in kw or 'ray_directions' not in kw:
        return
    lim = ax.axis()
    ray_origin = kw['ray_origins']
    ray_direct = kw['ray_directions']
    for beg, (vx, vy) in zip(ray_origin.flatten(), ray_direct):
        x0, y0 = verts[(beg), :]
        scale = 100.0
        x1, y1 = x0 + scale * vx, y0 + scale * vy
        ax.fill([x0, x1], [y0, y1], facecolor='none', edgecolor='k',
            linewidth=0.5)
    ax.axis(lim)


@staticmethod
def _get_response_message(response):
    """Returns the message enclosed in the provided server response.

        Args:
            response (requests.Response): The server response.

        Returns:
            A string containing the server response message.
        """
    return response.json().get('message')


def save_settings(config, ui):
    """Save current UI configuration to the OS repository, called when exiting the main application"""
    config.setValue('fan1_percent', ui.horizontalSliderFan1.value())
    config.setValue('fan2_percent', ui.horizontalSliderFan2.value())
    config.setValue('fan3_percent', ui.horizontalSliderFan3.value())
    config.setValue('fan4_percent', ui.horizontalSliderFan4.value())
    config.setValue('fan5_percent', ui.horizontalSliderFan5.value())
    config.setValue('fan6_percent', ui.horizontalSliderFan6.value())
    config.setValue('port', ui.comboBoxComPorts.currentText())
    config.setValue('polling', ui.comboBoxPolling.currentText())
    config.setValue('automatic_control', ui.radioButtonAutomatic.isChecked())
    config.setValue('manual_control', ui.radioButtonManual.isChecked())
    root = ui.treeWidgetSelectedCPUSensors.invisibleRootItem()
    child_count = root.childCount()
    cpu_sensor_ids = []
    for i in range(child_count):
        item = root.child(i)
        cpu_sensor_ids.append(item.text(1))
    config.setValue('cpu_sensor_ids', cpu_sensor_ids)
    root = ui.treeWidgetSelectedGPUSensors.invisibleRootItem()
    child_count = root.childCount()
    gpu_sensor_ids = []
    for i in range(child_count):
        item = root.child(i)
        gpu_sensor_ids.append(item.text(1))
    config.setValue('gpu_sensor_ids', gpu_sensor_ids)
    config.setValue('cpu_use_max', ui.radioButtonCPUMax.isChecked())
    config.setValue('cpu_use_avg', ui.radioButtonCPUAverage.isChecked())
    config.setValue('gpu_use_max', ui.radioButtonGPUMax.isChecked())
    config.setValue('gpu_use_avg', ui.radioButtonGPUAverage.isChecked())
    config.setValue('cpu_fan_1', ui.radioButtonCPUFan1.isChecked())
    config.setValue('cpu_fan_2', ui.radioButtonCPUFan2.isChecked())
    config.setValue('cpu_fan_3', ui.radioButtonCPUFan3.isChecked())
    config.setValue('cpu_fan_4', ui.radioButtonCPUFan4.isChecked())
    config.setValue('cpu_fan_5', ui.radioButtonCPUFan5.isChecked())
    config.setValue('cpu_fan_6', ui.radioButtonCPUFan6.isChecked())
    config.setValue('gpu_fan_1', ui.radioButtonGPUFan1.isChecked())
    config.setValue('gpu_fan_2', ui.radioButtonGPUFan2.isChecked())
    config.setValue('gpu_fan_3', ui.radioButtonGPUFan3.isChecked())
    config.setValue('gpu_fan_4', ui.radioButtonGPUFan4.isChecked())
    config.setValue('gpu_fan_5', ui.radioButtonGPUFan5.isChecked())
    config.setValue('gpu_fan_6', ui.radioButtonGPUFan6.isChecked())
    config.setValue('min_speed_fan_1', ui.spinBoxMinSpeedFan1.value())
    config.setValue('min_speed_fan_2', ui.spinBoxMinSpeedFan2.value())
    config.setValue('min_speed_fan_3', ui.spinBoxMinSpeedFan3.value())
    config.setValue('min_speed_fan_4', ui.spinBoxMinSpeedFan4.value())
    config.setValue('min_speed_fan_5', ui.spinBoxMinSpeedFan5.value())
    config.setValue('min_speed_fan_6', ui.spinBoxMinSpeedFan6.value())
    config.setValue('start_increase_speed_fan_1', ui.
        spinBoxStartIncreaseSpeedFan1.value())
    config.setValue('start_increase_speed_fan_2', ui.
        spinBoxStartIncreaseSpeedFan2.value())
    config.setValue('start_increase_speed_fan_3', ui.
        spinBoxStartIncreaseSpeedFan3.value())
    config.setValue('start_increase_speed_fan_4', ui.
        spinBoxStartIncreaseSpeedFan4.value())
    config.setValue('start_increase_speed_fan_5', ui.
        spinBoxStartIncreaseSpeedFan5.value())
    config.setValue('start_increase_speed_fan_6', ui.
        spinBoxStartIncreaseSpeedFan6.value())
    config.setValue('intermediate_speed_fan_1', ui.
        spinBoxIntermediateSpeedFan1.value())
    config.setValue('intermediate_speed_fan_2', ui.
        spinBoxIntermediateSpeedFan2.value())
    config.setValue('intermediate_speed_fan_3', ui.
        spinBoxIntermediateSpeedFan3.value())
    config.setValue('intermediate_speed_fan_4', ui.
        spinBoxIntermediateSpeedFan4.value())
    config.setValue('intermediate_speed_fan_5', ui.
        spinBoxIntermediateSpeedFan5.value())
    config.setValue('intermediate_speed_fan_6', ui.
        spinBoxIntermediateSpeedFan6.value())
    config.setValue('intermediate_temp_fan_1', ui.
        spinBoxIntermediateTempFan1.value())
    config.setValue('intermediate_temp_fan_2', ui.
        spinBoxIntermediateTempFan2.value())
    config.setValue('intermediate_temp_fan_3', ui.
        spinBoxIntermediateTempFan3.value())
    config.setValue('intermediate_temp_fan_4', ui.
        spinBoxIntermediateTempFan4.value())
    config.setValue('intermediate_temp_fan_5', ui.
        spinBoxIntermediateTempFan5.value())
    config.setValue('intermediate_temp_fan_6', ui.
        spinBoxIntermediateTempFan6.value())
    config.setValue('max_speed_fan_1', ui.spinBoxMaxSpeedFan1.value())
    config.setValue('max_speed_fan_2', ui.spinBoxMaxSpeedFan2.value())
    config.setValue('max_speed_fan_3', ui.spinBoxMaxSpeedFan3.value())
    config.setValue('max_speed_fan_4', ui.spinBoxMaxSpeedFan4.value())
    config.setValue('max_speed_fan_5', ui.spinBoxMaxSpeedFan5.value())
    config.setValue('max_speed_fan_6', ui.spinBoxMaxSpeedFan6.value())
    config.setValue('max_temp_fan_1', ui.spinBoxMaxTempFan1.value())
    config.setValue('max_temp_fan_2', ui.spinBoxMaxTempFan2.value())
    config.setValue('max_temp_fan_3', ui.spinBoxMaxTempFan3.value())
    config.setValue('max_temp_fan_4', ui.spinBoxMaxTempFan4.value())
    config.setValue('max_temp_fan_5', ui.spinBoxMaxTempFan5.value())
    config.setValue('max_temp_fan_6', ui.spinBoxMaxTempFan6.value())
    config.setValue('fan1_name', ui.lineEditFan1.text())
    config.setValue('fan2_name', ui.lineEditFan2.text())
    config.setValue('fan3_name', ui.lineEditFan3.text())
    config.setValue('fan4_name', ui.lineEditFan4.text())
    config.setValue('fan5_name', ui.lineEditFan5.text())
    config.setValue('fan6_name', ui.lineEditFan6.text())


def lcv(var, assignment, csp):
    """Least-constraining-values heuristic."""
    return sorted(csp.choices(var), key=lambda val: csp.nconflicts(var, val,
        assignment))


def index_of(pattern):
    """Return the index of a given pattern"""
    return pattern[0, 0] * 2 ** 0 + pattern[0, 1] * 2 ** 1 + pattern[0, 2
        ] * 2 ** 2 + pattern[1, 0] * 2 ** 3 + pattern[1, 1] * 2 ** 4 + pattern[
        1, 2] * 2 ** 5 + pattern[2, 0] * 2 ** 6 + pattern[2, 1
        ] * 2 ** 7 + pattern[2, 2] * 2 ** 8


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

        :param PaperAsFilesValue val:
        :rtype: UserFeatureValue
        """
    return cls('paper_as_files', val)


def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    return next(filter(pred, iterable), default)


def set(isamAppliance, client_id, options, endpoints, discovery_mechanisms,
    check_mode=False, force=False):
    """
    Set MMFA endpoint configuration
    """
    json_data = {'client_id': client_id, 'options': options, 'endpoints':
        endpoints, 'discovery_mechanisms': discovery_mechanisms}
    if check_mode is True:
        return isamAppliance.create_return_object(changed=True)
    else:
        return isamAppliance.invoke_post('Set MMFA endpoint configuration',
            '/iam/access/v8/mmfa-config/', json_data)


def read_sampling_params_from_config(cp, section_group=None, section=
    'sampling_params'):
    """Reads sampling parameters from the given config file.

    Parameters are read from the `[({section_group}_){section}]` section.
    The options should list the variable args to transform; the parameters they
    point to should list the parameters they are to be transformed to for
    sampling. If a multiple parameters are transformed together, they should
    be comma separated. Example:

    .. code-block:: ini

        [sampling_params]
        mass1, mass2 = mchirp, logitq
        spin1_a = logitspin1_a

    Note that only the final sampling parameters should be listed, even if
    multiple intermediate transforms are needed. (In the above example, a
    transform is needed to go from mass1, mass2 to mchirp, q, then another one
    needed to go from q to logitq.) These transforms should be specified
    in separate sections; see ``transforms.read_transforms_from_config`` for
    details.

    Parameters
    ----------
    cp : WorkflowConfigParser
        An open config parser to read from.
    section_group : str, optional
        Append `{section_group}_` to the section name. Default is None.
    section : str, optional
        The name of the section. Default is 'sampling_params'.

    Returns
    -------
    sampling_params : list
        The list of sampling parameters to use instead.
    replaced_params : list
        The list of variable args to replace in the sampler.
    """
    if section_group is not None:
        section_prefix = '{}_'.format(section_group)
    else:
        section_prefix = ''
    section = section_prefix + section
    replaced_params = set()
    sampling_params = set()
    for args in cp.options(section):
        map_args = cp.get(section, args)
        sampling_params.update(set(map(str.strip, map_args.split(','))))
        replaced_params.update(set(map(str.strip, args.split(','))))
    return list(sampling_params), list(replaced_params)


def check():
    """Returns a boolean. True allows the normal user login.
        False will disable the account and act like a failed login.
        """


@staticmethod
def expand_hintmask(program):
    """Expands collapsed hintmask tokens into two tokens"""
    piter = iter(enumerate(program))
    for i, tok in piter:
        if isinstance(tok, tuple):
            assert tok[0] in ('hintmask', 'cntrmask')
            program[i:i + 1] = tok


def _no_color(text, *a, **kw):
    """
    Colorizer that does not colorize.
    """
    return text


@classmethod
def _from_et(cls, root, parent):
    """
        Create a :class:`Text` from a :code:`text` element.

        :param root: The element tree tree to parse.
        :param parent: :class:`EagleFilePart` that should hold the resulting :class:`EagleFilePart`
        :rtype: :class:`Text`
        """
    n = cls()
    n._init_from_et(root, parent)
    return n


def xorCrypt(str, key=6):
    """Encrypt or decrypt a string with the given XOR key."""
    output = ''
    for x in range(0, len(str)):
        output += chr(key ^ ord(str[x]))
    return output


def maybe_update(sources, destination, func):
    """
    Updates defaults (values) in destination with values from func
    applied to sources, only if defaults (values) not already specified.
    """
    for source in sources:
        for key, value in func(source).items():
            if key not in destination:
                destination[key] = value


def findClosestSubPath(hdf5Object, path):
    """Find the closest existing path from the hdf5Object using a subset of the
    provided path.

    Returns None if no path found. It is possible if the path is a relative
    path.

    :param h5py.Node hdf5Object: An HDF5 node
    :param str path: A path
    :rtype: str
    """
    if path in ['', '/']:
        return '/'
    names = path.split('/')
    if path[0] == '/':
        names.pop(0)
    for i in range(len(names)):
        n = len(names) - i
        path2 = '/'.join(names[0:n])
        if path2 == '':
            return ''
        if path2 in hdf5Object:
            return path2
    if path[0] == '/':
        return '/'
    return None


def previous():
    """Move to previous folder

    """
    pass


def describe_workspace_bundles(BundleIds=None, Owner=None, NextToken=None):
    """
    Obtains information about the WorkSpace bundles that are available to your account in the specified region.
    You can filter the results with either the BundleIds parameter, or the Owner parameter, but not both.
    This operation supports pagination with the use of the NextToken request and response parameters. If more results are available, the NextToken response member contains a token that you pass in the next call to this operation to retrieve the next set of items.
    See also: AWS API Documentation

    :example: response = client.describe_workspace_bundles(
        BundleIds=[
            'string',
        ],
        Owner='string',
        NextToken='string'
    )

    :type BundleIds: list
    :param BundleIds: An array of strings that contains the identifiers of the bundles to retrieve. This parameter cannot be combined with any other filter parameter.
            (string) --

    :type Owner: string
    :param Owner: The owner of the bundles to retrieve. This parameter cannot be combined with any other filter parameter.
            This contains one of the following values:
            null- Retrieves the bundles that belong to the account making the call.
            AMAZON - Retrieves the bundles that are provided by AWS.

    :type NextToken: string
    :param NextToken: The NextToken value from a previous call to this operation. Pass null if this is the first call.

    :rtype: dict
    :return: {
        'Bundles': [
            {
                'BundleId': 'string',
                'Name': 'string',
                'Owner': 'string',
                'Description': 'string',
                'UserStorage': {
                    'Capacity': 'string'
                },
                'ComputeType': {
                    'Name': 'VALUE'|'STANDARD'|'PERFORMANCE'
                }
            },
        ],
        'NextToken': 'string'
    }

    """
    pass


def merge_dicts(base, updates):
    """
    Given two dicts, merge them into a new dict as a shallow copy.

    Parameters
    ----------
    base: dict
        The base dictionary.
    updates: dict
        Secondary dictionary whose values override the base.
    """
    if not base:
        base = dict()
    if not updates:
        updates = dict()
    z = base.copy()
    z.update(updates)
    return z


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


def range(start, stop=0, step=1):
    """
        put sequence of numbers in incoming things

        @param start: number to start with
        @param stop: number to stop with (default: 0)
        @param step: number of steps to advance per iteration (default: 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 decode_response(client_message, to_object=None):
    """ Decode response from client message"""
    parameters = dict(response=None)
    parameters['response'] = client_message.read_bool()
    return parameters


def get_fk_to_update(connection, tables):
    """ Method to get back all columns referencing another table
    """
    fk2update = {}
    with connection.cursor() as c:
        for table in tables:
            if table not in fk2update:
                if table == 'ir.actions':
                    table = 'ir.actions.actions'
                query = (
                    """
SELECT tc.table_name, kcu.column_name
FROM information_schema.table_constraints AS tc JOIN
information_schema.key_column_usage AS kcu ON
tc.constraint_name = kcu.constraint_name JOIN
information_schema.constraint_column_usage AS
ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND
ccu.table_name='%s';"""
                     % table)
                c.execute(query)
                results = c.fetchall()
                fk2update[table] = results
    result = {}
    for pointed_table, fknames in fk2update.iteritems():
        for fkname in fknames:
            result['.'.join(fkname)] = pointed_table
    return result


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

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

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


@classmethod
def from_data(cls, data):
    """Construct a frame from a data dict.

        Parameters
        ----------
        data : dict
            The data dictionary.

        Examples
        --------
        >>> line = Line.from_data({'start': [0.0, 0.0, 0.0], 'end': [1.0, 0.0, 0.0]})
        >>> line.end
        Point(1.000, 0.000, 0.000)
        """
    return cls(data['start'], data['end'])


def perm_get_local_account_usage(issuer, kwargs):
    """
    Checks if an account can get the account usage of an account.

    :param issuer: Account identifier which issues the command.
    :param kwargs: List of arguments for the action.
    :returns: True if account is allowed, otherwise False
    """
    return True


def clean(threshold: float=0.001, channels: bool=False):
    """Simplify F-Curves by removing closely spaced keyframes

    :param threshold: Threshold
    :type threshold: float
    :param channels: Channels
    :type channels: bool
    """
    pass


def identify_tyre_dynamic_rolling_coefficient(r_wheels, r_dynamic):
    """
    Identifies the dynamic rolling coefficient [-].

    :param r_wheels:
        Radius of the wheels [m].
    :type r_wheels: float

    :param r_dynamic:
        Dynamic radius of the wheels [m].
    :type r_dynamic: float

    :return:
        Dynamic rolling coefficient [-].
    :rtype: float
    """
    return r_dynamic / r_wheels


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


def _add_permanent_markers_to_signal(signal, marker_list):
    """Add a list of markers to a signal.

    Parameters
    ----------
    signal : PixelatedSTEM or Signal2D
    marker_list : list of markers

    Example
    -------
    >>> s = ps.dummy_data.get_cbed_signal()
    >>> peak_array = s.find_peaks(lazy_result=False, show_progressbar=False)
    >>> import pixstem.marker_tools as mt
    >>> marker_list = mt._get_4d_points_marker_list(
    ...     peak_array, s.axes_manager.signal_axes)
    >>> mt._add_permanent_markers_to_signal(s, marker_list)
    >>> s.plot()

    """
    if not hasattr(signal.metadata, 'Markers'):
        signal.metadata.add_node('Markers')
    marker_extra = len(signal.metadata.Markers)
    for imarker, marker in enumerate(marker_list):
        marker_name = 'marker{0}'.format(imarker + marker_extra)
        signal.metadata.Markers[marker_name] = marker


@staticmethod
def is_valid_end_char(char):
    """Checks if given character is valid at the end of a string"""
    allowed_end_chars = {'%'}
    return char.isalnum() or char in allowed_end_chars


def sum_all_enduses_fueltype(data_enduses, fueltype_str=False):
    """Sum across all enduses and fueltypes
    TODO
    """
    y_values_enduse_yrs = {}
    for year in data_enduses.keys():
        for enduse in data_enduses[year].keys():
            tot_across_fueltypes = data_enduses[year][enduse]
            try:
                y_values_enduse_yrs[year] += tot_across_fueltypes
            except KeyError:
                y_values_enduse_yrs[year] = tot_across_fueltypes
    return y_values_enduse_yrs


def get_json_field(json_data, field_names):
    """This function retrieves a value for a specific field from the JSON data for a user.

    :param json_data: The JSON data from which the field value must be retrieved
    :type json_data: json
    :param field_names: The field name along with any parent field paths
    :type field_names: tuple, list
    :returns: The value for the specific field in its original format
    :raises: :py:exc:`ValueError`, :py:exc:`TypeError`, :py:exc:`KeyError`
    """
    if type(field_names) == str:
        field_value = json_data[field_names]
    elif type(field_names) == tuple or type(field_names) == list:
        if len(field_names) == 2:
            field_one, field_two = field_names
            field_value = json_data[field_one][field_two]
        elif len(field_names) == 3:
            field_one, field_two, field_three = field_names
            field_value = json_data[field_one][field_two][field_three]
        elif len(field_names) == 4:
            field_one, field_two, field_three, field_four = field_names
            field_value = json_data[field_one][field_two][field_three][
                field_four]
    else:
        field_value = None
    return field_value


def export_discourse_spelling(corpus_context, discourse, path,
    words_per_line=10):
    """
    Export an orthography discourse to a text file

    Parameters
    ----------
    corpus_context: :class:`~polyglotdb.corpus.CorpusContext`
        Context manager for the corpus
    discourse : str
        Discourse to export
    path : str
        Path to export to
    words_per_line : int, optional
        Max number of words per line, set to -1 for a single line
    """
    discourse = corpus_context.discourse(discourse)
    with open(path, encoding='utf-8', mode='w') as f:
        count = 0
        for i, wt in enumerate(discourse):
            count += 1
            f.write(wt.label)
            if i != len(discourse) - 1:
                if words_per_line > 0 and count <= words_per_line:
                    f.write(' ')
                else:
                    count = 0
                    f.write('\n')


def convert():
    """
    This module converts a pdf to text

    Parameters:
    path (str): The path to a PDF File.

    Returns:
    str: the content of the PDF file as text.
    """
    print('print2text')


def can_cancel(payment):
    """If it's possible to cancel a payment

        :param payment: the payment to cancel
        """


def gps_create_topic():
    """
    This creates a Google Pub/Sub topic.

    TODO: finish this

    """


def path_convert_id2pos(model, id_path):
    """This function will transform a path of id into a path of position"""
    group = model.group
    id_path = id_path[:]
    indexes = []
    while id_path:
        current_id = id_path.pop(0)
        try:
            record = group.get(current_id)
            indexes.append(group.index(record))
            group = record.children_group(model.children_field)
        except (KeyError, AttributeError, ValueError):
            return None
    return tuple(indexes)


@classmethod
def from_xmldict(cls, xml_dict):
    """Create an `Author` from a datacite3 metadata converted by
        `xmltodict`.

        Parameters
        ----------
        xml_dict : :class:`collections.OrderedDict`
            A `dict`-like object mapping XML content for a single record (i.e.,
            the contents of the ``record`` tag in OAI-PMH XML). This dict is
            typically generated from :mod:`xmltodict`.
        """
    name = xml_dict['creatorName']
    kwargs = {}
    if 'affiliation' in xml_dict:
        kwargs['affiliation'] = xml_dict['affiliation']
    return cls(name, **kwargs)


def note_on_event(current_track, tick, channel, pitch, velocity):
    """appends a note on event"""
    current_track.append([144, 2, tick, channel, 0, pitch, velocity])


def validate_labels(labels):
    """ensure that labels are well formed.
  Args:
    labels (list): a list of integers on the range [0,1]
  """
    if (labels == 0).sum() == 0:
        raise Exception('All rank_set were corrupt')
    if (labels == 1).sum() == 0:
        raise Exception('All style_set were corrupt')


@classmethod
def index_set_field(cls, name):
    """Returns the index sort order of the field set calls."""
    return 0


def theta_Na_acetate_Cl_M83(T, P):
    """c-a-a': sodium acetate chloride [M83]."""
    theta = 0
    valid = T == 298.15
    return theta, valid


@staticmethod
def is_consumption() ->bool:
    """Whether the rule is a consumption rule or not

        Returns
        ----------
        is_consumption : bool
            Whether the rule is a consumption rule or not
        """
    return False


@classmethod
def isFieldTableName(cls, engine, name_str):
    """Returns True if given name resembles name of the field table"""
    return name_str.startswith(engine.getNameString(['field']))


def set_cors_config(app):
    """
    Flask-Cors (3.x.x) extension set the config as CORS_*,
     But we'll hold the config in CORS key.
     This function will convert them to CORS_* values
    :param app:
    :return:
    """
    if 'CORS' in app.config:
        for k, v in app.config['CORS'].items():
            _ = 'CORS_' + k.upper()
            if _ not in app.config:
                app.config[_] = v


def decodeP(p):
    """
    Translate a parameter into obj format

    Decompose a parameter.
    In this code. It only works for spline obj
    """
    try:
        ret = eval(p)
    except:
        ret = p
    return ret


def throttled(duration):
    """
    Syntax sugar over timecache decorator.

    With accent on throttling calls and not actual caching of values Concurrent
    callers will block if function is executing, since they might depend on
    side effect of function call.
    """
    from easypy.caching import timecache
    return timecache(expiration=duration)


@classmethod
def topic(cls, **kwargs) ->str:
    """Get MQTT topic for this message type."""
    return 'hermes/dialogueManager/configure'


@staticmethod
def _prepare_requirements(configs, requires_filters):
    """
        Overrides the filters specified in the decorator with the given ones

        :param configs: Field → (Requirement, key, allow_none) dictionary
        :param requires_filters: Content of the 'requires.filter' component
                                 property (field → string)
        :return: The new configuration dictionary
        """
    if not requires_filters or not isinstance(requires_filters, dict):
        return configs
    new_requirements = {}
    for field, config in configs.items():
        requirement, key, allow_none = config
        try:
            explicit_filter = requires_filters[field]
            requirement_copy = requirement.copy()
            requirement_copy.set_filter(explicit_filter)
            new_requirements[field] = requirement_copy, key, allow_none
        except (KeyError, TypeError, ValueError):
            new_requirements[field] = config
    return new_requirements


def setQualifiedTypes(qualified_types):
    """Set the qualified Types elements.

        The argument must be a sequence of Type `IDublinCoreElementItem`.
        """


def camelcase(text):
    """Converts text that may be underscored into a camelcase format"""
    return text[0] + ''.join(text.title().split('_'))[1:]


def _nbaLeague(x):
    """Takes in initials of league and returns numeric API Code

    Input Values: "NBA", "WNBA", or "NBADL"

    Used in: _Draft.Anthro(), _Draft.Agility(), _Draft.NonStationaryShooting(),
    _Draft.SpotUpShooting(), _Draft.Combine()

    """
    leagues = {'NBA': '00', 'WNBA': '10', 'NBADL': '20'}
    try:
        return leagues[x.upper()]
    except:
        raise ValueError(
            "Please use one of the following values for League: 'NBA', 'WNBA', 'NBADL'"
            )


@classmethod
def PontualLoad(cls, load, x):
    """
            Define a pontual load.

                Call signatures:

                    fc.PontualLoad(load, x)

                >>> pontual_load_1 = fc.Load.PontualLoad(-10.0, 200)
                >>> pontual_load_2 = fc.Load.PontualLoad('-10.0kN', '2m')
                >>> repr(pontual_load_1) == repr(pontual_load_2)
                True

            Parameters
            ----------
            load : number or str
                Represent the load measure. If it is a number, default unit is kN, but also [force] unit can be given. Example:
                '20kN', '10N', etc

            x : number or str
                Where the load is going to end. If it is a number, default unit is cm, but also [length] unit can be given. Example:
                '20cm', '10dm', etc

        """
    return cls(load, 0, x, x, q=0, order=0)


def is_four_prices_doji(body, top, bottom):
    """Se existir o doji de quatro preços retorna True."""
    if abs(body) > 0:
        return False
    if top > 0:
        return False
    if bottom > 0:
        return False
    return True


def fk_name(table_name, column_name, other_table_name):
    """Returns the name that will be used in the database for a foreign key, given:

       :arg table_name: The name of the table from which the foreign key points.
       :arg column_name: The name of the column in which the foreign key pointer is stored.
       :arg other_table_name: The name of the table to which this foreign key points.
    """
    return 'fk_%s_%s_%s' % (table_name, column_name, other_table_name)


@classmethod
def get_datasource_url(cls, ds_name):
    """Get a connection URL for the datasource"""
    return 'sqlite:///%s' % cls.get_datasource_filename(ds_name)


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

        :param ResellerSupportSessionStartType val:
        :rtype: EventType
        """
    return cls('reseller_support_session_start', val)


def identity(x):
    """Returns its argument.
    """
    return x


@staticmethod
def get_db_attributes(tag):
    """
        Given an <a> tag that we've identified as a page link embed (because it has a
        data-linktype="page" attribute), return a dict of the attributes we should
        have on the resulting <a linktype="page"> element.
        """
    return {'id': tag['data-id']}


def __call__():
    """
        Return a new `IDBDriver` as represented by this factory.

        If it is not possible to do this, for example because the
        module cannot be imported, raise an `DriverNotAvailableError`.
        """


def wordify_close(p, word_chars):
    """Append the word end markers."""
    return '{1}(?![{0}])'.format(word_chars, p)


def filter_insignificant(chunk, tag_suffixes=('DT', 'CC', 'PRP$', 'PRP')):
    """Filter out insignificant (word, tag) tuples from a chunk of text."""
    good = []
    for word, tag in chunk:
        ok = True
        for suffix in tag_suffixes:
            if tag.endswith(suffix):
                ok = False
                break
        if ok:
            good.append((word, tag))
    return good


def get_deployment_operations(client, resource_group_name, deployment_name,
    operation_ids):
    """get a deployment's operation."""
    result = []
    for op_id in operation_ids:
        dep = client.get(resource_group_name, deployment_name, op_id)
        result.append(dep)
    return result


def wcs(i, crpix, crval, cdelt):
    """calculate coordinates from WCS data"""
    return crval + (float(i + 1) - crpix) * cdelt


def add_arg(func, *args, **kwargs):
    """Bind CLI arguments to a shell.py `do_foo` function."""
    if not hasattr(func, 'arguments'):
        func.arguments = []
    if (args, kwargs) not in func.arguments:
        func.arguments.insert(0, (args, kwargs))


def scroll_backward(event, half=False):
    """
    Scroll window up.
    """
    w = event.app.layout.current_window
    b = event.app.current_buffer
    if w and w.render_info:
        info = w.render_info
        scroll_height = info.window_height
        if half:
            scroll_height //= 2
        y = max(0, b.document.cursor_position_row - 1)
        height = 0
        while y > 0:
            line_height = info.get_height_for_line(y)
            if height + line_height < scroll_height:
                height += line_height
                y -= 1
            else:
                break
        b.cursor_position = b.document.translate_row_col_to_index(y, 0)


def voltage_evq(energy, charge):
    """Usage: voltage_evq(energy, charge)"""
    return energy / charge


@classmethod
def checkbox_in_table_row(cls, nth):
    """Returns an XPath to find an HTML <tr> that contains a <td> / cell with text matching the text in `text`"""
    return cls('(//tr/td/input[@type="checkbox"])[%s]' % nth)


@staticmethod
def run_file(command, session, settings, timeout=1):
    """Runs a file in the provided session by feeding the interpreter
        one line at a time. At each iteration, run_file checks for a
        continuation or regular prompt and finally closes the expect properly,
        so that the REPLWrapper works properly the next run.
        """
    init, cont = settings.shell['prompt'], settings.shell['continuation']
    results, commands, a, b = [], command.splitlines(), init, cont
    session.sendline(commands[0])
    for line in commands:
        try:
            session.expect(a, timeout=timeout)
        except:
            session.expect(b, timeout=timeout)
            b, a = a, b
        session.sendline(line)
        if a == init:
            output = session.before.splitlines()[1:]
            results.extend(output)
    if a == cont:
        session.sendline('')
        session.expect(init)
        results.append(session.before)
    return '\n'.join(results)


def output(*objs) ->None:
    """
    Print all passed objects as is to standard output *without* logging these
    objects.

    This function is provided only for orthogonality with the function of the
    same name defined by the :mod:`betse.util.io.stderrs` module.

    This function is intentionally *not* named ``print()`` to avoid conflict
    with the builtin function of the same name.
    """
    print(*objs)


def add(principal_ids):
    """Share current shared lock with principal_ids.
        If all of the principals in the current interaction are not owners
        of the current token (in principal_ids), raise ParticipationError."""


def string_to_boolean(string):
    """
  Return True if the value of the "string" parameter can be parsed as True.
  Return False if the value of the "string" parameter can be parsed as False.
  Otherwise, Raise.

  The parser is completely arbitrary, see code for actual implementation.
  """
    try:
        return ('false', 'true').index(string.lower())
    except Exception:
        raise ValueError('%s is neither True nor False.' % string)


def metafetcher(bamfile, metacontig2contig, metatag):
    """ return reads in order of metacontigs"""
    for metacontig in metacontig2contig:
        for contig in metacontig2contig[metacontig]:
            for read in bamfile.fetch(contig):
                read.set_tag(metatag, metacontig)
                yield read


def _delete_substrings(string, substrings):
    """
    TODO: convert to a function called "_delete_suffixes" that only deletes
          substrings _at the end_.
    """
    for ss in substrings:
        string = string.replace(ss, '')
    return string


def termToWordIds(text):
    """Return a sequence of ids of the words parsed from the text.

        The input text may be either a string or a list of strings.

        Parse the text as if they are search terms, and skips words
        that aren't in the lexicon.
        """


@staticmethod
def default(content, units):
    """Handle a mimetype when no function is registered."""
    return content


@staticmethod
def __identity(scope, name, rse, rse_attrs, protocol_attrs):
    """
        Given a LFN, convert it directly to a path using the mapping:

            scope:path -> scope/path

        :param scope: Scope of the LFN.
        :param name: File name of the LFN.
        :param rse: RSE for PFN (ignored)
        :param rse_attrs: RSE attributes for PFN (ignored)
        :param protocol_attrs: RSE protocol attributes for PFN (ignored)
        :returns: Path for use in the PFN generation.
        """
    del rse
    del rse_attrs
    del protocol_attrs
    if scope.startswith('user') or scope.startswith('group'):
        scope = scope.replace('.', '/')
    return '%s/%s' % (scope, name)


def interpret_structure(struc_spec):
    """Interpret a DDLm structure specification"""
    from . import TypeContentsParser as t
    p = t.TypeParser(t.TypeParserScanner(struc_spec))
    return getattr(p, 'input')()


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 Cr(mw_atmos, mh=1):
    """Defines properties for Cr as condensible"""
    gas_mw = 51.996
    if mh == 1:
        gas_mmr = 8.8e-07 * (gas_mw / mw_atmos)
    elif mh == 10:
        gas_mmr = 8.6803e-06 * (gas_mw / mw_atmos)
    elif mh == 50:
        gas_mmr = 4.1308e-05 * (gas_mw / mw_atmos)
    else:
        raise Exception(
            'Chromium (Cr) gas properties are only available for 1, 10, and 50xSolar'
            )
    rho_p = 7.15
    return gas_mw, gas_mmr, rho_p


def DictReader(fp, *args, **kwargs):
    """
    Produce a csv.DictReader without specifying the fieldnames.
    Arguments get passed to csv.DictReader.
    """
    import csv
    position = fp.tell()
    header = next(csv.reader(fp, *args, **kwargs))
    fp.seek(position)
    _kwargs = dict(kwargs)
    _kwargs['fieldnames'] = _kwargs.get('fieldnames', header)
    _kwargs['restval'] = _kwargs.get('restval', '')
    data = csv.DictReader(fp, *args, **_kwargs)
    next(data)
    return data


@classmethod
def age(cls, daystart, s, isAfter):
    """Return a new MTimeFilter selecting before/after the given age."""
    epoch = daystart - int(s) * 60 * 60 * 24
    if isAfter:
        return cls(after=epoch)
    else:
        return cls(before=epoch)


def check_p(Q):
    """
    For leo dorsts check product
    """
    return Q(0, 1, 3) - Q(2, 4, 5)


def bake_animation():
    """Update the audio animation cache

    """
    pass


def uk_1000_words_standard_page(page_counter):
    """
    UK standard page is 1000 words per page.
    """
    pages = round(page_counter.word_count() / 1000)
    if pages == 0:
        return 1
    return pages


def iterable_to_dict(items, key_attr_name):
    """Converts iterable of certain objects to dict.

    :param iterable items:
    :param string key_attr_name: Attribute to use as a dictionary key.
    :return dict:
    """
    items_dict = {}
    for item in items:
        items_dict.update({getattr(item, key_attr_name): item})
    return items_dict


def ilshift(a, b):
    """Same as a <<= b."""
    a <<= b
    return a


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

    """
    pass


def write_output(output, path):
    """ Write output string to file at path """
    with open(path, 'w') as _file:
        _file.write(output)


@classmethod
def make_operand(cls, value):
    """Create an operand token."""
    if value.startswith('"'):
        subtype = cls.TEXT
    elif value.startswith('#'):
        subtype = cls.ERROR
    elif value in ('TRUE', 'FALSE'):
        subtype = cls.LOGICAL
    else:
        try:
            float(value)
            subtype = cls.NUMBER
        except ValueError:
            subtype = cls.RANGE
    return cls(value, cls.OPERAND, subtype)


def is_infohash(infohash):
    """
    A check to determine if a string is a valid infohash.

    Args:
        infohash (str): The string to check.

    Returns:
        bool: True if valid infohash, False otherwise.

    """
    return len(infohash) == 40 and infohash.isalnum()


def parse_debug_value(value):
    """Resolve the given string value to a debug option.

    Can be used to deal with os environment variables, for example.
    """
    if value is None:
        return value
    value = value.lower()
    if value in ('true', '1'):
        return True
    elif value in ('false', '0'):
        return False
    elif value in ('merge',):
        return 'merge'
    else:
        raise ValueError()


def _booleanise(value):
    """Try to booleanise something, return it unchanged if not possible"""
    try:
        if value.lower() in ['true', 'false']:
            value = value.lower() == 'true'
    except (AttributeError, TypeError):
        pass
    return value


def avg_angle(theta):
    """A function that finds the avage of an array of angles that are
    in the range [-180, 180].

    Parameters
    ----------
    theta : array
        An array of angles that are in the range [-180, 180] degrees

    Returns
    -------
    average : float
        The average angle
    """
    if theta.max() - theta.min() > 180:
        theta[theta < 0] += 360
    return theta.mean()


def get_select_field_choices(raw_choices_data, key_type=None, value_type=
    None, fail_silently=True):
    """Get select field choices.

    Used in ``radio``, ``select`` and other choice based
    fields.

    :param str raw_choices_data:
    :param type key_type:
    :param type value_type:
    :param bool fail_silently:
    :return list:
    """
    choices = []
    keys = set([])
    values = set([])
    for choice in raw_choices_data.split('\n'):
        choice = choice.strip()
        if ',' in choice:
            key, value = choice.split(',', 1)
            key = key.strip()
            if key_type and key is not None:
                try:
                    key = key_type(key)
                except (ValueError, TypeError):
                    return [] if fail_silently else None
            value = value.strip()
            if value_type and value is not None:
                try:
                    value = value_type(value)
                except (ValueError, TypeError):
                    return [] if fail_silently else None
            if key is not None and key not in keys and value not in values:
                choices.append((key, value))
                keys.add(key)
                values.add(value)
        else:
            choice = choice.strip()
            if (choice is not None and choice not in keys and choice not in
                values):
                choices.append((choice, choice))
                keys.add(choice)
                values.add(choice)
    return choices


def write_matrix(a, name):
    """Writes the matrix a to the file name.
    """
    Nx, Ny = a.shape
    f = open(name, 'w')
    for x in range(Nx):
        for y in range(Ny):
            print('{} '.format(a[x, y]), file=f, end='')
        print('', file=f)
    f.close()


def get_params(softVersion):
    """Parse and analyse command line parameters."""
    sensList = []
    for i in range(1, 9):
        sensList.append(float(i))
        for j in range(1, 10):
            fval = float(i + float(j / 10.0))
            if fval <= 7.5:
                sensList.append(fval)
    import argparse
    parser = argparse.ArgumentParser(description='SonicParanoid %s' %
        softVersion, usage=
        '%(prog)s -i <INPUT_DIRECTORY> -o <OUTPUT_DIRECTORY>[options]',
        prog='sonicparanoid')
    parser.add_argument('-i', '--input-directory', type=str, required=True,
        help=
        'Directory containing the proteomes (in FASTA format) of the species to be analyzed.'
        , default=None)
    parser.add_argument('-o', '--output-directory', type=str, required=True,
        help='The directory in which the results will be stored.', default=None
        )
    parser.add_argument('-p', '--project-id', type=str, required=False,
        help=
        'Name for the project reflecting the run. If not specified it will be automatically generated using the current date and time.'
        , default='')
    parser.add_argument('-sh', '--shared-directory', type=str, required=
        False, help=
        'The directory in which the alignment files are stored. If not specified it will be created inside the main output directory.'
        , default=None)
    parser.add_argument('-t', '--threads', type=int, required=False, help=
        'Number of parallel 1-CPU jobs to be used. Default=4', default=4)
    parser.add_argument('-at', '--force-all-threads', required=False, help=
        'Force using all the requested threads.', action='store_true')
    parser.add_argument('-sm', '--skip-multi-species', required=False, help
        ='Skip the creation of multi-species ortholog groups.', default=
        False, action='store_true')
    parser.add_argument('-d', '--debug', required=False, help=
        'Output debug information. (WARNING: extremely verbose)', default=
        False, action='store_true')
    parser.add_argument('-m', '--mode', required=False, help=
        'SonicParanoid execution mode. The default mode is suitable for most studies. Use sensitive or most-sensitive if the input proteomes are not closely related.'
        , choices=['fast', 'default', 'sensitive', 'most-sensitive'],
        default='default')
    parser.add_argument('-se', '--sensitivity', type=float, required=False,
        help=
        'Sensitivity for MMseqs2. This will overwrite the --mode option.',
        default=None)
    parser.add_argument('-ml', '--max-len-diff', type=float, required=False,
        help=
        """Maximum allowed length-difference-ratio between main orthologs and canditate inparalogs.
Example: 0.5 means one of the two sequences could be two times longer than the other
 0 means no length difference allowed; 1 means any length difference allowed. Default=0.5"""
        , default=0.5)
    parser.add_argument('-db', '--mmseqs-dbs', type=str, required=False,
        help=
        'The directory in which the database files for MMseqs2 will be stored. If not specified it will be created inside the main output directory.'
        , default=None)
    parser.add_argument('-noidx', '--no-indexing', required=False, help=
        """Avoid the creation of indexes for MMseqs2 databases. IMPORTANT: while this saves starting storage space it makes MMseqs2 slightly slower.
The results might also be sligthy different."""
        , default=False, action='store_true')
    parser.add_argument('-op', '--output-pairs', required=False, help=
        'Output a text file with all the orthologous relations.', default=
        False, action='store_true')
    parser.add_argument('-qfo11', '--qfo-2011', required=False, help=
        """Output a text file with all the orthologous relations formatted to be uploaded to the QfO benchmark service.
NOTE: implies --output-pairs"""
        , default=False, action='store_true')
    parser.add_argument('-ka', '--keep-raw-alignments', required=False,
        help=
        'Do not delete raw MMseqs2 alignment files. NOTE: this will triple the space required for storing the results.'
        , default=False, action='store_true')
    parser.add_argument('-ca', '--complete-aln', required=False, help=
        """Perform complete alignments.
""", default=False, action='store_true'
        )
    parser.add_argument('-I', '--inflation', type=float, required=False,
        help=
        'Affects the granularity of ortholog groups. This value should be between 1.2 (very coarse) and 5 (fine grained clustering). Default=1.5'
        , default=1.5)
    parser.add_argument('-slc', '--single-linkage', required=False, help=
        'Use single-linkage-clustering (MultiParanoid-like). NOTE: by default MCL clustering is used.'
        , default=False, action='store_true')
    parser.add_argument('-mgs', '--max-gene-per-sp', type=int, required=
        False, help=
        'Limits the maximum number of genes per species in the multi-species output table. This option reduces the verbosity of the multi-species output and only affects single-linkage-clustering. Default=30'
        , default=30)
    parser.add_argument('-ot', '--overwrite-tables', required=False, help=
        'This will force the re-computation of the ortholog tables. Only missing alignment files will be re-computed.'
        , default=False, action='store_true')
    parser.add_argument('-ow', '--overwrite', required=False, help=
        'Overwrite previous runs and execute it again. This can be useful to update a subset of the computed tables.'
        , default=False, action='store_true')
    parser.add_argument('-rs', '--remove-old-species', required=False, help
        =
        'Remove alignments and pairwise ortholog tables related to species used in a previous run. This option should be used when updating a run in which some input proteomes were modified or removed.'
        , default=False, action='store_true')
    parser.add_argument('-un', '--update-input-names', required=False, help
        =
        'Remove alignments and pairwise ortholog tables for an input proteome used in a previous which file name conflicts with a newly added species. This option should be used when updating a run in which some input proteomes or their file names were modified.'
        , default=False, action='store_true')
    args = parser.parse_args()
    return args, parser


def get_definition_without_template_args(data_object):
    """
    Return data_object.definition removing any template arguments from the class name in the member
    function.  Otherwise links to classes defined in the same template are not generated correctly.

    For example in 'Result<T> A< B<C> >::f' we want to remove the '< B<C> >' part.
    """
    definition = data_object.definition
    if len(data_object.bitfield) > 0:
        definition += ' : ' + data_object.bitfield
    qual_name = '::' + data_object.name
    if definition.endswith(qual_name):
        qual_name_start = len(definition) - len(qual_name)
        pos = qual_name_start - 1
        if definition[pos] == '>':
            bracket_count = 0
            while pos > 0:
                if definition[pos] == '>':
                    bracket_count += 1
                elif definition[pos] == '<':
                    bracket_count -= 1
                    if bracket_count == 0:
                        definition = definition[:pos] + definition[
                            qual_name_start:]
                        break
                pos -= 1
    return definition


def has(cls):
    """
    Check whether *cls* is a class with ``attrs`` attributes.

    :param type cls: Class to introspect.
    :raise TypeError: If *cls* is not a class.

    :rtype: :class:`bool`
    """
    return getattr(cls, '__attrs_attrs__', None) is not None


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

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

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


@classmethod
def dismiss_all_dialogs(cls):
    """Dispatches dismiss event for all dialogs."""
    dialogs = cls.dialogs[:]
    for dialog in dialogs:
        dialog.dismiss()


def is_sparse(arr) ->bool:
    """
    Check whether an array-like is a 1-D pandas sparse array.

    Check that the one-dimensional array-like is a pandas sparse array.
    Returns True if it is a pandas sparse array, not another type of
    sparse array.

    Parameters
    ----------
    arr : array-like
        Array-like to check.

    Returns
    -------
    bool
        Whether or not the array-like is a pandas sparse array.

    Examples
    --------
    Returns `True` if the parameter is a 1-D pandas sparse array.

    >>> is_sparse(pd.arrays.SparseArray([0, 0, 1, 0]))
    True
    >>> is_sparse(pd.Series(pd.arrays.SparseArray([0, 0, 1, 0])))
    True

    Returns `False` if the parameter is not sparse.

    >>> is_sparse(np.array([0, 0, 1, 0]))
    False
    >>> is_sparse(pd.Series([0, 1, 0, 0]))
    False

    Returns `False` if the parameter is not a pandas sparse array.

    >>> from scipy.sparse import bsr_matrix
    >>> is_sparse(bsr_matrix([0, 1, 0, 0]))
    False

    Returns `False` if the parameter has more than one dimension.
    """
    from pandas.core.arrays.sparse import SparseDtype
    dtype = getattr(arr, 'dtype', arr)
    return isinstance(dtype, SparseDtype)


def leave(list_id, email):
    """Unsubscribe from a mailing list.

        :param list_id: The list id of the mailing list the user is
            unsubscribing from.
        :type list_id: string
        :param email: The email address of the user getting unsubscribed.
        :type email: string
        :raises InvalidEmailAddressError: if the email address is not valid.
        :raises NoSuchListError: if the named mailing list does not exist.
        :raises NotAMemberError: if the given address is not a member of the
            mailing list.
        """


def sanitizer(name, replacements=[(':', '_'), ('/', '_'), ('\\', '_')]):
    """
    String sanitizer to avoid problematic characters in filenames.
    """
    for old, new in replacements:
        name = name.replace(old, new)
    return name


@staticmethod
def properties_non_controllable():
    """Return True if non controllable."""
    return None


def set_detail_size():
    """Set the mesh detail (either relative or constant one, depending on current dyntopo mode)

    """
    pass


def get_listOfCompartments(model):
    """Get list of compartments in a SBML model

    Args:
        model (xml.etree.ElementTree.Element): SBML model

    Returns:
        xml.etree.ElementTree.Element: list of compartments
    """
    listOfCompartments = None
    for e in model:
        if e.tag[0] == '{':
            uri, tag = e.tag[1:].split('}')
        else:
            tag = e.tag
        if tag == 'listOfCompartments':
            listOfCompartments = e
            break
    return listOfCompartments


def compat_compose_dictionary(dictionary, **kwargs):
    """
    This method allows us the one line dictionary composition that is offered by the ** dictionary unpacking
    available in 3.6.

    :param dictionary: the dictionary to add the kwargs elements to.
    :param kwargs: a set of key/value pairs to add to `dictionary`.
    :return: the composed dictionary.
    """
    composed_dict = dictionary.copy()
    composed_dict.update(kwargs)
    return composed_dict


def read_in_chunks(file_object, chunk_size=4096):
    """Lazy function (generator) to read a file piece by piece.
    Default chunk size: 4k."""
    while True:
        data = file_object.read(chunk_size)
        if not data:
            break
        yield data


def shared_lib_name(group_name: str) ->str:
    """Given a group name, return the actual name of its extension module.

    (This just adds a suffix to the final component.)
    """
    return '{}__mypyc'.format(group_name)


def mesh_linked_uv_islands(mesh: 'bpy.types.Mesh') ->list:
    """Splits the mesh into connected polygons, use this for separating cubes from other mesh elements within 1 mesh datablock.

    :param mesh: the mesh used to group with.
    :type mesh: 'bpy.types.Mesh'
    :return:  lists of lists containing polygon indices
    """
    pass


def __call__(context, request):
    """ Must return an object that implements IResponse. """


def _include_file_data(login, record):
    """Ensure that 'files' field is present in the input record"""
    if 'files' not in record:
        if 'files' in record.get('links', {}):
            url = record['links']['files']
        elif 'id' in record:
            url = login.base_url + 'api/deposit/depositions/{0}/files'.format(
                record['id'])
        else:
            return record
        r = login.session.get(url)
        if r.status_code == 200:
            r_json = r.json()
            record['files'] = r_json
    return record


def distance_point(p1, p2):
    """
    Returns the Euclidian distance between two points.
    Retourne la distance euclidienne entre deux points.

    @param      p1      point 1
    @param      p2      point 2
    @return             distance
    """
    d = 0
    for a, b in zip(p1, p2):
        d += (a - b) ** 2
    return d ** 0.5


def pitch_bend_to_semitones(pitch_bend, semitone_range=2.0):
    """Convert a MIDI pitch bend value (in the range ``[-8192, 8191]``) to the
    bend amount in semitones.

    Parameters
    ----------
    pitch_bend : int
        MIDI pitch bend amount, in ``[-8192, 8191]``.
    semitone_range : float
        Convert to +/- this semitone range.  Default is 2., which is the
        General MIDI standard +/-2 semitone range.

    Returns
    -------
    semitones : float
        Number of semitones corresponding to this pitch bend amount.

    """
    return semitone_range * pitch_bend / 8192.0


@classmethod
def mask(cls, dt, **options):
    """
        Return a datetime with the same value as ``dt``, to a
        resolution of minutes.
        """
    return dt.replace(second=0, microsecond=0)


def tio_is_callable(tree_item):
    """Returns 'True' if the tree item object is callable."""
    return str(callable(tree_item.obj))


def get(id):
    """Returns the conditional modifier with the given id.

        Returns a 'IConditionalModifier' object.

        Raises an exception if the item doesn't exist.
        """


def size():
    """Return the data length in bytes.
        """


def serie_spreads(prices1: list, prices2: list) ->list:
    """Retorna serie dos spreads entre duas séries de preços."""
    res = []
    for i in range(len(prices1)):
        spread = abs(prices2[i] - prices1[i])
        res.append(spread)
    return res


@staticmethod
def _getDefaultSettings():
    """
    Returns a dictionary containg the default settings specified in this class. These settings cover global settings,
    such as ``additionalInfo``, as well as the image pre-processing settings (e.g. resampling). Feature class specific
    are defined in the respective feature classes and and not included here. Similarly, filter specific settings are
    defined in ``imageoperations.py`` and also not included here.
    """
    return {'minimumROIDimensions': 2, 'minimumROISize': None, 'normalize':
        False, 'normalizeScale': 1, 'removeOutliers': None,
        'resampledPixelSpacing': None, 'interpolator': 'sitkBSpline',
        'preCrop': False, 'padDistance': 5, 'distances': [1], 'force2D':
        False, 'force2Ddimension': 0, 'resegmentRange': None, 'label': 1,
        'additionalInfo': True}


@staticmethod
def set_instance_attributes(arg_dict):
    """Set attributes of the :attr:`instance` based on the given arg_dict.

        Args:
          arg_dict (dict): Dictionary of (attribute, value).
        Raises:
          InvalidInputError: if attributes are not validly set.
        """
    for arg, value in arg_dict.items():
        if arg[0].isupper() and value is not None:
            setattr(arg_dict['instance'], arg.lower(), value)
    for arg, value in arg_dict.items():
        if arg == 'instance':
            continue
        if not arg[0].isupper() and value is not None:
            setattr(arg_dict['instance'], arg, value)


def _root_task(worker):
    """
    Return the first task scheduled by the worker, corresponding to the root task
    """
    return worker._add_task_history[0][0]


@classmethod
def from_file(cls, flo):
    """
        Create a new, parsed `SSHConfig` from file-like object ``flo``.

        .. versionadded:: 2.7
        """
    obj = cls()
    obj.parse(flo)
    return obj


@staticmethod
def search_for_items(document, selection_objects):
    """

        # todo: This search is currently restricted to GSD objects only.

        Selection objects is a list of items to search for.
        Example: selection_objects = ['Point', 'Line']

        Example query string to search for all lines and points
        "('Generative Shape Design'.Point + 'Generative Shape Design'.Line),in"

        :param document:
        :param list selection_objects:
        :return Selected Automation Object:
        """
    gsd_items = ['Point', 'Line']
    query_string = str()
    for counter, item in enumerate(selection_objects):
        boolean = str()
        if counter > 0 and not counter == len(selection_objects):
            boolean = ' + '
        if item in gsd_items:
            query_string = (
                f"{query_string}{boolean}'Generative Shape Design'.{item}")
    query_string = f'({query_string}),in'
    selection = document.document.Selection
    selection.Search(query_string)
    selected = list()
    for i in range(0, selection.Count):
        selected.append(selection.Item(i + 1).Value)
    return selected


def channels_select_all_toggle(invert: bool=False):
    """Toggle selection of all animation channels

    :param invert: Invert
    :type invert: bool
    """
    pass


def modifier_convert(modifier: str=''):
    """Convert particles to a mesh object

    :param modifier: Modifier, Name of the modifier to edit
    :type modifier: str
    """
    pass


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 is_classifier(estimator):
    """
    Returns True if the given estimator is (probably) a classifier.

    Parameters
    ----------
    estimator : class or instance
        The object to test if it is a Scikit-Learn clusterer, especially a
        Scikit-Learn estimator or Yellowbrick visualizer

    See also
    --------
    is_classifier
        `sklearn.is_classifier() <https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/base.py#L518>`_
    """
    return getattr(estimator, '_estimator_type', None) == 'classifier'


def psi_K_Na_CO3_HMW84(T, P):
    """c-c'-a: potassium sodium carbonate [HMW84]."""
    psi = 0.003
    valid = T == 298.15
    return psi, valid


def sentinel2_toa_cloud_mask(input_img):
    """Extract cloud mask from the Sentinel 2 TOA QA60 band

    Parameters
    ----------
    input_img : ee.Image
        Image from the COPERNICUS/S2 collection with a QA60 band.

    Returns
    -------
    ee.Image

    Notes
    -----
    Output image is structured to be applied directly with updateMask()
        i.e. 0 is cloud, 1 is cloud free

    Bits
        10: Opaque clouds present
        11: Cirrus clouds present

    The Sentinel 2 TOA and SR cloud masks functions are currently identical

    References
    ----------
    https://sentinel.esa.int/documents/247904/685211/Sentinel-2_User_Handbook
    https://sentinel.esa.int/web/sentinel/technical-guides/sentinel-2-msi/level-1c/cloud-masks

    """
    qa_img = input_img.select(['QA60'])
    cloud_mask = qa_img.rightShift(10).bitwiseAnd(1).neq(0).Or(qa_img.
        rightShift(11).bitwiseAnd(1).neq(0))
    return cloud_mask.Not()


def extract_metrics(qm_assessment):
    """
    Extract all metrics from a quality model assessment
    :param qm_assessment: a dict with the quality model assessment
    :return: a list with all the metrics
    """
    metrics = []
    for goal in qm_assessment:
        for attr in qm_assessment[goal]:
            for metric in qm_assessment[goal][attr]:
                metrics.append(qm_assessment[goal][attr][metric])
    return metrics


@classmethod
def enable(cls):
    """Enable collecting and reporting metrics.
        """
    return cls.build_send_payload('enable', {}), None


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

        :param EmmErrorType val:
        :rtype: EventType
        """
    return cls('emm_error', val)


def add_to_partition(cloudtrail_bucket, account, region, year, month):
    """ Returns query for adding partition to behold Athena table. """
    query_string = f"""ALTER TABLE behold
        ADD PARTITION (account='{account}', region='{region}', year='{year}', month='{month}')
        LOCATION 's3://{cloudtrail_bucket}/AWSLogs/{account}/CloudTrail/{region}/{year}/{month}/';"""
    return (query_string,
        f'setup/add_to_partition/{account}-{region}-{year}-{month}')


def partition(lst, nslices):
    """partition a list into N slices of roughly equal size

    The current strategy takes every Nth element from the input. If
    we ever write workers that need to preserve grouping in input
    we should consider allowing callers to specify a partition strategy.

    mpm is not a fan of this partitioning strategy when files are involved.
    In his words:

        Single-threaded Mercurial makes a point of creating and visiting
        files in a fixed order (alphabetical). When creating files in order,
        a typical filesystem is likely to allocate them on nearby regions on
        disk. Thus, when revisiting in the same order, locality is maximized
        and various forms of OS and disk-level caching and read-ahead get a
        chance to work.

        This effect can be quite significant on spinning disks. I discovered it
        circa Mercurial v0.4 when revlogs were named by hashes of filenames.
        Tarring a repo and copying it to another disk effectively randomized
        the revlog ordering on disk by sorting the revlogs by hash and suddenly
        performance of my kernel checkout benchmark dropped by ~10x because the
        "working set" of sectors visited no longer fit in the drive's cache and
        the workload switched from streaming to random I/O.

        What we should really be doing is have workers read filenames from a
        ordered queue. This preserves locality and also keeps any worker from
        getting more than one file out of balance.
    """
    for i in range(nslices):
        yield lst[i::nslices]


def flag_modified(instance, key):
    """Wrapper around `sqlalchemy.orm.attributes.flag_modified` to correctly dereference utils.ModelWrapper

    Since SqlAlchemy 1.2.12 (and maybe earlier but not in 1.0.19) the flag_modified function will check that the
    key is actually present in the instance or it will except. If we pass a model instance, wrapped in the ModelWrapper
    the call will raise an InvalidRequestError. In this function that wraps the flag_modified of SqlAlchemy, we
    derefence the model instance if the passed instance is actually wrapped in the ModelWrapper.
    """
    from sqlalchemy.orm.attributes import flag_modified as flag_modified_sqla
    from aiida.orm.implementation.sqlalchemy.utils import ModelWrapper
    if isinstance(instance, ModelWrapper):
        instance = instance._model
    flag_modified_sqla(instance, key)


def reset_time(evs, field, source='timestamps'):
    """Reset the time field on the event.

    Promote a specific timestamp to be the time of the whole
    event.

    Parameters
    ----------
    evs : iterable
        Iterable of events to work on

    field : str
        The field to use for the value

    source : {'timestamps', 'data'}, optional
        Where to look for that field

    Yields
    ------
    events
    """
    for ev in evs:
        ev = dict(ev)
        ev['time'] = ev[source][field]
        yield ev


def isLinked(source=None, target=None, maxDepth=1, filter=None):
    """given source, target, or both, return True if a link exists.

        maxDepth is the number of relationships through which the search
        should walk transitively.  It must be a positive integer.

        filter is an optional callable that takes a relationship and returns
        a boolean True value if it should be included, and a False if not.
        """


def printf(format, *args):
    """Emulation of more common printf() print function."""
    from sys import stdout
    stdout.write(format % args)


@classmethod
def get_elasticsearch_schema(clz, _es_version):
    """
        Returns the elasticsearch schema for the _invenio_explicit_acls property.

        The property looks like::

            _invenio_explicit_acls [{
               "timestamp": "...when the ACL has been applied to the resource",
               "acl": <id of the acl>,
               "operation": name of the operation
                user: [1, 2, 3]
            }]

        :return:
        """
    return {'type': 'integer'}


def config_logger(filename='epquery.log', level='DEBUG'):
    """
    Configure logger using logging.basicConfig. Use only if you don't
    have your own logger in your application.

    :param str filename: Log file name
    :param str level: Logging level ('DEBUG', 'WARNING', 'ERROR', 'INFO')
    """
    import logging
    logging.basicConfig(filename=filename, filemode='w', level=level,
        format='[%(asctime)s][%(name)s][%(levelname)s] %(message)s')


def settrace(func):
    """Set a trace function for all threads started from the threading module.

    The func will be passed to sys.settrace() for each thread, before its run()
    method is called.

    """
    global _trace_hook
    _trace_hook = func