def delete_stack(StackName=None, RetainResources=None, RoleARN=None,
    ClientRequestToken=None):
    """
    Deletes a specified stack. Once the call completes successfully, stack deletion starts. Deleted stacks do not show up in the  DescribeStacks API if the deletion has been completed successfully.
    See also: AWS API Documentation

    :example: response = client.delete_stack(
        StackName='string',
        RetainResources=[
            'string',
        ],
        RoleARN='string',
        ClientRequestToken='string'
    )

    :type StackName: string
    :param StackName: [REQUIRED]
            The name or the unique stack ID that is associated with the stack.

    :type RetainResources: list
    :param RetainResources: For stacks in the DELETE_FAILED state, a list of resource logical IDs that are associated with the resources you want to retain. During deletion, AWS CloudFormation deletes the stack but does not delete the retained resources.
            Retaining resources is useful when you cannot delete a resource, such as a non-empty S3 bucket, but you want to delete the stack.
            (string) --

    :type RoleARN: string
    :param RoleARN: The Amazon Resource Name (ARN) of an AWS Identity and Access Management (IAM) role that AWS CloudFormation assumes to delete the stack. AWS CloudFormation uses the role's credentials to make calls on your behalf.
            If you don't specify a value, AWS CloudFormation uses the role that was previously associated with the stack. If no role is available, AWS CloudFormation uses a temporary session that is generated from your user credentials.

    :type ClientRequestToken: string
    :param ClientRequestToken: A unique identifier for this DeleteStack request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to delete a stack with the same name. You might retry DeleteStack requests to ensure that AWS CloudFormation successfully received them.

    """
    pass


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 is_tlist(obj, **kwargs):
    """
        is_tlist([(1,2),(3,4)])
        is_tlist([(1,2,3),(4,5,6)])
        is_tlist([(1,2,3),(4,5,6)],width=3)

        is_tlist([(1,2),(3,)])
        is_tlist([(1,),(2,)])
        is_tlist([(1,),(2,)],width=1)

    """
    if 'width' in kwargs:
        width = kwargs['width']
    else:
        width = 2
    if isinstance(obj, list):
        pass
    else:
        return False
    if obj == []:
        return True
    else:
        cond = True
        for each in obj:
            if isinstance(each, tuple):
                if each.__len__() == width:
                    pass
                else:
                    return False
            else:
                return False
        return cond


def scale(scale: list):
    """Scale the current stack matrix.

    :param scale: Scale the current stack matrix.
    :type scale: list
    """
    pass


@classmethod
def has_resuming(cls):
    """Returns whether it supports to resume the fetch process.

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


@classmethod
def from_task(cls, task, current_time):
    """Constructs a TaskSample from a task

        Args:
            task (Task): The task to sample
            current_time (datetime): The current datetime used to sample the task

        Returns:
            TaskSample: The constructed sample
        """
    return cls(task.get_duration_sample(current_time), task.
        get_earliest_start_sample(current_time), task.
        get_latest_finish_sample())


@classmethod
def from_unpack_list(cls, *args):
    """
        Given a list of raw arguments, initialize a new cls instance.

        If this class has special rules for certain fields, apply them.
        """
    unpack_args = list(args)
    for i in range(len(args)):
        custom_rule = 'fix_unpack_' + cls.names[i]
        if hasattr(cls, custom_rule):
            unpack_args[i] = getattr(cls, custom_rule)(args[i])
    return cls(*unpack_args)


def words(byte_stream):
    """A generator that delivers a stream of 16 bit numbers, given a stream of bytes"""
    low = None
    for b in byte_stream:
        if low is not None:
            yield low + (b << 8)
            low = None
        else:
            low = b
    if low is not None:
        yield low


def project_to_package(project):
    """
    >>> print(project_to_package('abcdef'))
    abcdef
    >>> print(project_to_package('abc_DEF'))
    abc_DEF
    >>> print(project_to_package('abc-D..EF'))
    abc_D_EF
    """
    tmp = []
    for c in project:
        if 'a' <= c.lower() <= 'z' or c == '_':
            tmp.append(c)
        elif not tmp or tmp[-1] != '_':
            tmp.append('_')
        else:
            pass
    return ''.join(tmp)


def confRegions2PPlanes(majorAxis, minorAxis, theta, want2plot=True,
    confLvl=0.95):
    """Determines the :math:`\\mathbb{R}^2` coordinates of each confidence
    ellipse in the local Cartesyan System of the :math:`\\mathscr{P}-` planes
    that contain them. It is donde from their geometric parameters obtained
    from the ``eigVectsRegions`` function. If it is wanted,
    plots them too.

    Parameters:
        majorAxis (`numpy.ndarray`): Array with the three lengths of the
            ellipses' major axis that define the confidence region. The order
            is acording to the principal values returned from the
            ``getEigSorted`` function.
        minorAxis (`list`): list with the three couples of
            :math:`\\boldsymbol{\\mathrm{W}_i}`'s eigenvalues obtained with
            the ``getEigSorted`` function. The order is acording to the
            principal values returned from the ``getEigSorted`` function.
        theta (`list`): list with the three ellipse inclinations in radians
            measured from the horizontal axis of the local Cartesian System of
            each ellipse to the respective major axis counter clockwise.
        want2plot (`bool`): Logical variable to indicate if is wanted to plot
            the ellipes. ``True`` is the default value.
        confLvl (`float`): Confidence level of the limits of the
            variabilities of :math:`\\boldsymbol{k}`'s principal vectors and
            values. ``0.95`` is the default value.

    Returns:
        Three elements are returned; they are described below.

            - **x** (`list`): List of three arrays that contain the abscises                of the each ellipse.
            - **y** (`list`): List of three arrays that contain the ordinates                of the each ellipse.
            - **fig** (`list`): ``matplotlib`` object. use ``fig.show()`` for                displaying the plot

    Examples:
        >>> from numpy import array
        >>> from jelinekstat.tools import confRegions2PPlanes
        >>> majorAxis = array([ 0.66888885,  0.66949335,  0.13745895])
        >>> minorAxis = array([ 0.09950548,  0.09615434,  0.04640122])
        >>> theta = array([-0.01949436, -1.51693959, -0.81162812])
        >>> x, y, fig = confRegions2PPlanes(majorAxis, minorAxis, theta,
        >>>                                 want2plot=True, confLvl=0.95)
        >>> fig.show()

    .. figure:: https://rawgit.com/eamontoyaa/jelinekstat/master/examples/figures/tools_confRegions2PPlanes_example.svg
        :alt: tools_confRegions2PPlanes_example

    .. only:: html

       :download:`example script<../examples/figuresScripts/tools_confRegions2PPlanes_example.py>`.

    """
    import numpy as np
    import matplotlib.pyplot as plt
    numPoints = 500
    confLvl = round(confLvl * 100, 1)
    phi = np.linspace(0, 2 * np.pi, numPoints)
    x, y = list(), list()
    for i in range(3):
        rotMatrix = np.array([[np.cos(theta[i]), -np.sin(theta[i])], [np.
            sin(theta[i]), np.cos(theta[i])]])
        rotMatrix = [rotMatrix] * numPoints
        xyNoRot = np.array([np.cos(phi) * majorAxis[i], np.sin(phi) *
            minorAxis[i]]).T
        xyRot = np.array(list(map(np.dot, rotMatrix, xyNoRot)))
        x.append(xyRot[:, (0)])
        y.append(xyRot[:, (1)])
        plt.ioff()
        fig = plt.figure(num='Confidence regions')
        eigenVectName = ['major', 'intermediate', 'minor']
        xLabel = ['$p_2$', '$p_3$', '$p_1$']
        yLabel = ['$p_3$', '$p_1$', '$p_2$']
        if want2plot:
            ax = fig.add_subplot(1, 3, i + 1)
            ax.plot(x[i], y[i], '-k')
            ax.axis('equal')
            ax.grid(True, ls='--', lw=0.5)
            ax.set_xlabel(xLabel[i])
            ax.set_ylabel(yLabel[i])
            ax.set_title(str(confLvl) + '% confidence ellipse \nof ' +
                eigenVectName[i] + ' eigenvector', fontweight='bold',
                fontsize=9)
            ax.tick_params(labelsize=7)
            fig.subplots_adjust(wspace=0.7)
    return x, y, fig


def check_true(val, message):
    """
    Tests whether the provided expression is ``true``.

    :param val: (bool), the expression tested to see if it is ``true``.
    :param message: (str), the error message.
    """
    if not val:
        raise AssertionError(message)


def read_library_binary(lib_filename):
    """Read compiled shared library as binary blob into a numpy byte array."""
    import numpy
    return numpy.fromfile(lib_filename, dtype=numpy.uint8)


def Sphere2xyz(coords, lam=None, phi=None):
    """Compute (x,y,z) from coords=(r,lam,phi) or r,lam,phi, where lam=0 at the Equator, -90 <= lam <= 90 (latitude),
        and phi=0 along x-axis, 0 <= phi <= 360 (longitude)
        Also computes the normal along the radial direction (useful for placing and orienting the camera).

        INPUTS:
            coords - list of (radius,lambda,phi) or radius
            lam    - lambda (declination, latitude) if coords is radius
            phi    - phi (azimuth, longitude) if coords is radius
        OUTPUTS:
            xyzPos - list of corresponding (x,y,z)
            normal - list of (xn,yn,zn) along radial direction
    """
    from math import pi, sin, cos
    if isinstance(coords, list) or isinstance(coords, tuple):
        if len(coords) == 3:
            rr = coords[0]
            lam = coords[1]
            phi = coords[2]
        else:
            raise Exception(
                'Sphere2xyz: coords has to be a list of length 3 (r,lambda,phi), or a scalar'
                )
    else:
        rr = coords
    xyzPos = [rr * cos(lam * pi / 180) * cos(phi * pi / 180), rr * cos(lam *
        pi / 180) * sin(phi * pi / 180), rr * sin(lam * pi / 180)]
    rr = rr + 1
    p1 = [rr * cos(lam * pi / 180) * cos(phi * pi / 180), rr * cos(lam * pi /
        180) * sin(phi * pi / 180), rr * sin(lam * pi / 180)]
    normal = []
    for i in range(len(p1)):
        normal.append(p1[i] - xyzPos[i])
    return xyzPos, normal


def final(f):
    """This decorator can be used to indicate to type checkers that
    the decorated method cannot be overridden, and decorated class
    cannot be subclassed. For example:

        class Base:
            @final
            def done(self) -> None:
                ...
        class Sub(Base):
            def done(self) -> None:  # Error reported by type checker
                ...
        @final
        class Leaf:
            ...
        class Other(Leaf):  # Error reported by type checker
            ...

    There is no runtime checking of these properties.
    """
    return f


def get_tag_index(node, tag):
    """Return the (first) index of tag in node.

    If tag is not found, -1 is returned.
    """
    for i, elem in enumerate(list(node)):
        if elem.tag == tag:
            return i
    return -1


@staticmethod
def _on_alarm(signum, _frame):
    """Invoked when the alarm is raised every 5 seconds while processing"""
    pass


def do_byteswap(arr):
    """
    Return a copy of an array, byteswapped.
    """
    return arr.byteswap().view(arr.dtype.newbyteorder('>'))


def sort_data(data, cols):
    """Sort data rows and order columns by cols"""
    return data.sort_values(cols)[cols + ['value']].reset_index(drop=True)


def loadbalancer_not_found():
    """
    Verified 2015-06-16:
    - when trying to update a CLB node on a CLB that doesn't exist

    :return: a `tuple` of (dict body message, 404 http status code)
    """
    return {'message': 'Load balancer not found', 'code': 404}, 404


def emissivity(T_air):
    """Apparent atmospheric emissivity

    Apparent emissivity (Sedlar and Hock, 2009: Cryosphere 3:75-84)
    Atmospheric emissivity (clear-sky) Idso and Jackson (1969)

    Parameters
    ----------
    T_air : ee.Image
        Air temperature (Kelvin)

    Returns
    -------
    e_atm : ee.Image

    """
    e_atm = T_air.expression(
        '1.0 - (0.2811 * (exp(-0.0003523 * ((T_air - 273.16) ** 2.0))))', {
        'T_air': T_air})
    return e_atm


def __add__(other):
    """Create a collection as copy of self, and add value for
        other component or collection.
        """


def is_independent_set(G, indep_nodes):
    """Determines whether the given nodes form an independent set.

    An independent set is a set of nodes such that the subgraph
    of G induced by these nodes contains no edges.

    Parameters
    ----------
    G : NetworkX graph
       The graph on which to check the independent set.

    indep_nodes : list
       List of nodes that form a maximum independent set, as
       determined by the given sampler.

    Returns
    -------
    is_independent : bool
        True if indep_nodes form an independent set.

    Example
    -------
    This example checks two sets of nodes, both derived from a
    single Chimera unit cell, for an independent set. The first set is
    the horizontal tile's nodes; the second has nodes from the horizontal and
    verical tiles.

    >>> import dwave_networkx as dnx
    >>> G = dnx.chimera_graph(1, 1, 4)
    >>> dnx.is_independent_set(G, [0, 1, 2, 3])
    True
    >>> dnx.is_independent_set(G, [0, 4])
    False

    """
    return len(G.subgraph(indep_nodes).edges) == 0


@classmethod
def models_get(cls):
    """
        Return valid models allowed for origin
        """
    return [('sale.sale', 'Sale'), ('sale.line', 'Sale Line')]


@classmethod
def get_market_ticker(cls, pair):
    """returns simple current market status report"""
    return cls.api(cls.url + '/exchange/ticker?currencyPair=' + cls.
        format_pair(pair))


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

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

    """
    pass


