def attr_chain(obj, attr):
    """Follow an attribute chain.

    If you have a chain of objects where a.foo -> b, b.foo-> c, etc,
    use this to iterate over all objects in the chain. Iteration is
    terminated by getattr(x, attr) is None.

    Args:
        obj: the starting object
        attr: the name of the chaining attribute

    Yields:
        Each successive object in the chain.
    """
    next = getattr(obj, attr)
    while next:
        yield next
        next = getattr(next, attr)


def receive(request, namespace=u'message'):
    """ receive message, return a list of tuples (type, message)
        """


@staticmethod
def get_private_key_certificate_chain_pair(key_file, crt_file):
    """
        根据.key和.crt文件生成private_key_certificate_chain_pair

        @param {string} key_file - .key文件的路径(含文件名)，服务器端的私钥文件
        @param {string} crt_file - .crt文件的路径(含文件名)，服务器端的公钥证书文件，提供给客户端使用

        @return {(bytes, bytes)} - 对应签名证书的(private_key, certificate_chain)

        @example
            利用openssl创建自签名证书:
            1、命令行：openssl genrsa -out server.key 2048
               执行过程中输入各类证书信息
            2、生成了server.key和server.crt两个文件，服务端两个文件都需要，客户端只需要crt文件
            3、对于服务器端，server.key对应private_key，server.crt对应certificate_chain
            4、对于客户端，server.crt对应root_certificates
        """
    with open(key_file, 'rb') as f:
        _private_key = f.read()
    with open(crt_file, 'rb') as f:
        _certificate_chain = f.read()
    return _private_key, _certificate_chain


def set_mat_diag(mat, diag=0, val=0):
    """
    Set the nth diagonal of a symmetric 2D numpy array to a fixed value.
    Operates in place.

    Parameters
    ----------
    mat : numpy.array
        Symmetric 2D array of floats.
    diag : int
        0-based index of the diagonal to modify. Use negative values for the
        lower half.
    val : float
        Value to use for filling the diagonal
    """
    m = mat.shape[0]
    step = m + 1
    start = diag
    end = m ** 2 - diag * m
    mat.flat[start:end:step] = val


def compatible_encode_method(bytesorstring, encoding='utf-8', erraction=
    'ignore'):
    """When Py2 str.encode is called, it often means bytes.encode in Py3.

     This does either.
     """
    if isinstance(bytesorstring, str):
        return bytesorstring
    assert isinstance(bytesorstring, bytes), str(type(bytesorstring))
    return bytesorstring.decode(encoding, erraction)


@staticmethod
def perform(program):
    """
        # Perform routing
        Route to the app provided in the CLI's first argument
        """
    app_name = program.cli_args.app
    app = program.get_app(app_name)
    if not app:
        raise Exception(f'Unable to locate app "{app_name}"')
    app_method = getattr(program, f'run_{app_name}', None)
    if callable(app_method):
        return app_method(app)
    else:
        program.app_lifecycle(app=app)


def parse_kwargs(**kwargs):
    """
        Parses key-word arguments.
        It checks for the presence of key-words ending with '_col', these are
        popped and stored in a seperate dictionary, as they are to be passed
        to the constructor of the actual column or combobox (attribute mappings)
        In addition it sets a number of default attributes for the CellRenderer.

        Returns a tuple containing a dict with the CellRenderer attributes and a
        dict with the TreeViewColumn attribute mappings
    """
    kwargs['xalign'] = kwargs.get('xalign', 0.5)
    kwargs['yalign'] = kwargs.get('yalign', 0.5)
    col_attrs = dict()
    for key, value in dict(kwargs).items():
        if key.endswith('_col'):
            col_attrs[key[:-4]] = value
            kwargs.pop(key)
    return kwargs, col_attrs


def crossfade_sounds():
    """Do cross-fading volume animation of two selected sound strips

    """
    pass


def register_service_error_cb(error):
    """Service registration error callback."""
    print('Failed to register application: ' + str(error))


def __new__(_cls, *args, **kwargs):
    """
    Need to reset this special method or else
    dom_tag will think it's being used as a dectorator.

    This means lazy() can't be used as a dectorator, but
    thinking about when you might want that just confuses me.
    """
    return object.__new__(_cls)


def get_swarm_spans(coll):
    """
    Given a matplotlib Collection, will obtain the x and y spans
    for the collection. Will return None if this fails.
    """
    import numpy as np
    x, y = np.array(coll.get_offsets()).T
    try:
        return x.min(), x.max(), y.min(), y.max()
    except ValueError:
        return None


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


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 readfile(filename):
    """Read the contents of a file."""
    with open(filename) as fh:
        contents = fh.read()
    return contents


def get_kappa_ex(E, B, D):
    """
    Find kappa_ex for a given B field.
    Based on the deflection approximation used in
    Achterberg et al. 1999.
    """
    l = 1
    kappa_ex = []
    for i, e in enumerate(E):
        theta_p = 0.0401 * (e / 50) ** -1 * B * (D[i] / 10) ** 0.5 * l ** 0.5
        kappa_ex.append(2.3 / theta_p ** 2)
    return kappa_ex


def has_scheduled_methods(cls):
    """Decorator; use this on a class for which some methods have been
    decorated with :func:`schedule` or :func:`schedule_hint`. Those methods
    are then tagged with the attribute `__member_of__`, so that we may
    serialise and retrieve the correct method. This should be considered
    a patch to a flaw in the Python object model."""
    for member in cls.__dict__.values():
        if hasattr(member, '__wrapped__'):
            member.__wrapped__.__member_of__ = cls
    return cls


@classmethod
def parse(cls, element):
    """Parse xml element.

        :param element: an :class:`~xml.etree.ElementTree.Element` instance
        :rtype: dict
        """
    values = {}
    for child in element:
        node = cls.get_node(child)
        subs = cls.parse(child)
        value = subs or node['value']
        if node['tag'] not in values:
            values[node['tag']] = value
        else:
            if not isinstance(values[node['tag']], list):
                values[node['tag']] = [values.pop(node['tag'])]
            values[node['tag']].append(value)
    return values


def io_table_columns():
    """Accepted column names for a unit file."""
    return ('Name', 'Allegiance', 'HP', 'Armor', 'Damage', 'Accuracy',
        'Miss', 'Movement Speed', 'Range')


def _add_profile(api, profile, json_out=False):
    """ Add user profile. if json, dump json dict to stdout """
    if json_out:
        return profile
    return api.add_profile(profile)


def get_deployment_instance(deploymentId=None, instanceId=None):
    """
    Gets information about an instance as part of a deployment.
    See also: AWS API Documentation

    :example: response = client.get_deployment_instance(
        deploymentId='string',
        instanceId='string'
    )

    :type deploymentId: string
    :param deploymentId: [REQUIRED]
            The unique ID of a deployment.

    :type instanceId: string
    :param instanceId: [REQUIRED]
            The unique ID of an instance in the deployment group.

    :rtype: dict
    :return: {
        'instanceSummary': {
            'deploymentId': 'string',
            'instanceId': 'string',
            'status': 'Pending'|'InProgress'|'Succeeded'|'Failed'|'Skipped'|'Unknown'|'Ready',
            'lastUpdatedAt': datetime(2015, 1, 1),
            'lifecycleEvents': [
                {
                    'lifecycleEventName': 'string',
                    'diagnostics': {
                        'errorCode': 'Success'|'ScriptMissing'|'ScriptNotExecutable'|'ScriptTimedOut'|'ScriptFailed'|'UnknownError',
                        'scriptName': 'string',
                        'message': 'string',
                        'logTail': 'string'
                    },
                    'startTime': datetime(2015, 1, 1),
                    'endTime': datetime(2015, 1, 1),
                    'status': 'Pending'|'InProgress'|'Succeeded'|'Failed'|'Skipped'|'Unknown'
                },
            ],
            'instanceType': 'Blue'|'Green'
        }
    }

    :returns:
    Pending: The deployment is pending for this instance.
    In Progress: The deployment is in progress for this instance.
    Succeeded: The deployment has succeeded for this instance.
    Failed: The deployment has failed for this instance.
    Skipped: The deployment has been skipped for this instance.
    Unknown: The deployment status is unknown for this instance.

    """
    pass


def __repr__():
    """Returns a string identifier of the directory."""


def __contains__(key):
    """
        Return if a status exists in the container.
        """


def _sample_and_map(proj, parset, progset, progset_instructions,
    result_names, mapping_function, max_attempts, **kwargs):
    """
    Helper function to sample

    This function runs a sampled simulation and also calls an Ensemble's mapping
    function prior to returning. This means that the Result goes out of scope and
    is discarded. Used when performing parallel simulations via `Ensemble.run_sims()`
    (which is used for memory-constrained simulations)

    """
    results = proj.run_sampled_sims(n_samples=1, parset=parset, progset=
        progset, progset_instructions=progset_instructions, result_names=
        result_names, max_attempts=max_attempts)
    plotdata = mapping_function(results[0], **kwargs)
    return plotdata


def get_month_from_string(month_string):
    """Convert string month to int month with Jan == 1

    Arguments
    ----------
    month_string : str
        Month given as a string

    Returns
    --------
    month : int
        Month as an integer (jan = 1, dez = 12)
    """
    if month_string == 'Jan':
        month = 1
    elif month_string == 'Feb':
        month = 2
    elif month_string == 'Mar':
        month = 3
    elif month_string == 'Apr':
        month = 4
    elif month_string == 'May':
        month = 5
    elif month_string == 'Jun':
        month = 6
    elif month_string == 'Jul':
        month = 7
    elif month_string == 'Aug':
        month = 8
    elif month_string == 'Sep':
        month = 9
    elif month_string == 'Oct':
        month = 10
    elif month_string == 'Nov':
        month = 11
    elif month_string == 'Dec':
        month = 12
    return int(month)


def writeFragments(fragments, filepath):
    """Write fragments to file

    Parameters
    ----------
    fragments : list
        3-deep list of ATAC fragments
    filepath : str
        Path for output file
    """
    with open(filepath, 'a') as outf:
        for i in fragments:
            outstr = '\t'.join(map(str, i))
            outf.write(outstr + '\n')


def perimeter_parallelogram_one_side_and_diagonals(a, e, f):
    """
    P = 2a² + √(2e² + 2f² - 4a²)
    """
    pass


