def set_log_level(level):
    """
    Convenience function to set the log level of all hyperspy modules.

    Note: The log level of all other modules are left untouched.

    Parameters
    ----------
        level : {int | str}
            The log level to set. Any values that `logging.Logger.setLevel()`
            accepts are valid. The default options are:
                - 'CRITICAL'
                - 'ERROR'
                - 'WARNING'
                - 'INFO'
                - 'DEBUG'
                - 'NOTSET'

    Example use
    -----------

    For normal logging of hyperspy functions, you can set the log level like
    this:

        >>> import hyperspy.api as hs
        >>> hs.set_log_level('INFO')
        >>> hs.load(r'my_file.dm3')
        INFO:hyperspy.io_plugins.digital_micrograph:DM version: 3
        INFO:hyperspy.io_plugins.digital_micrograph:size 4796607 B
        INFO:hyperspy.io_plugins.digital_micrograph:Is file Little endian? True
        INFO:hyperspy.io_plugins.digital_micrograph:Total tags in root group: 15
        <Signal2D, title: My file, dimensions: (|1024, 1024)>

    If you need the log output during the initial import of hyperspy, you
    should set the log level like this:

        >>> from hyperspy.logger import set_log_level
        >>> set_log_level('DEBUG')
        >>> import hyperspy.api as hs
        DEBUG:hyperspy.gui:Loading hyperspy.gui
        DEBUG:hyperspy.gui:Current MPL backend: TkAgg
        DEBUG:hyperspy.gui:Current ETS toolkit: qt4
        DEBUG:hyperspy.gui:Current ETS toolkit set to: null

    """
    import logging
    logging.basicConfig()
    logging.getLogger('hyperspy').setLevel(level)


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 _convert_string_to_unicode(string):
    """
    If the string is bytes, decode it to a string (for python3 support)
    """
    result = string
    try:
        if string is not None and not isinstance(string, str):
            result = string.decode('utf-8')
    except (TypeError, UnicodeDecodeError, AttributeError):
        pass
    return result


def get_LA_GeoJson(LA_cd):
    """
    returns a link to LSOA geojson file within LA passed from https://github.com/martinjc/UK-GeoJSON/
    """
    link_base = (
        'https://raw.githubusercontent.com/martinjc/UK-GeoJSON/master/json/statistical/eng/lsoa_by_lad/'
        )
    new_link = link_base + str(LA_cd) + '.json'
    return new_link


@staticmethod
def _process_backup_data(data, compressor, encryptor, do_compress=True):
    """Compresses and encrypts provided data according to args"""
    if do_compress:
        data = compressor.compress(data)
    if encryptor:
        data = encryptor.encrypt(data)
    return data


def describe_hsm_client_certificates(HsmClientCertificateIdentifier=None,
    MaxRecords=None, Marker=None, TagKeys=None, TagValues=None):
    """
    Returns information about the specified HSM client certificate. If no certificate ID is specified, returns information about all the HSM certificates owned by your AWS customer account.
    If you specify both tag keys and tag values in the same request, Amazon Redshift returns all HSM client certificates that match any combination of the specified keys and values. For example, if you have owner and environment for tag keys, and admin and test for tag values, all HSM client certificates that have any combination of those values are returned.
    If both tag keys and values are omitted from the request, HSM client certificates are returned regardless of whether they have tag keys or values associated with them.
    See also: AWS API Documentation

    :example: response = client.describe_hsm_client_certificates(
        HsmClientCertificateIdentifier='string',
        MaxRecords=123,
        Marker='string',
        TagKeys=[
            'string',
        ],
        TagValues=[
            'string',
        ]
    )

    :type HsmClientCertificateIdentifier: string
    :param HsmClientCertificateIdentifier: The identifier of a specific HSM client certificate for which you want information. If no identifier is specified, information is returned for all HSM client certificates owned by your AWS customer account.

    :type MaxRecords: integer
    :param MaxRecords: The maximum number of response records to return in each call. If the number of remaining response records exceeds the specified MaxRecords value, a value is returned in a marker field of the response. You can retrieve the next set of records by retrying the command with the returned marker value.
            Default: 100
            Constraints: minimum 20, maximum 100.

    :type Marker: string
    :param Marker: An optional parameter that specifies the starting point to return a set of response records. When the results of a DescribeHsmClientCertificates request exceed the value specified in MaxRecords , AWS returns a value in the Marker field of the response. You can retrieve the next set of response records by providing the returned marker value in the Marker parameter and retrying the request.

    :type TagKeys: list
    :param TagKeys: A tag key or keys for which you want to return all matching HSM client certificates that are associated with the specified key or keys. For example, suppose that you have HSM client certificates that are tagged with keys called owner and environment . If you specify both of these tag keys in the request, Amazon Redshift returns a response with the HSM client certificates that have either or both of these tag keys associated with them.
            (string) --

    :type TagValues: list
    :param TagValues: A tag value or values for which you want to return all matching HSM client certificates that are associated with the specified tag value or values. For example, suppose that you have HSM client certificates that are tagged with values called admin and test . If you specify both of these tag values in the request, Amazon Redshift returns a response with the HSM client certificates that have either or both of these tag values associated with them.
            (string) --

    :rtype: dict
    :return: {
        'Marker': 'string',
        'HsmClientCertificates': [
            {
                'HsmClientCertificateIdentifier': 'string',
                'HsmClientCertificatePublicKey': 'string',
                'Tags': [
                    {
                        'Key': 'string',
                        'Value': 'string'
                    },
                ]
            },
        ]
    }

    """
    pass


def uninstall(name):
    """Install extension called ``name``.
        """


def check_response_dimensionality(train, test, allow_test_none=True):
    """Make sure matrices are 2D arrays before running models
    """
    if train.ndim == 1:
        train = train[..., None]
    if test is not None:
        if test.ndim == 1:
            test = test[..., None]
    elif not allow_test_none:
        test = train
    return train, test


def mercalli(mag):
    """
    Return Mercalli index.

    Parameters
    ----------
    mag : float
        Local magnitude.

    Returns
    -------
    merc : str
        Mercalli index

    """
    if mag < 2:
        merc = 'I'
    elif mag < 3:
        merc = 'II'
    elif mag < 4:
        merc = 'III'
    elif mag == 4:
        merc = 'IV'
    elif mag < 5:
        merc = 'V'
    elif mag < 6:
        merc = 'VI'
    elif mag == 6:
        merc = 'VII'
    elif mag < 7:
        merc = 'VIII'
    elif mag == 7:
        merc = 'IX'
    elif mag < 8:
        merc = 'X'
    elif mag == 8:
        merc = 'XI'
    else:
        merc = 'XII'
    return merc


def clickselect(extend: bool=False, deselect_all: bool=False, column: bool=
    False, curves: bool=False):
    """Select keyframes by clicking on them

    :param extend: Extend Select, Toggle keyframe selection instead of leaving newly selected keyframes only
    :type extend: bool
    :param deselect_all: Deselect On Nothing, Deselect all when nothing under the cursor
    :type deselect_all: bool
    :param column: Column Select, Select all keyframes that occur on the same frame as the one under the mouse
    :type column: bool
    :param curves: Only Curves, Select all the keyframes in the curve
    :type curves: bool
    """
    pass


@classmethod
def _try_write_with_flush(cls, fileobj, payload):
    """This method is here so that it can be patched to simulate write errors.

        This is because mock can't patch primitive objects like file objects.
        """
    fileobj.write(payload)
    fileobj.flush()


def _get_qt_qmake_config(qmake_config, qt_version):
    """ Return a dict of qmake configuration values for a specific Qt version.
    """
    qt_qmake_config = {}
    for name, value in qmake_config.items():
        name_parts = name.split(':')
        if len(name_parts) == 2 and name_parts[0] == qt_version:
            qt_qmake_config[name_parts[1]] = value
    return qt_qmake_config


def pytest_addoption(parser):
    """Add all our command line options"""
    group = parser.getgroup('pylint')
    group.addoption('--pylint', action='store_true', default=False, help=
        'run pylint on all')
    group.addoption('--no-pylint', action='store_true', default=False, help
        ='disable running pylint ')
    group.addoption('--pylint-rcfile', default=None, help=
        'Location of RC file if not pylintrc')
    group.addoption('--pylint-error-types', default='CRWEF', help=
        'The types of pylint errors to consider failures by letter, default is all of them (CRWEF).'
        )
    group.addoption('--pylint-jobs', default=None, help=
        'Specify number of processes to use for pylint')
    group.addoption('--pylint-output-file', default=None, help=
        'Path to a file where Pylint report will be printed to.')
    group.addoption('--pylint-ignore', default=None, help=
        'Files/directories that will be ignored')
    group.addoption('--pylint-ignore-patterns', default=None, help=
        'Files/directories patterns that will be ignored')


@classmethod
def database_connect(cls):
    """Make sure database is connected.

        Dont reopen connection.
        """
    if cls._meta.database.is_closed():
        cls._meta.database.connect()


def iter_slices(string, slice_length):
    """Iterate over slices of a string."""
    pos = 0
    if slice_length is None or slice_length <= 0:
        slice_length = len(string)
    while pos < len(string):
        yield string[pos:pos + slice_length]
        pos += slice_length


def black_b(string):
    """background color to black"""
    return '\x1b[40m' + string + '\x1b[0m'


def is_defined_in_module(o, module):
    """
    Checks if an object is defined in a given module and not imported.

    Args:
        o (object): Object to check
        module (module): Module

    Returns:
        True or False
    """
    return o.__module__ == module.__name__


@staticmethod
def __collection_init__(client):
    """Write some collection initial operation, like set some index."""
    client.storage.drop_indexes()
    client.storage.create_index('timestamp', expireAfterSeconds=86400)
    client.storage.create_index('mail')


def kill_process(pid, list_):
    """
	Kills given process pid in list_.
	"""
    for process in list_:
        if process.pid == pid:
            process.terminate()