@classmethod
def unique_routes_at_stop(cls, session, stop_id, agency_id=None, date=None,
    route_name_filter=False):
    """
        get a unique set of route records by looking for a given stop_id.
        further filtering can be had by providing an active date and agency id, and route name
        """
    ret_val = []
    route_ids = []
    route_names = []
    route_stops = cls.query_by_stop(session, stop_id, agency_id, date, sort
        =True)
    for rs in route_stops:
        if rs.route_id in route_ids:
            continue
        if route_name_filter and rs.route.route_name in route_names:
            continue
        route_ids.append(rs.route_id)
        route_names.append(rs.route.route_name)
        ret_val.append(rs.route)
    return ret_val


def pastebuffer(autoselect: bool=True, active_collection: bool=True):
    """Objects from the clipboard are pasted

    :param autoselect: Select, Select pasted objects
    :type autoselect: bool
    :param active_collection: Active Collection, Put pasted objects in the active collection
    :type active_collection: bool
    """
    pass


def getName():
    """Return the last segment of the physical path."""


@classmethod
def enQ(cls, f):
    """Enqueue a zero-argument function into the parsing queue"""
    cls.parsingQ.appendleft(f)


@classmethod
def utcnow(cls):
    """
        Return the current UTC date and time as :class:`.Zulu` object.

        Returns:
            :class:`.Zulu`
        """
    return cls.now()


def pseudocode(algorithm):
    """Print the pseudocode for the given algorithm."""
    from urllib.request import urlopen
    from IPython.display import Markdown
    algorithm = algorithm.replace(' ', '-')
    url = (
        'https://raw.githubusercontent.com/aimacode/aima-pseudocode/master/md/{}.md'
        .format(algorithm))
    f = urlopen(url)
    md = f.read().decode('utf-8')
    md = md.split('\n', 1)[-1].strip()
    md = '#' + md
    return Markdown(md)


def dump_cell_types(table):
    """ Return cell type in table, just for debugging """
    out_str = ''
    for i, _ in enumerate(table):
        current_row = ''
        for j, _ in enumerate(table[i]):
            current_row += 'None\t' if table[i][j] is None else table[i][j
                ].cell_type + '\t'
        out_str += current_row + '\n'
    return out_str


@classmethod
def enable(cls):
    """Enables the accessibility domain which causes `AXNodeId`s to remain consistent between method calls.
This turns on accessibility for the page, which can impact performance until accessibility is disabled.
        """
    return cls.build_send_payload('enable', {}), None


@classmethod
def get_dispatch_endpoint_url(cls, action: str) ->str:
    """Get dispatch endpoint URL depending on region"""
    return 'https://{}-disp.coolkit.cc:8080/{}'.format(cls._region, action)


def old_path_from_new_path(path: str) ->str:
    """Convert a new path to an old one.

    Useful for bucket migration. This is an example implementation.
    """
    parts = path.split('/')
    filename = parts[-1]
    md5 = filename.split('.')[0]
    first_dir = parts[0]
    namespace = ''.join(filter(str.isnumeric, first_dir))
    return namespace + '-' + md5


def _write_experiment_archive(exp_id, data):
    """ Write experiment archive contained in 'data' to 'exp_id.tar.gz' """
    with open('%s.tar.gz' % exp_id, 'wb') as archive:
        archive.write(data)


def get_cigar(var):
    """
    Return the cigar string describing how to align an
    alternate allele to the reference allele
    """
    return var.INFO.get('CIGAR')


def sample_builder(samples):
    """
    Given a dictionary with value: count pairs, build a list.
    """
    data = []
    for key in samples:
        data.extend([key] * samples[key])
    data.sort()
    return data


def bi_var_equal(var1, unifier1, var2, unifier2):
    """Check var equality.

    Returns True iff variable VAR1 in unifier UNIFIER1 is the same
    variable as VAR2 in UNIFIER2.
    """
    return var1 == var2 and unifier1 is unifier2


@classmethod
def _flatten_param(cls, params):
    """
        Flatten the query params to be compatible with the API.
        :param params: The params object to process.
        :return: Nested dict/list values are flatten into single level dict.
        """
    flatten = params
    if type(params) in [dict, list]:
        flatten = {}
        for k, v in (params.items() if type(params) is dict else enumerate(
            params)):
            f = cls._flatten_param(v)
            if type(f) is dict:
                for kk, vv in f.items():
                    flatten[u'%s.%s' % (k, kk)] = vv
            else:
                flatten[k] = v
    return flatten


def create_tree(gi, found_lib, folders):
    """
    Create a directory structure in the given library.
    Returns the id of the last folder of the tree
    """
    dist_folders = gi.libraries.get_folders(found_lib)
    dist_f = {}
    for f in dist_folders:
        dist_f[f['name']] = f
    path = ''
    last_f_id = None
    folder_to_create = []
    for f in folders:
        path += '/' + f
        if path in dist_f:
            print('Found folder ' + f)
            last_f_id = dist_f[path]['id']
        else:
            print('Did not find folder ' + f)
            folder_to_create.append(f)
    if len(folder_to_create) > 0:
        for f in folder_to_create:
            if last_f_id:
                print('Creating folder ' + f + ' in folder ' + last_f_id)
                f_c = gi.libraries.create_folder(found_lib, f, '', last_f_id)
            else:
                print('Creating folder ' + f + ' in root folder')
                f_c = gi.libraries.create_folder(found_lib, f, '')
            last_f_id = f_c[0]['id']
    return last_f_id


def focal_point(distance_image, distance_object):
    """Usage: Find focal point with distance of image and distance of object"""
    numerator = distance_image * distance_object
    denominator = distance_image + distance_object
    return numerator / denominator


