def help_file():
    """Displays the full, detailed help file for cfs_manager"""
    print(
        """
    All commands are preceded by dashes.
    Long-form commands are preceded by two dashes (eg. '--upload')
    Some of these commands have shortenings that do the same thing.
    These shortened commands only have one dash (eg. '-u')
    To see a list of all the valid commands, use '--commands'

    Commands can often be followed by 'arguments'.
    An argument is additional information that modifies how the command behaves.
    For example, if you're downloading files, you may want to say where to download to.
    You can do this by saying "--download-file [your preferred destination]".

    Some commands have defaults (eg. '--download-file' defaults to the Downloads folder).
    If a command has a default, it'll work without arguments by doing its default action.
    Other commands don't accept arguments (eg. '--list-files' just lists every file).
    If you use "[command] --help", you'll get a description of what it does and its arguments.

    A detailed version of a help page is given when the help command is followed by '--verbose'.
    (Following the '--help' with any argument does this, but '--verbose' and '-v' are typical.)
    To learn about CFS_Manager, use '--about'. To quit this interface, use '--quit' or '-q'.
    """
        )


@classmethod
def core(cls, num):
    """Get the :py:class:`.Routes` for the numbered core.

        Raises
        ------
        ValueError
            If the core number isn't in the range 0-17 inclusive.
        """
    if not 0 <= num <= 17:
        raise ValueError('Cores are numbered from 0 to 17')
    return cls(6 + num)


@classmethod
def from_filenames(cls, x_filename, y_filename, **kwargs):
    """Create geolocation from names of files with geolocation
        Parameters
        ----------
        x_filename : str
            name of file for X-dataset
        y_filename : str
            name of file for Y-dataset
        **kwargs : dict
            parameters for self._init_data()
        """
    self = cls.__new__(cls)
    self.x_vrt = None
    self.y_vrt = None
    self.data = {}
    self._init_data(x_filename, y_filename, **kwargs)
    return self


def number_of_digits(val, precision=1e-13):
    """returns the number of non-zero digits of a number, e.g. two for 1200 or three for 2.03.

    """
    raise NotImplementedError()


def _error_function(*args):
    """
    The default worker function. Should be replaced
    with the desired mapping function on the first
    call.

    """
    raise Exception(
        'Pool was sent tasks before being told what function to apply.')


@staticmethod
def p_can_id_slave(p):
    """can_id_slave : CAN_ID_SLAVE NUMERIC"""
    p[0] = p[2]


def get_execution_history(executionArn=None, maxResults=None, reverseOrder=
    None, nextToken=None):
    """
    Returns the history of the specified execution as a list of events. By default, the results are returned in ascending order of the timeStamp of the events. Use the reverseOrder parameter to get the latest events first. The results may be split into multiple pages. To retrieve subsequent pages, make the call again using the nextToken returned by the previous call.
    See also: AWS API Documentation

    :example: response = client.get_execution_history(
        executionArn='string',
        maxResults=123,
        reverseOrder=True|False,
        nextToken='string'
    )

    :type executionArn: string
    :param executionArn: [REQUIRED]
            The Amazon Resource Name (ARN) of the execution.

    :type maxResults: integer
    :param maxResults: The maximum number of results that will be returned per call. nextToken can be used to obtain further pages of results. The default is 100 and the maximum allowed page size is 1000.
            This is an upper limit only; the actual number of results returned per call may be fewer than the specified maximum.

    :type reverseOrder: boolean
    :param reverseOrder: Lists events in descending order of their timeStamp .

    :type nextToken: string
    :param nextToken: If a nextToken was returned by a previous call, there are more results available. To retrieve the next page of results, make the call again using the returned token in nextToken . Keep all other arguments unchanged.
            The configured maxResults determines how many results can be returned in a single call.

    :rtype: dict
    :return: {
        'events': [
            {
                'timestamp': datetime(2015, 1, 1),
                'type': 'ActivityFailed'|'ActivityScheduleFailed'|'ActivityScheduled'|'ActivityStarted'|'ActivitySucceeded'|'ActivityTimedOut'|'ChoiceStateEntered'|'ChoiceStateExited'|'ExecutionFailed'|'ExecutionStarted'|'ExecutionSucceeded'|'ExecutionAborted'|'ExecutionTimedOut'|'FailStateEntered'|'LambdaFunctionFailed'|'LambdaFunctionScheduleFailed'|'LambdaFunctionScheduled'|'LambdaFunctionStartFailed'|'LambdaFunctionStarted'|'LambdaFunctionSucceeded'|'LambdaFunctionTimedOut'|'SucceedStateEntered'|'SucceedStateExited'|'TaskStateEntered'|'TaskStateExited'|'PassStateEntered'|'PassStateExited'|'ParallelStateEntered'|'ParallelStateExited'|'WaitStateEntered'|'WaitStateExited',
                'id': 123,
                'previousEventId': 123,
                'activityFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'activityScheduleFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'activityScheduledEventDetails': {
                    'resource': 'string',
                    'input': 'string',
                    'timeoutInSeconds': 123,
                    'heartbeatInSeconds': 123
                },
                'activityStartedEventDetails': {
                    'workerName': 'string'
                },
                'activitySucceededEventDetails': {
                    'output': 'string'
                },
                'activityTimedOutEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'executionFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'executionStartedEventDetails': {
                    'input': 'string',
                    'roleArn': 'string'
                },
                'executionSucceededEventDetails': {
                    'output': 'string'
                },
                'executionAbortedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'executionTimedOutEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'lambdaFunctionFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'lambdaFunctionScheduleFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'lambdaFunctionScheduledEventDetails': {
                    'resource': 'string',
                    'input': 'string',
                    'timeoutInSeconds': 123
                },
                'lambdaFunctionStartFailedEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'lambdaFunctionSucceededEventDetails': {
                    'output': 'string'
                },
                'lambdaFunctionTimedOutEventDetails': {
                    'error': 'string',
                    'cause': 'string'
                },
                'stateEnteredEventDetails': {
                    'name': 'string',
                    'input': 'string'
                },
                'stateExitedEventDetails': {
                    'name': 'string',
                    'output': 'string'
                }
            },
        ],
        'nextToken': 'string'
    }

    """
    pass


def identity(x):
    """Identity Function."""
    return x


@classmethod
def func_from_hash(cls, hash):
    """Return the multihash `Func` for the hashlib-compatible `hash` object.

        If no `Func` is registered for the given hash, a `KeyError` is raised.

        >>> import hashlib
        >>> h = hashlib.sha256()
        >>> f = FuncReg.func_from_hash(h)
        >>> f is Func.sha2_256
        True
        """
    return cls._func_from_hash[hash.name]


def find_in_set(query, string_list):
    """Return the index (1-based!) of `query` in `string_list`.

    Analagous to the FIND_IN_SET function in MySQL.

    Examples
    --------
    >>> find_in_set(10, '1,3,5,10')
    4
    >>> find_in_set('40', ',,,20,,30,40')
    7
    >>> find_in_set(2, '1,3,5')
    0
    """
    try:
        return string_list.split(',').index(str(query)) + 1
    except ValueError:
        return 0


def realizeVolume(srcStream, setAbsoluteVelocity=False, useDynamicContext=
    True, useVelocity=True, useArticulations=True):
    """
    Given a Stream with one level of dynamics
    (e.g., a Part, or two Staffs that share Dynamics),
    destructively modify it to set all realized volume levels.
    These values will be stored in the Volume object as `cachedRealized` values.

    This is a top-down routine, as opposed to bottom-up values available with
    context searches on Volume. This thus offers a performance benefit.

    This is always done in place; for the option of non-in place processing,
    see Stream.realizeVolume().

    If setAbsoluteVelocity is True, the realized values will overwrite all
    existing velocity values, and the Volume objects velocityIsRelative
    parameters will be set to False.
    """
    bKeys = []
    boundaries = {}
    flatSrc = srcStream.flat
    dynamicsAvailable = False
    if flatSrc.iter.getElementsByClass('Dynamic'):
        dynamicsAvailable = True
    elif useDynamicContext is True:
        useDynamicContext = False
    if dynamicsAvailable:
        boundaries = flatSrc.extendDurationAndGetBoundaries('Dynamic')
        bKeys = list(boundaries.keys())
        bKeys.sort()
    lastRelevantKeyIndex = 0
    for e in flatSrc:
        if hasattr(e, 'volume') and 'NotRest' in e.classes:
            eStart = e.getOffsetBySite(flatSrc)
            if dynamicsAvailable and useDynamicContext is True:
                dm = False
                for k in range(lastRelevantKeyIndex, len(bKeys)):
                    start, end = bKeys[k]
                    if end > eStart >= start:
                        lastRelevantKeyIndex = k
                        dm = boundaries[bKeys[k]]
                        break
            else:
                dm = useDynamicContext
            val = e.volume.getRealized(useDynamicContext=dm, useVelocity=
                useVelocity, useArticulations=useArticulations)
            if setAbsoluteVelocity:
                e.volume.velocityIsRelative = False
                e.volume.velocityScalar = val


@classmethod
def parse(cls, raw_str, parser):
    """Factory for :class:`apacheconfig.ListNode` from a config string.

        Args:
            raw_str (str): Config string to parse.
            parser (:class:`apacheconfig.ApacheConfigParser`): parser object
                to use.
        Returns:
            :class:`apacheconfig.ListNode` containing data parsed from
            ``raw_str``.
        """
    raw = parser.parse(raw_str)
    return cls(raw, parser)


def generate_bio_assembly(data_api, struct_inflator):
    """Generate the bioassembly data.
    :param data_api the interface to the decoded data
    :param struct_inflator the interface to put the data into the client object"""
    bioassembly_count = 0
    for bioassembly in data_api.bio_assembly:
        bioassembly_count += 1
        for transform in bioassembly['transformList']:
            struct_inflator.set_bio_assembly_trans(bioassembly_count,
                transform['chainIndexList'], transform['matrix'])


def send_broadcast(command: str, toolkit=None):
    """
    发送广播，实际上是 adb shell am broadcast <command>

    :param command: 在 am broadcast 后的命令
    :param toolkit:
    :return:
    """
    return toolkit.adb.run(['shell', 'am', 'start', command.split(' ')])


def new():
    """Add New Pose Library to active Object

    """
    pass


def pump_string_file(bytes, file_handle, segment_size=None):
    """Write bytes to file_handle in many smaller writes.

    :param bytes: The string to write.
    :param file_handle: The file to write to.
    """
    if not segment_size:
        segment_size = 5242880
    offsets = range(0, len(bytes), segment_size)
    view = memoryview(bytes)
    write = file_handle.write
    for offset in offsets:
        write(view[offset:offset + segment_size])


@staticmethod
def findParentPath(item):
    """Provides the nearest parent path"""
    while item.path is None:
        item = item.parentItem
    return item.path


@classmethod
def expire_cache(cls):
    """Expire the results cache - needed for database upgrade code
           paths."""
    cls._dCache = {}


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

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

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


@staticmethod
def add_opts(parser):
    """Populate and return the parser with the options for this plugin.

        If the plugin does not need any options, it should return the same
        parser untouched.
        """
    return parser