def get_copy_command_for_frames(settings, queue_com, name):
    """
    Copy the frames based on stack or frames type.

    settings - TranSPHIRE settings.
    queue_com - Queue for communication.
    name - Name of the process.

    Returns:
    Command to use for copy.
    """
    message = None
    if settings['General']['Software'] == 'EPU >1.8':
        if settings['General']['Type'] == 'Stack':
            if settings['General']['Camera'] == 'K2':
                message = '\n'.join([
                    'Stack and K2 is not supported in EPU >1.8 version',
                    'Please contact the TranSPHIRE authors!'])
            elif settings['General']['Camera'] == 'Falcon2' or settings[
                'General']['Camera'] == 'Falcon3':
                return 'rsync'
            else:
                message = '\n'.join([
                    'Camera {0} not known for Software {1} with type {2}.'.
                    format(settings['General']['Camera'], settings[
                    'General']['Software'], settings['General']['Type']),
                    'Please contact the TranSPHIRE authors!'])
        elif settings['General']['Type'] == 'Frames':
            if settings['General']['Camera'] == 'K2':
                return settings['Path']['IMOD newstack']
            elif settings['General']['Camera'] == 'Falcon2' or settings[
                'General']['Camera'] == 'Falcon3':
                message = '\n'.join([
                    'Frames and Falcon2/Falcon3 is not supported, yet.',
                    'Please contact the TranSPHIRE authors!'])
            else:
                message = '\n'.join([
                    'Camera {0} not known for Software {1} with type {2}.'.
                    format(settings['General']['Camera'], settings[
                    'General']['Software'], settings['General']['Type']),
                    'Please contact the TranSPHIRE authors!'])
        else:
            message = '\n'.join(['{0}: Unknown Type!'.format(settings[
                'General']['Type']), 'Please contact the TranSPHIRE authors!'])
    elif settings['General']['Software'] == 'EPU >1.9':
        if settings['General']['Type'] == 'Stack':
            if settings['General']['Camera'] == 'K2':
                return 'rsync'
            elif settings['General']['Camera'] == 'Falcon2' or settings[
                'General']['Camera'] == 'Falcon3':
                return 'rsync'
            else:
                message = '\n'.join([
                    'Camera {0} not known for Software {1} with type {2}.'.
                    format(settings['General']['Camera'], settings[
                    'General']['Software'], settings['General']['Type']),
                    'Please contact the TranSPHIRE authors!'])
        elif settings['General']['Type'] == 'Frames':
            if settings['General']['Camera'] == 'K2':
                message = '\n'.join([
                    'Frames and K22 is not supported in EPU >1.9',
                    'Please contact the TranSPHIRE authors!'])
            elif settings['General']['Camera'] == 'Falcon2' or settings[
                'General']['Camera'] == 'Falcon3':
                message = '\n'.join([
                    'Frames and Falcon2/Falcon3 is not supported n EPU >1.9',
                    'Please contact the TranSPHIRE authors!'])
            else:
                message = '\n'.join([
                    'Camera {0} not known for Software {1} with type {2}.'.
                    format(settings['General']['Camera'], settings[
                    'General']['Software'], settings['General']['Type']),
                    'Please contact the TranSPHIRE authors!'])
        else:
            message = '\n'.join(['{0}: Unknown Type!'.format(settings[
                'General']['Type']), 'Please contact the TranSPHIRE authors!'])
    else:
        message = '\n'.join(['{0}: Unknown Software!'.format(settings[
            'General']['Software']), 'Please contact the TranSPHIRE authors!'])
    assert bool(message is not None)
    queue_com['error'].put(message, name)
    raise IOError(message)


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

        :param TokenScopeError val:
        :rtype: AuthError
        """
    return cls('missing_scope', val)


def extrude_edges_indiv(mirror: bool=False):
    """Extrude individual edges only

    :param mirror: Mirror Editing
    :type mirror: bool
    """
    pass


def get_sd_labels(centroid_indices, items, dist_func, distance_matrix=None):
    """Compute the assigned cluster label for each item given the indices of the approximate centroids"""
    labels = []
    for item_index in range(len(items)):
        min_distance = float('inf')
        label = -1
        for index in range(len(centroid_indices)):
            if distance_matrix is None:
                dist = dist_func(items[centroid_indices[index]], items[
                    item_index])
            else:
                dist = distance_matrix[centroid_indices[index], item_index]
            if dist < min_distance:
                min_distance = dist
                label = index
        labels.append(label)
    return labels


def controller_remove(controller: str='', object: str=''):
    """Remove a controller from the active object

    :param controller: Controller, Name of the controller to edit
    :type controller: str
    :param object: Object, Name of the object the controller belongs to
    :type object: str
    """
    pass


@classmethod
def from_pair(cls, allow, deny):
    """Creates an overwrite from an allow/deny pair of :class:`Permissions`."""
    ret = cls()
    for key, value in allow:
        if value is True:
            setattr(ret, key, True)
    for key, value in deny:
        if value is True:
            setattr(ret, key, False)
    return ret


def broadcast_greater_equal(lhs=None, rhs=None, out=None, name=None, **kwargs):
    """Returns the result of element-wise **greater than or equal to** (>=) comparison operation with broadcasting.

    Example::

       x = [[ 1.,  1.,  1.],
            [ 1.,  1.,  1.]]

       y = [[ 0.],
            [ 1.]]

       broadcast_greater_equal(x, y) = [[ 1.,  1.,  1.],
                                        [ 1.,  1.,  1.]]

    Defined in src/operator/tensor/elemwise_binary_broadcast_op_logic.cc:L100

    Parameters
    ----------
    lhs : NDArray
        First input to the function
    rhs : NDArray
        Second input to the function

    out : NDArray, optional
        The output NDArray to hold the result.

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.
    """
    return 0,


@classmethod
def from_file(cls, filepath):
    """Initialize the object from a netcdf_ file."""
    return cls(filepath)


def is_none_or_empty(obj):
    """Determine if object is None or empty
    :type any obj: object
    :rtype: bool
    :return: if object is None or empty
    """
    return obj is None or len(obj) == 0


def solution(func):
    """Attach the `func` a solution marker
    """
    func.__dict__['solution'] = True
    return func


def from_file(infilename, key):
    """
    Read histogram written out by heppy (using :py:class:`heppy.basehistogram.to_file`).

    :param infilename: name of the file that the histogram should be read from
    :type infilename: :code:`str`
    :param key: name/key of the histogram inside the input file
    :type key: :code:`str`

    :returns: :py:class:`heppy.histogram1d` or :py:class:`heppy.histogram2d`
    """
    with open(infilename, 'r') as infile:
        sep = ' : '
        for line in infile:
            if line.split(sep)[0] == key:
                from numpy import array, nan, inf
                return eval(line.split(sep)[1])
        raise RuntimeError(
            'Could not find histogram key "{key}" in input file "{infilename}"'
            .format(key=key, infilename=infilename))


@classmethod
def get_name(cls):
    """ Returns the name of the evaluation hook.

			# Return value

			A lower-case string unique to this evaluation hook.
		"""
    return cls.__name__.lower()


@classmethod
def get_deep(cls, session, include_concrete=False):
    """
        Will return the atk object and the entire tree under it.
        :param session: APIC session to use
        :param include_concrete: flag to indicate that concrete objects should also be included
        :return:
        """
    atk_objects = cls.get(session)
    for atk_object in atk_objects:
        atk_object.populate_children(deep=True, include_concrete=
            include_concrete)
    return atk_objects


@classmethod
def _cached_fields(cls):
    """
        _fields の取得をクラス変数にキャッシュする

        比較的重い処理なので。
        """
    if not hasattr(cls, '_fields_cache'):
        cls._fields_cache = cls._fields()
    return cls._fields_cache


def FakeEvent(ResourceType='Custom::CFN-Fake-Function', RequestType=
    'Create', Properties={}):
    """
	FakeEvent for py.test cases
	"""
    return {'FakeEvent': True, 'RequestType': RequestType, 'ResponseURL':
        'http://pre-signed-S3-url-for-response', 'StackId':
        'arn:aws:cloudformation:us-east-1:123456789012:stack/stack-name/guid',
        'RequestId': 'unique id for this create request',
        'LogicalResourceId': 'FakeResource', 'ResourceType': ResourceType,
        'ResourceProperties': Properties}


@classmethod
def __is_multivalued_dict__(cls, x):
    """
            >>> mv_d = multivalued_dict()
            >>> multivalued_dict.__is_multivalued_dict__(mv_d)
            True
        """
    return isinstance(x, cls) or ((True if x.default_factory == type([]) else
        False) if isinstance(x, cls.defaultdict) else False)


def value_or(value, default):
    """Return Value or Default if Value is None."""
    return default if value is None else value


def rsqrt(data=None, out=None, name=None, **kwargs):
    """Returns element-wise inverse square-root value of the input.

    .. math::
       rsqrt(x) = 1/\\sqrt{x}

    Example::

       rsqrt([4,9,16]) = [0.5, 0.33333334, 0.25]

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

    Defined in src/operator/tensor/elemwise_unary_op_pow.cc:L193

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

    out : NDArray, optional
        The output NDArray to hold the result.

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.
    """
    return 0,


@staticmethod
def get_dpi(value=1):
    """
        Returns current DPI used by DCC
        :param value: float
        :return: float
        """
    return 1.0


@staticmethod
def get_elastic_mappings(es_major):
    """Get Elasticsearch mapping.

        Non dynamic discovery of type for:
            * data.body (inmense field)

        :param es_major: major version of Elasticsearch, as string
        :returns:        dictionary with a key, 'items', with the mapping
        """
    mapping = """
         {
            "dynamic":true,
                "properties": {
                    "data": {
                        "properties": {
                            "body": {
                                "dynamic":false,
                                "properties": {}
                            }
                        }
                    }
                }
        }
        """
    return {'items': mapping}


def getProxies():
    """Returns the proxy configuration if it's provided by the registry.
        """
    pass


def seqs_continuous_indexesnot_slices(ol, value, seqs):
    """
        from elist.elist import *
        ol = [1,"a","a",2,3,"a",4,"a","a","a",5]
        seqs_continuous_indexesnot_slices(ol,"a",{0,2})
    """
    rslt = []
    length = ol.__len__()
    seq = -1
    cursor = 0
    begin = None
    slice = []
    while cursor < length:
        cond1 = not ol[cursor] == value
        cond2 = begin == None
        if cond1 & cond2:
            begin = cursor
            slice.append(cursor)
        elif cond1 & (not cond2):
            slice.append(cursor)
        elif (not cond1) & (not cond2):
            seq = seq + 1
            if seq in seqs:
                rslt.append(slice)
            else:
                pass
            begin = None
            slice = []
        else:
            pass
        cursor = cursor + 1
    if slice:
        seq = seq + 1
        if seq in seqs:
            rslt.append(slice)
        else:
            pass
    else:
        pass
    return rslt


def prepare_lookup_value(key, value):
    """
    Returns a lookup value prepared to be used in queryset filtering.
    """
    if key.endswith('__in'):
        value = value.split(',')
    if key.endswith('__isnull') and type(value) == str:
        if value.lower() in ('', 'false'):
            value = False
        else:
            value = True
    return value


def _get_well_row(idx, columns):
    """Map idx to well, row ordered."""
    return chr(ord('A') + idx / columns) + str(idx % columns + 1)


def setcktuple2str(setcktuple):
    """
        setcktuple = ('Set-Cookie', '__Host-user_session=Tz98; path=/; expires=Tue, 27 Mar 2018 05:30:16 -0000; secure; HttpOnly; SameSite=Strict')
        setckstr = setcktuple2str(setcktuple)
        setckstr
    """
    return setcktuple[1]


def psi_Mg_Na_SO4_HMW84(T, P):
    """c-c'-a: magnesium sodium sulfate [HMW84]."""
    psi = -0.015
    valid = T == 298.15
    return psi, valid