def example_networkx(ax=None, **options):
    """
    example using networks

    @param      ax          axis
    @param      options     look at the code
    @return                 ax
    """
    import networkx as nx
    import matplotlib.pyplot as plt
    G = nx.random_geometric_graph(200, 0.125)
    pos = nx.get_node_attributes(G, 'pos')
    dmin = 1
    ncenter = 0
    for n in pos:
        x, y = pos[n]
        d = (x - 0.5) ** 2 + (y - 0.5) ** 2
        if d < dmin:
            ncenter = n
            dmin = d
    p = nx.single_source_shortest_path_length(G, ncenter)
    if ax is None:
        _, ax = plt.subplots(nrows=1, ncols=1, figsize=options.get(
            'figsize', (5, 5)))
    nx.draw_networkx_edges(G, pos, nodelist=[ncenter], alpha=0.4, ax=ax)
    nx.draw_networkx_nodes(G, pos, nodelist=p.keys(), node_size=80, ax=ax)
    ax.set_xlim(-0.05, 1.05)
    ax.set_ylim(-0.05, 1.05)
    ax.axis('off')
    return ax


def _gene2n_transcripts(data):
    """
    Return a dictionary from gene id to number of transcripts in the gene.
    """
    return data.groupby('GeneID').apply(lambda df: len(set(df.
        TranscriptIDCluster))).to_dict()


def shape_propagate_to_all():
    """Apply selected vertex locations to all other shape keys

    """
    pass


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


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


def get_key_rotation_status(KeyId=None):
    """
    Retrieves a Boolean value that indicates whether key rotation is enabled for the specified key.
    See also: AWS API Documentation

    Examples
    The following example retrieves the status of automatic annual rotation of the key material for the specified CMK.
    Expected Output:

    :example: response = client.get_key_rotation_status(
        KeyId='string'
    )

    :type KeyId: string
    :param KeyId: [REQUIRED]
            A unique identifier for the customer master key. This value can be a globally unique identifier or the fully specified ARN to a key.
            Key ARN Example - arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012
            Globally Unique Key ID Example - 12345678-1234-1234-1234-123456789012

    :rtype: dict
    :return: {
        'KeyRotationEnabled': True|False
    }

    """
    pass


def load_handlers(name):
    """Load the (URL pattern, handler) tuples for each component."""
    mod = __import__(name, fromlist=['default_handlers'])
    return mod.default_handlers


def index(a):
    """Same as a.__index__()."""
    return a.__index__()


def create_tests(df, output_file, columns=None):
    """
    Creates ScienceOps compatible (JSON Line Format) smoke test files from your dataframes.
    Once created, these files can be uploaded directly to your model via ScienceOps --> '/models/{model}/unit-tests'

    Parameters
    ----------
    df: dataframe
        the dataframe you wish to pull test inputs from
    output_file: string
        the name you will give your exported test file
    columns: array of strings
        the columns in your df which will be made into inputs

    Example
    -------
    Let's say you've built a book recommender model that takes 2 inputs - title & page count:

    from yhat.utils import create_tests
    books =  pd.read_csv('./book_data.csv')
    create_tests(books, "book_model_inputs.ldjson", columns=["title","pages"])
    * That's it! *
    --> book_model_inputs.ldjson {"title":"harry potter","pages":"800"}\\n{"title":"war and peace","pages":"875"}\\n{"title":"lord of the rings","pages":"500"}

      """
    if columns is None:
        columns = df.columns
    with open(output_file, 'wb') as f:
        for _, row in df[columns].iterrows():
            f.write(row.to_json() + '\n')


def get_repo_from_tool(tool):
    """
    Get the minimum items required for re-installing a (list of) tools
    """
    if not tool.get('tool_shed_repository', None):
        return {}
    tsr = tool['tool_shed_repository']
    repo = {'name': tsr['name'], 'owner': tsr['owner'], 'tool_shed_url':
        tsr['tool_shed'], 'revisions': [tsr['changeset_revision']],
        'tool_panel_section_id': tool['panel_section_id'],
        'tool_panel_section_label': tool['panel_section_name']}
    return repo


def get_font_features(font_kerning='normal', font_variant_ligatures=
    'normal', font_variant_position='normal', font_variant_caps='normal',
    font_variant_numeric='normal', font_variant_alternates='normal',
    font_variant_east_asian='normal', font_feature_settings='normal'):
    """Get the font features from the different properties in style.

    See https://www.w3.org/TR/css-fonts-3/#feature-precedence

    """
    features = {}
    ligature_keys = {'common-ligatures': ['liga', 'clig'],
        'historical-ligatures': ['hlig'], 'discretionary-ligatures': [
        'dlig'], 'contextual': ['calt']}
    caps_keys = {'small-caps': ['smcp'], 'all-small-caps': ['c2sc', 'smcp'],
        'petite-caps': ['pcap'], 'all-petite-caps': ['c2pc', 'pcap'],
        'unicase': ['unic'], 'titling-caps': ['titl']}
    numeric_keys = {'lining-nums': 'lnum', 'oldstyle-nums': 'onum',
        'proportional-nums': 'pnum', 'tabular-nums': 'tnum',
        'diagonal-fractions': 'frac', 'stacked-fractions': 'afrc',
        'ordinal': 'ordn', 'slashed-zero': 'zero'}
    east_asian_keys = {'jis78': 'jp78', 'jis83': 'jp83', 'jis90': 'jp90',
        'jis04': 'jp04', 'simplified': 'smpl', 'traditional': 'trad',
        'full-width': 'fwid', 'proportional-width': 'pwid', 'ruby': 'ruby'}
    if font_kerning != 'auto':
        features['kern'] = int(font_kerning == 'normal')
    if font_variant_ligatures == 'none':
        for keys in ligature_keys.values():
            for key in keys:
                features[key] = 0
    elif font_variant_ligatures != 'normal':
        for ligature_type in font_variant_ligatures:
            value = 1
            if ligature_type.startswith('no-'):
                value = 0
                ligature_type = ligature_type[3:]
            for key in ligature_keys[ligature_type]:
                features[key] = value
    if font_variant_position == 'sub':
        features['subs'] = 1
    elif font_variant_position == 'super':
        features['sups'] = 1
    if font_variant_caps != 'normal':
        for key in caps_keys[font_variant_caps]:
            features[key] = 1
    if font_variant_numeric != 'normal':
        for key in font_variant_numeric:
            features[numeric_keys[key]] = 1
    if font_variant_alternates != 'normal':
        if font_variant_alternates == 'historical-forms':
            features['hist'] = 1
    if font_variant_east_asian != 'normal':
        for key in font_variant_east_asian:
            features[east_asian_keys[key]] = 1
    if font_feature_settings != 'normal':
        features.update(dict(font_feature_settings))
    return features


@classmethod
def get_or_create(cls, id, client=None, **kwargs):
    """Get an existing object from the Descartes Labs catalog or create a new object.

        If the Descartes Labs catalog object is found, and the remainder of the
        arguments do not differ from the values in the retrieved instance, it will be
        returned in the `~descarteslabs.catalog.DocumentState.SAVED` state.

        If the Descartes Labs catalog object is found, and the remainder of the
        arguments update one or more values in the instance, it will be returned in
        the `~descarteslabs.catalog.DocumentState.MODIFIED` state.

        If the Descartes Labs catalog object is not found, it will be created and the
        state will be `~descarteslabs.catalog.DocumentState.UNSAVED`.  Also see the
        example for :py:meth:`save`.

        Parameters
        ----------
        id : str
            The id of the object you are requesting.
        client : CatalogClient, optional
            A `CatalogClient` instance to use for requests to the Descartes Labs
            catalog.  The
            :py:meth:`~descarteslabs.catalog.CatalogClient.get_default_client` will
            be used if not set.
        kwargs : dict, optional
            With the exception of readonly attributes (`created`, `modified`), any
            attribute of a catalog object can be set as a keyword argument (Also see
            `ATTRIBUTES`).

        Returns
        -------
        :py:class:`~descarteslabs.catalog.CatalogObject`
            The requested catalog object that was retrieved or created.

        """
    obj = cls.get(id, client=client)
    if obj is None:
        obj = cls(id=id, client=client, **kwargs)
    else:
        obj.update(**kwargs)
    return obj


def _str_parser(str_list, seperator=',', strip=True, pop_check=False):
    """Converts a sets of inputs with a common seperator. strip applies `str.strip()` to all values
    It can also list.pop() the last variable if it's empty(enable it with `pop_check`)"""
    if str_list is None:
        print('Error : ' + str_list + ' is empty.')
        return None
    split_list = str_list.split(seperator)
    if strip is True:
        for idx, name in enumerate(split_list):
            split_list[idx] = name.strip()
    while split_list[len(split_list) - 1] == '' and pop_check is True:
        split_list.pop()
    else:
        return split_list


def vert_connect():
    """Connect selected vertices of faces, splitting the face

    """
    pass