def update_integration_response(restApiId=None, resourceId=None, httpMethod
    =None, statusCode=None, patchOperations=None):
    """
    Represents an update integration response.
    See also: AWS API Documentation

    :example: response = client.update_integration_response(
        restApiId='string',
        resourceId='string',
        httpMethod='string',
        statusCode='string',
        patchOperations=[
            {
                'op': 'add'|'remove'|'replace'|'move'|'copy'|'test',
                'path': 'string',
                'value': 'string',
                'from': 'string'
            },
        ]
    )

    :type restApiId: string
    :param restApiId: [REQUIRED]
            Specifies an update integration response request's API identifier.

    :type resourceId: string
    :param resourceId: [REQUIRED]
            Specifies an update integration response request's resource identifier.

    :type httpMethod: string
    :param httpMethod: [REQUIRED]
            Specifies an update integration response request's HTTP method.

    :type statusCode: string
    :param statusCode: [REQUIRED]
            Specifies an update integration response request's status code.

    :type patchOperations: list
    :param patchOperations: A list of update operations to be applied to the specified resource and in the order specified in this list.
            (dict) -- A single patch operation to apply to the specified resource. Please refer to http://tools.ietf.org/html/rfc6902#section-4 for an explanation of how each operation is used.
            op (string) --An update operation to be performed with this PATCH request. The valid value can be 'add', 'remove', or 'replace'. Not all valid operations are supported for a given resource. Support of the operations depends on specific operational contexts. Attempts to apply an unsupported operation on a resource will return an error message.
            path (string) --The op operation's target, as identified by a JSON Pointer value that references a location within the targeted resource. For example, if the target resource has an updateable property of {'name':'value'} , the path for this property is /name . If the name property value is a JSON object (e.g., {'name': {'child/name': 'child-value'}} ), the path for the child/name property will be /name/child~1name . Any slash ('/') character appearing in path names must be escaped with '~1', as shown in the example above. Each op operation can have only one path associated with it.
            value (string) --The new target value of the update operation. When using AWS CLI to update a property of a JSON value, enclose the JSON object with a pair of single quotes in a Linux shell, e.g., '{'a': ...}'. In a Windows shell, see Using JSON for Parameters .
            from (string) --Not supported.

    :rtype: dict
    :return: {
        'statusCode': 'string',
        'selectionPattern': 'string',
        'responseParameters': {
            'string': 'string'
        },
        'responseTemplates': {
            'string': 'string'
        },
        'contentHandling': 'CONVERT_TO_BINARY'|'CONVERT_TO_TEXT'
    }

    :returns:
    (string) --
    (string) --

    """
    pass


def ema(series, n):
    """
    指数加权移动平均线: 求series序列n周期的指数加权移动平均

        计算公式:
            ema(x, n) = 2 * x / (n + 1) + (n - 1) * ema(x, n).shift(1) / (n + 1)

        注意:
            1. n 需大于等于1
            2. 对距离当前较近的k线赋予了较大的权重

    Args:
        series (pandas.Series): 数据序列

        n (int): 周期

    Returns:
        pandas.Series: 指数加权移动平均线序列

    Example::

        from tqsdk import TqApi, TqSim, tafunc

        api = TqApi(TqSim())
        klines = api.get_kline_serial("CFFEX.IF1908", 24 * 60 * 60)
        ema = tafunc.ema(klines.close, 5)
        print(list(ema))
    """
    ema_data = series.ewm(span=n, adjust=False).mean()
    return ema_data


def unpack_nested_exception(error):
    """
        If exception are stacked, return the first one

        :param error: A python exception with possible exception embeded within
        :return: A python exception with no exception embeded within
    """
    i = 0
    while True:
        if error.args[i:]:
            if isinstance(error.args[i], Exception):
                error = error.args[i]
                i = 0
            else:
                i += 1
        else:
            break
    return error


def _check_is_max_context(doc_spans, cur_span_index, position):
    """Check if this is the 'max context' doc span for the token."""
    best_score = None
    best_span_index = None
    for span_index, doc_span in enumerate(doc_spans):
        end = doc_span.start + doc_span.length - 1
        if position < doc_span.start:
            continue
        if position > end:
            continue
        num_left_context = position - doc_span.start
        num_right_context = end - position
        score = min(num_left_context, num_right_context
            ) + 0.01 * doc_span.length
        if best_score is None or score > best_score:
            best_score = score
            best_span_index = span_index
    return cur_span_index == best_span_index


@classmethod
def dec_deg2deg_min(cls, coord):
    """Convert decimal degrees to degrees.minutes"""
    if coord < 0:
        sgn = -1
        coord = -coord
    else:
        sgn = 1
    deg = cls.int_trunc(coord)
    minutes = abs(coord - deg) * 0.6
    return sgn * (deg + minutes)


def symmetric_diff(a, b):
    """Computes the symmetric difference of sets ``a`` and ``b``."""
    return a ^ b


@classmethod
def abulk(cls, x):
    """
        calculate the bulk (relaxed) lattice parameter of the Ga_{1-x}In_{x}As
        alloy
        """
    return cls.aGaAs + 0.40505 * x


def getServerInfo(pbclient=None, dc_id=None):
    """ gets info of servers of a data center"""
    if pbclient is None:
        raise ValueError("argument 'pbclient' must not be None")
    if dc_id is None:
        raise ValueError("argument 'dc_id' must not be None")
    server_info = []
    servers = pbclient.list_servers(dc_id, 1)
    for server in servers['items']:
        props = server['properties']
        info = dict(id=server['id'], name=props['name'], state=server[
            'metadata']['state'], vmstate=props['vmState'])
        server_info.append(info)
    return server_info


def _num_tokens_of(rule):
    """Calculate the total number of tokens in a rule."""
    total = len(rule.get('tokens'))
    for _ in ('prev_classes', 'prev_tokens', 'next_tokens', 'next_classes'):
        val = rule.get(_)
        if val:
            total += len(val)
    return total


def p_class_name_constant(p):
    """class_name_constant : class_name DOUBLE_COLON CLASS"""
    p[0] = p[1]


def tfidf(corpus):
    """Compute a TFIDF matrix (Term Frequency and Inverse Document Freuqency matrix)"""
    raise NotImplementedError('Google TFIDF for canonical implementations')


@classmethod
def get_Instance(cls, inputdict):
    """
        This is the recommended method to generate a BibTeX Entry object.

        It returns an Entry object depending on the ENTRYTYPE as defined in the *inputdict*.
        To initialize an Entry object one need to commit an dictionary containing the initial tags
        of an Entry, like ``{'ID':'Doe2015', 'ENTRYTYPE':'article', 'year':'2015', ...}``.

        :param inputdict: the initial values of an Entry
        :type inputdict: .Entry.datadict
        :return: BibTeX Entry object
        :rtype: :class:`.Article` | :class:`.Book` | ...
        :raises NameError: if ENTRYTYPE is invalid
        :raises KeyError: if ENTRYTYPE is missed
        """
    if 'ENTRYTYPE' not in inputdict:
        msg = 'Entry type is not defined'
        raise KeyError(msg)
    if inputdict['ENTRYTYPE'] not in cls._registeredTypes:
        msg = str(inputdict['ENTRYTYPE']) + ' is not a valid Entry type!'
        raise NameError(msg)
    return cls._registeredTypes[inputdict['ENTRYTYPE']](inputdict)


def fastmrca_getter(tn, x):
    """Helper function for submitting stuff."""
    taxa = tn.get_taxa(labels=x)
    bitmask = 0
    for taxon in taxa:
        bitmask |= tn.taxon_bitmask(taxon)
    return bitmask


def delete_shorturl(ctx, slug):
    """Delete a shorturl from the database."""
    query = 'DELETE FROM `shorturls` WHERE `slug` = %s'
    ctx.execute(query, (slug,))


@classmethod
def __parse_extraports(cls, extraports_data):
    """
            Private method parsing the data from extra scanned ports.
            X extraports were in state "closed" server returned "conn-refused"
            tag: <extraports>

            :param extraports_data: XML data for extraports
            :type extraports_data: xml.ElementTree.Element or a string

            :return: python dict with following keys: state, count, reason
        """
    rdict = {'state': '', 'count': '', 'reasons': []}
    xelement = cls.__format_element(extraports_data)
    extraports_dict = cls.__format_attributes(xelement)
    if 'state' in extraports_dict:
        rdict['state'] = extraports_dict
    if 'count' in extraports_dict:
        rdict['count'] = extraports_dict
    for xelt in xelement:
        if xelt.tag == 'extrareasons':
            extrareasons_dict = cls.__format_attributes(xelt)
            rdict['reasons'].append(extrareasons_dict)
    return rdict


def SizeBenefitSurg(t):
    """Surgery benefit per policy"""
    return 0


def _make_namespaced_xattr_key(key, namespace='user'):
    """
    Create a fully-qualified xattr-key by including the intended namespace.

    Namespacing differs among OSes[1]:

        FreeBSD: user, system
        Linux: user, system, trusted, security
        MacOS X: not needed

    Mac OS X won't break if we include a namespace qualifier, so, for
    simplicity, we always include it.

    --
    [1] http://en.wikipedia.org/wiki/Extended_file_attributes
    """
    namespaced_key = '.'.join([namespace, key])
    return namespaced_key


def getTagsAndCounts(include_hidden=False):
    """Return a list of tags and counts - this is the summary information.
        """


def _get_return_value_type_name_from_line(line_str):
    """
    Get the type name of return value from the target line string.

    Parameters
    ----------
    line_str : str
        Target line string.

    Returns
    ----------
    return_value_type_name : str
        Type name of return value.
    """
    colon_exists = ':' in line_str
    if not colon_exists:
        return_value_type_name = line_str.split(':')[0]
    else:
        return_value_type_name = line_str.split(':')[1]
    return_value_type_name = return_value_type_name.strip()
    return return_value_type_name


def describe_workspaces(WorkspaceIds=None, DirectoryId=None, UserName=None,
    BundleId=None, Limit=None, NextToken=None):
    """
    Obtains information about the specified WorkSpaces.
    Only one of the filter parameters, such as BundleId , DirectoryId , or WorkspaceIds , can be specified at a time.
    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_workspaces(
        WorkspaceIds=[
            'string',
        ],
        DirectoryId='string',
        UserName='string',
        BundleId='string',
        Limit=123,
        NextToken='string'
    )

    :type WorkspaceIds: list
    :param WorkspaceIds: An array of strings that contain the identifiers of the WorkSpaces for which to retrieve information. This parameter cannot be combined with any other filter parameter.
            Because the CreateWorkspaces operation is asynchronous, the identifier it returns is not immediately available. If you immediately call DescribeWorkspaces with this identifier, no information is returned.
            (string) --

    :type DirectoryId: string
    :param DirectoryId: Specifies the directory identifier to which to limit the WorkSpaces. Optionally, you can specify a specific directory user with the UserName parameter. This parameter cannot be combined with any other filter parameter.

    :type UserName: string
    :param UserName: Used with the DirectoryId parameter to specify the directory user for whom to obtain the WorkSpace.

    :type BundleId: string
    :param BundleId: The identifier of a bundle to obtain the WorkSpaces for. All WorkSpaces that are created from this bundle will be retrieved. This parameter cannot be combined with any other filter parameter.

    :type Limit: integer
    :param Limit: The maximum number of items to return.

    :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: {
        'Workspaces': [
            {
                'WorkspaceId': 'string',
                'DirectoryId': 'string',
                'UserName': 'string',
                'IpAddress': 'string',
                'State': 'PENDING'|'AVAILABLE'|'IMPAIRED'|'UNHEALTHY'|'REBOOTING'|'STARTING'|'REBUILDING'|'MAINTENANCE'|'TERMINATING'|'TERMINATED'|'SUSPENDED'|'STOPPING'|'STOPPED'|'ERROR',
                'BundleId': 'string',
                'SubnetId': 'string',
                'ErrorMessage': 'string',
                'ErrorCode': 'string',
                'ComputerName': 'string',
                'VolumeEncryptionKey': 'string',
                'UserVolumeEncryptionEnabled': True|False,
                'RootVolumeEncryptionEnabled': True|False,
                'WorkspaceProperties': {
                    'RunningMode': 'AUTO_STOP'|'ALWAYS_ON',
                    'RunningModeAutoStopTimeoutInMinutes': 123
                }
            },
        ],
        'NextToken': 'string'
    }

    """
    pass