def convert_params(params, prefix):
    """Change prefix of a python dictionnary
    (necessary in some Challonge API methods)
    """
    new_params = {}
    for key in params:
        new_key = prefix + '[' + key + ']'
        new_params[new_key] = params[key]
    return new_params


def location_3d_to_region_2d(region, rv3d, coord, default=None):
    """
    Return the *region* relative 2d location of a 3d position.

    :arg region: region of the 3D viewport, typically bpy.context.region.
    :type region: :class:`bpy.types.Region`
    :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
    :type rv3d: :class:`bpy.types.RegionView3D`
    :arg coord: 3d worldspace location.
    :type coord: 3d vector
    :arg default: Return this value if ``coord``
       is behind the origin of a perspective view.
    :return: 2d location
    :rtype: :class:`mathutils.Vector` or ``default`` argument.
    """
    from mathutils import Vector
    prj = rv3d.perspective_matrix * Vector((coord[0], coord[1], coord[2], 1.0))
    if prj.w > 0.0:
        width_half = region.width / 2.0
        height_half = region.height / 2.0
        return Vector((width_half + width_half * (prj.x / prj.w),
            height_half + height_half * (prj.y / prj.w)))
    else:
        return default


def _timestamp_to_string(timestamp):
    """Extracts the date from a pandas timestamp and convert to a string

    :returns string of the format: '20190908' (for September 8th, 2019)

    """
    date_dashes = str(timestamp.date()).replace('-', '')
    return date_dashes


def append_lines(file, lines, encoding=None, errors=None):
    """Append the lines to a file.

    :param file: path to file or file descriptor
    :type file: :term:`path-like object` or int
    :param list(str) lines: list of strings w/o newline
    :param str encoding: name of the encoding
    :param str errors: error handler
    :return: number of characters written
    :rtype: int
    :raises OSError: on I/O failure

    .. versionchanged:: 0.6.0
       Add parameter ``errors``
    """
    with open(file, 'a', encoding=encoding, errors=errors) as fh:
        cnt = fh.write('\n'.join(lines))
        cnt += fh.write('\n')
        return cnt


def get_pil_channels(pil_mode):
    """Get the number of channels for PIL modes."""
    return {'1': 1, 'L': 1, 'P': 1, 'RGB': 3, 'CMYK': 4, 'YCbCr': 3, 'LAB':
        3, 'HSV': 3, 'I': 1, 'F': 1}.get(pil_mode, 3)


@staticmethod
def _build_mac(fields, data):
    """Build MAC string. Length is in bytes instead of symbols."""
    f = lambda x: data.get('VK_%s' % x)
    return u''.join(map(lambda k: '%03d%s' % (len(f(k)), f(k)), fields)
        ).encode('utf-8')


def cdp_file_output(in_seq_name1, in_seq_name2, ref, nt, ext):
    """
    Generate output file name
    :param in_seq_name1: sample name/s (str)
    :param in_seq_name2: sample name/s (str)
    :param ref: reference name (str)
    :param nt: aligned read length (int)
    :param ext: extension (ie. csv or pdf)
    :return: output filename (str)
    """
    file_name = '{0}_{1}_{2}_{3}.{4}'.format(in_seq_name1, in_seq_name2,
        ref, nt, ext)
    if len(file_name) > 240:
        print('Auto-generated file name too long\n')
        file_name = '{0}_{1}.{2}'.format(ref, nt, ext)
        print('{0} used instead\n'.format(file_name))
    return file_name


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

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

    For example::

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

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


def _convert_fun(fun):
    """hide obj-address from functions."""
    return 'fun: ', fun.__name__


def describe_events(ServerName=None, NextToken=None, MaxResults=None):
    """
    Describes events for a specified server. Results are ordered by time, with newest events first.
    This operation is synchronous.
    A ResourceNotFoundException is thrown when the server does not exist. A ValidationException is raised when parameters of the request are not valid.
    See also: AWS API Documentation

    :example: response = client.describe_events(
        ServerName='string',
        NextToken='string',
        MaxResults=123
    )

    :type ServerName: string
    :param ServerName: [REQUIRED]
            The name of the server for which you want to view events.

    :type NextToken: string
    :param NextToken: NextToken is a string that is returned in some command responses. It indicates that not all entries have been returned, and that you must run at least one more request to get remaining items. To get remaining results, call DescribeEvents again, and assign the token from the previous results as the value of the nextToken parameter. If there are no more results, the response object's nextToken parameter value is null . Setting a nextToken value that was not returned in your previous results causes an InvalidNextTokenException to occur.

    :type MaxResults: integer
    :param MaxResults: To receive a paginated response, use this parameter to specify the maximum number of results to be returned with a single call. If the number of available results exceeds this maximum, the response includes a NextToken value that you can assign to the NextToken request parameter to get the next set of results.

    :rtype: dict
    :return: {
        'ServerEvents': [
            {
                'CreatedAt': datetime(2015, 1, 1),
                'ServerName': 'string',
                'Message': 'string',
                'LogUrl': 'string'
            },
        ],
        'NextToken': 'string'
    }

    """
    pass


@classmethod
def inspect(cls, obj):
    """ Get the :class:`Deprecation` instance of a deprecated function. """
    return cls._deprecations[obj]


def append_variant_info(main_curr, chunk_db):
    """
    Append the variant and variant_info data from a chunk_db
    to the main database.
    """
    cmd = 'attach ? as toMerge'
    main_curr.execute(cmd, (chunk_db,))
    main_curr.execute('BEGIN TRANSACTION')
    cmd = 'INSERT INTO variants SELECT * FROM toMerge.variants'
    main_curr.execute(cmd)
    cmd = 'INSERT INTO variant_impacts SELECT * FROM toMerge.variant_impacts'
    main_curr.execute(cmd)
    main_curr.execute('END TRANSACTION')
    cmd = 'detach toMerge'
    main_curr.execute(cmd)


def make_normalizer_node(context, input, output, norm):
    """
    Helper function to construct a normalizer node
    """
    from ..common import NodeBuilder
    nb = NodeBuilder(context, 'Normalizer', op_domain='ai.onnx.ml')
    nb.add_attribute('norm', norm)
    nb.add_input(input)
    nb.add_output(output)
    return nb.make_node()


def __new__(cls, qname):
    """Create the `QName` instance.

        :param qname: the qualified name as a string of the form
                      ``{namespace-uri}local-name``, where the leading curly
                      brace is optional
        """
    if type(qname) is cls:
        return qname
    qname = qname.lstrip('{')
    parts = qname.split('}', 1)
    if len(parts) > 1:
        self = str.__new__(cls, '{%s' % qname)
        self.namespace, self.localname = list(map(str, parts))
    else:
        self = str.__new__(cls, qname)
        self.namespace, self.localname = None, str(qname)
    return self


def from_package_str(item):
    """
    Display name space info when it is different, then diagram's or
    parent's namespace.
    """
    subject = item.subject
    canvas = item.canvas
    if not subject or not canvas:
        return False
    namespace = subject.namespace
    parent = canvas.get_parent(item)
    if parent and parent.subject and parent.subject.namespace is not namespace:
        return False
    return (f'(from {namespace.name})' if namespace is not canvas.diagram.
        namespace else '')


def _stub_islink(path):
    """
    Always return C{False} if the operating system does not support symlinks.

    @param path: A path string.
    @type path: L{str}

    :return: C{False}
    :rtype: L{bool}
    """
    return False


def _preprocess_padding(padding):
    """Convert keras' padding to tensorflow's padding.

    # Arguments
        padding: string, `"same"` or `"valid"`.

    # Returns
        a string, `"SAME"` or `"VALID"`.

    # Raises
        ValueError: if `padding` is invalid.
    """
    if padding == 'same':
        padding = 'SAME'
    elif padding == 'valid':
        padding = 'VALID'
    else:
        raise ValueError('Invalid padding: ' + str(padding))
    return padding


def is_integer(value: str) ->bool:
    """Check if a value is an integer."""
    try:
        int(value)
        return True
    except ValueError:
        return False


def lighter(image1, image2):
    """
    Compares the two images, pixel by pixel, and returns a new image containing
    the lighter values. At least one of the images must have mode "1".

    .. code-block:: python

        out = max(image1, image2)

    :rtype: :py:class:`~PIL.Image.Image`
    """
    image1.load()
    image2.load()
    return image1._new(image1.im.chop_lighter(image2.im))


def lines_to_features(lines, source='imagery'):
    """ Create features from lines """
    gid = 0
    features = []
    for line in lines:
        feature = {'type': 'Feature', 'geometry': {'type': 'LineString',
            'coordinates': line}, 'properties': {'id': gid, 'source': source}}
        features.append(feature)
        gid += 1
    return features


@staticmethod
def create_sample_set(df_filt, annot_colname):
    """
        Create the set of all terms in the specific sample

        :param df_filt: DataFrame with one term per row, filtered so that only terms present in the sample of interest
        are included in the annot_colname column
        :param annot_colname: Name of annotation column - either tax_colname or func_colname
        :return: Set of all terms in df_filt
        """
    return set(df_filt[annot_colname])