def gammaln(data=None, name=None, attr=None, out=None, **kwargs):
    """Returns element-wise log of the absolute value of the gamma function \\
    of the input.

    The storage type of ``gammaln`` output is always dense

    Parameters
    ----------
    data : Symbol
        The input array.

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

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


@classmethod
def as_list(cls, *init_args, **init_kwargs):
    """
        Used for hooking up the actual list-style endpoints, this returns a
        wrapper function that creates a new instance of the resource class &
        calls the correct view method for it.

        :param init_args: (Optional) Positional params to be persisted along
            for instantiating the class itself.

        :param init_kwargs: (Optional) Keyword params to be persisted along
            for instantiating the class itself.

        :returns: View function
        """
    return cls.as_view('list', *init_args, **init_kwargs)


def get_content():
    """Return ALL content class availables for this extension.
        """


def add_notebook(args, library_db):
    """add a notebook to sqlite database"""
    import os
    from src.praxxis.library import sync_library
    root = os.path.sep.join(os.path.abspath(args.path).split(os.path.sep)[:-1])
    notebook_name = args.path.split(os.path.sep)[-1]
    print(root)
    relative_path = ''
    sync_library.load_notebook(notebook_name, root, library_db, 'none',
        relative_path)


def isCurrentDay():
    """Return true if this object represents a date/time that
        falls within the current day, in the context of this object's
        timezone representation"""


def load_json_file(infile):
    """Read file.  Strip out lines that begin with '//'."""
    lines = []
    for line in infile:
        if not line.lstrip().startswith('//'):
            lines.append(line)
    content = ''.join(lines)
    return content


def webbrowser(url):
    """Download the http/https resource given by the URL"""
    import requests
    r = requests.get(url)
    return r.text


@staticmethod
def _clean_weekday_param(weekday_arg):
    """
        Takes the given weekday argument from the user and returns a
        set of integers for input.
        :param weekday_arg: (int) or (str) or (list) or (tuple)
        input argument from user
        :return: (set)
        """
    _weekday_lookup = {'Monday': 0, 'Tuesday': 1, 'Wednesday': 2,
        'Thursday': 3, 'Friday': 4, 'Saturday': 5, 'Sunday': 6}
    if isinstance(weekday_arg, str):
        _cleaned_arg = {_weekday_lookup[weekday_arg.title()]}
    elif isinstance(weekday_arg, int) and weekday_arg in range(0, 7):
        _cleaned_arg = {weekday_arg}
    elif isinstance(weekday_arg, list) or isinstance(weekday_arg, tuple):
        _cleaned_arg = set()
        for w in weekday_arg:
            if isinstance(w, str):
                w = _weekday_lookup[w.title()]
            elif isinstance(w, int) and w in range(0, 7):
                w = w
            _cleaned_arg.add(w)
    return sorted(list(_cleaned_arg))


@staticmethod
def _build_name(name_id):
    """Formats names for storage

        Explored data is stored as 'xp_XXXXXXXX' where 'XXXXXXXX' is the index of the object.

        """
    return 'xp_%08d' % name_id


def __setitem__(specification, instance):
    """
        Saves a cached `instance` for given :term:`specification`. If there was
        already a cached instance for this specification, it is overriden.
        """


def open_vol(final_vol):
    """Converts the array of volumes with comp volumes to two lists of separate volumes"""
    number = len(final_vol[0])
    open_vol = []
    for i in range(number):
        string = 'comp' + str(i)
        string = []
        for row in final_vol:
            hold = row[i]
            string.append(hold)
        open_vol.append(string)
    return open_vol


def _make_logger_prefix(tag: str=None):
    """creates a function to add logger prefix"""
    return lambda text: '{}{}'.format(tag + ': ' if tag else '', text)


def repeat_history(index: int=0):
    """Display menu for previous actions performed

    :param index: Index
    :type index: int
    """
    pass


def enable_color():
    """Enable colors by setting colour code constants to ANSI color codes."""
    global LIGHT_GREEN
    LIGHT_GREEN = '\x1b[1;32m'
    global LIGHT_RED
    LIGHT_RED = '\x1b[1;31m'
    global LIGHT_BLUE
    LIGHT_BLUE = '\x1b[1;34m'
    global DARK_RED
    DARK_RED = '\x1b[0;31m'
    global END_COLOR
    END_COLOR = '\x1b[0m'


def cols_to_slugify(df, columns):
    """Slugify selected column values and return dataframe.

    Args:
        df: Pandas dataframe.
        columns: List of columns to convert.

    Returns:
        Original dataframe with converted column data.
    """
    for col in columns:
        df[col] = df[col].str.replace('[^0-9a-zA-Z]+', '_', regex=True)
    return df


def advance_cov12(phi, C12, x):
    """
    Explicit integration of covariance term in the 1/2 axes planes
    phi - density function
    C12 - transition matrices
    x - grid
    """
    for kk in range(len(x)):
        C = C12[kk]
        phi[:, :, (kk)] = (C * phi[:, :, (kk)].reshape(len(x) ** 2)).reshape(
            len(x), len(x))
    return phi


def collapse():
    """
        Collapse this node.
        """


def list_sum(l):
    """
    Return the sum of a list, when the convetiional
    method (like `sum`) it not working.
    For example if you have a list of dolfin functions.

    :param list l: a list of objects
    :returns: The sum of the list. The type depends on
              the type of elemets in the list

    """
    if not isinstance(l, list):
        return l
    out = l[0]
    for item in l[1:]:
        out += item
    return out


def subscribers():
    """ Returns the list of subscribers
        """


def subclasses_wrapper(klass):
    """Wrapper around __subclass__ as it is not as easy as it should."""
    method = getattr(klass, '__subclasses__', None)
    if method is None:
        return []
    try:
        return method()
    except TypeError:
        try:
            return method(klass)
        except TypeError:
            return []


def r_squared(yhatss, yss, return_error=False):
    """
  Returns the coefficient of determination of two 2d tensors
  (where the first dimension in each indexes the examples),
  one holding the yhatss (the predicted outputs) and the other
  holding the actual outputs, yss.

  Note: this is rigorously relevant only to linear, meaning
  possibly polynomial linear, regression.

  Args:
    yhatss (torch.Tensor): The predicted outputs.
    yss (torch.Tensor): The actual outputs.
    return_error (bool): If False return the proportion of the
        variation explained by the regression line. If True,
        return 1 minus that proportion. Default: False.
  """
    SS_E, SS_T = 0.0, 0.0
    mean = yss.mean(0)
    for yhats, ys in zip(yhatss, yss):
        SS_E += (ys - yhats).pow(2)
        SS_T += (ys - mean).pow(2)
    if return_error:
        return (SS_E / SS_T).item()
    else:
        return 1.0 - (SS_E / SS_T).item()


def p_multiple_encapsed(p):
    """multiple_encapsed : multiple_encapsed ENCAPSED_AND_WHITESPACE
                         | empty"""
    if len(p) == 3:
        p[0] = p[1] + p[2]
    else:
        p[0] = ''


def get_pk_columns(cls):
    """Return primary key fields of a Spyne object."""
    retval = []
    for k, v in cls.get_flat_type_info(cls).items():
        if (v.Attributes.sqla_column_args is not None and v.Attributes.
            sqla_column_args[-1].get('primary_key', False)):
            retval.append((k, v))
    return tuple(retval) if len(retval) > 0 else None


def offsetRect(rect, dx, dy):
    """Offset the rectangle by dx, dy."""
    xMin, yMin, xMax, yMax = rect
    return xMin + dx, yMin + dy, xMax + dx, yMax + dy


def merge_intervals_strandaware(ranges_dict):
    """
    Perform in-silico mutagenesis on what the dataloader has returned.

    This function has to convert the DNA regions in the model input according to ref, alt, fwd, rc and
    return a dictionary of which the keys are compliant with evaluation_function arguments

    DataLoaders that implement fwd and rc sequence output *__at once__* are not treated in any special way.
    Perform in-silico mutagenesis on what the dataloader has returned.

    This function has to convert the DNA regions in the model input according to ref, alt, fwd, rc and
    return a dictionary of which the keys are compliant with evaluation_function arguments

    DataLoaders that implement fwd and rc sequence output *__at once__* are not treated in any special way.
    `ranges_dict`: dictionary of GenomicsRanges
    Returns unified ranges
    """
    from intervaltree import IntervalTree
    chrom_trees = {}
    for k in ranges_dict:
        assert len(ranges_dict[k]['chr']) == 1
        chr_str = [ranges_dict[k]['chr'][0], ranges_dict[k]['strand'][0]]
        start = ranges_dict[k]['start'][0]
        end = ranges_dict[k]['end'][0]
        if chr_str not in chrom_trees:
            chrom_trees[chr_str] = IntervalTree()
        chrom_trees[chr_str][start:end] = [k]
    [chrom_trees[chr_str].merge_overlaps(lambda x, y: x + y) for chr_str in
        chrom_trees]
    out_regions = {k: [] for k in ['chr', 'start', 'end', 'strand']}
    ranges_ks = []
    for chr_str in chrom_trees:
        for interval in chrom_trees[chr_str]:
            out_regions['chr'].append(chr_str[0])
            out_regions['strand'].append(chr_str[1])
            out_regions['start'].append(interval.begin)
            out_regions['end'].append(interval.end)
            ranges_ks.append(interval.data)
    return out_regions, ranges_ks


def simplegoo(com, kw, tsl=0):
    """
    Simply Google (simplegoo) companies plus the keyword given.
    com and kw must be lists, excluding NaN elements.
    tsl is the time sleep level when opening each tab.
    """
    import time
    import numpy as np
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    wh = 'https://www.google.com/'
    js = "window.open('https://www.google.com/')"
    sch = webdriver.Chrome()
    li = []
    for i in com:
        for j in kw:
            b = str(i) + ' ' + str(j)
            li.append(b)
    n = 1
    for i in li:
        a = i
        sch.get(wh)
        sch.find_element_by_name('q').send_keys(a)
        sch.find_element_by_name('q').send_keys(Keys.ENTER)
        time.sleep(tsl * np.random.rand() + 0.002)
        sch.execute_script(js)
        handles = sch.window_handles
        sch.switch_to.window(handles[n])
        n += 1
    sch.close()
    sch.switch_to.window(handles[0])


def escape_eid(eid):
    """Replace slashes with underscores, to avoid recognizing them
    as directories.
    """
    return eid.replace('/', '_')


def list(project):
    """Return the list of versions which have eggs stored (for the given
        project) in order (the latest version is the currently used)."""


def globalcounter():
    """Resets the globalcount to 0"""
    global globalcount
    globalcount = 0


def toTypeURIs(namespace_map, alias_list_s):
    """Given a namespace mapping and a string containing a
    comma-separated list of namespace aliases, return a list of type
    URIs that correspond to those aliases.

    @param namespace_map: The mapping from namespace URI to alias
    @type namespace_map: openid.message.NamespaceMap

    @param alias_list_s: The string containing the comma-separated
        list of aliases. May also be None for convenience.
    @type alias_list_s: str or NoneType

    @returns: The list of namespace URIs that corresponds to the
        supplied list of aliases. If the string was zero-length or
        None, an empty list will be returned.

    @raise KeyError: If an alias is present in the list of aliases but
        is not present in the namespace map.
    """
    uris = []
    if alias_list_s:
        for alias in alias_list_s.split(','):
            type_uri = namespace_map.getNamespaceURI(alias)
            if type_uri is None:
                raise KeyError('No type is defined for attribute name %r' %
                    (alias,))
            else:
                uris.append(type_uri)
    return uris


def epsilon_Stiel_Thodos(Tc, Zc):
    """Calculates Lennard-Jones depth of potential-energy minimum.
    Uses Critical temperature and critical compressibility. CSP method by [1]_.

    .. math::
        \\epsilon/k = 65.3 T_c Z_c^{3.6}

    Parameters
    ----------
    Tc : float
        Critical temperature of fluid [K]
    Zc : float
        Critical compressibility of fluid, [-]

    Returns
    -------
    epsilon_k : float
        Lennard-Jones depth of potential-energy minimum over k, [K]

    Notes
    -----

    Examples
    --------
    Fluorobenzene

    >>> epsilon_Stiel_Thodos(358.5, 0.265)
    196.3755830305783

    References
    ----------
    .. [1] Stiel, L. I., and George Thodos. "Lennard-Jones Force Constants
       Predicted from Critical Properties." Journal of Chemical & Engineering
       Data 7, no. 2 (April 1, 1962): 234-36. doi:10.1021/je60013a023
    """
    epsilon_k = 65.3 * Tc * Zc ** 3.6
    return epsilon_k


def VoltageControlledCurrentSource(G, Z0=50):
    """VoltageControlledCurrentSource
    Voltage controlled current source
    @param G float or complex transconductance
    @param Z0 (optional) float or complex reference impedance Z0 (defaults to 50 ohms)
    @return list of list s-parameter matrix of a voltage controlled current source
    @remark
    The four port voltage controlled current source has
    the voltage sense element sensing the voltage difference between the plus terminal
    at port 1 and the minus terminal at port 2.

    The current generated by the amplifier enters port 4 and exits port 3
    """
    return [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [2.0 * G * Z0, -2.0 *
        G * Z0, 1.0, 0.0], [-2.0 * G * Z0, 2.0 * G * Z0, 0.0, 1.0]]


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


def mb_to_gb(mbytes):
    """Converts a MegaByte int to GigaByte. mbytes/2^10"""
    return round(mbytes / 2 ** 10, 4)


def get_path(D, path):
    """Get a path from a dictionary

    :param dict D: a dictionary
    :param list path: an iterable of hashables
    :return: the item at the path from the dictionary
    """
    assert isinstance(D, dict)
    try:
        assert map(hash, path)
    except TypeError:
        raise TypeError('path should be an iterable of hashables')
    item = D
    for p in path:
        item = item[p]
    return item


def _populate_valid_params(params=None, valid_keys=None):
    """构建只包含有效keys的params

    :param params: 需要过滤的params
    :type params: dict

    :param valid_keys: 有效的关键key列表
    :type valid_keys: list

    :return: 只包含有效keys的params
    """
    if params is None or valid_keys is None:
        return None
    valid_params = dict()
    for key in valid_keys:
        if params.get(key) is not None:
            valid_params[key] = params[key]
    if len(valid_params) == 0:
        valid_params = None
    return valid_params


def isVIS(channel):
    """Check if VIMS channel is VIS (visible) or IR (infra-red)"""
    ch = channel.upper()
    if ch == 'VIS':
        return True
    elif ch == 'IR':
        return False
    else:
        raise KeyError('Unknown VIMS channel [VIS|IR]: {}'.format(channel))


def primitive_grid_add(x_subdivisions: int=10, y_subdivisions: int=10,
    radius: float=1.0, calc_uvs: bool=False, view_align: bool=False,
    enter_editmode: bool=False, location: float=(0.0, 0.0, 0.0), rotation:
    float=(0.0, 0.0, 0.0), layers: bool=(False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False, False)):
    """Construct a grid mesh

    :param x_subdivisions: X Subdivisions
    :type x_subdivisions: int
    :param y_subdivisions: Y Subdivisions
    :type y_subdivisions: int
    :param radius: Radius
    :type radius: float
    :param calc_uvs: Generate UVs, Generate a default UV map
    :type calc_uvs: bool
    :param view_align: Align to View, Align the new object to the view
    :type view_align: bool
    :param enter_editmode: Enter Editmode, Enter editmode when adding this object
    :type enter_editmode: bool
    :param location: Location, Location for the newly added object
    :type location: float
    :param rotation: Rotation, Rotation for the newly added object
    :type rotation: float
    :param layers: Layer
    :type layers: bool
    """
    pass


def is_inside(a, lims):
    """Is a value inside the limits"""
    return a[(a >= lims[0]) & (a <= lims[1])]


def check_for_missing_glosses(gloss_ref_marker, glosses, examples, log):
    """Log an error message when an example references an unknown gloss."""
    for example in examples:
        gloss_ref = example.get(gloss_ref_marker)
        if not gloss_ref:
            continue
        if example.id not in glosses:
            log.error("Gloss '\\%s %s' not found (ex. %s)",
                gloss_ref_marker, gloss_ref, example.id)


def default_motion_cor_2_v1_0_0():
    """
    Content of MotionCor2 version 1.0.0.

    Arguments:
    None

    Return:
    Content items as list
    """
    items = [['WIDGETS MAIN', '5', int, '', 'PLAIN', '', ''], [
        'WIDGETS ADVANCED', '5', int, '', 'PLAIN', '', ''], ['WIDGETS RARE',
        '5', int, '', 'PLAIN', '', ''], ['-FmDose', '0', float, '', 'PLAIN',
        'Main',
        'Frame dose in e/A^2. If not specified, dose weighting will be skipped.'
        ], ['-PixSize', '0', float, '', 'PLAIN', 'Main',
        'Pixel size in A of input stack in angstrom. If not specified, dose weighting will be skipped.'
        ], ['-kV', '300', float, '', 'PLAIN', 'Main',
        'High tension in kV needed for dose weighting.  Default is 300.'],
        ['-Patch', '0 0', [int, int], '', 'PLAIN', 'Main',
        'Number of patches to be used for patch based alignment, default 0 0 corresponding full frame alignment.'
        ], ['-Bft', '100', float, '', 'PLAIN', 'Main',
        'B-Factor for alignment, default 100.'], ['-Throw', '0', int, '',
        'PLAIN', 'Main', 'Throw initial number of frames, default is 0'], [
        '-Trunc', '0', int, '', 'PLAIN', 'Main',
        'Truncate last number of frames, default is 0'], ['-Gain', '', str,
        '', 'FILE', 'Main',
        'MRC file that stores the gain reference. If not specified, MRC extended header will be visited to look for gain reference.'
        ], ['-RotGain', '0', int, '', 'PLAIN', 'Main',
        'Rotate gain reference counter-clockwise.  0 - no rotation, default, 1 - rotate 90 degree, 2 - rotate 180 degree, 3 - rotate 270 degree.'
        ], ['-FlipGain', '0', int, '', 'PLAIN', 'Main',
        'Flip gain reference after gain rotation.  0 - no flipping, default, 1 - flip upside down, 2 - flip left right.'
        ], ['-MaskCent', '0 0', [float, float], '', 'PLAIN', 'Advanced',
        'Center of subarea that will be used for alignement, default 0 0 corresponding to the frame center.'
        ], ['-MaskSize', '1 1', [float, float], '', 'PLAIN', 'Advanced',
        'The size of subarea that will be used for alignment, default 1.0 1.0 corresponding full size.'
        ], ['-Iter', '7', int, '', 'PLAIN', 'Advanced',
        'Maximum iterations for iterative alignment, default 5 iterations.'
        ], ['-Tol', '0.5', float, '', 'PLAIN', 'Advanced',
        'Tolerance for iterative alignment, default 0.5 pixel.'], [
        '-PhaseOnly', '0', int, '', 'PLAIN', 'Advanced',
        'Only phase is used in cross correlation.  default is 0, i.e., false.'
        ], ['-StackZ', '0', int, '', 'PLAIN', 'Advanced',
        'Number of frames per stack. If not specified, it will be loaded from MRC header.'
        ], ['-FtBin', '1', float, '', 'PLAIN', 'Advanced',
        'Binning performed in Fourier space, default 1.0.'], ['-InitDose',
        '0', float, '', 'PLAIN', 'Advanced',
        'Initial dose received before stack is acquired'], ['-Group', '1',
        int, '', 'PLAIN', 'Advanced',
        'Group every specified number of frames by adding them together. The alignment is then performed on the summed frames. By default, no grouping is performed.'
        ], ['-FmRef', '-1', int, '', 'PLAIN', 'Advanced',
        'Specify which frame to be the reference to which all other frames are aligned. By default (-1) the the central frame is chosen. The central frame is at N/2 based upon zero indexing where N is the number of frames that will be summed, i.e., not including the frames thrown away.'
        ], ['-DefectFile', '', str, '', 'FILE', 'Advanced',
        '1. Defect file that stores entries of defects on camera.  2. Each entry corresponds to a rectangular region in image.  The pixels in such a region are replaced by neighboring good pixel values.  3. Each entry contains 4 integers x, y, w, h representing the x, y coordinates, width, and heights, respectively.'
        ], ['-Tilt', '0 0', [float, float], '', 'PLAIN', 'Advanced',
        'Specify the starting angle and the step angle of tilt series. They are required for dose weighting. If not given, dose weighting will be disabled.'
        ], ['-Mag', '1 1 0', [float, float, float], '', 'PLAIN', 'Advanced',
        '1. Correct anisotropic magnification by stretching image along the major axis, the axis where the lower magificantion is detected.  2. Three inputs are needed including magnifications along major and minor axes and the angle of the major axis relative to the image x-axis in degree.  3. By default no correction is performed.'
        ], ['-InFmMotion', '0', int, '', 'PLAIN', 'Advanced',
        '1. 1 - Account for in-frame motion.  0 - Do not account for in-frame motion.'
        ], ['-Crop', '0 0', [int, int], '', 'PLAIN', 'Advanced',
        '1. Crop the loaded frames to the given size.  2. By default the original size is loaded.'
        ], ['-Gpu', '0', [int] * 99, '', 'PLAIN', 'Advanced',
        ' GPU IDs. Default 0.  For multiple GPUs, separate IDs by space.  For example, -Gpu 0 1 2 3 specifies 4 GPUs.'
        ], ['Split Gpu?', ['True', 'False'], bool, '', 'COMBO', 'Advanced',
        'NOT A CRYOLO OPTION. Split the gpu values specified in --Gpu to be able to run mutliple crYOLO jobs in parallel.'
        ], ['dose cutoff', '4', float, '', 'PLAIN', 'Advanced',
        'NOT A MOTIONCOR OPTION. Used to create the Relion3 bayesian polishing files.'
        ]]
    return items


def assign_use_api_permission(setup_context):
    """Assign the 'plone.restapi: Use REST API' permission to Anonymous.
    """
    setup_context.runImportStepFromProfile(
        'profile-plone.restapi.upgrades:0002', 'rolemap', run_dependencies=
        False, purge_old=False)


def lookupMailBox(name, timeout=None):
    """
        Perform an MB record lookup.

        @type name: L{bytes} or L{str}
        @param name: DNS name to resolve.

        @type timeout: Sequence of C{int}
        @param timeout: Number of seconds after which to reissue the query.
            When the last timeout expires, the query is considered failed.

        @rtype: L{Deferred}
        @return: A L{Deferred} which fires with a three-tuple of lists of
            L{twisted.names.dns.RRHeader} instances.  The first element of the
            tuple gives answers.  The second element of the tuple gives
            authorities.  The third element of the tuple gives additional
            information.  The L{Deferred} may instead fail with one of the
            exceptions defined in L{twisted.names.error} or with
            C{NotImplementedError}.
        """


def snap(frame: int=0):
    """Frame where selected strips will be snapped

    :param frame: Frame, Frame where selected strips will be snapped
    :type frame: int
    """
    pass


def encode_baseline(a1, a2):
    """Encode the baseline. Use the miriad convention to handle more than 255 antennas (up to 2048)."""
    if a1 > a2:
        te = a2
        a2 = a1
        a1 = te
    if a2 > 255:
        return a1 * 2048 + a2 + 65536
    else:
        return a1 * 256 + a2


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


@classmethod
def from_catmaid(cls, catmaid_client, stack_id):
    """
        Return a CoordinateTransformer for a particular CATMAID stack.

        Parameters
        ----------
        catmaid_client : AbstractCatmaidClient
            Object capable of interfacing with Catmaid
        stack_id : int

        Returns
        -------
        CoordinateTransformer
        """
    stack_info = catmaid_client.get((catmaid_client.project_id, 'stack',
        stack_id, 'info'))
    return cls(stack_info['resolution'], stack_info['translation'],
        stack_info['orientation'])


def generate_uncovered_set(q, uncovered_intervals):
    """
    Returns set {k | 0 <=k < q, [k, (k+1)] is uncovered}
    from uncoverd_intervals which is a list of componenents.

    EXAMPLES::

        sage: from cutgeneratingfunctionology.igp import *
        sage: uncovered_intervals = [set([0,2]), set([3,4])]
        sage: generate_uncovered_set(5, uncovered_intervals)
        {0, 2, 3, 4}
    """
    uncovered_set = set([])
    for component in uncovered_intervals:
        uncovered_set.update(component)
    return uncovered_set


def get_students_by_promo(wrapper, promo: int) ->list:
    """Get list of student by promo."""
    student_list = []
    students = wrapper.get_students(promotion_id=promo)
    if 'does not exist' in students:
        print('Promo ID does not exist')
        return None
    for student in students['students']:
        student_list.append(student['login'])
    return student_list


def getInheritedSelf():
    """Return itself but in the next higher up Locale."""


def Knudsen(path, L):
    """Calculates Knudsen number or `Kn` for a fluid with mean free path
    `path` and for a characteristic length `L`.

    .. math::
        Kn = \\frac{\\lambda}{L}

    Parameters
    ----------
    path : float
        Mean free path between molecular collisions, [m]
    L : float
        Characteristic length, [m]

    Returns
    -------
    Kn : float
        Knudsen number []

    Notes
    -----
    Used in mass transfer calculations.

    .. math::
        Kn = \\frac{\\text{Mean free path length}}{\\text{Characteristic length}}

    Examples
    --------
    >>> Knudsen(1e-10, .001)
    1e-07

    References
    ----------
    .. [1] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,
       Eighth Edition. McGraw-Hill Professional, 2007.
    .. [2] Cengel, Yunus, and John Cimbala. Fluid Mechanics: Fundamentals and
       Applications. Boston: McGraw Hill Higher Education, 2006.
    """
    return path / L


def release_dict(d, d_list, holdbacks):
    """Ensures that only new variables are returned"""
    response = dict()
    for i in d:
        if not i in d_list and not i in holdbacks:
            response[i] = d[i]
    return response


@staticmethod
def _patch_for_win_iomodule(orig_file, patch_file):
    """ _iomodule.c in Python v3.6 includes consoleapi.h when it should
        include windows.h (as it does in Python v3.7).
        """
    for line in orig_file:
        patch_file.write(line.replace('consoleapi.h', 'windows.h'))


def bias(mass, z, h=h, Om_M=Om_M, Om_L=Om_L):
    """Calculate halo bias, from Seljak & Warren 2004.

    Parameters
    ----------
    mass : ndarray or float
        Halo mass to calculate bias for.
    z : ndarray or float
        Halo z, same type and size as mass.
    h : float, optional
        Hubble parameter, defaults to astropy.cosmology.Planck13.h
    Om_M : float, optional
        Fractional matter density, defaults to
        astropy.cosmology.Planck13.Om0
    Om_L : float, optional
        Fractional dark energy density, defaults to 1-Om_M.

    Returns
    ----------
    ndarray or float
        Returns the halo bias, of same type and size as input mass_halo and
        z_halo. Calculated according to Seljak & Warren 2004 for z = 0.
        For halo z > 0, the non-linear mass is adjusted using the input
        cosmological parameters.

    References
    ----------
    Based on fitting formula derived from simulations in:

    U. Seljak and M.S. Warren, "Large-scale bias and stochasticity of
    haloes and dark matter," Monthly Notices of the Royal Astronomical
    Society, Volume 355, Issue 1, pp. 129-136 (2004).
    """
    M_nl_0 = 8.73 / h * 10.0 ** 12.0
    M_nl = M_nl_0 * (Om_M + Om_L / (1.0 + z) ** 3.0)
    x = mass / M_nl
    b = 0.53 + 0.39 * x ** 0.45 + 0.13 / (40.0 * x + 1.0) + 0.0005 * x ** 1.5
    return b


@staticmethod
def accepted_ct():
    """Return a list of content types accepted by the tile."""
    return ['sc.embedder']


@staticmethod
def p_in_measurement_optional_list(p):
    """in_measurement_optional_list : in_measurement_optional
                                        | in_measurement_optional in_measurement_optional_list"""
    try:
        p[0] = [p[1]] + p[2]
    except IndexError:
        p[0] = [p[1]]


def xor_decode(data, axis=-1, out=None):
    """Decode XOR delta.

    >>> xor_decode(b'0\\x01\\x03\\x01\\x07\\x01\\x03\\x01\\x0f\\x01')
    b'0123456789'

    """
    if isinstance(data, (bytes, bytearray)):
        prev = data[0]
        b = [chr(prev)]
        for c in data[1:]:
            prev = c ^ prev
            b.append(chr(prev))
        return ''.join(b).encode('latin1')
    raise NotImplementedError()


def ONLY_CONFIG(s, t, v):
    """Only config events pass"""
    from taurus.core import TaurusEventType
    if t == TaurusEventType.Config:
        return s, t, v
    else:
        return None


def underline(line, underline='~'):
    """Return an underline string for ``line``.

    Intended for use with level 3 and lower headings.

    Note that the default for ``underline`` assumes that the level
    1 and 2 underlines are the standard ``=`` and ``-``. You can
    pass a different underline character to this function if needed.
    """
    if line.endswith('\n'):
        line = line[:-1]
    return '{}\n'.format(underline * len(line))


def reshape_t(x, shape):
    """Work around fact that x.reshape(()) doesn't work"""
    if shape != ():
        return x.reshape(shape)
    else:
        return x[0]