def initial_sequence(player, opponent, action, initial_seq):
    """Play the moves in `seq` first (must be a list), ignoring the strategy's
    moves until the list is exhausted."""
    index = len(player.history)
    if index < len(initial_seq):
        return initial_seq[index]
    return action


def get_requires(working_set, distribution):
    """ Return all of the other distributions that a distribution requires. """
    requires = []
    for requirement in distribution.requires():
        required = working_set.find(requirement)
        if required is not None:
            requires.append(working_set.find(requirement))
    return requires


@classmethod
def unregister_dict_to_class(cls, classname):
    """
        Removes the converter registered for the given classname. Dicts with that classname tag
        will be deserialized by the default mechanism again.

        This mechanism is not used for the pickle serializer.
        """
    if classname in cls.__custom_dict_to_class_registry:
        del cls.__custom_dict_to_class_registry[classname]


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

        :param NoteAclLinkDetails val:
        :rtype: EventDetails
        """
    return cls('note_acl_link_details', val)


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


def get_subnet_id(subnet: dict):
    """
    Convenience function to extract subnet ID from subnet dictionary.
    :param subnet: Subnet dictionary returned by get_subnet() or list_subnets()
    :return: subnet ID.
    """
    return subnet.get('SubnetId')


@classmethod
def create(cls, root, definitions):
    """
        Create an object based on the root tag name.

        @param root: An XML root element.
        @type root: L{Element}
        @param definitions: A definitions object.
        @type definitions: L{Definitions}
        @return: The created object.
        @rtype: L{WObject}

        """
    fn = cls.tags.get(root.name)
    if fn is not None:
        return fn(root, definitions)


def logging_arguments(parser, core=core):
    """Logging command line arguments, allows override of the core class
    instance where required.

    `parser`
        Instance of ArgumentParser.
    `core`
        Package core instance.
    """
    log_level_kwargs = {'type': str, 'default': core.DEFAULT_LOG_LEVEL,
        'metavar': 'LEVEL', 'help': 'logging level'}
    parser.add_argument('-l', **log_level_kwargs)
    log_file_kwargs = {'type': str, 'default': core.DEFAULT_LOG_FILE,
        'metavar': 'FILE', 'help': 'logging file'}
    parser.add_argument('--log-file', **log_file_kwargs)


@classmethod
def find_by(cls, parent=None, **attributes):
    """
        Gets the first resource of the given type and parent (if provided) with matching attributes.
        This will trigger an api GET request.
        :param parent ResourceBase: the parent of the resource - used for nesting the request url, optional
        :param **attributes: any number of keyword arguments as attributes to search the resource by
        :returns: the matching resource, None if not found
        :raises ResourceError: if the no valid attributes are provided
        """
    all_nones = not all(attributes.values())
    if not attributes or all_nones:
        raise cls.ResourceError('at least one attribute must be provided')
    matches = cls.filter(parent, **attributes)
    if matches:
        return matches[0]


@staticmethod
def _year_from_2digits(short_year, current_year):
    """
        Converts a relative 2-digit year to an absolute 4-digit year
        :param short_year: the relative year
        :param current_year: the current year
        :return: the absolute year
        """
    if short_year < 100:
        short_year += current_year - current_year % 100
        if abs(short_year - current_year) >= 50:
            if short_year < current_year:
                return short_year + 100
            else:
                return short_year - 100
    return short_year


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


@staticmethod
def import_json():
    """Import a module for JSON"""
    try:
        import json
    except ImportError:
        import simplejson as json
    else:
        return json


@staticmethod
def gene_name(name):
    """
        Split the FASTA header string into its components, including gene name, allele, and accession
        :param name: FASTA header
        :return: gname, genename, accession, allele: name of gene. Often the same as genename, but for certain entries
        it is longer, full gene name, accession, and allele extracted from the FASTA header
        """
    if ('Van' in name or 'mcr' in name or 'aph' in name or 'ddlA' in name or
        'ant' in name or 'aadE_Cc' in name):
        try:
            if name == "ant(3'')_Ih_aac(6')_IId_1_AF453998":
                gene1, version1, gene2, version2, allele, accession = (name
                    .split('_'))
                gname = '{g1}-{v1}-{g2}-{v2}'.format(g1=gene1, v1=version1,
                    g2=gene2, v2=version2)
                genename = gname
            elif name == 'ant(3)_Ia_1_X02340':
                gene, version, allele, accession = name.split('_')
                gname = '{g}-{v}'.format(g=gene, v=version)
                genename = gname
            elif 'mcr_3' in name or 'mcr_2' in name or 'mcr_1.10' in name:
                gene, combinedversion, allele, accession = name.split('_')
                version = combinedversion.split('.')[0]
                gname = '{gene}-{version}'.format(gene=gene, version=version)
                genename = gname
            else:
                try:
                    pregene, postgene, allele, accession = name.split('_')
                    gname = '{pre}-{post}'.format(pre=pregene, post=postgene)
                    genename = gname
                except ValueError:
                    (pregene, postgene, allele, preaccession, postaccession
                        ) = name.split('_')
                    genename = '{pre}-{post}'.format(pre=pregene, post=postgene
                        )
                    accession = '{pre}_{post}'.format(pre=preaccession,
                        post=postaccession)
                    gname = pregene
        except ValueError:
            genename, allele, accession = name.split('_')
            gname = genename
    elif 'bla' in name or 'aac' in name or 'ARR' in name or 'POM' in name:
        if 'OKP' in name or 'CTX' in name or 'OXY' in name:
            gene, version1, version2, allele, accession = name.split('_')
            gname = '{g}-{v1}-{v2}'.format(g=gene, v1=version1, v2=version2)
            genename = gname
        elif 'CMY' in name:
            try:
                gname, allele, version, accession = name.split('_')
            except ValueError:
                gname, allele, version, pre_accession, post_accession = (name
                    .split('_'))
                accession = '{pre}_{post}'.format(pre=pre_accession, post=
                    post_accession)
            genename = gname
        elif name == "aac(3)_Ib_aac(6')_Ib_1_AF355189":
            gene1, version1, gene2, version2, allele, accession = name.split(
                '_')
            gname = '{g1}-{v1}-{g2}-{v2}'.format(g1=gene1, v1=version1, g2=
                gene2, v2=version2)
            genename = gname
        elif 'alias' in name:
            gene1, version1, alias, gene2, version2, allele, accession = (name
                .split('_'))
            gname = '{g1}-{v1}'.format(g1=gene1, v1=version1)
            genename = gname
        else:
            try:
                genename, allele, accession = name.split('_')
                gname = genename
            except ValueError:
                try:
                    genename, version, allele, accession = name.split('_')
                    gname = '{g}-{v}'.format(g=genename, v=version)
                except ValueError:
                    (genename, version, allele, preaccession, postaccession
                        ) = name.split('_')
                    gname = '{g}-{v}'.format(g=genename, v=version)
                    genename = gname
                    accession = '{preaccess}_{postaccess}'.format(preaccess
                        =preaccession, postaccess=postaccession)
    else:
        try:
            genename, allele, accession = name.split('_')
            gname = genename
        except ValueError:
            genename, allele, preaccession, postaccession = name.split('_')
            accession = '{preaccess}_{postaccess}'.format(preaccess=
                preaccession, postaccess=postaccession)
            gname = genename
    return gname, genename, accession, allele


def longueur_chemin(chemin, distance):
    """
    Retourne la longueur d'un chemin.
    """
    s = 0
    nb = len(chemin)
    for i in range(0, nb):
        s += distance(chemin[i], chemin[(i + 1) % nb])
    return s


def is_cuda_ndarray(obj):
    """Check if an object is a CUDA ndarray"""
    return getattr(obj, '__cuda_ndarray__', False)


def validate_age(name: str, tolerance: float, from_timestamp: float,
    to_timestamp: float) ->None:
    """Check if age is valid (within tolerance)"""
    age = to_timestamp - from_timestamp
    assert age <= tolerance, f'{name} is too old! (Age: {age} > Tolerance: {tolerance})'


def centroid(X):
    """ Calculate the centroid from a vectorset X """
    C = sum(X) / len(X)
    return C


@classmethod
def create(cls, package=None, version=None):
    """
        Create a new, empty changelog
        """
    dch_options = ['--create']
    if package:
        dch_options.extend(['--package', package])
    if version:
        dch_options.extend(['--newversion', version])
    cls.spawn_dch(dch_options=dch_options)
    return cls(filename='debian/changelog')


def jd_to_mjd(jd):
    """Convert Julian Day to Modified Julian Day.
    :param jd: Julian Day (float)
    :returns: Modified Julian Day (float)
    """
    return jd - 2400000.5


def next_pow_two(n):
    """Returns the next power of two greater than or equal to `n`"""
    i = 1
    while i < n:
        i = i << 1
    return i


def replace_pattern(tokens, new_pattern):
    """ Given a RegexLexer token dictionary 'tokens', replace all patterns that
        match the token specified in 'new_pattern' with 'new_pattern'.
    """
    for state in tokens.values():
        for index, pattern in enumerate(state):
            if isinstance(pattern, tuple) and pattern[1] == new_pattern[1]:
                state[index] = new_pattern


def underride(d, **kwds):
    """Adds entries from (kwds) to (d) only if they are not already set."""
    for key, val in kwds.items():
        d.setdefault(key, val)


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

        :param ShowcaseFileDownloadDetails val:
        :rtype: EventDetails
        """
    return cls('showcase_file_download_details', val)


def get_project_milestones(gl, project_id):
    """ Get Project's Milestones
    :param gl: GitLab Object Instance
    :param project_id: Project Identifier (int)
    :return: Milestones (List)
    """
    return False