def fn_winkler(weight_jaro, pre_matches, pre_scale):
    """
    Scale the standard Jaro metric by 'pre_scale' units per 'pre_matches'.

    Note the warning in the docstring of jaro_winkler() regarding the scale.
    """
    weight_jaro += pre_matches * pre_scale * (1.0 - weight_jaro)
    assert weight_jaro <= 1.0
    return weight_jaro


def prime_factor(obj):
    """get the primary factor on the `obj`, returns None if none."""
    f = getattr(obj, '_e_factors', None)
    if f:
        return f[0], getattr(obj, f[0], None)


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 abort():
    """**Abort the entire program execution**
    """
    print('Aborting program...')
    raise SystemExit


def validate_version_str(version_str: str):
    """
    Check the version string is of the form x.y.z.

    If the version string is not valid raise a ValueError.
    """
    is_str = isinstance(version_str, str)
    if not (is_str and len(version_str.split('.')) == 3):
        msg = f'version must be a string of the form x.y.z, not {version_str}'
        raise ValueError(msg)


def increment_dict_val(dict_obj, key, value, zero_value=0):
    """Increments the value mapped by the given key by the given val.
    If the key is missing from the dict, the given mapping is added.

    Parameters
    ----------
    dict_obj : dict
        The dict to increment a value in.
    key : object
        The key whose value is to be incremented.
    value : object
        The value to increment the existing mapping by.
    zero_value : object, optional
        The value added to the given value if no existing mapping is found.
        Set to 0 by default. Thus, this should be set to the corresponding
        identity element (with respect to addition) for non-numeric-valued
        dictionaries.

    Examples
    --------
    >>> dict_obj = {'a':2, 'b':1}
    >>> increment_dict_val(dict_obj, 'a', 4)
    >>> print(dict_obj['a'])
    6
    >>> increment_dict_val(dict_obj, 'd', 4)
    >>> print(dict_obj['d'])
    4
    """
    dict_obj[key] = dict_obj.get(key, zero_value) + value


def _get_best_indexes(logits, n_best_size):
    """Get the n-best logits from a list."""
    index_and_score = sorted(enumerate(logits), key=lambda x: x[1], reverse
        =True)
    best_indexes = []
    for i in range(len(index_and_score)):
        if i >= n_best_size:
            break
        best_indexes.append(index_and_score[i][0])
    return best_indexes


def trim_docstring(docstring):
    """Trim a docstring.  This should probably go into the inspect module."""
    lines = docstring.expandtabs().splitlines()
    from sys import maxint
    margin = maxint
    for line in lines[1:]:
        content = len(line.lstrip())
        if content:
            indent = len(line) - content
            margin = min(margin, indent)
    if lines:
        lines[0] = lines[0].lstrip()
    if margin < maxint:
        for i in range(1, len(lines)):
            lines[i] = lines[i][margin:]
    while lines and not lines[-1]:
        lines.pop()
    while lines and not lines[0]:
        lines.pop(0)
    return '\n'.join(lines)


def vertex_group_mirror(mirror_weights: bool=True, flip_group_names: bool=
    True, all_groups: bool=False, use_topology: bool=False):
    """Mirror vertex group, flip weights and/or names, editing only selected vertices, flipping when both sides are selected otherwise copy from unselected

    :param mirror_weights: Mirror Weights, Mirror weights
    :type mirror_weights: bool
    :param flip_group_names: Flip Group Names, Flip vertex group names
    :type flip_group_names: bool
    :param all_groups: All Groups, Mirror all vertex groups weights
    :type all_groups: bool
    :param use_topology: Topology Mirror, Use topology based mirroring (for when both sides of mesh have matching, unique topology)
    :type use_topology: bool
    """
    pass


@staticmethod
def split(examples, ratio=0.8):
    """
        Utility function that can be used within the parse() implementation of
        sub classes to split a list of example into two lists for training and
        testing.
        """
    split = int(ratio * len(examples))
    return examples[:split], examples[split:]


def _list_response(data):
    """
    If `data` is not a `list`, return a list with `data` as the only element.
    Otherwise, return `data`
    """
    if not isinstance(data, list):
        return [data]
    return data


def typed_masses_to_spans(typed_masses):
    """ Converts typed segmentations in the masses format to spans.

    The resulting spans are non-overlapping and in linear order.

    >>> list(typed_masses_to_spans([(1, 'A'), (1, 'B'), (1, 'C')]))
    [(0, 1, 'A'), (1, 1, 'B'), (2, 1, 'C')]
    >>> list(typed_masses_to_spans([(3, 'A'), (2, 'B'), (1, 'C')]))
    [(0, 3, 'A'), (3, 2, 'B'), (5, 1, 'C')]
    >>> list(typed_masses_to_spans([(1, 'A'), (2, 'B'), (3, 'C')]))
    [(0, 1, 'A'), (1, 2, 'B'), (3, 3, 'C')]
    """
    start = 0
    for length, cat in typed_masses:
        yield start, length, cat
        start += length


def _strxfrm(s):
    """ strxfrm(string) -> string.
        Returns a string that behaves for cmp locale-aware.
    """
    return s


@staticmethod
def help():
    """ Help information. """
    return """
        For information on the supported equation format use
            from sbmlutils import equation
            help(equation)
        """


def different_values_constraint(A, a, B, b):
    """A constraint saying two neighboring variables must differ in value."""
    return a != b


def multiply(x, y):
    """
    Multiplies the input by the second input
    :param x:
    :param y:
    :return: (x*y)

    >>> multiply(8, 7)
    56
    """
    return x * y


@classmethod
def enum(cls, enum):
    """Accepts any form of an enum and returns the enum"""
    for item in cls:
        if (enum is item or enum == item.name or enum == item.value or cls.
            title(enum) == item):
            return item
    raise ValueError('Value "{}" is not a valid {}'.format(enum, cls.__name__))


def keyframe_clear_button(all: bool=True):
    """Clear all keyframes on the currently active property

    :param all: All, Clear keyframes from all elements of the array
    :type all: bool
    """
    pass


def operator_defaults():
    """Set the active operator to its default values

    """
    pass