def build_table_id(dataset_name, table_name):
    """ Combines dataset name and annotation to create specific table id

    :param dataset_name: str
    :param table_name: str
    :return: str
    """
    return 'annov1__%s__%s' % (dataset_name, table_name)


def _parse_block_name(block_name):
    """
    Obtain a path and the class name from the given block name.

    :return: A tuple path, class name.
    :rtype: tuple

    """
    names = block_name.split('.')
    if len(names) == 1:
        return '', block_name
    return '.'.join(names[:-1]), names[-1]


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


def get_class(class_name):
    """Get a class from the class name throuth the 'reflection' property."""
    parts = class_name.split('.')
    module = '.'.join(parts[:-1])
    m = __import__(module)
    for comp in parts[1:]:
        m = getattr(m, comp)
    return m


def __getitem__(key):
    """Lookup fallback if item is not available on node.
        """


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

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


def safe_issubclass(*args):
    """Like issubclass, but will just return False if not a class."""
    try:
        if issubclass(*args):
            return True
    except TypeError:
        pass
    return False


def ref(path, id_):
    """
    A "ref" is either a path or file ID. Here, given an argument for both,
    where only one is really present, return the ref.
    """
    assert (path is not None) ^ (id_ is not None)
    if path is not None and not path.startswith('/'):
        raise ValueError('Path must be absolute.')
    return path if path is not None else str(id_)