def sub_summarylevel(v):
    """Replace summary level names with SL numbers"""
    from geoid.core import names
    try:
        int(v)
        return v
    except ValueError:
        return names[v.lower()]


def _quadrature_trapz(x1, x2, f, norm_func):
    """
    Composite trapezoid quadrature
    """
    x3 = 0.5 * (x1 + x2)
    f1 = f(x1)
    f2 = f(x2)
    f3 = f(x3)
    s2 = 0.25 * (x2 - x1) * (f1 + 2 * f3 + f2)
    round_err = 0.25 * abs(x2 - x1) * (float(norm_func(f1)) + 2 * float(
        norm_func(f3)) + float(norm_func(f2))) * 2e-16
    s1 = 0.5 * (x2 - x1) * (f1 + f2)
    err = 1 / 3 * float(norm_func(s1 - s2))
    return s2, err, round_err


def refl_vgroupv(refl):
    """
        >>> refl_vgroupv([0, 0, 0, 1, 2, 2, 2])
        [[0, 0, 0], [1], [2, 2, 2]]
    """
    rslts = []
    prev_value = refl[0]
    prev_index = 0
    for i in range(1, len(refl)):
        curr_value = refl[i]
        if curr_value == prev_value:
            pass
        else:
            slc = refl[prev_index:i]
            rslts.append(slc)
            prev_value = curr_value
            prev_index = i
    slc = refl[prev_index:]
    rslts.append(slc)
    return rslts


@staticmethod
def find_site_name(soup) ->str:
    """
        Attempts to find Site Name

        :param soup: BeautifulSoup of site
        :return: str
        """
    site_name_meta = ['og:site_name', 'og:title', 'application:name',
        'twitter:app:name:iphone']
    for p in site_name_meta:
        try:
            name = soup.find(name='meta', property=p).get('content')
            if name:
                return name
        except AttributeError:
            pass
    try:
        title = soup.find(name='title').text
        if title:
            return title
    except AttributeError:
        pass
    return ''


def _import_mpl():
    """This function is not needed outside this utils module."""
    try:
        import matplotlib.pyplot as plt
    except:
        raise ImportError('Matplotlib is not found.')
    return plt


def block_name(model_selector):
    """
    return canonical block name for model_selector

    Ordinarily and ideally this would just be model_selector, but since mp_tasks saves all
    shared data blocks in a common dict to pass to sub-tasks, we want to be able override
    block naming convention to handle any collisions between model_selector names and skim names.
    Until and unless that happens, we just use model_selector name.

    Parameters
    ----------
    model_selector

    Returns
    -------
    block_name : str
        canonical block name
    """
    return model_selector


def noneorbool(s):
    """Turn empty or 'none' string to None, all others to boolean."""
    if s.lower() in ('', 'none'):
        return None
    elif s.lower() in ('true', 't', 'yes', 'y', '1'):
        return True
    else:
        return False


def unset_permission_from_role(permission_id, role_id):
    """Clear the setting of the permission to the role.
        """


def init():
    """
    This file may be distributed in Leo's plugin folder, but this file is NOT
    a Leo plugin!

    The init method returns False to tell Leo's plugin manager and unit tests to
    skip this file.
    """
    return False


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

        :param NoExpirationLinkGenReportFailedDetails val:
        :rtype: EventDetails
        """
    return cls('no_expiration_link_gen_report_failed_details', val)


def trim_chain_between(chain, start_res, end_res):
    """
    Remove all nucleotides between start_res and end_res, inclusive.

    The chain is modified in place so there is no return value.
    """
    to_detach = []
    for res in chain:
        if start_res <= res.id[1] and res.id[1] <= end_res:
            to_detach += [res]
    for res in to_detach:
        chain.detach_child(res.id)


@classmethod
def calculate_penalty(cls, virtual_step_used: int, step_price: int) ->int:
    """Returns penalty according to given parameters

        :param virtual_step_used:
        :param step_price:
        """
    return virtual_step_used * step_price


def __call__(request):
    """ Return the *default* root object for an application """


def datetime_to_ecma262(value):
    """
    Convert a convencional datetime object
    to ecma-262 javascript/json format.
    """
    r = value.isoformat()
    if value.microsecond:
        r = r[:23] + r[26:]
    if r.endswith('+00:00'):
        r = r[:-6] + 'Z'
    return r


def create_pdic_param(name, values):
    """
    Create a fake procpar dictionary element of with given name and values.
    """
    dic = dict()
    dic['Dgroup'] = '1'
    dic['Ggroup'] = '2'
    dic['active'] = '1'
    dic['basictype'] = '1'
    dic['enumerable'] = '0'
    dic['intptr'] = '64'
    dic['maxvalue'] = '32767'
    dic['minvalue'] = '0'
    dic['name'] = name
    dic['protection'] = '0'
    dic['stepsize'] = '0'
    dic['subtype'] = '7'
    dic['values'] = values
    return dic


def reload(adjust_length: bool=False):
    """Reload strips in the sequencer

    :param adjust_length: Adjust Length, Adjust length of strips to their data length
    :type adjust_length: bool
    """
    pass


def get_schema():
    """Schema structure of this resource

    :return: schema dictionary
    :rtype: dict
    """
    return {'allow_unknown': True, 'auth_field': '_user', 'item_methods': [
        'GET', 'PATCH', 'PUT', 'DELETE'], 'schema': {'schema_version': {
        'type': 'integer', 'default': 1}, 'host': {'schema_version': 1,
        'type': 'string'}, '_user': {'schema_version': 1, 'type':
        'objectid', 'data_relation': {'resource': 'user', 'embeddable':
        True}}}, 'schema_deleted': {}}


def expand_resources(resources):
    """
    Construct the submit_job arguments from the resource dict
    """
    cmd = ''
    for field, val in resources.items():
        if type(val) is bool:
            if val is True:
                cmd += '--{} '.format(field)
        elif type(val) is list or type(val) is tuple:
            for mp in val:
                cmd += '--{} {} '.format(field, mp)
        else:
            cmd += '--{} {} '.format(field, val)
    return cmd


@classmethod
def from_geojson(cls, geojson):
    """
        Construct a Workflows GeometryCollection from a GeoJSON mapping.

        Note that the GeoJSON must be relatively small (under 10MiB of serialized JSON).

        Parameters
        ----------
        geojson: Dict

        Returns
        -------
        ~descarteslabs.workflows.GeometryCollection

        Example
        -------
        >>> from descarteslabs.workflows import GeometryCollection
        >>> geojson = {"type": "GeometryCollection", "geometries": [{"type": "Point", "coordinates": [1, 2]}]}
        >>> gc = GeometryCollection.from_geojson(geojson)
        >>> gc.compute().__geo_interface__ # doctest: +SKIP
        {'type': 'GeometryCollection', 'geometries': [{'type': 'Point', 'coordinates': [1, 2]}]}
        """
    try:
        return cls._from_apply(cls._constructor, type=geojson['type'],
            geometries=geojson['geometries'])
    except KeyError:
        raise ValueError(
            "Expected a GeoJSON mapping containing the fields 'type' and 'geometries', but got {}"
            .format(geojson))


def _parse_error_body(response):
    """Parses the given error response to extract Auth error code and message."""
    error_dict = {}
    try:
        parsed_body = response.json()
        if isinstance(parsed_body, dict):
            error_dict = parsed_body.get('error', {})
    except ValueError:
        pass
    code = error_dict.get('message') if isinstance(error_dict, dict) else None
    custom_message = None
    if code:
        separator = code.find(':')
        if separator != -1:
            custom_message = code[separator + 1:].strip()
            code = code[:separator]
    return code, custom_message


@staticmethod
def interface_roles_change_and_tree_transitions_from_active_to_unsure_and_best_upstream_neighbor_is_not_null(
    interface: 'TreeInterfaceDownstream'):
    """
        Tree transitions from Active to Unsure state AND
        BestUpstream neighbor is not null
        """
    interface.logger.debug(
        'interface_roles_change_and_tree_transitions_from_active_to_unsure_and_best_upstream_neighbor_is_not_null'
        )
    interface.send_no_interest()


def _stylize_axes(ax, title, xlabel, ylabel):
    """
    Customize axes spines, title, labels, ticks, and ticklabels.

    Args:
        :ax: the axes to customize
        :title: the title to set
        :xlabel: the label on the x axis
        :ylabel: the label on the y axis

    Returns:
        None
    """
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.xaxis.set_tick_params(top=False, direction='out', width=1)
    ax.yaxis.set_tick_params(right=False, direction='out', width=1)
    ax.set_title(title)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)


@classmethod
def from_string(cls, string):
    """ Retrieve a System value by name (case-insensitively) """
    folded = str(string).casefold()
    for system in cls:
        if system.sys_name == folded:
            return system
    raise ValueError(f'System not found: “{string!s}”')


def shift_y(point, dy):
    """Shifts a given point in the y direction."""
    return point[0], point[1] + dy


def sliceit(iterable, lower=0, upper=None):
    """Apply a slice on input iterable.

    :param iterable: object which provides the method __getitem__ or __iter__.
    :param int lower: lower bound from where start to get items.
    :param int upper: upper bound from where finish to get items.
    :return: sliced object of the same type of iterable if not dict, or specific
        object. otherwise, simple list of sliced items.
    :rtype: Iterable
    """
    if upper is None:
        upper = len(iterable)
    try:
        result = iterable[lower:upper]
    except TypeError:
        result = []
        if lower < 0:
            lower += len(iterable)
        if upper < 0:
            upper += len(iterable)
        if upper > lower:
            iterator = iter(iterable)
            for index in range(upper):
                try:
                    value = next(iterator)
                except StopIteration:
                    break
                else:
                    if index >= lower:
                        result.append(value)
    iterablecls = iterable.__class__
    if not (isinstance(result, iterablecls) or issubclass(iterablecls, dict)):
        try:
            result = iterablecls(result)
        except TypeError:
            pass
    return result


def area_proportion(area, height, width):
    """
        proportion of the image corresponding to the object
    """
    return float(area) / (height * width) * 100


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

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

    For example::

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

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


@staticmethod
def _decode_temp(byte_1, byte_2):
    """Decode a signed short temperature as two bytes to a single number."""
    temp = (byte_1 << 8) + byte_2
    if temp > 32767:
        temp = temp - 65536
    temp = temp / 10
    return temp


def t_VALUE(t):
    """([ ]*)value:[ ](.+)\\n"""
    tab = int(len(t.lexer.lexmatch.group(5)) / 2)
    value = t.lexer.lexmatch.group(6)
    t.value = [tab, value]
    return t


def with_metaclass(meta, *bases):
    """Create a base class with a metaclass."""
    return meta('_NewBase', bases, {})


def get_many_to_many_fields_from_model(model_class):
    """Return only M2M fields, including inherited ones?"""
    return model_class._meta.many_to_many


@classmethod
def _as_convention(cls, name):
    """Get a named convention as a GraphConvention object."""
    try:
        return cls.CONVENTION[name]
    except KeyError:
        raise ValueError('convention not understood ({0})'.format(name))


@staticmethod
def _get_argument_count(complete_path, current_path):
    """
        Returns the number of URL elements left over for between
        the current path and the complete path.
        """
    complete_path_comps = complete_path.rstrip('/').split('/')
    current_path_comps = current_path.rstrip('/').split('/')
    return len(complete_path_comps) - len(current_path_comps)


@staticmethod
def model(t, state, action, params):
    """
        ordinary differential equations
        """
    raise NotImplementedError


def last_arg_byref(args):
    """Return the last C argument's value by reference."""
    return args[-1]._obj.value