@staticmethod
def _contains_vars(data):
    """
        returns True if the data contains a variable pattern
        """
    if isinstance(data, str):
        for marker in ('{%', '{{', '{#'):
            if marker in data:
                return True
    return False


@classmethod
def from_formula(cls, formula, data, subset=None):
    """
        Not implemented for State space models
        """
    raise NotImplementedError


def _format_local(local_path, local_is_path):
    """Format a path for log output"""
    if local_is_path:
        return local_path
    else:
        return getattr(local_path, 'name', '<file obj>')


def insert_duplicate_kanji(kanji_string):
    """
    Inserts full kanji for characters where a shorthand is used.

        >>> k = insert_duplicate_kanji(u'私々')
        >>> expected = u'私私'
        >>> k == expected
        True
    """
    loc = kanji_string.find('々')
    while loc > 0:
        dup = kanji_string[loc - 1]
        kanji_string = kanji_string[:loc] + dup + kanji_string[loc + 1:]
        loc = kanji_string.find('々')
    return kanji_string


def in_(*possibilities) ->dict:
    """Helper that produces mongo query dict for items being one of"""
    if len(possibilities) == 1:
        return possibilities[0]
    return {'$in': list(possibilities)}


def __get_data_at_step(file, mtm_dat, var):
    """

    Find the data step that corresponds to an BPM image file and get the
    corresponding data (key `var`) from an MTM data file.

    Parameters
    ----------
    file: str
        The path to a BMP image file. The file name given by the PCS instrument
        may not be changed, otherwise the step extraction may fail.
    mtm_dat: dict
        Instrument output data loaded from npz database file.
    var: str
        A key in the npz database.

    Returns
    -------
    dat: ndarray
        An array containing a single data point (float, int)

    """
    if '_ZERO.bmp' in file:
        step = 1
    else:
        step = int(file.split('_')[-1].replace('.bmp', ''))
    step_idx = mtm_dat['step_start'][step - 1]
    dat = mtm_dat[var][step_idx]
    return dat


def text_leading(leading):
    """Sets the spacing between lines of text in units of pixels

	:param leading: the size in pixels for spacing between lines
	:type align_x: int

	"""
    global _text_leading
    _text_leading = leading


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_path(dict_, path):
    """
    Get value at specific path in dictionary. Path is specified by slash-
    separated string, eg _get_path(foo, 'bar/baz') returns foo['bar']['baz']
    """
    cur = dict_
    for part in path.split('/'):
        cur = cur[part]
    return cur


@classmethod
def timestamp_str(cls, tzinfo='Asia/Shanghai'):
    """return string format of now as: '20180730115800'"""
    return f'{cls.now(tzinfo):%Y%m%d%H%M%S}'


def _outermost_bracket_groups(string, type='{}'):
    """
    >>> outermost_bracket_groups('{my name}')
    ['my name']
    >>> outermost_bracket_groups("{my nam\\'{e}}")
    ["my nam\\'{e}"]
    >>> outermost_bracket_groups('{my} {name}')
    ['my', 'name']
    >>> outermost_bracket_groups("{my} {nam\\'{e}}")
    ['my', "nam\\'{e}"]
    """
    l, r = type
    level = 0
    matches = []
    for c in string:
        if c == l:
            level += 1
            if level == 1:
                expr = []
        elif c == r:
            level -= 1
            if level == 0:
                matches.append(''.join(expr))
        elif level >= 1:
            expr.append(c)
    return matches


def float_to_str(value: float) ->str:
    """Converts double number to string using {.12g} formatter."""
    return format(value, '.12g')


def is_iter(obj):
    """
    evaluate is the object is an iterator

    Arguments
    ---------
    obj: any type

    Returns
    -------
    bool
        True if the object is iterable
    """
    try:
        iter(obj)
        return True
    except TypeError as e:
        return False


def info(dsList):
    """Display more info on an instance of DatasetList."""
    dsList.info()


def canonical_form(k, v):
    """
    Returns an iterable of key-value-pairs corresponding to the header in
    canonical form. This means that the header is split on commas unless for
    any reason it's a super-special snowflake (I'm looking at you Set-Cookie).
    """
    SPECIAL_SNOWFLAKES = set([b'set-cookie', b'set-cookie2'])
    k = k.lower()
    if k in SPECIAL_SNOWFLAKES:
        yield k, v
    else:
        for sub_val in v.split(b','):
            yield k, sub_val.strip()


def fatal_error(error):
    """Print out the error message that gets passed, then quit the program.

    Inputs:
    error = error message text

    :param error: str
    :return:
    """
    raise RuntimeError(error)


def do_authorization(transactionid, amt):
    """ DoAuthorization """


def hat(k):
    """Converts a 3-vector to an anti-sym matrix """
    import numpy as np
    A = np.zeros((3, 3))
    A[0, 1] = -k[2]
    A[0, 2] = k[1]
    A[1, 2] = -k[0]
    A = A - A.transpose()
    return A


def next_power_of_2(n):
    """Return the smallest integer power of 2 larger than the argument.

    Parameters
    ----------
    n : int
        A positive integer.

    Returns
    -------
    m : int
        Smallest integer power of 2 larger than n.
    """
    return 1 << n.bit_length()


def R(X, destination, a1, a2, b):
    """A single Salsa20 row operation"""
    a = X[a1] + X[a2] & 4294967295
    X[destination] ^= a << b | a >> 32 - b


def rpc_gas_price_strategy(web3, transaction_params=None):
    """
    A simple gas price strategy deriving it's value from the eth_gasPrice JSON-RPC call.
    """
    return web3.manager.request_blocking('eth_gasPrice', [])


def _update_mpcs(model, starting_id_dict, mpc_id, mpc_map):
    """updates the mpcs"""
    if 'mpc_id' in starting_id_dict and mpc_id is not None:
        for mpc_idi, mpc_group in sorted(model.mpcadds.items()):
            for unused_i, mpc in enumerate(mpc_group):
                assert hasattr(mpc, 'conid')
                mpc.conid = mpc_id
            mpc_map[mpc_idi] = mpc_id
            mpc_id += 1
        for mpc_idi, mpc_group in sorted(model.mpcs.items()):
            for unused_i, mpc in enumerate(mpc_group):
                assert hasattr(mpc, 'conid')
                mpc.conid = mpc_id
            mpc_map[mpc_idi] = mpc_id
            mpc_id += 1
    else:
        for mpc_id in model.mpcadds:
            mpc_map[mpc_id] = mpc_id
        for mpc_id in model.mpcs:
            mpc_map[mpc_id] = mpc_id


def flatted_conversions(conv_graph: dict) ->iter:
    """Yield 3-uplet (predecessors, successors, conversion function)"""
    for preds, succ_map in conv_graph.items():
        for succs, funcs in succ_map.items():
            for func in funcs:
                yield preds, succs, func


def merge_dicts(*dicts: dict) ->dict:
    """ 依次合并多个字典。merge multiple dict one by one.

    Examples::

        offset_limit_schema = {'offset': Validation(...), 'limit': Validation(...)}
        ...
        schema = merge_dicts(offset_limit_schema, from_to_schema, payment_schema)
    """
    dict_merged = {}
    for d in dicts:
        dict_merged.update(d)
    return dict_merged


@classmethod
def is_legacy_accession(cls, name: str):
    """
        Determines if an accession was created via the `legacy_accession` property.
        """
    return bool(cls._LEGACY_IDENTIFIER.match(name))


@staticmethod
def format_timedelta_ticks(x, pos, n_decimals):
    """
        Convert seconds to 'D days HH:MM:SS.F'
        """
    s, ns = divmod(x, 1000000000.0)
    m, s = divmod(s, 60)
    h, m = divmod(m, 60)
    d, h = divmod(h, 24)
    decimals = int(ns * 10 ** (n_decimals - 9))
    s = f'{int(h):02d}:{int(m):02d}:{int(s):02d}'
    if n_decimals > 0:
        s += f'.{decimals:0{n_decimals}d}'
    if d != 0:
        s = f'{int(d):d} days {s}'
    return s


def filter_nodes(nodes_list, ids=None, subtree=True):
    """Filters the contents of a nodes_list. If any of the nodes is in the
       ids list, the rest of nodes are removed. If none is in the ids list
       we include or exclude the nodes depending on the subtree flag.

    """
    if not nodes_list:
        return None
    nodes = nodes_list[:]
    if ids is not None:
        for node in nodes:
            if node.id in ids:
                nodes = [node]
                return nodes
    if not subtree:
        nodes = []
    return nodes


@classmethod
def __methods__(cls):
    """This method should return a list of GRPCMethod objects."""
    return []


def check_file_for_carriage_return(full_file_path):
    "with open(full_file_path, 'rb') as f:\n        Line_Read = f.readlines()\n        if ('\r\n' in Line_Read):\n            return '\r\n'\n        elif ('\n' in Line_Read):\n            return '\n'\n        else:\n            return None "
    infile = open(full_file_path, 'rb')
    for index, line in enumerate(infile.readlines()):
        if line[-2:] == '\r\n':
            return '\r\n'
        else:
            return '\n'


def _get_pathway_name(line):
    """Split the pathway name word and returns the name.

    :param line: first word from gmt file
    :rtype: str
    :return: pathway name
    """
    return line.split('%')[0]


def getNewChild(name):
    """
        Return the :class:`IPath` for child with `name`.

        Raise ChildAlreadyExists if child exists.
        """


def samples_with_hetero_calls(data, hetero_c):
    """Gets male and heterozygous calls.

    Args:
        data (pandas.DataFrame): the probability matrix
        hetero_c (str): the name of the heterozygous column

    Returns:
        pandas.Index: samples where call is heterozygous

    """
    return data[data.idxmax(axis=1) == hetero_c].index


def is_subsequence(short_seq, long_seq):
    """Is short_seq a subsequence of long_seq."""
    if not short_seq:
        return True
    pos = 0
    for x in long_seq:
        if pos == len(short_seq):
            return True
        if short_seq[pos] == x:
            pos += 1
    if pos == len(short_seq):
        return True
    return False


@staticmethod
def _padded_len(length):
    """Return length rounded up to the next multiple of 4 bytes"""
    return (length + 3) // 4 * 4


def _different_phases(row_i, row_j):
    """Return True if exon start or end phases are different."""
    value = row_i['StartPhase'] != row_j['StartPhase'] or row_i['EndPhase'
        ] != row_j['EndPhase']
    return value


def DEFREEZE_XRANGE(d):
    """ TODO reversing the operation of freezing xranges done by module alfanous.output """
    pass


def setSource(text, content_type='text/html'):
    """Save the source of the page template.

        'text' must be Unicode.
        """


def vertex_group_assign():
    """Assign the selected vertices to the active vertex group

    """
    pass