def itertools_chain(*iterables):
    """For the shortage of Python2's, Python3: `from itertools import chain`."""
    for it in iterables:
        for element in it:
            yield element


def strvalidator(value):
    """Cast a value to string."""
    if value is None:
        return None
    return str(value)


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

    .. math::
        C_D = \\left\\{ \\begin{array}{ll}
        \\frac{24}{Re} & \\mbox{if $Re < 0.1$}\\\\
        \\frac{22.73}{Re}+\\frac{0.0903}{Re^2} + 3.69 & \\mbox{if $0.1 < Re < 1$}\\\\
        \\frac{29.1667}{Re}-\\frac{3.8889}{Re^2} + 1.2220 & \\mbox{if $1 < Re < 10$}\\\\
        \\frac{46.5}{Re}-\\frac{116.67}{Re^2} + 0.6167 & \\mbox{if $10 < Re < 100$}\\\\
        \\frac{98.33}{Re}-\\frac{2778}{Re^2} + 0.3644 & \\mbox{if $100 < Re < 1000$}\\\\
        \\frac{148.62}{Re}-\\frac{4.75\\times10^4}{Re^2} + 0.3570 & \\mbox{if $1000 < Re < 5000$}\\\\
        \\frac{-490.5460}{Re}+\\frac{57.87\\times10^4}{Re^2} + 0.46 & \\mbox{if $5000 < Re < 10000$}\\\\
        \\frac{-1662.5}{Re}+\\frac{5.4167\\times10^6}{Re^2} + 0.5191 & \\mbox{if $10000 < Re < 50000$}\\end{array} \\right.

    Parameters
    ----------
    Re : float
        Particle Reynolds number of the sphere using the surrounding fluid
        density and viscosity, [-]

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

    Notes
    -----
    Range is Re <= 2E5.
    Original was reviewed, and confirmed to contain the cited equations.

    Examples
    --------
    >>> Morsi_Alexander(200)
    0.7866

    References
    ----------
    .. [1] Morsi, S. A., and A. J. Alexander. "An Investigation of Particle
       Trajectories in Two-Phase Flow Systems." Journal of Fluid Mechanics
       55, no. 02 (September 1972): 193-208. doi:10.1017/S0022112072001806.
    .. [2] Barati, Reza, Seyed Ali Akbar Salehi Neyshabouri, and Goodarz
       Ahmadi. "Development of Empirical Models with High Accuracy for
       Estimation of Drag Coefficient of Flow around a Smooth Sphere: An
       Evolutionary Approach." Powder Technology 257 (May 2014): 11-19.
       doi:10.1016/j.powtec.2014.02.045.
    """
    if Re < 0.1:
        return 24.0 / Re
    elif Re < 1:
        return 22.73 / Re + 0.0903 / Re ** 2 + 3.69
    elif Re < 10:
        return 29.1667 / Re - 3.8889 / Re ** 2 + 1.222
    elif Re < 100:
        return 46.5 / Re - 116.67 / Re ** 2 + 0.6167
    elif Re < 1000:
        return 98.33 / Re - 2778.0 / Re ** 2 + 0.3644
    elif Re < 5000:
        return 148.62 / Re - 47500.0 / Re ** 2 + 0.357
    elif Re < 10000:
        return -490.546 / Re + 578700.0 / Re ** 2 + 0.46
    else:
        return -1662.5 / Re + 5416700.0 / Re ** 2 + 0.5191


def convertbits(data, frombits, tobits, pad=True):
    """General power-of-2 base conversion."""
    acc = 0
    bits = 0
    ret = []
    maxv = (1 << tobits) - 1
    max_acc = (1 << frombits + tobits - 1) - 1
    for value in data:
        if value < 0 or value >> frombits:
            return None
        acc = (acc << frombits | value) & max_acc
        bits += frombits
        while bits >= tobits:
            bits -= tobits
            ret.append(acc >> bits & maxv)
    if pad:
        if bits:
            ret.append(acc << tobits - bits & maxv)
    elif bits >= frombits or acc << tobits - bits & maxv:
        return None
    return ret


def get_doc():
    """Get documentation of this resource

    :return: rst string
    :rtype: str
    """
    return """
    The ``history`` model is used to maintain a log of the received checks results.

    The Alignak backend stores all the checks results it receives to keep a full log of the system
    checks results.
    """


def convertToMapPic(byteString, mapWidth):
    """convert a bytestring into a 2D row x column array, representing an existing map of fog-of-war, creep, etc."""
    data = []
    line = ''
    for idx, char in enumerate(byteString):
        line += str(ord(char))
        if (idx + 1) % mapWidth == 0:
            data.append(line)
            line = ''
    return data


@staticmethod
def _env(param: str):
    """Environment variable form of a parameter"""
    return 'OAAS_{}'.format(param.upper())


def is_rewrite_file(filename):
    """ template file? (default: filename.mako.tmpl)"""


def unique_color(n=1):
    """

    Returns one of 14 unique colors.
    see https://xkcd.com/color/rgb/
    and https://matplotlib.org/tutorials/colors/colors.html

    Parameters
    ----------
    n : int, optional, default 1
        which unique color do you want [1..13]
        if n is not in 1..13, return mint

    Returns
    -------
    c : matplotlib.colors.Colormap
        one of 13 unique colors

    """
    if n == 1:
        c = 'xkcd:red'
    elif n == 2:
        c = 'xkcd:green'
    elif n == 3:
        c = 'xkcd:yellow'
    elif n == 4:
        c = 'xkcd:blue'
    elif n == 5:
        c = 'xkcd:orange'
    elif n == 6:
        c = 'xkcd:purple'
    elif n == 7:
        c = 'xkcd:cyan'
    elif n == 8:
        c = 'xkcd:magenta'
    elif n == 9:
        c = 'xkcd:lime green'
    elif n == 10:
        c = 'xkcd:candy pink'
    elif n == 11:
        c = 'xkcd:teal'
    elif n == 12:
        c = 'xkcd:lavender'
    elif n == 13:
        c = 'xkcd:brown'
    else:
        c = 'xkcd:mint'
    return c


def cfg():
    """General configuration values."""
    return None


def list_reviewable_hits(HITTypeId=None, Status=None, NextToken=None,
    MaxResults=None):
    """
    The ListReviewableHITs operation retrieves the HITs with Status equal to Reviewable or Status equal to Reviewing that belong to the Requester calling the operation.
    See also: AWS API Documentation

    :example: response = client.list_reviewable_hits(
        HITTypeId='string',
        Status='Reviewable'|'Reviewing',
        NextToken='string',
        MaxResults=123
    )

    :type HITTypeId: string
    :param HITTypeId: The ID of the HIT type of the HITs to consider for the query. If not specified, all HITs for the Reviewer are considered

    :type Status: string
    :param Status: Can be either Reviewable or Reviewing . Reviewable is the default value.

    :type NextToken: string
    :param NextToken: Pagination Token

    :type MaxResults: integer
    :param MaxResults: Limit the number of results returned.

    :rtype: dict
    :return: {
        'NextToken': 'string',
        'NumResults': 123,
        'HITs': [
            {
                'HITId': 'string',
                'HITTypeId': 'string',
                'HITGroupId': 'string',
                'HITLayoutId': 'string',
                'CreationTime': datetime(2015, 1, 1),
                'Title': 'string',
                'Description': 'string',
                'Question': 'string',
                'Keywords': 'string',
                'HITStatus': 'Assignable'|'Unassignable'|'Reviewable'|'Reviewing'|'Disposed',
                'MaxAssignments': 123,
                'Reward': 'string',
                'AutoApprovalDelayInSeconds': 123,
                'Expiration': datetime(2015, 1, 1),
                'AssignmentDurationInSeconds': 123,
                'RequesterAnnotation': 'string',
                'QualificationRequirements': [
                    {
                        'QualificationTypeId': 'string',
                        'Comparator': 'LessThan'|'LessThanOrEqualTo'|'GreaterThan'|'GreaterThanOrEqualTo'|'EqualTo'|'NotEqualTo'|'Exists'|'DoesNotExist'|'In'|'NotIn',
                        'IntegerValues': [
                            123,
                        ],
                        'LocaleValues': [
                            {
                                'Country': 'string',
                                'Subdivision': 'string'
                            },
                        ],
                        'RequiredToPreview': True|False
                    },
                ],
                'HITReviewStatus': 'NotReviewed'|'MarkedForReview'|'ReviewedAppropriate'|'ReviewedInappropriate',
                'NumberOfAssignmentsPending': 123,
                'NumberOfAssignmentsAvailable': 123,
                'NumberOfAssignmentsCompleted': 123
            },
        ]
    }

    :returns:
    (integer) --

    """
    pass


@classmethod
def readonly(cls, *args, **kwargs):
    """
        Return an already closed read-only instance of Fridge.
        Arguments are the same as for the constructor.
        """
    fridge = cls(*args, **kwargs)
    fridge.close()
    return fridge


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


def psi_H_Na_HSO4_HMW84(T, P):
    """c-c'-a: hydrogen sodium bisulfate [HMW84]."""
    psi = -0.0129
    valid = T == 298.15
    return psi, valid


def Date():
    """Return the date string for the object."""


def product(xs):
    """Multiplies together all the elements of a list"""
    result = xs[0]
    for x in xs[1:]:
        result *= x
    return result


def type_object_attrgetter(obj, attr, *defargs):
    """
    This implements an improved attrgetter for type objects (i.e. classes)
    that can handle class attributes that are implemented as properties on
    a metaclass.

    Normally `getattr` on a class with a `property` (say, "foo"), would return
    the `property` object itself.  However, if the class has a metaclass which
    *also* defines a `property` named "foo", ``getattr(cls, 'foo')`` will find
    the "foo" property on the metaclass and resolve it.  For the purposes of
    autodoc we just want to document the "foo" property defined on the class,
    not on the metaclass.

    For example::

        >>> class Meta(type):
        ...     @property
        ...     def foo(cls):
        ...         return 'foo'
        ...
        >>> class MyClass(metaclass=Meta):
        ...     @property
        ...     def foo(self):
        ...         ""\"Docstring for MyClass.foo property.""\"
        ...         return 'myfoo'
        ...
        >>> getattr(MyClass, 'foo')
        'foo'
        >>> type_object_attrgetter(MyClass, 'foo')
        <property at 0x...>
        >>> type_object_attrgetter(MyClass, 'foo').__doc__
        'Docstring for MyClass.foo property.'

    The last line of the example shows the desired behavior for the purposes
    of autodoc.
    """
    for base in obj.__mro__:
        if attr in base.__dict__:
            if isinstance(base.__dict__[attr], property):
                return base.__dict__[attr]
            break
    return getattr(obj, attr, *defargs)


def get_quantiles(data_frame, field_name, quantile_list=None):
    """Get quantiles for specific field

    Args:
        data_frame (DataFrame): data
        field_name (str): data_frame column name
        quantile_list (list): list of quantile values

    Returns:
        list: list of counted quantiles
    """
    if not quantile_list:
        quantile_list = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95,
            0.98, 0.99, 1.0]
    data_frame[field_name] = data_frame[field_name].fillna(0).astype(int)
    quantiles = data_frame[field_name].quantile(quantile_list)
    quantiles = quantiles.to_frame().reset_index()
    quantiles.rename(columns={'index': 'quantile'}, inplace=True)
    return quantiles