def p_table_reference_w_database(p):
    """table_reference : identifier '.' identifier"""
    p[0] = p[1], p[3]


def get_local_ip():
    """ Returns the local IP. Can be overwritten in the config with --local-ip so don't call
    this function directly, instead get the current value from the config """
    import socket
    try:
        return socket.gethostbyname(socket.gethostname())
    except:
        return '127.0.0.1'


def float_if_not_none(value):
    """
    Returns an float(value) if the value is not None.

    :param value: None or a value that can be converted to an float.
    :return: None or float(value)
    """
    return None if value is None else float(value)


def list_equal(_list1, _list2):
    """
    are 2x lists equal (deep check)
    """
    return len(_list1) == len(_list2) and sorted(_list1) == sorted(_list2)


def wread(filename):
    """Read a file from wvfs, using data filters."""


def numerify(input_text, default=-1):
    """ (number or string, default=-1) -> number

    This is good for query string operations.

    >>> numerify(1)
    1
    >>> numerify("1")
    1
    >>> numerify("1a")
    -1
    >>> numerify("ab")
    -1
    >>> numerify("abc", default=44)
    44
    """
    if str(input_text).isnumeric():
        return int(input_text)
    return default


@classmethod
def add_arguments(cls):
    """
        sub parser document
        """
    return [(('--preview',), dict(action='store_true', help='show task')),
        (('node',), dict(nargs='?', help='which node to active'))]
    pass


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

        :returns: list of strings containing APIC class names
        """
    return ['fvAp']


def clear():
    """Clear the live log"""
    global LiveLog
    LiveLog = []


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 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 signal_delete_twilio_number(sender, **kwargs):
    """Release/delete twilio number phone from the account."""
    tw_number = kwargs.get('instance')
    tw_number.release_twilio_number()


def locale_explode(locale):
    """For non-complete locales, missing elements will be None.

    :param locale: The ISO locale string to explode.
    :return:  A tuple (language, country, variant, language_country, language@variant).
    """
    pass


def _normalize(file):
    """Convenience function to support path objects."""
    if 'Path' in type(file).__name__:
        return str(file)
    else:
        return file


def should_extract_this(item, NXDL_file_endings_list,
    allowed_parent_directories):
    """
    decide if this item should be extracted from the ZIP download

    :return bool:
    """
    for ending in NXDL_file_endings_list:
        if item.endswith(ending):
            if item.split('/')[-2] in allowed_parent_directories:
                return True
    return False


def makedirs(*unused_args, **unused_kwargs):
    """Method os.makedirs() is forbidden"""
    raise RuntimeError(
        'Usage of os.makedirs() is forbidden. Use certbot.compat.filesystem.makedirs() instead.'
        )


def getid(thing: object, module: str=None, qualname: str=None, name: str=None
    ) ->str:
    """Returns some kind of id for `thing`

    :param thing: object to get the id for

    :param module: str fallback

    :param qualname: str fallback

    :param name: str fallback    """
    parts = []
    module = getattr(thing, '__module__', module)
    name = getattr(thing, '__qualname__', None) or getattr(thing,
        '__name__', name)
    if module:
        parts.append(module)
    if name:
        parts.append(name)
    return '.'.join(parts)


def egg_name(name, version, build):
    """
    Return the egg filename (including the .egg extension) for the given
    arguments
    """
    return '{0}-{1}-{2}.egg'.format(name, version, build)


def friction_cfn(coefficient, normal):
    """Usage: Find friction using coefficient and normal force"""
    return coefficient * normal


@staticmethod
def _wrap_function(original_func, wrapper_infodict):
    """Return a wrapped version of func.

        :param original_func: The function to be wrapped.
        :param wrapper_infodict: The infodict to use for constructing the
            wrapper.
        """
    src = ('lambda %(signature)s: _original_func_(%(signature)s)' %
        wrapper_infodict)
    wrapped_func = eval(src, dict(_original_func_=original_func))
    wrapped_func.__name__ = wrapper_infodict['name']
    wrapped_func.__doc__ = wrapper_infodict['doc']
    wrapped_func.__module__ = wrapper_infodict['module']
    wrapped_func.__dict__.update(wrapper_infodict['dict'])
    wrapped_func.__defaults__ = wrapper_infodict['defaults']
    return wrapped_func


def buffered_read(fh, lock, offsets, bytecounts, buffersize=2 ** 26):
    """Return iterator over segments read from file."""
    length = len(offsets)
    i = 0
    while i < length:
        data = []
        with lock:
            size = 0
            while size < buffersize and i < length:
                fh.seek(offsets[i])
                bytecount = bytecounts[i]
                data.append(fh.read(bytecount))
                size += bytecount
                i += 1
        for segment in data:
            yield segment


def emptylanding():
    """This function returns and example landing page"""
    return """# Test Project

This is a great place to start making your documentation!

You should link to a couple of pages:

* [.](testpage1.md){step: True}
* [.](testpage2.md){step: True}

And you should definitely let people know about the {{BOMlink}} page."""


def head(list):
    """Returns the first element of the given list or string. In some libraries