@staticmethod
def readFile(path, out_type=None):
    """Reads the contents of an artifact file.

        Args:
            path: Path to the artifact
            out_type: The data type
        Returns:
            The contents of the artifact encoded as specified by the
            output type.  So for an Array, this will return a Numpy array,
            for an Image, an IPython Image, etc.
        """
    if out_type is None:
        with open(path, 'rb') as fp:
            res = fp.read()
        return res
    return out_type.read_from_file(path)


def aug_remove(current, extra):
    """Remove extra from current. Not in formal
       specifications. Allowed to fail silently."""
    have_list = isinstance(current, list)
    if have_list:
        if extra in current:
            current.remove(extra)
            return current
        else:
            print('Removal Warning: %s not in %s' % (repr(extra), repr(
                current)))
            return current
    else:
        raise ValueError('Cannot remove %s from %s' % (repr(extra), repr(
            current)))


def remove_high_influence(x_train, y_train, lm):
    """
    This function studentize residuals and remove the ones with high influence
    studentizing means that removing one observation at the time and fit a line using the remaining ones.
    Effect on response variable is measured and the observations with high impact are labelled outliers.
    Outliers are removed afterwards.

    parameters:
    x_train: supplied for removing Outliers
    y_train: supplied for deleting same rows for convenience
    lm: regression classifier in order to obtain the influences

    returns:
    x_train & y_train without the outliers
    """
    import pandas as pd
    import numpy as np
    influence = lm.get_influence()
    resid_student = influence.resid_studentized_external
    resid = pd.concat([x_train, pd.Series(resid_student, name=
        'Studentized Residuals')], axis=1, join='inner')
    ind = resid.loc[(np.absolute(resid['Studentized Residuals']) > 3), :].index
    y_train.drop(ind, axis=0, inplace=True)
    x_train.drop(ind, axis=0, inplace=True)
    print('{} observations are removed'.format(len(ind)))
    print(resid.loc[(np.absolute(resid['Studentized Residuals']) > 3), :])
    return x_train, y_train


def builderAdded(builderName, builder):
    """
        A new Builder has just been added. This method may return an
        IStatusReceiver (probably 'self') which will be subscribed to receive
        builderChangedState and buildStarted/Finished events.

        @type  builderName: string
        @type  builder:     L{buildbot.status.builder.BuilderStatus}
        @rtype: implementer of L{IStatusReceiver}
        """


def Vcell_Calc(Enernst, Loss):
    """
    Calculate cell voltage.

    :param Enernst:  Enernst [V}
    :type Enernst : float
    :param Loss:  loss [V]
    :type Loss : float
    :return:  cell voltage [V] as float
    """
    try:
        result = Enernst - Loss
        return result
    except TypeError:
        print('[Error] Vcell Calculation Error (Enernst:%s, Loss:%s)' % (
            str(Enernst), str(Loss)))


def seek(offset, whence=0):
    """Set the reader's current position.

        The `offset` is a number of bytes.  The direction and source
        of the measurement is determined by the `whence` argument.

        The `whence` argument is optional and defaults to 0 (absolute
        file positioning); other recognized values are 1 (seek
        relative to the current position) and 2 (seek relative to the
        end).

        There is no return value.

        """


def is_escaped(value, index):
    """Returns True if the character at index is escaped with a \\ """
    cur = index - 1
    if cur < 0:
        return False
    while value[cur] == '\\':
        cur -= 1
        if cur < 0:
            break
    return (index - cur - 1) % 2