@staticmethod
def pgcd(a, b):
    """
        Computes the :epkg:`PGCD`.
        """
    while a != b:
        d = abs(a - b)
        c = min(a, b)
        a, b = d, c
    return a


@staticmethod
def parse_condition(condition):
    """
        Transforms conditions in the correct format.

        Conditions are given by users as key-value params, and arrive here as
        (key, value) tuple.

        Value can be a string with an operator prefixed, e.g. '>value', or a
        tuple like (operator, value).
        """
    column = condition[0]
    value = condition[1]
    if value[0:2] in ('>=', '<='):
        return column, value[0:2], value[2:]
    elif value[0] in ('!', '>', '<'):
        return column, value[0], value[1:]
    elif value[0] in ('<=', '>='):
        return column, value[0], (value[1],)
    return column, '=', value


def longest_match(list1, list2):
    """
    Find the length of the longest substring match between list1 and list2.

    >>> longest_match([], [])
    0
    >>> longest_match('test', 'test')
    4
    >>> longest_match('test', 'toast')
    2
    >>> longest_match('supercalifragilisticexpialidocious', 'mystical californication')
    5
    """
    m = len(list1)
    n = len(list2)
    data = [[(0) for col in range(n + 1)] for row in range(m + 1)]
    for a in range(1, m + 1):
        for b in range(1, n + 1):
            if list1[a - 1] == list2[b - 1]:
                data[a][b] = 1 + data[a - 1][b - 1]
            else:
                data[a][b] = 0
    maxes = [max(row) for row in data]
    return max(maxes)