def get_type_name_value(obj):
    """
    Returns object type name from LLDB value.

    It returns type name with asterisk if object is a pointer.

    :param lldb.SBValue obj: LLDB value object.
    :return: Object type name from LLDB value.
    :rtype: str | None
    """
    return None if obj is None else obj.GetTypeName()


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

        :returns: this backend does not support items archive
        """
    return False


def dqm_urls():
    """Return list of DQM urls"""
    urls = ['https://cmsweb.cern.ch/dqm/dev',
        'https://cmsweb.cern.ch/dqm/offline',
        'https://cmsweb.cern.ch/dqm/relval',
        'https://cmsweb-testbed.cern.ch/dqm/dev',
        'https://cmsweb-testbed.cern.ch/dqm/offline',
        'https://cmsweb-testbed.cern.ch/dqm/relval']
    return urls


@classmethod
def get_binary_types(cls):
    """Get the list of all binary types"""
    return [cls.TINY_BLOB, cls.MEDIUM_BLOB, cls.LONG_BLOB, cls.BLOB]


def _wider_test_jpeg(data):
    """Test for a jpeg file following the UNIX file implementation which
    uses the magic bytes rather than just looking for the bytes that
    represent 'JFIF' or 'EXIF' at a fixed position.
    """
    if data[:2] == b'\xff\xd8':
        return 'jpeg'


def commit_message(consumer):
    """
    A convenience method to ensure messages are committed/handled synchronously.
    :param consumer: A confluent-kafka Consumer object
    :type consumer: confluent_kafka.Consumer or confluent_kafka.avro.AvroConsumer
    """
    consumer.commit(asynchronous=False)


def precomp(point):
    """
    Precomputation placeholder
    :param point:
    :return:
    """
    return point


@staticmethod
def get_document_field(instance):
    """
        Returns which field the search index has marked as it's
        `document=True` field.
        """
    for name, field in instance.searchindex.fields.items():
        if field.document is True:
            return name


def temp_f(c):
    """Convert temperature from Celsius to Fahrenheit"""
    if c is None:
        return None
    return c * 9.0 / 5.0 + 32.0


def pendantNodes(G):
    """
    Given a graph G, finds it's pendant nodes and
    the edge connecting them to another node.

    INPUT
    G: A networkx graph

    OUTPUT
    pendant: A list of the format [[vertex, edge] ... ]
    """
    nodes = G.nodes()
    pendant = []
    for node in nodes:
        if G.degree(node) == 1:
            pendant.append([node, G.edges(node)[0]])
    return pendant


def _check_hdf5_path(h5_file, path):
    """Check that an HDF5 path exists in a file."""
    if path not in h5_file:
        raise ValueError("{path} doesn't exist.".format(path=path))


def save_text_to_file(content: str, path: str):
    """ Saves text to file """
    with open(path, mode='w') as text_file:
        text_file.write(content)


def keys():
    """Return all components id contained in the collection.
        """


def enable_proxies(proxy_25: bool=False, proxy_50: bool=False, proxy_75:
    bool=False, proxy_100: bool=False, overwrite: bool=False):
    """Enable selected proxies on all selected Movie, Image and Meta strips

    :param proxy_25: 25%
    :type proxy_25: bool
    :param proxy_50: 50%
    :type proxy_50: bool
    :param proxy_75: 75%
    :type proxy_75: bool
    :param proxy_100: 100%
    :type proxy_100: bool
    :param overwrite: Overwrite
    :type overwrite: bool
    """
    pass


def merge_dictionary(target, new_items):
    """ Merges a dictionary into the master set,
    warning when a duplicate name is detected. Keys from new_items that
    are already present in target will generate warnings without modifying
    target.

    And yes, I know there are builtin methods to merge dictionaries (update),
    but I wanted finer control over handling for existing keys.

    Args:
        target (dictionary): The destination dictionary.
        new_items (dictionary): The dictionary of new items to merge.

    Returns:
        dict: target, with all unique items merged from new items.
    """
    for name, data in new_items.items():
        if name in target:
            pass
        else:
            target[name] = data
    return target


def _unquote(quote_char, row):
    """Remove quote characters from all value in row if present."""
    for i in range(0, len(row)):
        if row[i] and row[i][0] == quote_char and row[i][-1] == quote_char:
            row[i] = row[i][1:-1]


def names(zelf, *args, **kwargs):
    """ skip the unwanted keys e.g those that start with a "_". """
    for key in zelf.keys():
        k = str(key)
        if k.startswith('_'):
            continue
        yield key


def f_to_c(f=0):
    """ Convert fahrenheight to celcius """
    return round((f - 32.0) / 1.8, 2)


@classmethod
def is_transient(cls):
    """ Return whether the model is transient.

        See :class:`TransientModel`.

        """
    return cls._transient


def project_opened(project):
    """This function is called after opening the project"""


def _qname_matches(tag, namespace, qname):
    """Logic determines if a QName matches the desired local tag and namespace.

    This is used in XmlElement.get_elements and XmlElement.get_attributes to
    find matches in the element's members (among all expected-and-unexpected
    elements-and-attributes).

    Args:
      expected_tag: string
      expected_namespace: string
      qname: string in the form '{xml_namespace}localtag' or 'tag' if there is
             no namespace.

    Returns:
      boolean True if the member's tag and namespace fit the expected tag and
      namespace.
    """
    if qname is None:
        member_tag = None
        member_namespace = None
    elif qname.startswith('{'):
        member_namespace = qname[1:qname.index('}')]
        member_tag = qname[qname.index('}') + 1:]
    else:
        member_namespace = None
        member_tag = qname
    return (tag is None and namespace is None or namespace is None and
        member_tag == tag or tag is None and member_namespace == namespace or
        tag is None and namespace == '' and member_namespace is None or tag ==
        member_tag and namespace == member_namespace or tag == member_tag and
        namespace == '' and member_namespace is None)


@staticmethod
def add_error_item_to_testcase(stderr_type, tc_key, testcases, lines):
    """
        Update a test case in the base report with an assertion or error
        :param stderr_type: error or assertion
        :param tc_key: key into base report dict
        :param testcases: base report
        :param lines: captured stacktrace to add
        :return:
        """
    assert tc_key in testcases
    if stderr_type == 'error':
        testcases[tc_key].add_error(lines)
    else:
        testcases[tc_key].add_assertion(lines)


def lstrip_wildcard(string, wildcard='%'):
    """Strip starting wildcard from string"""
    if not string:
        return string
    return string.lstrip(wildcard)


@classmethod
def reset_counters(cls):
    """
        reset the class related counters

        """
    for field in cls.__fields__:
        if field.should_auto_increment:
            cls._reset_counter(*field.get_counter({}))


def trace_replicas_for_ensemble(ensemble, steps):
    """
    List of which replica a given ensemble held at each MC step.

    Parameters
    ----------
    ensemble : paths.Ensemble
        selected ensemble
    steps : iterable of :class:`.MCStep`
        MC steps to analyze (nonsense if not contiguous

    Returns
    -------
    list
        list of replica IDs
    """
    trace = []
    for step in steps:
        sset = step.active
        trace.append(sset[ensemble].replica)
    return trace


def calc_std_error_abc(empirical_influence):
    """
    Calculates the standard error of the MLE estimates for use in calculating
    the approximate bootstrap confidence (ABC) intervals.

    Parameters
    ----------
    empirical_influence : 2D ndarray.
        Should have one row for each observation. Should have one column for
        each parameter in the parameter vector being estimated. Elements should
        denote the empirical influence of the associated observation on the
        associated parameter.

    Returns
    -------
    std_error : 1D ndarray.
        Contains the standard error of the MLE estimates for use in the ABC
        confidence intervals.

    References
    ----------
    Efron, Bradley, and Robert J. Tibshirani. An Introduction to the Bootstrap.
        CRC press, 1994. Section 22.6, Equation 22.31.
    """
    num_obs = empirical_influence.shape[0]
    std_error = (empirical_influence ** 2).sum(axis=0) ** 0.5 / num_obs
    return std_error


def sortedbytype(iterable):
    """Sorts an iterable by types first, then value."""
    items = {}
    for x in iterable:
        t = type(x).__name__
        if t not in items:
            items[t] = []
        items[t].append(x)
    rtn = []
    for t in sorted(items.keys()):
        rtn.extend(sorted(items[t]))
    return rtn


def dict_merge(*dicts):
    """
    Merge all provided dicts into 1 dict.
    """
    merged = {}
    for d in dicts:
        if not isinstance(d, dict):
            raise ValueError('Value should be of dict type')
        else:
            merged.update(d)
    return merged


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 face_flip(faces):
    """Flip the faces direction.

    :param face: Face to flip.
    :type face: 'bmesh.types.BMFace'
    """
    pass


def celcius_2_kelvin(x):
    """Convert celcius to kelvin."""
    return x + 273.15


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

        :param PaperDocChangeSharingPolicyDetails val:
        :rtype: EventDetails
        """
    return cls('paper_doc_change_sharing_policy_details', val)


def rsplit(text, sep=None, maxsplit=-1):
    """
    Creates a tuple of the words in ``text``, using ``sep`` as the delimiter string.

    If ``maxsplit`` is given, at most maxsplit splits are done (thus, the tuple will have at
    most maxsplit+1 elements). If ``maxsplit`` is not specified or -1, then there is no
    limit on the number of splits (all possible splits are made).

    If ``sep`` is given, consecutive delimiters are not grouped together and are deemed to
    delimit empty strings (for example, ``rsplit('1,,2',',')`` returns ``('1', '', '2')``).
    The ``sep`` argument may consist of multiple characters (for example,
    ``rsplit('1<>2<>3','<>')`` returns ``('1', '2', '3')``). Splitting an empty string
    with a specified separator returns ``('',)``.

    This function only differs from :func:`split` if ``maxsplit`` is given and is less than
    the possible number of splits.  In that case, the splits are favored to the right,
    and so the remainder is to the left.

    :param text: The string to split
    :type text:  ``str``

    :param sep: The separator to split at
    :type sep:  ``str``

    :param maxsplit: The maximum number of splits to perform
    :type maxsplit:  ``int``

    :return: A list of the words in ``text``, using ``sep`` as the delimiter string.
    :rtype:  ``str``
    """
    assert isinstance(text, str), '%s is not a string' % text
    return tuple(text.rsplit(sep, maxsplit))


def open_for_pre_pack():
    """
        Open a connection to be used for the pre-pack phase.

        This connection will make many different queries; each one
        must be consistent unto itself, but they do not all have to be
        consistent with each other. This is because the *first* query
        this object makes establishes a base state, and we will
        manually discard later changes seen in future queries.

        It will read from the state tables and write to the pack tables;
        it will not write to the state tables, nor hold the commit lock.
        It may hold share locks on state rows temporarily.

        This connection may be open for a long period of time, and
        will be committed as appropriate between queries. It is
        acceptable for this connection to be in autocommit mode, if
        required, but it is preferred for it not to be. This should be
        opened in ``READ COMMITTED`` isolation level.

        :return: ``(conn, cursor)``
        """


def check_ipython():
    """A boolean function to check if IPython
    is available"""
    try:
        import IPython
    except ImportError:
        return False
    return True


def __call__():
    """Returns allowed types for categorizing."""


def sort(system):
    """Sort particles by species id."""
    system.particle = sorted(system.particle, key=lambda a: a.species)
    return system


def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.
    If no true value is found, returns *default*
    http://docs.python.org/3.4/library/itertools.html#itertools-recipes
    """
    return next(filter(pred, iterable), default)


def info():
    """
tijd_en_datum_nu(value) = command to retutn or print

tijd_zone() = returns your time zone
times_and_days_pam(): returns the date and time of gmt and local
times_and_days() = returns date and time  of gmt and local in 0 to 24 not in pm or am
times_pam() = returns the time gmt and local in pm or am
times() = returns the time gmt and local not in pm or am
days() = returns the day in gmt and in local
"""


@classmethod
def generateLabelName(cls, index):
    """Generate a label name string.
		The name does not include the final ':' character.
		"""
    maxIndex = 26 ** 4 - 1
    if index < 0 or index > maxIndex:
        raise ValueError('Label index %d out of range 0 - %d.' % (index,
            maxIndex))
    labelChars = [None] * 4
    for i in range(3, -1, -1):
        labelChars[i] = chr(ord('A') + index % 26)
        index //= 26
    return ''.join(labelChars)


def flatten(x):
    """Flatten function
    Usage:
        out = flatten(x)
    """
    return x.contiguous().view(x.size(0), -1)


@classmethod
def getFrontmostApp(cls):
    """Get the current frontmost application.

        Raise a ValueError exception if no GUI applications are found.
        """
    return cls.frontmost()


@classmethod
def activation_func_names(cls):
    """Get list of internal activation function names"""
    return cls._internal_activation_funcs.keys()


@classmethod
def get_radius(cls, atom):
    """Returns atomic radius for a given element"""
    atnum = cls.get_atnum(atom)
    return float(cls.ptable[atom.atnum][2])


def check_infos(data, infos, required_infos=None):
    """Implement infos verification logic."""
    if required_infos is False or required_infos is None:
        return data
    if required_infos is True:
        return data, infos
    if not isinstance(required_infos, (tuple, list)):
        raise ValueError('required_infos must be tuple or list')
    for required, actual in zip(required_infos, infos):
        raise ValueError(
            f"actual info {actual} doesn't match required info {required}")
    return data


def trading_mode_parent_inspection(element, parent):
    """
    Check if the trading class has the specified parent
    :param element: the element to check
    :param parent: the expected parent
    :return: the check result
    """
    return hasattr(element, 'get_parent_trading_mode_classes'
        ) and element.get_parent_trading_mode_classes(parent)


def sigmoid(data=None, name=None, attr=None, out=None, **kwargs):
    """Computes sigmoid of x element-wise.

    .. math::
       y = 1 / (1 + exp(-x))

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

    Defined in src/operator/tensor/elemwise_unary_op_basic.cc:L119

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

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

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


@staticmethod
def write_file_raw(file_name, data):
    """
        Salva um arquivo de cache, conforme os parâmetros informados, sem alterar o seu formato
        :param file_name: Path completo(caminho, nome e extensão) onde o arquivo será salvo
        :param data: str
        :return: bool
        """
    handle = open(file_name, 'w+')
    handle.write(data)
    handle.close()
    return True


def model_from_config(config, custom_objects=None):
    """Instantiates a Keras model from its config.

    # Arguments
        config: Configuration dictionary.
        custom_objects: Optional dictionary mapping names
            (strings) to custom classes or functions to be
            considered during deserialization.

    # Returns
        A Keras model instance (uncompiled).

    # Raises
        TypeError: if `config` is not a dictionary.
    """
    if isinstance(config, list):
        raise TypeError(
            '`model_from_config` expects a dictionary, not a list. Maybe you meant to use `Sequential.from_config(config)`?'
            )
    from ..layers import deserialize
    return deserialize(config, custom_objects=custom_objects)


def text_add(radius: float=1.0, view_align: bool=False, enter_editmode:
    bool=False, location: float=(0.0, 0.0, 0.0), rotation: float=(0.0, 0.0,
    0.0), layers: bool=(False, False, False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False)):
    """Add a text object to the scene

    :param radius: Radius
    :type radius: float
    :param view_align: Align to View, Align the new object to the view
    :type view_align: bool
    :param enter_editmode: Enter Editmode, Enter editmode when adding this object
    :type enter_editmode: bool
    :param location: Location, Location for the newly added object
    :type location: float
    :param rotation: Rotation, Rotation for the newly added object
    :type rotation: float
    :param layers: Layer
    :type layers: bool
    """
    pass


@classmethod
def add(cls, pid, connection):
    """Add a new connection and session to a pool.

        :param str pid: The pool id
        :type connection: psycopg2.extensions.connection
        :param connection: The connection to add to the pool

        """
    with cls._lock:
        cls._ensure_pool_exists(pid)
        cls._pools[pid].add(connection)


def to_futurenow_level(level):
    """Convert the given Home Assistant light level (0-255) to FutureNow (0-100)."""
    return int(level * 100 / 255)


def interval_set_to_id_list(itvs):
    """ Convert an interval set to a list of ID (int)"""
    ids = []
    for itv in itvs:
        b, e = itv
        ids.extend(range(b, e + 1))
    return ids


def rm_covered(object, pos_df, neg_df):
    """ Return pos and neg dfs of examples that are not covered by object """
    return pos_df.drop(object.covers(pos_df).index, axis=0, inplace=False
        ), neg_df.drop(object.covers(neg_df).index, axis=0, inplace=False)


def maglimits(inst, wfs, site, iq, cc, sb, verbose=False):
    """
    Magnitude correction for conditions

    Parameters
        inst:       Instrument ['GMOS', 'F2']
        wfs:        Wavefront sensor ['OIWFS', 'PWFS1', 'PWFS2']
        site:       Gemini site ['N', 'S', 'mko', 'cpo']
        iq:         Image quality constraint ['20', '70', '85', 'Any']
        cc:         Cloud cover constraint [0.0, -0.3, -1.0, -3.0]
        sb:         Sky brightness constraint ['20', '50', '80', 'Any']
        verbose     Verbose output?

    Return
        magbright
        mangmax
    """
    magbright = 9999.0
    magfaint = 9999.0
    oifaint = {'GMOS-N': 16.95, 'GMOS-S': 15.65, 'F2': 16.15}
    oibright = {'GMOS-N': 6.0, 'GMOS-S': 6.0, 'F2': 6.0}
    p1faint = {'N': 15.65, 'S': 14.15}
    p1bright = {'N': 7.0, 'S': 7.0}
    p2faint = {'N': 15.65, 'S': 15.65}
    p2bright = {'N': 7.0, 'S': 7.0}
    dmag = 0.0
    dmcc = [0.0, -0.3, -1.0, -3.0]
    try:
        ii = ['50', '70', '80', 'Any'].index(cc)
    except Exception:
        if verbose:
            print("cc must be one of '50','70','80','Any'")
        return magbright, magfaint
    dmag += dmcc[ii]
    dmiq = [0.25, 0.0, -0.25, -1.25]
    try:
        ii = ['20', '70', '85', 'Any'].index(iq)
    except Exception:
        if verbose:
            print("iq must be one of '20','70','85','Any'")
        return magbright, magfaint
    dmag += dmiq[ii]
    dmsb = [0.1, 0.0, -0.1, -0.2]
    try:
        ii = ['20', '50', '80', 'Any'].index(sb)
    except Exception:
        if verbose:
            print("sb must be one of '20','50','80','Any'")
        return magbright, magfaint
    dmag += dmsb[ii]
    if verbose:
        print('Dmag = ', dmag)
    if wfs == 'OIWFS':
        try:
            magbright = oibright[inst] + dmag
            magfaint = oifaint[inst] + dmag
        except Exception:
            if verbose:
                print('Only GMOS-N, GMOS-S, and F2 have supported OIs.')
    elif wfs == 'PWFS1':
        magbright = p1bright[site] + dmag
        magfaint = p1faint[site] + dmag
    elif wfs == 'PWFS2':
        magbright = p2bright[site] + dmag
        magfaint = p2faint[site] + dmag
    return magbright, magfaint


def get_iam_objects(iam_client_function, object_key, f_args=dict()):
    """
    users = get_iam_objects(iam_client.list_users, 'Users')
    """
    iam_objects = []
    response = iam_client_function(**f_args)
    iam_objects += response[object_key]
    if 'IsTruncated' in response:
        while response['IsTruncated']:
            response = iam_client_function(Marker=response['Marker'], **f_args)
            iam_objects += response[object_key]
    return iam_objects


def p_testlist_comp_star_1(p):
    """testlist_comp_star : COMMA test"""
    p[0] = [p[2]]


def is_null_vector(v):
    """
    Calculate the scalar product of two vectors
    """
    return v == (0, 0)


def first_true(iterable, predicate=None, default=None):
    """
    Returns first value for which predicate(item) is true

    If no value is found, returns default.
    """
    return next(filter(predicate, iterable), default)


@staticmethod
def get_available_name(name):
    """Return the name as-is; in CAS, given names are ignored anyway."""
    return name


def get(isamAppliance, uuid, check_mode=False, force=False):
    """
    Get a specific snmp object
    """
    return isamAppliance.invoke_get('Get a specific snmp object',
        '/core/rsp_snmp_objs/{0}'.format(uuid))


def __iter__():
    """Returns an iterator on content in the current batch view.
        """


@staticmethod
def interfaces_roles_change_and_tree_was_active_and_transitions_to_unsure_and_best_upstream_neighbor_is_null(
    interface: 'TreeInterfaceUpstream'):
    """
        Interfaces roles change (NonRoot->Root) AND
        Tree transitions from Active to Unsure state AND
        BestUpstreamNeighbor is null
        """
    interface.logger.debug(
        'interfaces_roles_change_and_tree_was_active_and_transitions_to_unsure_and_best_upstream_neighbor_is_null'
        )
    interface.send_i_am_no_longer_upstream()


@classmethod
def get_namespace(cls, shorthand: str) ->str:
    """
        Get the namespace for the given shorthand.

        :param shorthand: The shorthand, e.g. 'xsd'
        :return: The namespace, e.g. 'http://www.w3.org/2001/XMLSchema#'
        """
    return cls._namespaces[shorthand]


@classmethod
def expireAll(sqlmeta, connection=None):
    """
        Expire all instances of this class.
        """
    soClass = sqlmeta.soClass
    connection = connection or soClass._connection
    cache_set = connection.cache
    cache_set.weakrefAll(soClass)
    for item in cache_set.getAll(soClass):
        item.expire()


def mapfio(ol, **kwargs):
    """
        #mapfio           v不作为map_func参数                 NOT take value as a param for map_func
        #map_func         diff_func(index,*diff_args)
    """
    diff_funcs_arr = kwargs['map_funcs']
    diff_args_arr = kwargs['map_func_args_array']
    lngth = ol.__len__()
    rslt = []
    for i in range(0, lngth):
        index = i
        value = ol[i]
        func = diff_funcs_arr[i]
        args = diff_args_arr[i]
        ele = func(index, *args)
        rslt.append(ele)
    return rslt


def Probability(o):
    """Computes the probability corresponding to given odds.

    Example: o=2 means 2:1 odds in favor, or 2/3 probability

    o: float odds, strictly positive

    Returns: float probability
    """
    return o / (o + 1)


def name_from_path(path):
    """
    Gets the name of a key from its path
    """
    path = path.replace('/', '\\')
    if path[-1] == '\\':
        path = path[:-1]
    return path.split('\\')[-1]


def calculate_cold_start_speeds_delta(cold_start_speed_model, on_engine,
    engine_coolant_temperatures, engine_speeds_out_hot, idle_engine_speed):
    """
    Calculates the engine speed delta and phases due to the cold start [RPM, -].

    :param cold_start_speed_model:
        Cold start speed model.
    :type cold_start_speed_model: ColdStartModel

    :param on_engine:
        If the engine is on [-].
    :type on_engine: numpy.array

    :param engine_coolant_temperatures:
        Engine coolant temperature vector [°C].
    :type engine_coolant_temperatures: numpy.array

    :param engine_speeds_out_hot:
        Engine speed at hot condition [RPM].
    :type engine_speeds_out_hot: numpy.array

    :param idle_engine_speed:
        Engine speed idle median and std [RPM].
    :type idle_engine_speed: (float, float)

    :return:
        Engine speed delta due to the cold start and its phases [RPM, -].
    :rtype: numpy.array, numpy.array
    """
    delta = cold_start_speed_model(idle_engine_speed, on_engine,
        engine_coolant_temperatures, engine_speeds_out_hot)
    return delta


def filter_stream(req, method, filename, stream, data):
    """Return a filtered Genshi event stream, or the original unfiltered
        stream if no match.

        `req` is the current request object, `method` is the Genshi render
        method (xml, xhtml or text), `filename` is the filename of the template
        to be rendered, `stream` is the event stream and `data` is the data for
        the current template.

        See the Genshi_ documentation for more information.

        .. _Genshi: http://genshi.edgewall.org/wiki/Documentation/filters.html
        """


def restore(node):
    """ Restore node value to original source text snippet.
        ~ Seems, stupid ;-), but in the meantime
          pattern has been matched: format is OK.
    """
    node.value = node.snippet


def insert_target_children(tree, xpath, namespaces, children, insertbefore,
    insertafter):
    """
    Insert the given children before or after the given xpath. If insertbefore is True, it is inserted before the
    first xpath hit, with insertafter, it is inserted after the last xpath hit.
    """
    insert_target = tree.xpath(xpath, namespaces=namespaces)
    loc_index = 0 if insertbefore else -1
    index_in_parent = insert_target[loc_index].getparent().index(insert_target
        [loc_index])
    parent = insert_target[0].getparent()
    if insertafter:
        index_in_parent += 1
    for child in children:
        parent.insert(index_in_parent, child)
        index_in_parent += 1


def naive_covariance(data1, data2):
    """Fast but prone to catastrophic cancellaion when
    E[XY] ~ E[X]E[Y] i.e. the numbers are small and
    not negligible to the computer precision limit"""
    n = len(data1)
    sum12 = 0
    sum1 = sum(data1)
    sum2 = sum(data2)
    for i1, i2 in zip(data1, data2):
        sum12 += i1 * i2
    covariance = (sum12 - sum1 * sum2 / n) / (n - 1)
    return covariance


def __sanitize_items_in(df, sanitize):
    """Sanitize the dataframe values if it has EOL or space in it"""
    for i, row in df.iterrows():
        for key, value in row.iteritems():
            if type(value) != str:
                continue
            if '\n' in value or ' ' in value:
                df.at[i, key] = sanitize(value)


def add_all(tap_stream_id):
    """
    Adds all to the generic term e.g. groups_all for groups
    """
    return tap_stream_id.split('-')[0] + '_all'


def bram():
    """Stub method, which returns block RAM (kilobytes)"""
    return 630000


def parse_bool(x):
    """
    Parse boolean options
    """
    if x.lower() == 'true':
        return True
    elif x.lower() == 'false':
        return False
    else:
        raise ValueError('Valid options: True, False.')


def extract_entities_wih_custom_model(custom_nlp_text):
    """
    Helper function to extract different entities with custom
    trained model using SpaCy's NER

    :param custom_nlp_text: object of `spacy.tokens.doc.Doc`
    :return: dictionary of entities
    """
    entities = {}
    for ent in custom_nlp_text.ents:
        if ent.label_ not in entities.keys():
            entities[ent.label_] = [ent.text]
        else:
            entities[ent.label_].append(ent.text)
    for key in entities.keys():
        entities[key] = list(set(entities[key]))
    return entities


def ordenado(seq, chave=None):
    """
    Retorna uma cópia da sequência fornecida com os elementos ordenados.

    Examples
    --------

    >>> sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]
    """
    return sorted(seq, key=chave)


def _loop_once():
    """Run the main loop once
    """
    pass


@staticmethod
def _get_number(expr):
    """Extracts numbers (integers and floats) of arbitrary length from the overall string representation."""
    for idx, digit in enumerate(expr):
        if not digit.isnumeric() and digit is not '.':
            if digit.isalpha():
                raise ValueError('invalid expression')
            return idx, expr[:idx]
    return expr


def rendersize():
    """Set render size and aspect from active sequence

    """
    pass


def count():
    """Returns a collection with a single value which is the integer count of
        the number of items in the input collection.
        Returns 0 when the input collection is empty."""


def show_debug_toolbar(request):
    """Custom function to determine whether to show the debug toolbar."""
    from django.conf import settings
    if request.is_ajax():
        return False
    return bool(settings.DEBUG and settings.DEBUG_TOOLBAR)


def read_uic3tag(fh, byteorder, dtype, plane_count):
    """Read MetaMorph STK UIC3Tag from file and return as dictionary."""
    assert dtype == '2I' and byteorder == '<'
    values = fh.read_array('<u4', 2 * plane_count).reshape(plane_count, 2)
    return {'wavelengths': values[:, (0)] / values[:, (1)]}


def _fill_mi_header(row, control_row):
    """Forward fill blank entries in row but only inside the same parent index.

    Used for creating headers in Multiindex.
    Parameters
    ----------
    row : list
        List of items in a single row.
    control_row : list of bool
        Helps to determine if particular column is in same parent index as the
        previous value. Used to stop propagation of empty cells between
        different indexes.

    Returns
    -------
    Returns changed row and control_row
    """
    last = row[0]
    for i in range(1, len(row)):
        if not control_row[i]:
            last = row[i]
        if row[i] == '' or row[i] is None:
            row[i] = last
        else:
            control_row[i] = False
            last = row[i]
    return row, control_row


def read_uic2tag(fh, byteorder, dtype, planecount, offsetsize):
    """Read MetaMorph STK UIC2Tag from file and return as dict."""
    assert dtype == '2I' and byteorder == '<'
    values = fh.read_array('<u4', 6 * planecount).reshape(planecount, 6)
    return {'ZDistance': values[:, (0)] / values[:, (1)], 'DateCreated':
        values[:, (2)], 'TimeCreated': values[:, (3)], 'DateModified':
        values[:, (4)], 'TimeModified': values[:, (5)]}


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 get_in(dct, keys):
    """Gets the value in dct at the nested path indicated by keys"""
    for key in keys:
        if not isinstance(dct, dict):
            return None
        if key in dct:
            dct = dct[key]
        else:
            return None
    return dct


def add_libav_on_win(ext):
    """ no pkg-config on windows, simply assume these libs are available """
    ext.libraries += ['avformat', 'avutil', 'avcodec', 'swresample']
    for define_macro in ['HAVE_LIBAV', 'HAVE_SWRESAMPLE']:
        ext.define_macros += [(define_macro, 1)]


@staticmethod
def get_outlet_temperature(T_pinch, T_limit, iscooling):
    """
        Return outlet temperature of the utility in a counter current heat exchanger

        Parameters
        ----------
        T_pinch : float
                  Pinch temperature of utility stream [K].
        iscooling : bool
                  True if utility is loosing energy.

        """
    if iscooling:
        return T_limit if T_limit and T_limit < T_pinch else T_pinch
    else:
        return T_limit if T_limit and T_limit > T_pinch else T_pinch


def CO2LOGSERVER_ACCEPT_NEW_COLUMN(col):
    """
    This function is called with the name of a received nonexistant column name
    and should return a boolean value indicating whether this column should be
    created.  By default, all new columns are accepted.
    """
    return True


def axis_labels_from_ctype(ctype, unit):
    """
    Returns axis labels for the given coordinate type and unit.

    Parameters
    ----------
    ctype: `str`
        Coordinate type.
    unit: `str`
        Required unit.

    Returns
    -------
    `str`
        "Axis Label [Unit]"
    """
    ctype_short = ctype[:4]
    labels = {'HGLN': f'Heliographic Longitude [{unit}]', 'CRLN':
        f'Carrington Longitude [{unit}]', 'HPLN':
        f'Helioprojective Longitude (Solar-X) [{unit}]', 'SOLX':
        f'Heliocentric X [{unit}]', 'HGLT': f'Latitude [{unit}]', 'CRLT':
        f'Latitude [{unit}]', 'HPLT':
        f'Helioprojective Latitude (Solar-Y) [{unit}]', 'SOLY':
        f'Heliocentric Y [{unit}]'}
    return labels.get(ctype_short, f'{ctype} [{unit}]')


def marker_jump(next: bool=True):
    """Jump to previous/next marker

    :param next: Next Marker
    :type next: bool
    """
    pass


@staticmethod
def get_ui_message(list_of_equation_names):
    """
        The message returned by this method should be displayed if
        the equation with the given name couldn't be evaluated in all points.
        """
    if list_of_equation_names:
        return 'Could not evaluate the ' + ', '.join(list_of_equation_names
            ) + ' equation(s) in all the points. Some of the values were changed.'
    else:
        return ''


def fetch_courses(soups):
    """Fetches each course inside a given page."""
    courses = []
    for soup in soups:
        course = soup.find_all('div', class_='item-frame')
        courses.append(course)
    return courses


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


def prep_curve(x_y_tuples, curve_type):
    """
    Prepares and returns a list of x_y tuples by prepending or appending the appropriate endpoints depending on the curve type.

    If <curve_type> is 'ROC', (0,1) and (1,0) points will be added to extend the curve to the corners.

    If <curve_type> is 'PR', (0,y_0) and (x_n,0) points will be added, where y_0 is the first y-value (precision)
    and x_n is the last x-value (recall). This has the effect of terminating the ends of the curve with line
    segments directly to the axes.

    If <curve_type> is 'plain', no points will be added and only the area under the known points will be calculated (no extrapolation).
    """
    sorted_tuples = sorted(x_y_tuples, key=lambda x: (x[0], -x[1]))
    if curve_type == 'PR':
        if sorted_tuples[0][0] != 0:
            sorted_tuples = [(0, sorted_tuples[0][1])] + sorted_tuples
        if sorted_tuples[-1][1] != 0:
            sorted_tuples += [(sorted_tuples[-1][0], 0)]
    elif curve_type == 'ROC':
        if sorted_tuples[0] != (1, 0):
            sorted_tuples = [(1, 0)] + sorted_tuples
        if sorted_tuples[-1] != (0, 1):
            sorted_tuples += [(0, 1)]
    elif curve_type == 'plain':
        pass
    else:
        raise ValueError('Invalid value for curve_type. Got: {}'.format(
            curve_type))
    return sorted_tuples


def read_comment_section(filename):
    """Pull out the comments section from the top of a chain file"""
    lines = []
    for line in open(filename):
        if not line.startswith('#'):
            break
        lines.append(line)
    return lines


@staticmethod
def wrapnested(data, tmpl, sep):
    """wrap nested data by appropriate type"""
    return data


def min2(a, b):
    """ returns the minimum element between given a and b;
        note: this is slightly more efficient than using standard Python min function
    """
    if a <= b:
        return a
    return b


def set_name_yend_sp(name_y):
    """Set the spatial lag name in regression; return generic name if user
    provides no explicit name."

    Parameters
    ----------
    name_y      : string
                  User provided dependent variable name.

    Returns
    -------
    name_yend_sp : string

    """
    return 'W_' + name_y


def getColorSettings(key='HE'):
    """Returns color parameters for false coloring data.

    Parameters
    ----------

    key : str
        Defaults to 'HE'. Which RGB settings to use, when 'HE' will use
        RGB settings for virtual H&E staining.

        'IHC' will return color settings for virtual IHC/DAB staining.

    Returns
    -------
    color_dict : dict
        Dictionary with keys ('nuclei', 'cyto') or ('nuclei', 'anti'),
        which correspond to lists containing empirically derived
        RGB constants for false coloring.

    """
    color_dict = {'HE': {'nuclei': [0.17, 0.27, 0.105], 'cyto': [0.05, 1.0,
        0.54]}, 'IHC': {'nuclei': [0.65, 0.45, 0.15], 'anti': [0.4, 0.7, 0.9]}}
    return color_dict[key]


@staticmethod
def is_dn_vpc(dn):
    """
        Check if the DN is a VPC

        :param dn: String containing the DN
        :return: True if the the DN is a VPC. False otherwise.
        """
    if '/protpaths' in dn:
        return True
    return False


def getName():
    """Gives the name of this result field.
        """


def find_direction(start, end):
    """
    Find direction from start to end
    """
    if start[0] == end[0]:
        if start[1] < end[1]:
            return 5
        else:
            return 1
    elif start[1] == end[1]:
        if start[0] < end[0]:
            return 3
        else:
            return 7
    elif start[0] < end[0]:
        if start[1] < end[1]:
            return 4
        else:
            return 2
    elif start[0] > end[0]:
        if start[1] < end[1]:
            return 6
        else:
            return 8


def func_args(func) ->bool:
    """Return the arguments of `func`."""
    code = func.__code__
    return code.co_varnames[:code.co_argcount]


def update_config_data(msg, cfg):
    """
    Updates the profile's config entry with values set in each attr by the
    user.  This will overwrite existing values.

    Args:
        :msg: (Message class) an instance of a message class.
        :cfg: (jsonconfig.Config) config instance.
    """
    for attr in msg:
        if attr in cfg.data[msg.profile] and attr is not 'auth':
            cfg.data[msg.profile][attr] = getattr(msg, attr)


def process_master_records(data_file, pdb_file):
    """Takes a :py:class:`.PdbDataFile` and updates it based on the
    MASTER records in the provided :py:class:`.PdbFile`

    :param PdbDataFile data_file: the Data File to update.
    :param PdbFile pdb_file: The source Pdb File"""
    master = pdb_file.get_record_by_name('MASTER')
    data_file._master = {'remark_num': master[10:15], 'het_num': master[20:
        25], 'helix_num': master[25:30], 'sheet_num': master[30:35],
        'site_num': master[40:45], 'crystal_num': master[45:50],
        'coordinate_num': master[50:55], 'ter_num': master[55:60],
        'conect_num': master[60:65], 'seqres_num': master[65:70]
        } if master else None


@classmethod
def conv_block(cls, inputs, layout, filters, bottleneck, bottleneck_factor=
    None, **kwargs):
    """ ResNet convolution block

        Parameters
        ----------
        inputs
            input tensor
        layout : str
            a sequence of layers in the block
        filters : int
            number of output filters
        downsample : bool
            whether to decrease spatial dimensions with strides=2
        bottleneck : bool
            whether to use a simple or a bottleneck block
        bottleneck_factor : int
            filter count scaling factor
        kwargs : dict
            conv_block parameters

        Returns
        -------
        nn.Module
        """
    if layout is None:
        layout = cls.default_layout(bottleneck=bottleneck, filters=filters,
            **kwargs)
    if bottleneck:
        x = cls.bottleneck_block(inputs, layout, filters, bottleneck_factor
            =bottleneck_factor, **kwargs)
    else:
        x = cls.simple_block(inputs, layout, filters, **kwargs)
    return x


def IS_CHARACTER_JUNK(ch, ws=' \t'):
    """
    Return 1 for ignorable character: iff `ch` is a space or tab.

    Examples:

    >>> IS_CHARACTER_JUNK(' ')
    True
    >>> IS_CHARACTER_JUNK('\\t')
    True
    >>> IS_CHARACTER_JUNK('\\n')
    False
    >>> IS_CHARACTER_JUNK('x')
    False
    """
    return ch in ws


def int_to_alpha(n, upper=True):
    """Generates alphanumeric labels of form A-Z, AA-ZZ etc."""
    casenum = 65 if upper else 97
    label = ''
    count = 0
    if n == 0:
        return str(chr(n + casenum))
    while n >= 0:
        mod, div = n % 26, n
        for _ in range(count):
            div //= 26
        div %= 26
        if count == 0:
            val = mod
        else:
            val = div
        label += str(chr(val + casenum))
        count += 1
        n -= 26 ** count
    return label[::-1]


def show_string_length(series):
    """Show statistical information about row length in the series"""
    max_length = series.str.len().max()
    min_length = series.str.len().min()
    mean = series.str.len().mean()
    median = series.str.len().median()
    print('max_length: ', max_length, '\nmin_length: ', min_length,
        '\nmean: ', mean, '\nmedian: ', median)


def skip_redundant(iterable, skipset=None):
    """Redundant items are repeated items or items in the original skipset."""
    if skipset is None:
        skipset = set()
    for item in iterable:
        if item not in skipset:
            skipset.add(item)
            yield item


@classmethod
def get_block_aggregators(cls, block_structure, block_key):
    """
        Return the aggregators which contain this block.

        Arguments:
            block_structure: a BlockStructure instance
            block_key: the key of the block whose aggregators we want
        Returns:
            aggregators: list or None

        """
    return block_structure.get_transformer_block_field(block_key, cls, cls.
        AGGREGATORS)


def get_chars(s, offset, gochars):
    """ Scan the string `s` for characters in `gochars` starting at `offset`.
      Return `(match,new_offset)`.
  """
    ooffset = offset
    while offset < len(s) and s[offset] in gochars:
        offset += 1
    return s[ooffset:offset], offset


def _shape_setup(shape):
    """Array shape preprocessing, return (shape,) if shape is an integer."""
    return (shape,) if isinstance(shape, int) else shape


def Window(title='New Window', width='auto', height='auto', resizable=False):
    """
    Return a basic config for new windows

    :param title: The window title
    :type title: str
    :param width: Width of the window at startup
    :type width: int
    :param height: Height of the window at startup
    :type height: int
    :param resizable: Wether the user can resize the window
    :type resizable: bool
    :rtype: dict
    """
    return {'title': title, 'width': width, 'height': height, 'resizable':
        resizable}


def get_host(environ):
    """Return the real host for the given WSGI environment.  This takes care
    of the `X-Forwarded-Host` header.

    :param environ: the WSGI environment to get the host of.
    """
    scheme = environ.get('wsgi.url_scheme')
    if 'HTTP_X_FORWARDED_HOST' in environ:
        result = environ['HTTP_X_FORWARDED_HOST']
    elif 'HTTP_HOST' in environ:
        result = environ['HTTP_HOST']
    else:
        result = environ['SERVER_NAME']
        if (scheme, str(environ['SERVER_PORT'])) not in (('https', '443'),
            ('http', '80')):
            result += ':' + environ['SERVER_PORT']
    if result.endswith(':80') and scheme == 'http':
        result = result[:-3]
    elif result.endswith(':443') and scheme == 'https':
        result = result[:-4]
    return result


def qn(namespace, tag_name):
    """Return the qualified name for a given namespace and tag name

    This is the ElementTree representation of a qualified name
    """
    return '{%s}%s' % (namespace, tag_name)


def normalize_hpo_id(hpo_term):
    """Reformat HPO Term to database Id

    Arguments:
        hpo_term (str): HPO Term

    Returns:
        int: HPO database Id
    """
    if hpo_term.startswith('HP:'):
        hpo_id = hpo_term.lstrip('HP:')
    else:
        hpo_id = hpo_term
    return int(hpo_id.lstrip('0'))


def response_sent(address, response_type):
    """Record the fact that another response is being sent to the address.

        :param address: The address who is the recipient of the auto-response.
        :type address: `IAddress`
        :param response_type: The response type being sent.
        :type response_type: `Response`
        """


def filter_macrofy(value: str) ->str:
    """
    Filter to transform an input into a valid C preprocessor identifier token.

    .. invisible-code-block: python

        from nunavut.lang.c import filter_macrofy

    .. code-block:: python

        # Given
        template = '#ifndef {{ "my full name" | macrofy }}'

        # then
        rendered = '#ifndef MY_FULL_NAME'

    .. invisible-code-block: python

        jinja_filter_tester(filter_macrofy, template, rendered, 'c')

    :param str value: The value to transform.

    :returns: A valid C preprocessor identifier token.
    """
    return value.replace(' ', '_').replace('.', '_').upper()


def resolve_name(name):
    """Resolve a name like ``module.object`` to an object and return it.

    Raise `ImportError` if the module or name is not found.
    """
    parts = name.split('.')
    cursor = len(parts) - 1
    module_name = parts[:cursor]
    attr_name = parts[-1]
    while cursor > 0:
        try:
            ret = __import__('.'.join(module_name), fromlist=[attr_name])
            break
        except ImportError:
            if cursor == 0:
                raise
            cursor -= 1
            module_name = parts[:cursor]
            attr_name = parts[cursor]
            ret = ''
    for part in parts[cursor:]:
        try:
            ret = getattr(ret, part)
        except AttributeError:
            raise ImportError(name)
    return ret


def dtype(input):
    """Return the data type of the tensor.

    Parameters
    ----------
    input : Tensor
        The input tensor.

    Returns
    -------
    data type
        It should be one of the values in the data type dict.
    """
    pass


def psi_H_MgOH_Cl_HMW84(T, P):
    """c-c'-a: hydrogen magnesium-hydroxide chloride [HMW84]."""
    psi = 0.0
    valid = T == 298.15
    return psi, valid


@classmethod
def set_sync_plan(cls, options=None):
    """
        Assign sync plan to product.
        """
    cls.command_sub = 'set-sync-plan'
    result = cls.execute(cls._construct_command(options))
    return result


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

        :param AccountLockOrUnlockedType val:
        :rtype: EventType
        """
    return cls('account_lock_or_unlocked', val)


@staticmethod
def get_previous_symbol(curr_future_symbol: str) ->str:
    """
        >>> assert(EminiFuture.get_previous_symbol('ESH9') == 'ESZ8')
        """
    month = curr_future_symbol[2]
    year = int(curr_future_symbol[3])
    prev_month = {'H': 'Z', 'M': 'H', 'U': 'M', 'Z': 'U'}[month]
    prev_year = year if prev_month != 'Z' else year - 1
    if prev_year == -1:
        prev_year == 9
    return f'ES{prev_month}{prev_year}'


def calc_point_dist(vsA, entryA):
    """
    This function is used to determine the distance between two points.

    Parameters
    ----------
    vsA : list or numpy.array or similar
        An array of point 1's position in the \\chi_i coordinate system
    entryA : list or numpy.array or similar
        An array of point 2's position in the \\chi_i coordinate system
    MMdistA : float
        The minimal mismatch allowed between the points

    Returns
    --------
    val : float
        The metric distance between the two points.
    """
    chi_diffs = vsA - entryA
    val = (chi_diffs * chi_diffs).sum()
    return val


def sequence_difference(nth, first_term, term_number):
    """Usage: Find the difference in a sequence"""
    return (nth - first_term) / (term_number - 1)


def AddMultipleSplat(x, *args):
    """Call x.Add(*i) for each args given
       Return x
       NOTE: each "arg" after x must be a tuple
       """
    for i in args:
        x.Add(*i)
    return x


def getLevels():
    """Returns a list of ILevel in the hierarchy."""


def turbulent_Churchill_Zajic(Re, Pr, fd):
    """Calculates internal convection Nusselt number for turbulent flows
    in pipe according to [2]_ as developed in [1]_. Has yet to obtain
    popularity.

    .. math::
        Nu = \\left\\{\\left(\\frac{Pr_T}{Pr}\\right)\\frac{1}{Nu_{di}} +
        \\left[1-\\left(\\frac{Pr_T}{Pr}\\right)^{2/3}\\right]\\frac{1}{Nu_{D\\infty}}
        \\right\\}^{-1}

    .. math::
        Nu_{di} = \\frac{Re(f/8)}{1 + 145(8/f)^{-5/4}}

    .. math::
        Nu_{D\\infty} = 0.07343Re\\left(\\frac{Pr}{Pr_T}\\right)^{1/3}(f/8)^{0.5}

    .. math::
        Pr_T = 0.85 + \\frac{0.015}{Pr}

    Parameters
    ----------
    Re : float
        Reynolds number, [-]
    Pr : float
        Prandtl number, [-]
    fd : float
        Darcy friction factor [-]

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

    Notes
    -----
    No restrictions on range. This is equation is developed with more
    theoretical work than others.

    Examples
    --------
    >>> turbulent_Churchill_Zajic(Re=1E5, Pr=1.2, fd=0.0185)
    260.5564907817961

    References
    ----------
    .. [1] Churchill, Stuart W., and Stefan C. Zajic. “Prediction of Fully
       Developed Turbulent Convection with Minimal Explicit Empiricism.”
       AIChE Journal 48, no. 5 (May 1, 2002): 927–40. doi:10.1002/aic.690480503.
    .. [2] Plawsky, Joel L. Transport Phenomena Fundamentals, Third Edition.
       CRC Press, 2014.
    """
    Pr_T = 0.85 + 0.015 / Pr
    Nu_di = Re * (fd / 8.0) / (1.0 + 145 * (8.0 / fd) ** -1.25)
    Nu_dinf = 0.07343 * Re * (Pr / Pr_T) ** (1.0 / 3.0) * (fd / 8.0) ** 0.5
    return 1.0 / (Pr_T / Pr / Nu_di + (1.0 - (Pr_T / Pr) ** (2 / 3.0)) /
        Nu_dinf)


def htmlquote(text):
    """
    Encodes `text` for raw use in HTML.

        >>> htmlquote(u"<'&\\">")
        u'<'&">'
    """
    text = text.replace(u'&', u'&')
    text = text.replace(u'<', u'<')
    text = text.replace(u'>', u'>')
    text = text.replace(u"'", u''')
    text = text.replace(u'"', u'"')
    return text


def get_object(connection, object_meta_data: dict, dirname: str):
    """
    Download object from objectstore.
    object_meta_data is an object retured when
    using 'get_full_container_list'
    """
    return connection.get_object(dirname, object_meta_data['name'])[1]


@classmethod
def get_fbits(cls, beyging):
    """ Get the (cached) fbits for a BIN 'beyging' field """
    fbits = cls._MEANING_CACHE.get(beyging)
    if fbits is None:
        fbits = cls.fbits(beyging)
        cls._MEANING_CACHE[beyging] = fbits
    return fbits


def is_ignore_file(file_path, blueprints_dict):
    """Should the file be ignored based on some conditions."""
    if '__pycache__' in file_path:
        return True
    if file_path.endswith('.pyc'):
        return True
    for blueprint_name, blueprint_kwargs in blueprints_dict.items():
        blueprint_placeholder = '/BP_{bp_name_upper}/'.format(bp_name_upper
            =blueprint_name.upper())
        if blueprint_placeholder in file_path and blueprint_kwargs['include'
            ] is not True:
            print('IGNORING BLUEPRINT FILE: {}: {}'.format(blueprint_name,
                file_path))
            return True
    return False


def vertex_group_fix(dist: float=0.0, strength: float=1.0, accuracy: float=1.0
    ):
    """Modify the position of selected vertices by changing only their respective groups’ weights (this tool may be slow for many vertices)

    :param dist: Distance, The distance to move to
    :type dist: float
    :param strength: Strength, The distance moved can be changed by this multiplier
    :type strength: float
    :param accuracy: Change Sensitivity, Change the amount weights are altered with each iteration: lower values are slower
    :type accuracy: float
    """
    pass


def insertmany_query(tablename, objects):
    """
    Function to process the query for insert many  process
    """
    if isinstance(tablename, str):
        pass
    else:
        raise ValueError('Tablename should be a String')
    """
        Sanity check of bulk insert
    """
    len_objects = []
    for val in map(len, objects):
        len_objects.append(val)
    if len(set(len_objects)) != 1:
        raise ValueError('Objects are off different length')
    columns = set(objects[0].keys())
    for val in objects:
        if columns != set(val.keys()):
            raise ValueError(
                'The number of columns that has to be updated must be same across all the objects'
                )
    cols = objects[0].keys()
    data = []
    for i in objects:
        data.append(tuple(i.values()))
    reg_string = ''
    for i in range(len(data[0])):
        reg_string += '%s, '
    reg_string = reg_string[:len(reg_string) - 2]
    query = 'INSERT INTO ' + tablename + ' (%s) VALUES(%s)' % (','.join(
        cols), reg_string)
    return query, data


def get_gates(cur_state, hard_boundaries, buffer_width):
    """Obtains the gates that represent the edges that a dihedral must exit
    from to undergo a buffered transition.

    Parameters
    -----------
    cur_state : int,
        Rotameric basin index presently being occupied by the dihedral
    hard_boundaries : array-like, shape=(1, n_boundaries)
        Single set of numbers containing the "hard" boundaries denoting
        rotamer basins. This array MUST contain 0 as the first value and
        360 as the last value.
    buffer_width : int, default=15
        size of the buffer region on either side of the
        rotamer barrier.

    Returns
    ----------
    lower_bound : int
        Lower gate that must be crossed for a transition to occur
    upper_bound : int
        Upper gate that must be crossed for a transition to occur

    See also
    ---------
    _rotamers, is_buffered_transition

    """
    n_basins = len(hard_boundaries) - 1
    state_num = int(cur_state)
    lower_bound = hard_boundaries[state_num]
    upper_bound = hard_boundaries[state_num + 1]
    if lower_bound == 0:
        lower_bound = 360
    if upper_bound == 360:
        upper_bound = 0
    lower_bound -= buffer_width
    upper_bound += buffer_width
    return lower_bound, upper_bound


def to_molar_ratio(massfrac_numerator, massfrac_denominator, numerator_mass,
    denominator_mass):
    """
    Converts per-mass concentrations to molar elemental ratios.

    Be careful with units.

    Parameters
    ----------
    numerator_mass, denominator_mass : float or array-like
        The atomic mass of the numerator and denominator.
    massfrac_numerator, massfrac_denominator : float or array-like
        The per-mass fraction of the numnerator and denominator.

    Returns
    -------
    float or array-like : The molar ratio of elements in the material
    """
    return massfrac_numerator / numerator_mass / (massfrac_denominator /
        denominator_mass)


def exclusive_joint(prob_a, prob_b):
    """
    Returns the joint probability of (A and not B) or (B and not A)
    """
    return prob_a + prob_b - prob_a * prob_b


def _is_spark_step_type(step_type):
    """Does the given step type indicate that it uses Spark?"""
    return step_type.split('_')[0] == 'spark'


@classmethod
def get_connection_resolver(cls):
    """
        Get the connection resolver instance.
        """
    return cls.__resolver


def check_mouse_press_for_buttons(x, y, button_list):
    """ Given an x, y, see if we need to register any button clicks. """
    for button in button_list:
        if x > button.center_x + button.width / 2:
            continue
        if x < button.center_x - button.width / 2:
            continue
        if y > button.center_y + button.height / 2:
            continue
        if y < button.center_y - button.height / 2:
            continue
        button.on_press()


@staticmethod
def _size_to_string(num_bytes):
    """ Convert a number of bytes into a binary size string """
    LOG2_STEP = 10
    STEP = 1024
    units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
    unit_i = max(num_bytes.bit_length() - 1, 1) // LOG2_STEP
    unit_val = 1 << unit_i * LOG2_STEP
    n_units = num_bytes / unit_val
    del unit_val
    if round(n_units) == STEP:
        unit_i += 1
        n_units /= STEP
    if unit_i >= len(units):
        new_unit_i = len(units) - 1
        n_units *= 1 << (unit_i - new_unit_i) * LOG2_STEP
        unit_i = new_unit_i
    unit_name = units[unit_i]
    if unit_i == 0:
        return '{:.0f} {}'.format(n_units, unit_name)
    elif round(n_units) < 1000:
        return '{:#.3g} {}'.format(n_units, unit_name)
    else:
        return '{:#.0f} {}'.format(n_units, unit_name)


def set_node_attributes(G, name, values):
    """Set node attributes from dictionary of nodes and values

    Parameters
    ----------
    G : NetworkX Graph

    name : string
       Attribute name

    values: dict
       Dictionary of attribute values keyed by node. If `values` is not a
       dictionary, then it is treated as a single attribute value that is then
       applied to every node in `G`.

    Examples
    --------
    >>> G = nx.path_graph(3)
    >>> bb = nx.betweenness_centrality(G)
    >>> nx.set_node_attributes(G, 'betweenness', bb)
    >>> G.node[1]['betweenness']
    1.0
    """
    try:
        values.items
    except AttributeError:
        values = dict(zip(G.nodes(), [values] * len(G)))
    for node, value in values.items():
        G.node[node][name] = value


@classmethod
def _process_attrs(cls, attrs):
    """ Private method for processing attrs.
    Param for this processor got from `get_attrs_processor_param`.
    Param is dict contains two key: `default` and `raname`.
    First add default value to attrs if key does not exist.
    Second rename key to new key.

    For example:
      attrs = {"keep_dims": True}
      param = {"default": {"axis": 1},
               "rename": {"keep_dims": "keepdims"}}

      processed_attrs = {"axis": "1", "keepdims": True}

    :param attrs: Process target attrs.
    :return: Processed attrs.
    """
    param = {'rename': {}, 'default': {}}
    param.update(cls.get_attrs_processor_param())
    for k, v in param['default'].items():
        attrs.setdefault(k, v)
    for k, new_k in param['rename'].items():
        if k in attrs:
            attrs[new_k] = attrs.pop(k)
    return attrs


def _get_study_name_from_url(tree_input_url):
    """Name of study is the URL part after 'trees'"""
    parts = tree_input_url.split('/')
    trees_index = parts.index('trees')
    study_name = parts[trees_index + 1]
    return study_name


def dict_factory(cursor, row):
    """Changes the data returned from the db from a
    tupple to a dictionary"""
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d


def query_yes_no(question, default='yes'):
    """Ask a yes/no question and return the answer.

    Parameters
    ----------

    question : string
       String that is presented to the user.

    default : bool
       The default answer if the user just hits <Enter>.
       It must be "yes" (the default), "no" or None (meaning
       an answer is required of the user).

    Returns
    -------

    answer : bool
       The returned answer.
    """
    valid = {'yes': True, 'y': True, 'no': False, 'n': False}
    if default is None:
        prompt = ' [y/n] '
    elif default == 'yes':
        prompt = ' [Y/n] '
    elif default == 'no':
        prompt = ' [y/N] '
    else:
        raise ValueError("invalid default answer: '%s'" % default)
    while True:
        print(question + prompt, flush=True, end='')
        choice = input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            print("Please respond with 'yes' or 'no' (or 'y' or 'n').",
                flush=True)


def groupfinder(userid, request):
    """Fetch principals from permission backend for the specified `userid`.

    This is plugged by default using the ``multiauth.groupfinder`` setting.
    """
    backend = getattr(request.registry, 'permission', None)
    if not backend:
        return []
    if request.prefixed_userid:
        userid = request.prefixed_userid
    reify_key = userid + '_principals'
    if reify_key not in request.bound_data:
        principals = backend.get_user_principals(userid)
        request.bound_data[reify_key] = principals
    return request.bound_data[reify_key]


def visual_transform_apply():
    """Apply the object’s visual transformation to its data

    """
    pass


def gmsh_grid_adapt3D(out_dim=(100.0, 100.0), in_dim=(50.0, 50.0), z_dim=-
    10.0, out_res=(10.0, 10.0, 10.0), in_res=(5.0, 5.0, 5.0), out_pos=(0.0,
    0.0), in_pos=(25.0, 25.0), z_pos=0.0):
    """Generate the mesh adapter."""
    try:
        from pygmsh import Geometry
    except ImportError:
        from pygmsh.built_in import Geometry
    geo = Geometry()
    code = ['dimz = {};'.format(z_dim), 'outx = {};'.format(out_dim[0]),
        'outy = {};'.format(out_dim[1]), 'inx = {};'.format(in_dim[0]),
        'iny = {};'.format(in_dim[1]), 'grioutx = {};'.format(out_res[0]),
        'griouty = {};'.format(out_res[1]), 'grioutz = {};'.format(out_res[
        2]), 'grix = {};'.format(in_res[0]), 'griy = {};'.format(in_res[1]),
        'griz = {};'.format(in_res[2]), 'obx = {};'.format(out_pos[0]),
        'oby = {};'.format(out_pos[1]), 'ibx = {};'.format(in_pos[0]),
        'iby = {};'.format(in_pos[1]), 'bz = {};'.format(z_pos),
        'Point(1) = {obx,       oby,        bz,         grioutx};',
        'Point(2) = {obx+outx,  oby,        bz,         grioutx};',
        'Point(3) = {obx+outx,  oby+outy,   bz,         grioutx};',
        'Point(4) = {obx,       oby+outy,   bz,         grioutx};',
        'Point(5) = {obx,       oby,        bz+dimz,    grioutx};',
        'Point(6) = {obx+outx,  oby,        bz+dimz,    grioutx};',
        'Point(7) = {obx+outx,  oby+outy,   bz+dimz,    grioutx};',
        'Point(8) = {obx,       oby+outy,   bz+dimz,    grioutx};',
        'Point(9) =  {ibx,      iby,        bz,         grix};',
        'Point(10) = {ibx+inx,  iby,        bz,         grix};',
        'Point(11) = {ibx+inx,  iby+iny,    bz,         grix};',
        'Point(12) = {ibx,      iby+iny,    bz,         grix};',
        'Point(13) = {ibx,      iby,        bz+dimz,    grix};',
        'Point(14) = {ibx+inx,  iby,        bz+dimz,    grix};',
        'Point(15) = {ibx+inx,  iby+iny,    bz+dimz,    grix};',
        'Point(16) = {ibx,      iby+iny,    bz+dimz,    grix};',
        'Line(1) = {1, 2}; //s top', 'Line(2) = {2, 3}; //e top',
        'Line(3) = {3, 4}; //n top', 'Line(4) = {4, 1}; //w top',
        'Line(5) = {5, 6}; //s bottom', 'Line(6) = {6, 7}; //e bottom',
        'Line(7) = {7, 8}; //n bottom', 'Line(8) = {8, 5}; //w bottom',
        'Line(9) = {1, 5}; //sw vert', 'Line(10) = {2, 6}; //se vert',
        'Line(11) = {3, 7}; //ne vert', 'Line(12) = {4, 8}; //nw vert',
        '// inner block lines', 'Line(13) = {9, 10}; //s top',
        'Line(14) = {10, 11}; //e top', 'Line(15) = {11, 12}; //n top',
        'Line(16) = {12, 9}; //w top', 'Line(18) = {13, 14}; //s top',
        'Line(19) = {14, 15}; //e bottom',
        'Line(20) = {15, 16}; //n bottom',
        'Line(21) = {16, 13}; //w bottom', 'Line(22) = {9, 13}; //sw vert',
        'Line(23) = {10, 14}; //se vert', 'Line(24) = {11, 15}; //nw vert',
        'Line(25) = {12, 16}; //ne vert', 'Line Loop(26) = {1, 2, 3, 4};',
        'Line Loop(27) = {13, 14, 15, 16};',
        'Plane Surface(28) = {26, 27};', 'Line Loop(29) = {5, 6, 7, 8};',
        'Line Loop(30) = {18, 19, 20, 21};',
        'Plane Surface(31) = {29, 30};', 'Line Loop(32) = {1, 10, -5, -9};',
        'Plane Surface(33) = {32};', 'Line Loop(34) = {2, 11, -6, -10};',
        'Plane Surface(35) = {34};', 'Line Loop(36) = {3, 12, -7, -11};',
        'Plane Surface(37) = {36};', 'Line Loop(38) = {4, 9, -8, -12};',
        'Plane Surface(39) = {38};', 'Line Loop(40) = {13, 23, -18, -22};',
        'Plane Surface(41) = {40};', 'Line Loop(42) = {14, 24, -19, -23};',
        'Plane Surface(43) = {42};', 'Line Loop(44) = {15, 25, -20, -24};',
        'Plane Surface(45) = {44};', 'Line Loop(46) = {16, 22, -21, -25};',
        'Plane Surface(47) = {46};',
        'Transfinite Line{1, 3, 5, 7} = outx/grioutx + 1;',
        'Transfinite Line{2, 4, 6, 8} = outy/griouty + 1;',
        'Transfinite Line{9, 10, 11, 12} = Fabs(dimz)/grioutz + 1;',
        'Transfinite Surface{33};', 'Transfinite Surface{35};',
        'Transfinite Surface{37};', 'Transfinite Surface{39};',
        'Recombine Surface{33};', 'Recombine Surface{35};',
        'Recombine Surface{37};', 'Recombine Surface{39};',
        'Transfinite Line{13, 15, 18, 20} = inx/grix + 1;',
        'Transfinite Line{14, 16, 19, 21} = iny/griy + 1;',
        'Transfinite Line{22, 23, 24, 25} = Fabs(dimz)/griz + 1;',
        'Transfinite Surface{41};', 'Transfinite Surface{43};',
        'Transfinite Surface{45};', 'Transfinite Surface{47};',
        'Recombine Surface{41};', 'Recombine Surface{43};',
        'Recombine Surface{45};', 'Recombine Surface{47};',
        'Surface Loop(48) = {39, 28, 33, 35, 37, 31, 47, 41, 43, 45};',
        'Volume(49) = {48};']
    geo.add_raw_code(code)
    return geo


def glFinish():
    """Block until all GL execution is complete

    """
    pass


def Custom(*data, **kwargs):
    """Apply a custom operator implemented in a frontend language (like Python).

    Custom operators should override required methods like `forward` and `backward`.
    The custom operator must be registered before it can be used.
    Please check the tutorial here: https://mxnet.incubator.apache.org/api/faq/new_op

    Defined in src/operator/custom/custom.cc:L546

    Parameters
    ----------
    data : NDArray[]
        Input data for the custom operator.
    op_type : string
        Name of the custom operator. This is the name that is passed to `mx.operator.register` to register the operator.

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

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.

    Example
    -------
    Applies a custom operator named `my_custom_operator` to `input`.

    >>> output = mx.symbol.Custom(op_type='my_custom_operator', data=input)
    """
    return 0,


def diff_month(d1, d2):
    """
    Helper function to calculate the number of month between two dates
    @param d1:
    @param d2:
    @return:
    """
    return (d1.year - d2.year) * 12 + d1.month - d2.month


def set_param(self_, *args, **kwargs):
    """
        For each param=value keyword argument, sets the corresponding
        parameter of this object or class to the given value.

        For backwards compatibility, also accepts
        set_param("param",value) for a single parameter value using
        positional arguments, but the keyword interface is preferred
        because it is more compact and can set multiple values.
        """
    BATCH_WATCH = self_.self_or_cls.param._BATCH_WATCH
    self_.self_or_cls.param._BATCH_WATCH = True
    self_or_cls = self_.self_or_cls
    if args:
        if len(args) == 2 and not args[0] in kwargs and not kwargs:
            kwargs[args[0]] = args[1]
        else:
            self_.self_or_cls.param._BATCH_WATCH = False
            raise ValueError(
                'Invalid positional arguments for %s.set_param' %
                self_or_cls.name)
    for k, v in kwargs.items():
        if k not in self_or_cls.param:
            self_.self_or_cls.param._BATCH_WATCH = False
            raise ValueError("'%s' is not a parameter of %s" % (k,
                self_or_cls.name))
        try:
            setattr(self_or_cls, k, v)
        except:
            self_.self_or_cls.param._BATCH_WATCH = False
            raise
    self_.self_or_cls.param._BATCH_WATCH = BATCH_WATCH
    if not BATCH_WATCH:
        self_._batch_call_watchers()


def humanize_path(path: str) ->str:
    """ Replace python dotted path to directory-like one.

    ex. foo.bar.baz -> foo/bar/baz

    :param str path: path to humanize
    :return str: humanized path
    """
    return path.replace('.', '/')


def python_3000_not_equal(logical_line):
    """New code should always use != instead of <>.

    The older syntax is removed in Python 3.

    Okay: if a != 'no':
    W603: if a <> 'no':
    """
    pos = logical_line.find('<>')
    if pos > -1:
        yield pos, "W603 '<>' is deprecated, use '!='"


@classmethod
def build_tag(cls, tag, text='', attrs=None):
    """Build tag full info include the attributes.

        :param tag: tag name.
        :param text: tag text.
        :param attrs: tag attributes. Default：``None``.
        :type attrs: dict or None
        :rtype: str
        """
    return '{}{}{}'.format(cls.tag_start(tag, attrs), text, cls.tag_end(tag))


def columns_instantaneous_df(weighted, keys=[]):
    """Obtain the columns of dataframe according with the keys and the weighting."""
    cols = ['ts']
    if weighted:
        cols.append('w')
    return keys + cols


def map_tag_to_subfield(tag_type, line, cur_misc_txt, dest):
    """Create a new reference element"""
    closing_tag = '</cds.%s>' % tag_type
    idx_closing_tag = line.find(closing_tag)
    if idx_closing_tag == -1:
        identified_citation_element = None
        line = line[len('<cds.%s>' % tag_type):]
    else:
        tag_content = line[:idx_closing_tag]
        identified_citation_element = {'type': tag_type, 'misc_txt':
            cur_misc_txt, dest: tag_content}
        ending_tag_pos = idx_closing_tag + len(closing_tag)
        line = line[ending_tag_pos:]
        cur_misc_txt = u''
    return identified_citation_element, line, cur_misc_txt


def fsliceafter(astr, sub):
    """Return the slice after at sub in string astr"""
    findex = astr.find(sub)
    return astr[findex + len(sub):]


def marching_cubes_to_obj(marching_cubes_out, output_file):
    """
    Saves the output of skimage.measure.marching_cubes as an .obj file

    :param marching_cubes_out: tuple
    :param output_file: str

    """
    verts, faces, normals, _ = marching_cubes_out
    with open(output_file, 'w') as f:
        for item in verts:
            f.write(f'v {item[0]} {item[1]} {item[2]}\n')
        for item in normals:
            f.write(f'vn {item[0]} {item[1]} {item[2]}\n')
        for item in faces:
            f.write(
                f'f {item[0]}//{item[0]} {item[1]}//{item[1]} {item[2]}//{item[2]}\n'
                )
        f.close()


def rpc_completion_callback(callback):
    """Verify callback is callable if not None

    :returns: boolean indicating nowait
    :rtype: bool
    :raises: TypeError

    """
    if callback is None:
        return True
    if callable(callback):
        return False
    else:
        raise TypeError('completion callback must be callable if not None')


def p_expression_binop(t):
    """expression : expression PLUS expression
                  | expression MINUS expression
                  | expression TIMES expression
                  | expression DIVIDE expression
    """
    if t[2] == '+':
        t[0] = t[1] + t[3]
    elif t[2] == '-':
        t[0] = t[1] - t[3]
    elif t[2] == '*':
        t[0] = t[1] * t[3]
    elif t[2] == '/':
        t[0] = t[1] / t[3]


def get_result_color(value=0, ok_thershold=90, warning_thershold=70):
    """
    Get color code that corresponds to the result.

    Parameters:
    - value : value to check
    - ok_thershold : OK threshold value
    - warning_thershold : warning thershold value
    """
    if not (type(value) in (int, float) and type(ok_thershold) in (int,
        float) and type(warning_thershold) in (int, float)):
        return 'lightgrey'
    if value >= ok_thershold:
        return 'green'
    elif value >= warning_thershold:
        return 'yellow'
    else:
        return 'red'


def getPrettyTextFromSet(frames):
    """
    Given a set of integers returns a more human readable string
    """
    if not frames:
        return ''
    if len(frames) == 1:
        framesSet = frames.copy()
        return str(framesSet.pop())
    framesList = list(frames)
    framesList.sort(reverse=True)
    lastNum = framesList.pop()
    currentStrStart = lastNum
    pStr = str(lastNum)
    while framesList:
        currNum = framesList.pop()
        if not lastNum + 1 == currNum:
            if not lastNum == currentStrStart:
                pStr = pStr + '-' + str(lastNum)
            pStr = pStr + ',' + str(currNum)
            currentStrStart = currNum
        lastNum = currNum
    if currentStrStart != currNum:
        pStr = pStr + '-' + str(lastNum)
    return pStr


@classmethod
def create_generic(cls):
    """
        Return a UnknownLanguage instance..
        :return: UnknownLanguage instance.
        """
    return cls('unknown')


def _STEPS2TIME(step):
    """Conversion from time steps in milliseconds to seconds as float"""
    return step / 1000.0


def evalCreate(ctx, u):
    """
    http://www.w3.org/TR/sparql11-update/#create
    """
    g = ctx.dataset.get_context(u.graphiri)
    if len(g) > 0:
        raise Exception('Graph %s already exists.' % g.identifier)
    raise Exception('Create not implemented!')


def find_file(path_dir, search_str, file_ext):
    """Find path of file in directory containing the search string"""
    import os
    file_path = None
    for file_name in os.listdir(path_dir):
        if search_str in file_name and file_name.endswith(file_ext):
            file_path = os.path.join(path_dir, file_name)
            break
    if file_path is None:
        raise SystemError('No file found containing string: {}.'.format(
            search_str))
    return file_path


@classmethod
def get_variant_description(cls, variant_id) ->str:
    """Get a textual description of the given variant id"""
    field_id = cls.get_variant_field_id()
    txt = cls.get_description_for_value(field_id, variant_id
        ) if field_id is not None else None
    if txt:
        return '%s %s' % (cls.get_root_variant().__name__, txt)
    elif variant_id in cls.__cls_variants_bidict:
        return cls.__cls_variants_bidict[variant_id].__name__
    elif variant_id is not None:
        return '%s Type %d' % (cls.get_root_variant().__name__, variant_id)
    else:
        return cls.get_root_variant().__name__