def table(rows):
    """returns rows wrapped in an HTML table"""
    content = []
    content.append('

')
    for row in rows:
        content.append('
')
        for item in row:
            content.append('')
            content.append(str(item))
            content.append('	')
        content.append('
')
    content.append('

')
    return ''.join(content)


def has_elements(*args):
    """
    Check if args has elements.

    :param args: a tuple
    :return: returns true if args has elements
    """
    if not args:
        raise ValueError('No elements found!')
    return True


def WriteMethodDeclaration(c, name, args, optargs):
    """ Write a method declaration:
    def name(self, args, optargs):
    in c """
    c.Write('def %s(self' % name)
    for a in args:
        c.Write(', %s' % a)
    for a in optargs:
        c.Write(', %s = None' % a)
    c.Write('):')
    c.NewLine()
    return


def orientation(p, q, r):
    """ Returns 1 if p q r are oriented clockwise, 2 if p q r are oriented
        counterclockwise and 0 if p q r lie on a line - are collinear."""
    val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])
    if val == 0:
        return 0
    if val > 0:
        return 1
    else:
        return 2


def _check_mod_11_2(numeric_string):
    """
    Validate numeric_string for its MOD-11-2 checksum.

    Any "-" in the numeric_string are ignored.

    The last digit of numeric_string is assumed to be the checksum, 0-9 or X.

    See ISO/IEC 7064:2003 and
    https://support.orcid.org/knowledgebase/articles/116780-structure-of-the-orcid-identifier
    """
    nums = numeric_string.replace('-', '')
    total = 0
    for num in nums[:-1]:
        digit = int(num)
        total = (total + digit) * 2
    remainder = total % 11
    result = (12 - remainder) % 11
    if result == 10:
        checkdigit = 'X'
    else:
        checkdigit = str(result)
    return nums[-1].upper() == checkdigit


def _format_lineno(session, line):
    """Helper function to format line numbers properly."""
    if session == 0:
        return str(line)
    return '%s#%s' % (session, line)


def get_base_url(htmlpage):
    """Return the base url of the given HtmlPage"""
    for element in htmlpage.parsed_body:
        if getattr(element, 'tag', None) == 'base':
            return element.attributes.get('href') or htmlpage.url
    return htmlpage.url


@staticmethod
def zero():
    """
        Return @c 0, the neutral element of integer addition.
        """
    return 0


@classmethod
def define(cls, name, parent=None, interleave=False):
    """Create define node."""
    node = cls('define', parent, interleave=interleave)
    node.occur = 0
    node.attr['name'] = name
    return node


def after_nothing(retry_state):
    """After call strategy that does nothing."""


def project_parser(parser, positional=True):
    """ Parser settings for every action using projects. """
    group = parser.add_argument_group('projects specifications options')
    group.add_argument('-a', '--all', action='store_true', help=
        'Work on all projects')
    group.add_argument('-s', '--single', action='store_true', help=
        'Work on specified projects without taking dependencies into account.')
    group.add_argument('-g', '--group', dest='groups', action='append',
        help='Specify a group of projects.')
    if positional:
        group.add_argument('projects', nargs='*', metavar='PROJECT', help=
            'Project name(s)')
    else:
        group.add_argument('-p', '--project', dest='projects', action=
            'append', help='Project name(s)')
    parser.set_defaults(single=False, projects=list())
    return group


def classname(obj):
    """Get a classname from an object.

    :rtype: str
    """
    return obj.__class__.__name__.lower()


def ext_right(data):
    """
    Extract the right half of the spectrum.

    Parameters
    ----------
    data : ndarray
        Array of NMR data.

    Returns
    -------
    ndata : ndarray
        Right half of spectrum.

    """
    return data[(...), int(data.shape[-1] / 2.0):]


def get_better_name(book_name):
    """
    Sometimes book name is slightly different than entered.
    This will try find more suitable book name using google search.

    """
    return book_name


def _text_point_at_line_end(size, p1, p2):
    """
    Calculate position of the text relative to a line defined by points
    p1 and p2.

    Parameters:
     - size: text size, a (width, height) tuple
     - p1:      beginning of line segment
     - p2:      end of line segment
    """
    name_dx = 0.0
    name_dy = 0.0
    ofs = 5
    dx = float(p2[0]) - float(p1[0])
    dy = float(p2[1]) - float(p1[1])
    name_w, name_h = size
    if dy == 0:
        rc = 1000.0
    else:
        rc = dx / dy
    abs_rc = abs(rc)
    h = dx > 0
    v = dy > 0
    if abs_rc > 6:
        if h:
            name_dx = ofs
            name_dy = -ofs - name_h
        else:
            name_dx = -ofs - name_w
            name_dy = -ofs - name_h
    elif 0 <= abs_rc <= 0.2:
        if v:
            name_dx = -ofs - name_w
            name_dy = ofs
        else:
            name_dx = -ofs - name_w
            name_dy = -ofs - name_h
    else:
        r = abs_rc < 1.0
        align_left = h ^ r
        align_bottom = v ^ r
        if align_left:
            name_dx = ofs
        else:
            name_dx = -ofs - name_w
        if align_bottom:
            name_dy = -ofs - name_h
        else:
            name_dy = ofs
    return p1[0] + name_dx, p1[1] + name_dy


@staticmethod
def _offshore_get_means(data, gen_gid):
    """Get the mean point data from the data array for gen_gid.

        Parameters
        ----------
        data : np.ndarray | None
            Array of mean data values or None if no data is available.
        gen_gid : int
            location to get mean data for

        Returns
        -------
        mean_data : float | None
            Mean data value or None if no data available.
        """
    mean_data = None
    if data is not None:
        mean_data = data[gen_gid]
    return mean_data


def resample_2_epi(T1, epi, aparc_aseg=None):
    """
        Resample images to epi resolution
    """
    import os
    import shutil
    from p3.utility import get_basename
    cwd = os.getcwd()
    epi = epi[0]
    out_file = os.path.join(cwd, '{}_funcres.nii.gz'.format(get_basename(T1)))
    os.system('3dresample -rmode Li -master {} -prefix {} -inset {}'.format
        (epi, out_file, T1))
    T1_epi = out_file
    if aparc_aseg:
        out_file = os.path.join(cwd, '{}_funcres.nii.gz'.format(
            get_basename(aparc_aseg)))
        os.system('3dresample -rmode NN -master {} -prefix {} -inset {}'.
            format(epi, out_file, aparc_aseg))
        aparc_aseg_epi = out_file
    else:
        aparc_aseg_epi = ''
    return T1_epi, aparc_aseg_epi


def get_field_info(field_file):
    """
    A utility for easily extracting information about the host model from a
    Django FileField (or subclass). This is especially useful for when you want
    to alter processors based on a property of the source model. For example::

        class MySpec(ImageSpec):
            def __init__(self, source):
                instance, attname = get_field_info(source)
                self.processors = [SmartResize(instance.thumbnail_width,
                                               instance.thumbnail_height)]

    """
    return getattr(field_file, 'instance', None), getattr(getattr(
        field_file, 'field', None), 'attname', None)


def p_cuesheet_items(t):
    """cuesheet_items : cuesheet_item
                      | cuesheet_items cuesheet_item"""
    if len(t) == 2:
        t[0] = [t[1]]
    else:
        t[0] = t[1] + [t[2]]


@staticmethod
def line_parser(line):
    """Define a simple parser for reading the file.

        It is used in the `self.load()` to parse the input file.

        Parameters
        ----------
        line : string
            A line to parse.

        Returns
        -------
        out : tuple of ints
            out is (step number, interface number and direction).

        Note
        ----
        The interface will be subtracted '1' in the analysis.
        This is just for backwards compatibility with the old Fortran
        code.
        """
    linessplit = line.strip().split()
    try:
        step, inter = int(linessplit[0]), int(linessplit[1])
        direction = -1 if linessplit[2] == '-' else 1
        return step, inter, direction
    except IndexError:
        return None


def shorten(string, maxlen):
    """shortens string if longer than maxlen, appending ellipsis"""
    if 1 < maxlen < len(string):
        string = string[:maxlen - 1] + u'…'
    return string[:maxlen]


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

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

        :returns:
            Iterator over instances of :class:`CellId` s.
        """
    cellid_int = cls.begin(level).id()
    endid_int = cls.end(level).id()
    increment = cls.begin(level).lsb() << 1
    while cellid_int != endid_int:
        yield cls(cellid_int)
        cellid_int += increment


def object_in_list(obj, l):
    """Returns True if object o is in list.

    Required compatibility function to handle WeakSet objects.
    """
    for o in l:
        if o is obj:
            return True
    return False


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

        :param TeamFolderCreateDetails val:
        :rtype: EventDetails
        """
    return cls('team_folder_create_details', val)


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 isnan(x):
    """
    Check if something is NaN.

    >>> import numpy as np
    >>> isnan(np.NaN)
    True

    >>> isnan(0)
    False

    :param object x: Any object
    :return: True if x is NaN
    :rtype: bool
    """
    return x != x


def make_subrequest(request, path):
    """ Make a subrequest

    Copies request environ data for authentication.

    May be better to just pull out the resource through traversal and manually
    perform security checks.
    """
    env = request.environ.copy()
    if path and '?' in path:
        path_info, query_string = path.split('?', 1)
        path_info = path_info
    else:
        path_info = path
        query_string = ''
    env['PATH_INFO'] = path_info
    env['QUERY_STRING'] = query_string
    subreq = request.__class__(env, method='GET', content_type=None, body=b'')
    subreq.remove_conditional_headers()
    subreq.__parent__ = request
    return subreq


def __strip_list(attrs):
    """ This assumes that if you have a list of outputs you just want the second one (the second class).
    """
    if isinstance(attrs, list):
        return attrs[1]
    else:
        return attrs


@staticmethod
def canRead(path: str) ->bool:
    """
        Returns true if it can read the source defined by path
        :param path: source uri
        :return: True, if source is readable.
        """
    return False


def is_rgb_like(image):
    """Return True if the image *looks* like it's RGB.

    This function should not be public because it is only intended to be used
    for functions that don't accept volumes as input, since checking an image's
    shape is fragile.
    """
    return image.ndim == 3 and image.shape[2] in (3, 4)


@classmethod
def supports_to_pcm(cls):
    """returns True if all necessary components are available
        to support the .to_pcm() method"""
    return True


@classmethod
def gbandjoin(cls, bands):
    """
        Returns a new pyvips.Image that is a bandwise join of `bands`.

        bands: Sequence of pyvips.Image objects.

        This previously used the vipsCC gbandjoin method which doesn't
        exist in pyvips.  pyvips' bandjoin method takes either a single 'other'
        band or a list of bands, so we can make it join the first image in the
        list to the remainder
        """
    return bands[0].bandjoin(bands[1:])


def is_not_empty(my_string):
    """Is the string NOT empty"""
    return bool(my_string and my_string.strip())


def _int_arith_flags(rettype):
    """
    Return the modifier flags for integer arithmetic.
    """
    if rettype.signed:
        return ['nsw']
    else:
        return []


def _read_params_from_file(filepath):
    """Extract key=value pairs from a file.

    :param filepath: path to a file containing key=value pairs separated by
                     whitespace or newlines.
    :returns: a dictionary representing the content of the file
    """
    with open(filepath) as f:
        cmdline = f.read()
    options = cmdline.split()
    params = {}
    for option in options:
        if '=' not in option:
            continue
        k, v = option.split('=', 1)
        params[k] = v
    return params


@staticmethod
def append_sig_to_list_replacing_if_identical(sig_list, sig):
    """Return `sig_list` either with `sig` appended or with any identical
        signature (according only to type equality, not attributes) replaced
        if one is there.  This is called in `register_handler_funs`."""
    try:
        sig_list.remove(sig)
    except ValueError:
        pass
    sig_list.append(sig)
    return sig_list


@classmethod
def normalize_term(cls, term):
    """Return a string of the qualified term, all lower cased. """
    return '{}.{}'.format(*cls.split_term_lower(term))


def total_mass_and_mass_ratio_to_component_masses(mass_ratio, total_mass):
    """
    Convert total mass and mass ratio of a binary to its component masses.

    Parameters
    ----------
    mass_ratio: float
        Mass ratio (mass_2/mass_1) of the binary
    total_mass: float
        Total mass of the binary

    Return
    ------
    mass_1: float
        Mass of the heavier object
    mass_2: float
        Mass of the lighter object
    """
    mass_1 = total_mass / (1 + mass_ratio)
    mass_2 = mass_1 * mass_ratio
    return mass_1, mass_2


def phase_pivot(d, p0, p1, pivot=0.5):
    """ three parameter phasing routine
        pivot = 0 is on left side
        pivot = 1 is on right side
        all intermediate values are possible
        returns actual (P0, P1)
    """
    lp0, lp1 = p0 + (0.5 - pivot) * p1, p1
    d.phase(lp0, lp1)
    return lp0, lp1


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 TA(value, activate=False, New_line=True, seperater=':'):
    """有些人可能想要在LovU 之前添加上对方的名字,这样更加的暖,也更加的好玩儿.
    比如说,本函数默认情况下是不启用的, 那么这个时候,只是会输出例如: 我爱你 ,这样的简单语句.如果激活本函数,那么可以添加上 TA 的名字,比如说 xxx, 我爱你! ,或者是 xxx 我爱你!
    :param str value:
    :param bool activate: If set to True, receiver's name will be added to the message.If False, then the program will not add anything.
    :param bool New_line: If set to True, the message itself will be writen in the new line after the receiver's name. if False, the message and the receiver's name will be written in the same line.
    :param str seperater: you can choose use what to seperate the receiver's name and the message. for example ,you can use : , or any other marks that you would like to use.
    :return str:
    """
    if activate is False:
        TA = ''
        return TA
    if activate is True and New_line is True:
        name = value
        TA = name + seperater + '\n'
        return TA
    if activate is True and New_line is False:
        name = value
        TA = name + seperater
        return TA


def parse_command_line(argv):
    """ argv should be sys.argv """
    param_type = {'nh_size': int, 'nn_pure_ratio': float, 'outlier_ratio':
        float, 'min_size_cluster': int, 'perplexity': int,
        'n_iteration_tsne': int, 'late_exag': int, 'alpha_late': float,
        'n_cluster_init': int, 'eta': float, 'fdc_test_ratio_size': float,
        'root': str, 'n_clf_sample_max': int, 'clf_type': str,
        'n_bootstrap': int, 'clf_test_size_ratio': float, 'n_edge_kNN': int,
        'gap_min': float}
    parameters = {}
    for arg in argv[1:]:
        param, value = arg.strip(' ').strip('\n').split('=')
        tmp_type = param_type[param]
        if tmp_type is int:
            parameters[param] = int(float(value))
        else:
            parameters[param] = tmp_type(value)
    return parameters


def rule(port, action='ACCEPT', source='net', dest='$FW', proto='tcp'):
    """
    Helper to build a firewall rule.

    Examples::

        from fabtools.shorewall import rule

        # Rule to accept connections from example.com on port 1234
        r1 = rule(port=1234, source=hosts(['example.com']))

        # Rule to reject outgoing SMTP connections
        r2 = rule(port=25, action='REJECT', source='$FW', dest='net')

    """
    return {'action': action, 'source': source, 'dest': dest, 'proto':
        proto, 'dest_port': port}


def _imageLabel(img):
    """Used to generate labels for the :attr:`.VectorOpts.modulateImage`,
    :attr:`.VectorOpts.clipImage`, and other :class:`.Image`-based
    choice properties.
    """
    if img is None:
        return 'None'
    else:
        return img.name


def _default_key_normalizer(key_class, request_context):
    """
    Create a pool key of type ``key_class`` for a request.

    According to RFC 3986, both the scheme and host are case-insensitive.
    Therefore, this function normalizes both before constructing the pool
    key for an HTTPS request. If you wish to change this behaviour, provide
    alternate callables to ``key_fn_by_scheme``.

    :param key_class:
        The class to use when constructing the key. This should be a namedtuple
        with the ``scheme`` and ``host`` keys at a minimum.

    :param request_context:
        A dictionary-like object that contain the context for a request.
        It should contain a key for each field in the :class:`HTTPPoolKey`
    """
    context = {}
    for key in key_class._fields:
        context[key] = request_context.get(key)
    context['scheme'] = context['scheme'].lower()
    context['host'] = context['host'].lower()
    return key_class(**context)


def _get_single_element_by_id(api, type_, id_, recurse_down=True):
    """ Retrieves a single OpenStreetMap element by its id.

      api - an initialised Overpass API object
      type_ - the element type to query, one of node, way or relation
      id_ - the id of the element to retrieve
      recurse_down - whether to get child nodes of ways and relations
    """
    query = '%s(%d);%s' % (type_, id_, '(._;>;);' if recurse_down else '')
    result = api.Get(query, responseformat='xml')
    return result


def parse_parameters(param_str):
    """
    Parse parameter string return by librenderman into a dictionary keyed on parameter
    index with values being the name / short descriptions for the parameter at that index.

    :param param_str: A parameter decription string returned by librenderman
    :type param_str: str
    :returns: A dictionary with parameter index as keys and parameter name / description for values
    :rtype: dict
    """
    param_list = param_str.split('\n')
    param_dict = {}
    for param in param_list:
        param_vals = param.split(':')
        try:
            param_index = int(param_vals[0])
            param_name = param_vals[1].strip()
            param_dict[param_index] = param_name
        except ValueError:
            continue
    return param_dict


def _get_variant(handle):
    """
    Read one line from the input file, strip the newline and return it.

    :arg stream handle: Open handle to the input file.
    """
    return handle.readline().strip('\n')


def parse_git_path(git_path):
    """ Returns tuple (repo_url, git_ref, code_path) """
    git_ref = 'master'
    repo_url, code_path = git_path.replace('git://', '').split('//')
    if '#' in repo_url:
        repo_url, git_ref = repo_url.split('#')
    repo_url = repo_url.rstrip('.git')
    if not code_path:
        code_path = '/'
    return repo_url, git_ref, code_path


def add_sshpubkey_to_attrs_pre(context, attrs_list):
    """
    Attribute ipasshpubkey should be added to attrs_list to be able compute
    ssh fingerprint. This attribute must be removed later if was added here
    (see remove_sshpubkey_from_output_post).
    """
    if not ('ipasshpubkey' in attrs_list or '*' in attrs_list):
        setattr(context, 'ipasshpubkey_added', True)
        attrs_list.append('ipasshpubkey')


def rekey(keys_number: int=2):
    """Change the number of keys of selected particles (root and tip keys included)

    :param keys_number: Number of Keys
    :type keys_number: int
    """
    pass


def interpret_number(s, context=None):
    """Convert a raw Number value to the integer it represents.

    This is a little more lenient than the SGF spec: it permits leading and
    trailing spaces, and spaces between the sign and the numerals.

    """
    return int(s, 10)


def p_compound_stmt(p):
    """compound_stmt : if_stmt
                     | if_else_stmt
                     | for_stmt
                     | do_stmt
                     | loop_stmt
                     | with_stmt
                     | repeat_stmt
                     | funcdef """
    p[0] = ['STATEMENTS', [p[1]]]


def _extend(baseData, newData):
    """Assuming a is shorter than b, copy the end of b onto a
    """
    baseData.extend(newData[len(baseData):])


def key_to_node(obj, key):
    """Return node form object ane ky"""
    return obj, key


def exit_leg_1_delta(data, value, idx):
    """
    Exit the trade when the delta of leg 1 is below the min or above the max.

    For example, it would exit when the delta of the
    first leg is below .10 or above .90 delta.
    """
    pass


def get_url(environ):
    """Return the request URL."""
    url = environ['SCRIPT_NAME'] + environ['PATH_INFO']
    qs = environ.get('QUERY_STRING')
    if qs:
        url += '?' + qs
    return url


def read_diet_file(diet_filename):
    """ Read a diet file and convert to medium dictionary.

    Each line of the diet file has three fields: (1) exchange reaction ID, (2) reaction name,
    and (3) absolute value of bound in direction of metabolite creation (i.e. lower bound
    for `met <--` or upper bound for `met -->`). The first line of the file is a header that
    is ignored and the reaction name field is not used. Fields are separated by tabs.

    Parameters
    ----------
    diet_filename : str
        Path to file with nutrient conditions for a diet

    Returns
    -------
    dict
        Dictionary with reaction ID as key and bound as value
    """
    medium = dict()
    with open(diet_filename, 'rU') as handle:
        handle.readline()
        line_num = 1
        for line in handle:
            line_num += 1
            fields = line.strip().split('\t')
            if len(fields) != 3:
                raise ValueError(
                    'Line {0} in file "{1}" must have three fields'.format(
                    line_num, diet_filename))
            medium[fields[0]] = abs(float(fields[2]))
    return medium


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 '+'


@classmethod
def get_intention(cls, view):
    """Return the value of the intention from the view"""
    result = {}
    for param in cls.parameters:
        value = view.params(param)
        if value is None:
            value = []
        result[param] = value
    return result


def updater(event, progresstext):
    """Updater function to be called by threads."""
    while True:
        event.wait(0.5)
        if event.is_set():
            break
        progresstext.autoupdate()
    progresstext.clear()


@staticmethod
def _create_metadata(dtm):
    """Returns a dict containing meta-information about a DTM"""
    return {'PATH': dtm.path, 'MESH_SCALE': dtm.mesh_scale,
        'DTM_RESOLUTION': dtm.terrain_resolution, 'BIN_SIZE': dtm.bin_size,
        'MAP_SIZE': dtm.map_size, 'MAP_SCALE': dtm.map_scale * dtm.
        unit_scale, 'UNIT_SCALE': dtm.unit_scale, 'IS_TERRAIN': True,
        'HAS_UV_MAP': True}


def calculate_expectation(samples, weights, f):
    """Calculate the expectation value of function ``f`` using weighted
    samples (like the output of an importance-sampling run).

    Denoting :math:`x_n` as the sample n and :math:`w_n` as its (normalized)
    weight, the following is returned:

    .. math::

        \\sum_{n=1}^{N} w_n f(x_n)
        \\mathrm{\\ \\ where\\ \\ } \\sum_{n=1}^{N}w_n \\overset{!}{=} 1

    :param samples:

        Matrix-like numpy array; the samples to be used.

    :param weights:

        Vector-like numpy array; the (unnormalized) importance weights.

    :param f:

        Callable, the function to be evaluated.

    """
    assert len(samples) == len(weights
        ), 'The number of samples (got %i) must equal the number of weights (got %i).' % (
        len(samples), len(weights))
    normalization = 0.0
    out = 0.0
    for weight, sample in zip(weights, samples):
        normalization += weight
        out += weight * f(sample)
    return out / normalization


def adjmat2vec(adjmat):
    """Convert adjacency matrix into vector with source and target.

    Parameters
    ----------
    adjmat : pd.DataFrame()
        Adjacency matrix.

    Returns
    -------
    adjacency matrix : pd.DataFrame()
        Nodes that are connected based on source and target.

    """
    adjmat = adjmat.stack().reset_index()
    adjmat.columns = ['source', 'target', 'weight']
    Iloc1 = adjmat['source'] != adjmat['target']
    Iloc2 = adjmat['weight'] > 0
    Iloc = Iloc1 & Iloc2
    adjmat = adjmat.loc[(Iloc), :]
    adjmat.reset_index(drop=True, inplace=True)
    return adjmat


def detach_node(node, reattach_tail=True):
    """
    Just like calling node.getparent().remove(node), but takes care of reattaching the node's tail text. And it's shorter to type.
    """
    tail_str = node.tail
    parent_el = node.getparent()
    if tail_str and reattach_tail:
        prev_el = node.getprevious()
        if prev_el is not None:
            prev_el.tail = (prev_el.tail or '') + tail_str
        else:
            parent_el.text = (parent_el.text or '') + tail_str
    parent_el.remove(node)
    return node


def cast(typ, val):
    """Cast a value to a type.

    This returns the value unchanged.  To the type checker this
    signals that the return value has the designated type, but at
    runtime we intentionally don't check anything (we want this
    to be as fast as possible).
    """
    return val


def record(event_name) ->None:
    """
        record request event
        """


def description(filename):
    """Provide a short description."""
    with open(filename) as fp:
        for lineno, line in enumerate(fp):
            if lineno < 3:
                continue
            line = line.strip()
            if len(line) > 0:
                return line


def check_duplicated_labels(dataframe):
    """
        Checks if there are duplications on column labels. Raises `ValueError` if there is any duplicated label.

        :param dataframe: The DataFrame object to work on.
        :type dataframe: :class:`DataFrame <pandas.DataFrame>`

        :returns: The original DataFrame
        :rtype: :class:`DataFrame <pandas.DataFrame>`

        :raises: :exc:`ValueError`
    """
    if not dataframe.columns.is_unique:
        raise ValueError('Duplicated columns: {}'.format(', '.join(
            dataframe.columns[~dataframe.columns.duplicated()].tolist())))
    return dataframe


@staticmethod
def _handle_captcha(captcha_data, message=''):
    """ Called when a captcha must be solved
        Writes the image to a temporary file and asks the user to enter the code.

        Args:
            captcha_data: Bytestring of the PNG captcha image.
            message: Optional. A message from Steam service.

        Returns:
            A string containing the solved captcha code.
        """
    from tempfile import NamedTemporaryFile
    tmpf = NamedTemporaryFile(suffix='.png')
    tmpf.write(captcha_data)
    tmpf.flush()
    captcha_text = input(
        'Please take a look at the captcha image "%s" and provide the code:' %
        tmpf.name)
    tmpf.close()
    return captcha_text


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

        :param DeviceLinkFailDetails val:
        :rtype: EventDetails
        """
    return cls('device_link_fail_details', val)


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


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

            path -> path
        This is valid only for the belleii convention where the scope can be determined
        from the LFN using a determinitic function.

        :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 scope
    del rse
    del rse_attrs
    del protocol_attrs
    return name


@classmethod
def wraa(cls, woba, lg_woba, pa, woba_scale=1.24):
    """
        Weighted Runs Above Average(wRAA)
        http://1point02.jp/
        :param woba: weighted on-base average
        :param lg_woba: weighted on-base average(league average)
        :param woba_scale: Weighted Runs Above Average scale(default:1.2
        :param pa: plate appearance
        :param woba_scale: weighted on-base average scale(default:1.24)
        :return: (float) wRAA
        """
    return round((woba - lg_woba) / woba_scale * float(pa), 1)


def addReader(reader):
    """
        I add reader to the set of file descriptors to get read events for.

        @param reader: An L{IReadDescriptor} provider that will be checked for
                       read events until it is removed from the reactor with
                       L{removeReader}.

        @return: C{None}.
        """


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

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

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


def surrounding_join(j, it, l='', r=''):
    """ Example: surrounding_join(", ", ("a", "b", "c"), l="[", r="]") -> "[a], [b], [c]"
	"""
    s = (r + j + l).join(it)
    if s != '':
        return l + s + r
    return ''


def seconds_to_days(seconds):
    """Convert seconds to days"""
    return seconds / 86400.0


def insert_pure_function(module, fnty, name):
    """
    Insert a pure function (in the functional programming sense) in the
    given module.
    """
    fn = module.get_or_insert_function(fnty, name=name)
    fn.attributes.add('readonly')
    fn.attributes.add('nounwind')
    return fn


@classmethod
def get_values(cls):
    """Values supported by this filter"""
    aVals = sorted([cls.__sStealth, cls.__sIntercept, cls.__sUnlock, cls.
        __sBounce, cls.__sEnterCombat, cls.__sBleedModifier, cls.
        __sBleedAction, cls.__sBleedReduction])
    return aVals


def rglen(ar):
    """return generator ``range(len(.))`` with shortcut ``rglen(.)``
    """
    return range(len(ar))


@staticmethod
def set_streets_weight(streets):
    """
        Set the streets weight equal to theirt length ; in-place.
        """
    streets['weight'] = None
    for i, street in streets.iterrows():
        weight = street['geometry'].length
        streets.at[i, 'weight'] = weight


def shape_key_rekey(location: bool=True, feather: bool=True):
    """Recalculate animation data on selected points for frames selected in the dopesheet

    :param location: Location
    :type location: bool
    :param feather: Feather
    :type feather: bool
    """
    pass


def get_positive_int(obj: dict, name: str) ->int:
    """Get and check the value of name in obj is positive integer."""
    value = obj[name]
    if not isinstance(value, int):
        raise TypeError(f'{name} must be integer: {type(value)}')
    elif value < 0:
        raise ValueError(f'{name} must be positive integer: {value}')
    return value


def release_interface(device, interface):
    """Explicitly release an interface.

    This function is used to release an interface previously claimed,
    either through a call to claim_interface or internally by the
    device object.

    Normally, you do not need to worry about claiming policies, as
    the device object takes care of it automatically.
    """
    device._ctx.managed_release_interface(device, interface)


def __delitem__(key):
    """Deny deleting, read-only.
        """


def dashboardActivities():
    """Return list of dashboard activities"""
    activity = ['reprocessing', 'production', 'relval', 'harvesting',
        'storeresults', 'integration', 'test']
    return activity


def render(animation: bool=False, write_still: bool=False, use_viewport:
    bool=False, layer: str='', scene: str=''):
    """Render active scene

    :param animation: Animation, Render files from the animation range of this scene
    :type animation: bool
    :param write_still: Write Image, Save rendered the image to the output path (used only when animation is disabled)
    :type write_still: bool
    :param use_viewport: Use 3D Viewport, When inside a 3D viewport, use layers and camera of the viewport
    :type use_viewport: bool
    :param layer: Render Layer, Single render layer to re-render (used only when animation is disabled)
    :type layer: str
    :param scene: Scene, Scene to render, current scene if not specified
    :type scene: str
    """
    pass


def isosurface(da, coord, target):
    """
        Returns the values of a coordinate in the input array where the input array values equals
        a prescribed target. E.g. returns the depth of the 20 degC isotherm. Returns nans for all
        points in input array where isosurface is not defined. If
        Author: Thomas Moore
        Date: 02/10/2018

        Parameters
        ----------
        da : xarray DataArray
            Array of values to be isosurfaced
        coord : str
            Name of coordinate to contruct isosurface about
        target : value
            Isosurface value

        Returns
        -------
        isosurface : xarray DataArray
            Values of coord where da is closest to target. If multiple occurences of target occur
            along coord, only the maximum value of coord is returned

        Examples
        --------
        >>> A = xr.DataArray(np.random.normal(size=(5,5)),
        ...                  coords=[('x', np.arange(5)), ('y', np.arange(5))])
        >>> isosurface(A, coord='x', target=0)
        >>> doppyo.utils.isosurface(A, coord='x', target=0)
        <xarray.DataArray 'isosurface' (y: 5)>
        array([ 4.,  1., nan,  3.,  4.])
        Coordinates:
          * y        (y) int64 0 1 2 3 4

        Limitations
        -----------
        If multiple occurences of target occur along coord, only the maximum value of coord is
        returned

        To do
        -----
        The current version includes no interpolation between grid spacing. This should be added as
        an option in the future
    """
    mask = da > target
    da_mask = mask * da[coord]
    isosurface = da_mask.max(coord)
    return isosurface.where(da.max(dim=coord) > target).rename('isosurface')


def _check_proc_keys(merged_procs_par, schema):
    """Diagnostic for _assign_proc_keys."""
    crit1 = merged_procs_par['TimeGenerated_orig_par'].isin(merged_procs_par
        [schema.time_stamp])
    crit2 = merged_procs_par['EffectiveLogonId'].isin(merged_procs_par[
        schema.logon_id])
    if schema.target_logon_id:
        c2a = merged_procs_par['EffectiveLogonId'].isin(merged_procs_par[
            schema.target_logon_id])
    crit3 = merged_procs_par['parent_proc_lc'].isin(merged_procs_par[
        'new_process_lc'])
    crit4 = merged_procs_par[schema.process_id].isin(merged_procs_par[
        schema.parent_id])
    crit5 = merged_procs_par['parent_key'].isin(merged_procs_par.index)
    crit6 = merged_procs_par['parent_key'].isna()
    print('has parent time', len(merged_procs_par[crit1]))
    print('effectivelogonId in subjectlogonId', len(merged_procs_par[crit2]))
    if schema.target_logon_id:
        print('effectivelogonId in targetlogonId', len(merged_procs_par[c2a]))
    print('parent_proc_lc in procs', len(merged_procs_par[crit3]))
    print('ProcessId in ParentProcessId', len(merged_procs_par[crit4]))
    print('Parent_key in proc_key', len(merged_procs_par[crit5]))
    print('Parent_key not in proc_key', len(merged_procs_par[~crit5]))
    print('Parent_key is NA', len(merged_procs_par[crit6]))


def color(fontid: int, r: float, g: float, b: float, a: float):
    """Set the color for drawing text.

    :param fontid: The id of the typeface as returned by blf.load(), for default font use 0.
    :type fontid: int
    :param r: red channel 0.0 - 1.0.
    :type r: float
    :param g: green channel 0.0 - 1.0.
    :type g: float
    :param b: blue channel 0.0 - 1.0.
    :type b: float
    :param a: alpha channel 0.0 - 1.0.
    :type a: float
    """
    pass


def _remove_items(items, text):
    """Remove each item from the text."""
    for item in items:
        text = text.replace(item, ' ')
    return text


def get_losses(point_margin):
    """Determine a loss based on the point margin.

    Parameters
    ----------
    point_margin : int
        The point margin can be positive, zero, or negative.

    Returns
    -------
    lost : int
        If the point margin is less than 0, return 1, else 0.

    """
    lost = 1 if point_margin < 0 else 0
    return lost


def def_plotly_date_range_widgets(my_rangeselector=None, as_layout=True,
    as_dict=False):
    """old name; def_my_plotly_stock_layout,
    REPLACES DEF_RANGE_SELECTOR"""
    if as_dict:
        as_layout = False
    from plotly import graph_objs as go
    if my_rangeselector is None:
        my_rangeselector = {'bgcolor': 'lightgray', 'buttons': [{'count': 1,
            'label': '1m', 'step': 'month', 'stepmode': 'backward'}, {
            'count': 3, 'label': '3m', 'step': 'month', 'stepmode':
            'backward'}, {'count': 6, 'label': '6m', 'step': 'month',
            'stepmode': 'backward'}, {'count': 1, 'label': '1y', 'step':
            'year', 'stepmode': 'backward'}, {'step': 'all'}, {'count': 1,
            'step': 'year', 'stepmode': 'todate'}], 'visible': True}
    my_layout = {'xaxis': {'rangeselector': my_rangeselector, 'rangeslider':
        {'visible': True}, 'type': 'date'}}
    if as_layout:
        return go.Layout(my_layout)
    else:
        return my_layout


def _repr(obj, clip=80):
    """Clip long repr() string.
    """
    try:
        r = repr(obj)
    except Exception:
        r = 'N/A'
    if 0 < clip < len(r):
        h = clip // 2 - 2
        if h > 0:
            r = r[:h] + '....' + r[-h:]
    return r


@classmethod
def fix_char(cls, c):
    """a filter which changes overly large c values to 'unknown'"""
    if ord(c) <= 65535:
        return c
    else:
        return u'�'


def clean_code(code, comments=True, macros=False, pragmas=False):
    """
    Naive comment and macro striping from source code

    :param comments: If True, all comments are stripped from code
    :param macros: If True, all macros are stripped from code
    :param pragmas: If True, all pragmas are stripped from code

    :return: cleaned code. Line numbers are preserved with blank lines,
    and multiline comments and macros are supported. BUT comment-like
    strings are (wrongfully) treated as comments.
    """
    if macros or pragmas:
        lines = code.split('\n')
        in_macro = False
        in_pragma = False
        for i in range(len(lines)):
            l = lines[i].strip()
            if macros and (l.startswith('#') and not l.startswith('#pragma'
                ) or in_macro):
                lines[i] = ''
                in_macro = l.endswith('\\')
            if pragmas and (l.startswith('#pragma') or in_pragma):
                lines[i] = ''
                in_pragma = l.endswith('\\')
        code = '\n'.join(lines)
    if comments:
        idx = 0
        comment_start = None
        while idx < len(code) - 1:
            if comment_start is None and code[idx:idx + 2] == '//':
                end_idx = code.find('\n', idx)
                code = code[:idx] + code[end_idx:]
                idx -= end_idx - idx
            elif comment_start is None and code[idx:idx + 2] == '/*':
                comment_start = idx
            elif comment_start is not None and code[idx:idx + 2] == '*/':
                code = code[:comment_start] + '\n' * code[comment_start:idx
                    ].count('\n') + code[idx + 2:]
                idx -= idx - comment_start
                comment_start = None
            idx += 1
    return code


def tag2version(ver):
    """convert a tag to a version.

    Here are some examples:
    >>> tag2version("1-2")
    '1-2'
    >>> tag2version("R1-2")
    '1-2'
    >>> tag2version("R-1-2")
    '1-2'
    >>> tag2version("seq-1-2")
    '1-2'
    >>> tag2version("head")
    'head'
    >>> tag2version("")
    ''
    """
    if not ver:
        return ver
    mode = 0
    for i in range(len(ver)):
        if mode == 0:
            if ver[i].isalpha():
                continue
            mode = 1
        if mode == 1:
            if ver[i] == '-' or ver[i] == '_':
                mode = 2
                continue
            mode = 2
        if mode == 2:
            if ver[i].isdigit():
                return ver[i:]
            return ver
    return ver


def get_mau_from_student_modules(student_modules, year, month):
    """
    Return records modified in year and month

    Inspect StudentModule records to see if modified is set to created date
    when records are created. If so, then we can just get the modified date in
    the specified month

    """
    qs = student_modules.filter(modified__year=year, modified__month=month)
    return qs.values_list('student__id', flat=True).distinct()


def GetIndex(header):
    """

    Returns the height/index of a header

    """
    pass


def change_label_of_state(apps, schema_editor):
    """
    Changes the label of former state "commited a bill" to "refered to committee".
    """
    State = apps.get_model('motions', 'State')
    try:
        state = State.objects.get(name='commited a bill')
    except State.DoesNotExist:
        pass
    else:
        state.name = 'refered to committee'
        state.action_word = 'Refer to committee'
        state.save(skip_autoupdate=True)


def get_prepopulated_value(field, instance):
    """
    Returns preliminary value based on `populate_from`.
    """
    if hasattr(field.populate_from, '__call__'):
        return field.populate_from(instance)
    else:
        attr = getattr(instance, field.populate_from)
        return callable(attr) and attr() or attr


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 filetypes():
    """Get supported text filetypes for system import."""
    return {'ini': 'Nemoa System Description', 'txt':
        'Nemoa System Description'}