this function is named first"""
    for x in list:
        return x


def print_update(percentage):
    """Print percentage read-in.

    Prints a percentage of how much as been read in at a given time.

    Parameters
    ----------
    string: int
        Percentage read-in complete.
    """
    print('[{} {} % ]'.format('#' * int(percentage / 10), int(percentage /
        10) * 10))


def valid_choices(choices):
    """
    Return list of choices's keys
    """
    for key, value in choices:
        if isinstance(value, (list, tuple)):
            for key, _ in value:
                yield key
        else:
            yield key


def KK_RC7_fit(params, w, t_values):
    """
    Kramers-Kronig Function: -RC-

    Kristian B. Knudsen (kknu@berkeley.edu / kristianbknudsen@gmail.com)
    """
    Rs = params['Rs']
    R1 = params['R1']
    R2 = params['R2']
    R3 = params['R3']
    R4 = params['R4']
    R5 = params['R5']
    R6 = params['R6']
    R7 = params['R7']
    return Rs + R1 / (1 + w * 1.0j * t_values[0]) + R2 / (1 + w * 1.0j *
        t_values[1]) + R3 / (1 + w * 1.0j * t_values[2]) + R4 / (1 + w *
        1.0j * t_values[3]) + R5 / (1 + w * 1.0j * t_values[4]) + R6 / (1 +
        w * 1.0j * t_values[5]) + R7 / (1 + w * 1.0j * t_values[6])


def count_clusters_no_pandas(inTbl, debug=False):
    """Count the clusters with orthologs."""
    from collections import Counter
    tmpDict = {}
    cnt = Counter()
    for line in open(inTbl):
        if line.startswith('#cl') or line.startswith('clusterID'):
            continue
        line = line.rstrip()
        flds = line.split('\t')
        clstrId = flds[0]
        if not clstrId in tmpDict:
            tmpDict[clstrId] = None
            cnt.update([flds[-1]])
    no_conflict = cnt['No']
    diff_names = cnt['diff. names']
    diff_numbers = cnt['diff. numbers']
    tot_conflicts = diff_names + diff_numbers
    clstrCnt = tot_conflicts + no_conflict
    if debug:
        print('Clusters:\t%d' % clstrCnt)
        print('No conflict:\t%d' % no_conflict)
        print('diff.names conflict:\t%d' % diff_names)
        print('diff.numbers conflict:\t%d' % diff_numbers)
        print('Total conflicts:\t%d' % tot_conflicts)
    return clstrCnt, no_conflict, diff_names, diff_numbers


def _is_ssl_timeout(exc):
    """ Returns True if the exception is for an SSL timeout """
    return exc.message in ('The handshake operation timed out',
        'The write operation timed out', 'The read operation timed out')


def constraint_to_fcurve():
    """Create F-Curves for object which will copy object’s movement caused by this constraint

    """
    pass


def codon_table_10plus(table):
    """Return a codon table only representing codons with > 10% occurrence frequency."""
    table = table.ix[table.Fraction >= 0.1]
    table = table.groupby(level=0).transform(lambda x: x / x.sum())
    return table


def highlight():
    """Highlight selected file(s)

    """
    pass


@staticmethod
def fix_value_null(value):
    """Fix <null> values in some Jira parameters.

        In some values fields, as returned by the Jira API,
        some fields appear as <null>. This function convert Them
        to None.

        :param value: string found in a value fields
        :return: same as value, or None
        """
    if value == '<null>':
        return None
    else:
        return value


@classmethod
def get_period_start_datetime(cls, log_time, summary_freq):
    """Periods can be: days, weeks, months, years.
        Days referenced from midnight on the current computer's clock.
        Weeks referenced from Monday morning @ 00:00:00am.
        Months and years follow from the above."""
    summary_freq_qty = summary_freq[0]
    summary_freq_period = summary_freq[1].lower()
    base_time = log_time.replace(microsecond=0, second=0, minute=0, hour=0)
    if summary_freq_period in ['day', 'days']:
        assert summary_freq_qty == 1, 'Days only supports 1'
        return base_time
    elif summary_freq_period in ['week', 'weeks']:
        assert summary_freq_qty == 1, 'Weeks only supports 1'
        raise NotImplementedError('Still working to implement weeks.')
    elif summary_freq_period in ['month', 'months']:
        assert summary_freq_qty in [1, 2, 3, 4, 6
            ], 'Months only supports [1,2,3,4,6]'
        return base_time.replace(day=1, month=log_time.month /
            summary_freq_qty * summary_freq_qty)
    elif summary_freq_period in ['year', 'years']:
        assert summary_freq_qty in [1, 2, 3, 4, 6], 'Years only supports 1'
        return base_time.replace(day=1, month=1)
    else:
        raise NotImplementedError(
            'Unrecognized summary frequency period: %s' % summary_freq_period)


def _get_cast_kind(kind0, kind1):
    """determine the kind to cast into
    """
    if kind0 == kind1:
        return kind0, True
    elif 'O' in (kind0, kind1):
        return 'O', False
    elif 'f' in (kind0, kind1):
        return 'f', True
    elif 'i' in (kind0, kind1):
        return 'i', True
    else:
        return 'O', False


def _default_list(length: int) ->list:
    """ Returns a list filled with None values. """
    return [None for _ in range(length)]


def load_identity():
    """Empty stack and set to identity.

    """
    pass


def rk4_step(state, time, tau, state_derivative_function, **kwargs):
    """
    Routine for Rungge-Kutta steps.
    """
    fun = state_derivative_function
    k1 = tau * fun(state, time, **kwargs)
    state_ = state + 0.5 * k1
    k2 = tau * fun(state_, time + tau * 0.5, **kwargs)
    state_ = state + 0.5 * k2
    k3 = tau * fun(state_, time + tau * 0.5, **kwargs)
    state_ = state + k3
    k4 = tau * fun(state_, time + tau, **kwargs)
    ans = state + k1 / 6 + k2 / 3 + k3 / 3 + k4 / 6
    return ans


def _validate_dependencies_met():
    """
    Verifies that PyOpenSSL's package-level dependencies have been met.
    Throws `ImportError` if they are not met.
    """
    from cryptography.x509.extensions import Extensions
    if getattr(Extensions, 'get_extension_for_class', None) is None:
        raise ImportError(
            "'cryptography' module missing required functionality.  Try upgrading to v1.3.4 or newer."
            )
    from OpenSSL.crypto import X509
    x509 = X509()
    if getattr(x509, '_x509', None) is None:
        raise ImportError(
            "'pyOpenSSL' module missing required functionality. Try upgrading to v0.14 or newer."
            )


def load_currents(cursor, oids):
    """
        Returns the oid integer, state, and integer tid for all the specified
        objects.

        *oids* is an iterable of integers. If any objects do no exist,
        they are ignored.
        """


def somevalues(ddtt):
    """returns some values"""
    return ddtt.Name, ddtt.Construction_Name, ddtt.obj


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

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

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


def get_value_from_valuation_sheets(df, loc1, row_name, loc2, alt_row=None):
    """
    loc1  ------ loc2
     -
     -
     -
     -
    row_name(alt_row) --- value
    :param df: 设置好 column name 的 pandas dataframe
    :param loc1: 如图
    :param row_name: 如图
    :param loc2: 如图
    :param alt_row: 如图
    :return: 如图 value
    """
    value = df[df[loc1] == row_name][loc2].values
    if value.size == 0 and alt_row is not None:
        value = df[df[loc1] == alt_row][loc2].values
    if value.size == 0:
        return None
    else:
        if isinstance(value[0], str):
            ret = value[0].replace(',', '').replace('，', '')
        else:
            ret = value[0]
        return ret


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


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


@classmethod
def prepare(cls):
    """Prepare for use as part of an idiosync user database"""


def get_fixture_or_param_value(request, fixture_or_param_name):
    """
    Returns the value associated with parameter or fixture named `fixture_name`, in provided request context.
    This is just an easy way to use `getfixturevalue` or `getfuncargvalue` according to whichever is available in
    current pytest version.

    Note: it seems that this is the same than `request.node.callspec.params[fixture_or_param_name]` but maybe it is
    less 'internal' as an api ?

    :param request:
    :param fixture_or_param_name:
    :return:
    """
    try:
        return request.getfixturevalue(fixture_or_param_name)
    except AttributeError:
        return request.getfuncargvalue(fixture_or_param_name)


@classmethod
def get_config_opts(cls):
    """Defines the configuration options to be associated to this loadable

        :return: A list of configuration options relative to this Loadable
        :rtype: list of :class:`oslo_config.cfg.Opt` instances
        """
    return []


def _join_file_parts(path, filename, ext):
    """Join together path components to the full path.

    Any of the segments can be blank, to skip them.
    """
    return (path + '/' if path else '') + filename + ('.' + ext if ext else '')


def mask_eiger4m(data, mask):
    """
    Mask data measured with an Eiger4M detector

    :param data: the 2D data to mask
    :param mask: the 2D mask to be updated
    :return: the masked data and the updated mask
    """
    if data.ndim != 2 or mask.ndim != 2:
        raise ValueError('Data and mask should be 2D arrays')
    if data.shape != mask.shape:
        raise ValueError('Data and mask must have the same shape\n data is ',
            data.shape, ' while mask is ', mask.shape)
    data[:, 1030:1040] = 1
    data[514:551, :] = 1
    data[1065:1102, :] = 1
    data[1616:1653, :] = 1
    mask[:, 1030:1040] = 1
    mask[514:551, :] = 1
    mask[1065:1102, :] = 1
    mask[1616:1653, :] = 1
    return data, mask


def user_transforms_clear(only_selected: bool=True):
    """Reset pose on selected bones to keyframed state

    :param only_selected: Only Selected, Only visible/selected bones
    :type only_selected: bool
    """
    pass


def is_valid_componenet_name(name):
    """Validate actor name
    """
    return True


def _print_com(marker, offset, info):
    """String output for a COM segment."""
    _m, fill, info = info
    ss = []
    ss.append('\n{:-^63}'.format(' {} marker at offset {}, length {} '.
        format(marker, offset, info['Lc'] + 2)))
    comment = "'" + info['Cm'].decode('utf-8') + "'"
    ss.append('{}'.format(comment[:47]))
    comment = comment[47:]
    while True:
        if not comment:
            break
        line = comment[:63]
        comment = comment[63:]
        ss.append('         {}'.format(line))
    return '\n'.join(ss)


@staticmethod
def get_internal_summary(provider):
    """
        SKProductsResponseInternal summary.

        :param SKProductsResponseInternal.SKProductsResponseInternalSyntheticProvider provider: SKProductsResponseInternal provider.
        :return: SKProductsResponseInternal summary.
        :rtype: str
        """
    return provider.summary()


def is_white_key(note):
    """True if note is represented by a white key"""
    key_pattern = [True, False, True, True, False, True, False, True, True,
        False, True, False]
    return key_pattern[(note - 21) % len(key_pattern)]


def update_dic_dist(dic_dist, dic_xyz, d_real, d_approx, phase):
    """ For every annotation in a single image, update the final dictionary"""
    if phase == 'train':
        dic_dist['heights']['head'].append(float(dic_xyz['head'][0][1]))
        dic_dist['heights']['shoulder'].append(float(dic_xyz['shoulder'][0][1])
            )
        dic_dist['heights']['hip'].append(float(dic_xyz['hip'][0][1]))
        dic_dist['heights']['ankle'].append(float(dic_xyz['ankle'][0][1]))
    if phase == 'val':
        error = abs(d_real - d_approx)
        if d_real <= 10:
            dic_dist['error']['10'].append(error)
        elif d_real <= 20:
            dic_dist['error']['20'].append(error)
        elif d_real <= 30:
            dic_dist['error']['30'].append(error)
        else:
            dic_dist['error']['>30'].append(error)
        dic_dist['error']['all'].append(error)
    return dic_dist


def rgb2gray(img):
    """
    Converts a batch of RGB images to gray.

    :param img:
        an RGB image batch of any type.
    :return:
        a batch of gray images.
    """
    if len(img.shape) != 4:
        raise ValueError('Input images must have four dimensions, not %d' %
            len(img.shape))
    return (0.299 * img[:, (0)] + 0.587 * img[:, (1)] + 0.114 * img[:, (2)]
        ).unsqueeze(1)


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

    The ".dev0" means dirty.

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


@classmethod
def from_raw(cls, packed, partial=False):
    """ Initialize a new packet from the raw bytes """
    instance = cls()
    instance.unpack(packed, partial)
    return instance


def KK_RC13_fit(params, w, t_values):
    """
    Kramers-Kronig Function: -RC-

    Kristian B. Knudsen (kknu@berkeley.edu / kristianbknudsen@gmail.com)
    """
    Rs = params['Rs']
    R1 = params['R1']
    R2 = params['R2']
    R3 = params['R3']
    R4 = params['R4']
    R5 = params['R5']
    R6 = params['R6']
    R7 = params['R7']
    R8 = params['R8']
    R9 = params['R9']
    R10 = params['R10']
    R11 = params['R11']
    R12 = params['R12']
    R13 = params['R13']
    return Rs + R1 / (1 + w * 1.0j * t_values[0]) + R2 / (1 + w * 1.0j *
        t_values[1]) + R3 / (1 + w * 1.0j * t_values[2]) + R4 / (1 + w *
        1.0j * t_values[3]) + R5 / (1 + w * 1.0j * t_values[4]) + R6 / (1 +
        w * 1.0j * t_values[5]) + R7 / (1 + w * 1.0j * t_values[6]) + R8 / (
        1 + w * 1.0j * t_values[7]) + R9 / (1 + w * 1.0j * t_values[8]
        ) + R10 / (1 + w * 1.0j * t_values[9]) + R11 / (1 + w * 1.0j *
        t_values[10]) + R12 / (1 + w * 1.0j * t_values[11]) + R13 / (1 + w *
        1.0j * t_values[12])


@staticmethod
def _parse_message(message):
    """Extracts required attributes out of the messages properties.

        This extracts the `reply_to` and the `correlation_id` properties. If
        any of these required properties are missing a `ValueError` is raised.
        """
    properties = []
    for prop in ('reply_to', 'correlation_id'):
        try:
            properties.append(message.properties[prop])
        except KeyError:
            raise ValueError("The '%s' message property is missing" % prop)
    return properties


@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 guess_pos_columns(f):
    """ Guess the position columns from a given feature DataFrame """
    if 'z' in f:
        pos_columns = ['z', 'y', 'x']
    else:
        pos_columns = ['y', 'x']
    return pos_columns


def __setitem__(name, object):
    """ Add IArticle Content """


def _check_equal_dts(G, H, custom_msg=None):
    """
    A helper function to assert whether the given objects have the same
    sampling periods.
    """
    if not G._dt == H._dt:
        if custom_msg is None:
            custom_msg = "The sampling periods don't match."
        raise ValueError(custom_msg)


def update(dict1, dict2, overwrite=True, append=True):
    """ overwrites dict1 with dict2 """
    if overwrite and append:
        dict1.update(dict2)
    if overwrite and not append:
        for k in dict1:
            if k in dict2:
                dict1[k] = dict2[k]
    if not overwrite and append:
        for k in dict2:
            if k not in dict1:
                dict1[k] = dict2[k]
    return dict1


@classmethod
def migrate_settings(cls, settings, version):
    """Fix settings to work with the current version of widgets

        Parameters
        ----------
        settings : dict
            dict of name - value mappings
        version : Optional[int]
            version of the saved settings
            or None if settings were created before migrations
        """


@classmethod
def add_exception_handler(cls, handler):
    """Adds a specific L{ExceptionHandler} to the HTTP client
        @warning: SHOULD ONLY BE CALLED FROM A PROVIDER THROUGH A TEST
                  FIXTURE
        """
    cls._exception_handlers.append(handler)


@classmethod
def validate_enum_field(cls, value, enum_list, null=True):
    """
        Validate enum field value

        :type value: object
        :param value:

        :type enum_list: list
        :param enum_list: list of allow value

        :type null: bool
        :param null: is allow None value

        :rtype: dict
        :return: {'is_valid':bool, 'error_msg':str}
        """
    is_valid = True
    error_msg = None
    if null is False and value is None:
        is_valid = False
        error_msg = 'Data should not be None'
    if value is not None:
        if value in enum_list is False:
            is_valid = False
            error_msg = 'Data value should be from list: {}'.format(enum_list)
    return {'is_valid': is_valid, 'error_msg': error_msg}


def line_edit_val(le_wg, default_val):
    """Get QLineEdit field value.

    Parameters
    ----------
    le_wg : QtGui.QLineEdit
        QtGui.QLineEdit widget
    default_val : float
        Default value of the widget

    Returns
    -------
    le_val : float
        the value in the widget
    """
    le_val = le_wg.text()
    try:
        return float(le_val)
    except ValueError:
        return default_val


@staticmethod
def is_glob(glob):
    """
        Determine if the given string is a glob or not.

        :param glob: The potential glob pattern.
        :type glob: str | Any
        :return: Whether the given string is a glob or not.
        :rtype: bool
        """
    if glob is None or not isinstance(glob, str):
        return False
    i = 0
    length = len(glob)
    while i < length:
        c = glob[i]
        if c == '\\':
            i += 1
        elif c in ('?', '*'):
            return True
        i += 1
    return False


def current_data_indexes(data, two_columns_argument):
    """
    Transform the columns argument to the indexes of data tuple.

    Parameters
    ----------
    data : tuple
        A value returned by the get_data() function.
    two_columns_argument : list
        A list which contains two indexes of used columns - columns argument.

    Returns
    -------
    tuple
        A tuple which contains two indexes.
    """
    first_index = -1
    second_index = -1
    for index, column_data in enumerate(data):
        if two_columns_argument[0] == column_data[0]:
            first_index = index
        if two_columns_argument[1] == column_data[0]:
            second_index = index
    return first_index, second_index


def write(data):
    """
        Write some data to the body of the response to this request.  Response
        headers are written the first time this method is called, after which
        new response headers may not be added.

        @param data: Bytes of the response body.
        @type data: L{bytes}
        """


def bool2int(val):
    """
    Funkcja zamienia wartość boolową 0 lub 1

    true -> 1
    false -> 0
    """
    return 1 if val else 0


def _get(key, default=None):
    """Use it if a setting may not exist, and a default is necessary"""
    return globals().get(key, default)


@staticmethod
def resolve_response_data(head_key, data_key, data):
    """
        Resolves the responses you get from billomat
        If you have done a get_one_element request then you will get a dictionary
        If you have done a get_all_elements request then you will get a list with all elements in it

        :param head_key: the head key e.g: CLIENTS
        :param data_key: the data key e.g: CLIENT
        :param data: the responses you got
        :return: dict or list
        """
    new_data = []
    if isinstance(data, list):
        for data_row in data:
            if head_key in data_row and data_key in data_row[head_key]:
                if isinstance(data_row[head_key][data_key], list):
                    new_data += data_row[head_key][data_key]
                else:
                    new_data.append(data_row[head_key][data_key])
            elif data_key in data_row:
                return data_row[data_key]
    elif head_key in data and data_key in data[head_key]:
        new_data += data[head_key][data_key]
    elif data_key in data:
        return data[data_key]
    return new_data


def double_complex_from_npy_cdouble(var):
    """Cast a numpy cdouble to a cython double complex."""
    res = '_complexstuff.double_complex_from_npy_cdouble({})'.format(var)
    return res


def run(args):
    """Initializes the REST application with all configured component endpoints.
    """
    from clearshare import app, start, stop
    start()


def _format_generic(lines, element, printed, spacer=''):
    """Generically formats all remaining docstrings and custom XML
    tags that don't appear in the list of already printed documentation.

    :arg printed: a list of XML tags for the element that have already
      been handled by a higher method.
    """
    for doc in element.docstring:
        if doc.doctype.lower() not in printed:
            lines.append(spacer + doc.__str__())


def camel_to_underscore(name):
    """
    convert CamelCase style to under_score_case
    """
    as_list = []
    length = len(name)
    for index, i in enumerate(name):
        if index != 0 and index != length - 1 and i.isupper():
            as_list.append('_%s' % i.lower())
        else:
            as_list.append(i.lower())
    return ''.join(as_list)


def parse_global_range_dataframe(global_ranges):
    """ Cleans up the global ranges dataframe """
    global_df = global_ranges[global_ranges.columns[:-3]]
    global_df.columns = ['reference_designator', 'parameter_id_r',
        'parameter_id_t', 'global_range_min', 'global_range_max',
        'data_level', 'units']
    return global_df


def tolist(val):
    """
    a convenience method to return an empty list instead of None
    """
    if val is None:
        return []
    else:
        return [val]


def recursiveGetAttr(obj, name):
    """Can call down into e.g. object1.object2[4].attr"""
    return eval(name, obj.__dict__)


@classmethod
def create(cls, domain, source, destinations):
    """Create a domain mail forward."""
    cls.echo('Creating mail forward %s@%s' % (source, domain))
    options = {'destinations': list(destinations)}
    result = cls.call('domain.forward.create', domain, source, options)
    return result


def addpoi():
    """
    @api {post} /map/collect/addpoi 增加收藏
    @apiVersion 1.0.0
    @apiGroup Collect
    @apiDescription 增加收藏

    @apiParam (Headers) {String} token 令牌
    @apiParam (Headers) {String} device_token 设备令牌
    @apiParam (Headers) {String} content_type 内容类型
    @apiParam (Headers) {String} timestamp 时间戳

    @apiParam (Body) {String} poi_id poi_id
    @apiParam (Body) {String} location 经纬度

    @apiSuccess (Success) {String} data 成功标识

    @apiSuccessExample {json} Success-Response:
    {
        "data": "Success.",
        "req_id": "r_049b93db7754407bb872aaee3d28f352",
        "err_resp": {
            "code": "0",
            "msg": null
        }
    }
    @apiError (Error) 21020  No poi_id in the request params

    @apiErrorExample {json} Error-Response:
    {
        "err_resp": {
            "code": "21020",
            "msg": "No poi_id in the request params!"
        },
        "req_id": "r_da328a55dfbc46bda249122030b8677d"
    }
    """


def with_base(bases, cls):
    """
    Return a copy of bases tuple that contains the given additional class `cls`.
    """
    if cls in bases:
        return bases
    bases = list(bases)
    tail = []
    while bases:
        if issubclass(cls, bases[-1]):
            tail.append(bases.pop())
        else:
            bases.append(cls)
            break
    return *bases, *reversed(tail)


def p_exprlist_star_1(p):
    """exprlist_star : COMMA expr"""
    p[0] = [p[2]]


def set_origin(use_median: bool=False):
    """Set active marker as origin by moving camera (or its parent if present) in 3D space

    :param use_median: Use Median, Set origin to median point of selected bundles
    :type use_median: bool
    """
    pass


def calc_info(node):
    """Return a string with the summary of the state of a CalculationNode."""
    from aiida.orm import ProcessNode, WorkChainNode
    if not isinstance(node, ProcessNode):
        raise TypeError('Unknown type: {}'.format(type(node)))
    process_label = node.process_label
    process_state = node.process_state.value.capitalize()
    exit_status = node.exit_status
    if exit_status is not None:
        string = '{}<{}> {} [{}]'.format(process_label, node.pk,
            process_state, exit_status)
    else:
        string = '{}<{}> {}'.format(process_label, node.pk, process_state)
    if isinstance(node, WorkChainNode) and node.stepper_state_info:
        string += ' [{}]'.format(node.stepper_state_info)
    return string


@classmethod
def _find_localzeros(cls, values, **options):
    """
        Sequentially allocate values to localzeros.

        When a value is identified as being more extreme than another member it
        replaces that member; if this is never true, then the value is simply
        appended to the localzeros.

        """
    localzeros = set()
    for v in values:
        is_newzero = True
        localzeros_ = list(localzeros)
        for z in localzeros_:
            assert v != z
            con = cls._is_connected(v, z)
            if con:
                is_newzero = False
                if con is True or con == cls:
                    localzeros.remove(z)
                    localzeros.update([v])
        if is_newzero:
            localzeros.update([v])
    return localzeros


def binary(s):
    """return true if a string is binary data"""
    return bool(s and b'\x00' in s)


def _root_block(block):
    """
    Looks up the root of the stack of blocks containing the given ``block``.

    Example
    -------

    Parameters
    ----------
    block : Block
        The block of interest for which the root block will be obtained.

    Returns
    -------
    Block
        The block at the root of the block stack containing ``block``.
    """
    if not block:
        return block
    while block.logical_parent:
        block = block.logical_parent
    return block


def validate_format(*_arg):
    """
    This method can be overridden with format validation logic.
    """
    return True


def energy_res_comptel(e):
    """COMPTEL energy resolution :math:`\\Delta E / E`.

    Taken from `ch. II, page 11
    <http://wwwgro.unh.edu/users/ckappada/thesis_stuff/thesis.html>`_.
    """
    return 0.05


def matchTypes(accept_types, have_types):
    """Given the result of parsing an Accept: header, and the
    available MIME types, return the acceptable types with their
    quality markdowns.

    For example:

    >>> acceptable = parseAcceptHeader('text/html, text/plain; q=0.5')
    >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg'])
    [('text/html', 1.0), ('text/plain', 0.5)]

    Type signature: ([(str, str, float)], [str]) -> [(str, float)]
    """
    if not accept_types:
        default = 1
    else:
        default = 0
    match_main = {}
    match_sub = {}
    for main, sub, q in accept_types:
        if main == '*':
            default = max(default, q)
            continue
        elif sub == '*':
            match_main[main] = max(match_main.get(main, 0), q)
        else:
            match_sub[main, sub] = max(match_sub.get((main, sub), 0), q)
    accepted_list = []
    order_maintainer = 0
    for mtype in have_types:
        main, sub = mtype.split('/')
        if (main, sub) in match_sub:
            q = match_sub[main, sub]
        else:
            q = match_main.get(main, default)
        if q:
            accepted_list.append((1 - q, order_maintainer, q, mtype))
            order_maintainer += 1
    accepted_list.sort()
    return [(mtype, q) for _, _, q, mtype in accepted_list]


def active_from_pos(pos_hsh, pos):
    """
    >>> s = "* evnt @s 2p fri @e 90m @r w &w 2fr &u 6/1 9a @c dag @l home"
    >>> pos_hsh, hsh = process_entry(s)
    >>> print(pos_hsh)
    {(0, 1): ('itemtype', '*'), (1, 7): ('summary', 'evnt'), (7, 17): ('s', '2p fri'), (17, 24): ('e', '90m'), (24, 29): ('rr', 'w'), (29, 36): ('rw', '2fr'), (36, 46): ('ru', '6/1 9a'), (46, 53): ('c', 'dag'), (53, 61): ('l', 'home')}
    >>> active_from_pos(pos_hsh, 18)
    ((17, 24), ('e', '90m'))
    >>> active_from_pos(pos_hsh, 45)
    ((36, 46), ('ru', '6/1 9a'))
    >>> pos_hsh, hsh = process_entry("- ")
    >>> active_from_pos(pos_hsh, 0)
    ((0, 1), ('itemtype', '-'))
    >>> active_from_pos(pos_hsh, 1)
    ((1, 3), ('summary', ''))
    >>> pos_hsh, hsh = process_entry("")
    >>> active_from_pos(pos_hsh, 1)
    (None, None)
    >>> pos_hsh, hsh = process_entry("+ bad type character")
    >>> active_from_pos(pos_hsh, 3)
    ((0, 21), ('itemtype', '+'))
    """
    for p, v in pos_hsh.items():
        if p[0] <= pos < p[1]:
            return p, v
    return None, None


def gen_excel_name(row, col):
    """Translate (0,0) into A1.

    Args:
        row: row index (zero-based)
        col: column index (zero-based)

    Returns:
        string representing cell name

    """
    if col < 26:
        col_name = chr(col + ord('A'))
    else:
        col_name = chr(int(col / 26) - 1 + ord('A')) + chr(col % 26 + ord('A'))
    return '%s%s' % (col_name, row + 1)


@classmethod
def update_all(cls, sheet):
    """
        Updates the sheet geometry by updating:
        * the edge vector coordinates
        * the edge lengths
        * the face centroids
        * the normals to each edge associated face
        * the face areas
        * the vertices heights (depends on geometry)
        * the face volumes (depends on geometry)

        """
    cls.update_dcoords(sheet)
    cls.update_length(sheet)
    cls.update_centroid(sheet)
    cls.update_height(sheet)
    cls.update_normals(sheet)
    cls.update_areas(sheet)
    cls.update_perimeters(sheet)
    cls.update_vol(sheet)


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 moduleNeedsTests(modulename):
    """
    Determine whether a module is a is a special module.
    like __init__
    """
    return not modulename.split('.')[-1].startswith('_')


def terminal_encoding(term):
    """Return our best guess of encoding for the given *term*."""
    if getattr(term, 'encoding', None):
        return term.encoding
    import locale
    return locale.getpreferredencoding()


def showOperandLines(rh):
    """
    Produce help output related to operands.

    Input:
       Request Handle
    """
    if rh.function == 'HELP':
        rh.printLn('N', '  For the GetHost function:')
    else:
        rh.printLn('N', 'Sub-Functions(s):')
    rh.printLn('N', '      diskpoolnames - ' +
        'Returns the names of the directory manager disk pools.')
    rh.printLn('N', '      diskpoolspace - ' +
        'Returns disk pool size information.')
    rh.printLn('N', '      fcpdevices    - ' +
        'Lists the FCP device channels that are active, free, or')
    rh.printLn('N', '                      offline.')
    rh.printLn('N', '      general       - ' +
        'Returns the general information related to the z/VM')
    rh.printLn('N', '                      hypervisor environment.')
    rh.printLn('N', '      help          - Returns this help information.')
    rh.printLn('N', '      version       - Show the version of this function')
    if rh.subfunction != '':
        rh.printLn('N', 'Operand(s):')
    rh.printLn('N', '      <poolName>    - Name of the disk pool.')
    return


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

        :param DomainVerificationAddDomainFailType val:
        :rtype: EventType
        """
    return cls('domain_verification_add_domain_fail', val)