def is_genotyped_or_well_imputed(info, r2=0):
    """Determine if the current variant was genotyped or was well-imputed

    Parameters
    ----------
    info : str
        Data from the INFO column of an imputed VCF file
    r2 : float
        R-squared threshold for inclusion based on imputation quality

    Returns
    -------
    bool
        True if the current variant either was genotyped or was well-imputed,
        (i.e. imputation quality exceeds threshold) False otherwise.
    """
    info_list = info.split(';')
    return info_list[-1] == 'TYPED' or float(info_list[2].split('=')[1]) > r2


@staticmethod
def after_registration(cls):
    """Operations that should be preformed to modify class attributes after
        registration. These actions will not be performed if the environment
        variable YGG_RUNNING_YGGSCHEMA is set."""
    pass


@classmethod
def parse(cls, json):
    """Parse a json dict and return the correct subclass of :class:`ValidatorEffect`.

        It uses the 'effect' key to determine which :class:`ValidatorEffect` to instantiate.
        Please refer to :class:`enums.ValidatorEffectTypes` for the supported effects.

        :param json: dictionary containing the specific keys to parse into a :class:`ValidatorEffect`
        :type json: dict
        :returns: the instantiated subclass of :class:`ValidatorEffect`
        :rtype: :class:`ValidatorEffect` or subclass
        """
    effect = json.get('effect')
    if effect:
        from pykechain.models.validators import effects
        effect_implementation_classname = effect[0].upper() + effect[1:]
        if hasattr(effects, effect_implementation_classname):
            return getattr(effects, effect_implementation_classname)(json=json)
        else:
            raise Exception('unknown effect in json')
    raise Exception("Effect unknown, incorrect json: '{}'".format(json))


def result(problem, action):
    """The outcome of applying an action to the current problem"""
    if action is not None:
        problem.act(action)
        return problem
    else:
        return problem


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

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

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


def inv(a, prime):
    """
    Compute multiplicative inverse modulo a prime.
    """
    return pow(a, prime - 2, prime)


def spacedata_cleanup():
    """Remove unused settings for invisible editors

    """
    pass


def format_date(dt):
    """
    Converts date time to yyyy-MM-dd HH:mm format
    Parameters
    ----------
    dt : datetime.datetime

    Returns
    -------
    str
    """
    if dt is None:
        return None
    return dt.strftime('%Y-%m-%d %R')


def IsDifferentDockingPosition(pane1, pane2):
    """
    Returns whether `pane1` and `pane2` are in a different docking position
    based on pane status, docking direction, docking layer and docking row.

    :param `pane1`: a :class:`AuiPaneInfo` instance;
    :param `pane2`: another :class:`AuiPaneInfo` instance.
    """
    return (pane1.IsFloating() != pane2.IsFloating() or pane1.
        dock_direction != pane2.dock_direction or pane1.dock_layer != pane2
        .dock_layer or pane1.dock_row != pane2.dock_row)


def keyitem_restore(item_id: int=0):
    """Restore key map item

    :param item_id: Item Identifier, Identifier of the item to remove
    :type item_id: int
    """
    pass


def check_banned_networks(networks, banned_networks):
    """Verifies banned networks are not present."""
    if banned_networks:
        msg = 'Networks (%s) not allowed'
        msg_networks = ','.join(banned_networks)
        if banned_networks.intersection(networks) != set():
            return msg % msg_networks
    return ''


def convert_state_dict(state_dict):
    """Converts a state dict saved from a dataParallel module to normal
       module state_dict inplace
       :param state_dict is the loaded DataParallel model_state

    """
    for k, v in state_dict.items():
        name = k[7:]
        state_dict[name] = v
        del state_dict[k]
    return state_dict


def _is_key_file_encrypted(key_file):
    """Detects if a key file is encrypted or not."""
    with open(key_file, 'r') as f:
        for line in f:
            if 'ENCRYPTED' in line:
                return True
    return False


def process_data(data_list, process_by_line=False):
    """Process a list of extractions into a dictionary of `loc` and `text`
    organized by `frame`

    Parameters
    ----------
    data_list : list
        A list of extractions created by
        :meth:`panoptes_aggregation.extractors.poly_line_text_extractor.poly_line_text_extractor`

    Returns
    -------
    processed_data : dict
        A dictionary with keys for each `frame` of the subject and values being dictionaries
        with `x`, `y`, `text`, and `slope` keys. `x`, `y`, and `text` are list-of-lists, each inner
        list is from a single annotaiton, `slope` is the list of slopes (in deg) for each of these
        inner lists.
    """
    data_by_frame = {}
    for data_index, data in enumerate(data_list):
        for frame, value in data.items():
            gs = value.get('gold_standard', False)
            data_by_frame.setdefault(frame, {})
            data_by_frame[frame].setdefault('x', [])
            data_by_frame[frame].setdefault('y', [])
            data_by_frame[frame].setdefault('text', [])
            data_by_frame[frame].setdefault('slope', [])
            data_by_frame[frame].setdefault('gold_standard', [])
            data_by_frame[frame].setdefault('data_index', [])
            for x, y, t, s in zip(value['points']['x'], value['points']['y'
                ], value['text'], value['slope']):
                if process_by_line:
                    data_by_frame[frame]['x'].append([x[0], x[-1]])
                    data_by_frame[frame]['y'].append([y[0], y[-1]])
                    data_by_frame[frame]['text'].append([' '.join(t)])
                else:
                    data_by_frame[frame]['x'].append(x)
                    data_by_frame[frame]['y'].append(y)
                    data_by_frame[frame]['text'].append(t)
                data_by_frame[frame]['slope'].append(s)
                data_by_frame[frame]['gold_standard'].append(gs)
                data_by_frame[frame]['data_index'].append(data_index)
    return data_by_frame


def isiterable(obj):
    """Returns true of the given object is iterable."""
    try:
        from collections import Iterable
        if isinstance(obj, Iterable):
            return True
    except ImportError:
        pass
    try:
        iter(obj)
        return True
    except TypeError:
        return False


def count_junctions(graph):
    """Return the number of junctions in graph"""
    junc_count = 0
    for node in graph.nodes():
        if graph.in_degree(node) > 1:
            junc_count += 1
        if graph.out_degree(node) > 1:
            junc_count += 1
    return junc_count