def id_from_url(url: str) ->int:
    """
    Parse the id from the URL

    :param url: url to get id from.
    :raises NotImplementedError: If getting id from this url is not supported.
    :return: integer id.
    """
    parts = url.split('/')
    if 'aanbod' in parts:
        id = parts[parts.index('aanbod') + 1]
    elif 'list_messages' in parts:
        id = parts[parts.index('list_messages') + 1]
    elif 'pricewatch' in parts:
        id = parts[parts.index('pricewatch') + 1]
    else:
        raise NotImplementedError(
            'Getting the id for url ({url}) is not yet implemented')
    return int(id)


def unload_driver(driver):
    """Shutdown given webdriver instance.

    Args:
        driver (selenium.webdriver): The running webdriver.
    """
    driver.quit()


def get_host_fsids(node_metadata):
    """
    Return all the cluster FSIDs found for each socket in a host
    """
    all_fsids = []
    for socket_metadata in node_metadata['ceph']['sockets'].values():
        config = socket_metadata.get('config', {})
        if not config:
            continue
        fsid = config.get('fsid')
        if not fsid:
            continue
        all_fsids.append(fsid)
    return all_fsids


def screen_resolution():
    """
    Returns the current screen's resolution.

    Should be multi-platform.

    :return: A tuple containing the width and height of the screen.
    """
    w = 0
    h = 0
    try:
        import ctypes
        user32 = ctypes.windll.user32
        w, h = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)
    except AttributeError:
        try:
            import AppKit
            size = AppKit.NSScreen.screens()[0].frame().size
            w, h = int(size.width), int(size.height)
        except ImportError:
            try:
                import Xlib
                import Xlib.display
                display = Xlib.display.Display()
                root = display.screen().root
                size = root.get_geometry()
                w, h = size.width, size.height
            except ImportError:
                w = 1920
                h = 1080
    return w, h


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

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

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


def hardsigmoid(attrs, inputs, proto_obj):
    """Computes elementwise hard sigmoid of the input array"""
    return 'hard_sigmoid', attrs, inputs


def slide_point(slide_feather: bool=False, is_new_point: bool=False):
    """Slide control points

    :param slide_feather: Slide Feather, First try to slide feather instead of vertex
    :type slide_feather: bool
    :param is_new_point: Slide New Point, Newly created vertex is being slid
    :type is_new_point: bool
    """
    pass


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

        :param TeamProfileChangeDefaultLanguageType val:
        :rtype: EventType
        """
    return cls('team_profile_change_default_language', val)


@classmethod
def serialize(cls, value):
    """
        Serialize a type to GraphSON2.

        e.g {'@type': 'gx:Duration', '@value': 'P2DT4H'}

        :param value: The python object to serialize.
        """
    serializer = cls.get_serializer(value)
    if not serializer:
        return value
    value = serializer.serialize(value)
    out = {cls.TYPE_KEY: serializer.graphson_type}
    if value is not None:
        out[cls.VALUE_KEY] = value
    return out


def imageparts(msg):
    """Return a list of all msg parts with type 'image/*'."""
    return filter(lambda part: part.get_content_type().startswith('image/'),
        msg.walk())


@classmethod
def __format_comparison_segments(cls, name, private, common):
    """
        Method to create the string that will be printed out to screen for the stats file.
        :return:
        """
    if common > 0:
        perc = 100 * (private - common) / private
    else:
        perc = 0
    string = '{0} {1}/{2}  ({3:.2f}%)'.format(cls.__format_rowname(name),
        private - common, private, perc)
    return string


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

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

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


def interpret_report_url(base_url, report_url):
    """ Allows flexibility in how report urls are passed to functions

    Args:
        base_url (string): The url including uri scheme and hostname.
            Example: https://summit.schoolmint.net
        report_url (string): A version of the URI of a report. Can either be
            partial or full (the purpose of this function is to recognize
            and correct for if it is partial or full).

    Returns: A string containing the full URL to report.
    """
    if report_url[0:len(base_url)] == base_url:
        return report_url
    elif report_url[0] == '/':
        return base_url + report_url
    else:
        return base_url + '/' + report_url


def __getitem__(username):
    """
        Return the user if and only if the user (login) name exists
        and the user is a member of the group, otherwise raise KeyError.
        """


def clean_data(data):
    """
    The API returns the company results as a list for multiple results
    and a dictionary for just a single result. This requires unnecessary
    type checking everywhere else so just enforcing a list here is the
    simplest thing to do. It makes the result more consistent.
    """
    try:
        if not isinstance(data['companies']['company'], list):
            data['companies']['company'] = [data['companies']['company']]
    except KeyError:
        pass
    return data


def _check_user(config, user):
    """Check if *user* is in *config*.  Raise a :exc:`ValueError` if not."""
    if user not in config['users']:
        raise ValueError('User "%s" does not exist.' % user)