def iter_without_duplicates(it, key=lambda x: x):
    """Yields non-repeating items from `iter`.

    `key` has the same meaning as in `delete_duplicates`:func:.

    The difference between this function and `iter_delete_duplicates`:func: is
    that we ensure the same item (as per `key`) is produced only once; while
    `iter_delete_duplicates`:func: only remove consecutive repeating items.

    Example:

      >>> list(iter_without_duplicates('AAAaBBBA', key=lambda x: x.lower()))
      ['A', 'B']

    """
    done = set()
    for what in it:
        k = key(what)
        if k not in done:
            yield what
            done.add(k)


def freestyle_stroke_material_create():
    """Create Freestyle stroke material for testing

    """
    pass


def rm_csv_tag(csv: str, rm_value: str):
    """Given a csv string, returns the string with matching value removed.
    """
    tags = csv.split(',')
    return ','.join(filter(lambda x: x != rm_value, tags))


@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]


@classmethod
def extract(cls, filename, compression, sources, destination='.'):
    """
        Extract files from a tar archive
        :param filename: name of the archive
        :type filename: str
        :param compression: compression mode
        :type compression: str
        :param sources: file to be extracted
        :type sources: list
        :param destination: final destination of extracted files
        :type destination: str
        """
    raise NotImplementedError


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

        :param DirectoryRestrictionsRemoveMembersDetails val:
        :rtype: EventDetails
        """
    return cls('directory_restrictions_remove_members_details', val)


def context_toggle(data_path: str=''):
    """Toggle a context value

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    """
    pass


def add_warnings(pand_dict, timing, sat_level, flags, instrument):
    """Add warnings for front end

    Adds in necessary warning flags for a JWST observation usually associated with
    too few or too many groups or saturation. Alerts user if saturation level is higher
    than 80 percent and if the number of groups is less than 5. Or, if the full well is
    greater than 80. These warnings are currently very arbitrary. Will be updated as
    better JWST recommendations are made.

    Parameters
    ----------
    pand_dict :
        output from pandeia run
    timing : dict
        output from **compute_timing**
    sat_level : int or float
        user specified saturation level in fractional (00/100)
    flags : dict
        warning flags taken from output of **compute_timing**
    instrument : str
        Only allowable strings are: "nirspec", "niriss", "nircam", "miri"

    Returns
    -------
    dict
        all warnings

    Notes
    -----
    These are warnings are just suggestions and are not yet required.
    """
    ngroups_per_int = timing['APT: Num Groups per Integration']
    try:
        flag_nonl = pand_dict['warnings']['nonlinear']
    except:
        flag_nonl = 'All good'
    try:
        flag_sat = pand_dict['warnings']['saturated']
    except:
        flag_sat = 'All good'
    flag_low = 'All good'
    flag_perc = 'All good'
    if (sat_level > 0.8) & (ngroups_per_int < 3):
        flag_low = '% full well>80% & only ' + str(ngroups_per_int) + ' groups'
    if sat_level > 0.8:
        flag_perc = '% full well>80%'
    warnings = {'Group Number Too Low?': flag_low, 'Group Number Too High?':
        flags['flag_high'], 'Non linear?': flag_nonl, 'Saturated?':
        flag_sat, '% full well high?': flag_perc, 'Num Groups Reset?':
        flags['flag_default']}
    return warnings


def _int_to_slice(idx):
    """Return a slice that indexes the same entries as a single int."""
    if idx == -1:
        return slice(-1, None)
    else:
        return slice(idx, idx + 1)


def __new__(cls, name, value=False):
    """Get or create a new symbol instance.

        See `~Symbol.__new__`:meth: for information about parameters.
        """
    return super().__new__(cls, name, bool(value))


def describe_notification_subscriptions(OrganizationId=None, Marker=None,
    Limit=None):
    """
    Lists the specified notification subscriptions.
    See also: AWS API Documentation

    :example: response = client.describe_notification_subscriptions(
        OrganizationId='string',
        Marker='string',
        Limit=123
    )

    :type OrganizationId: string
    :param OrganizationId: [REQUIRED]
            The ID of the organization.

    :type Marker: string
    :param Marker: The marker for the next set of results. (You received this marker from a previous call.)

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

    :rtype: dict
    :return: {
        'Subscriptions': [
            {
                'SubscriptionId': 'string',
                'EndPoint': 'string',
                'Protocol': 'HTTPS'
            },
        ],
        'Marker': 'string'
    }

    """
    pass


def iaslist(term):
    """
    Iterate over items in term as if term was a list. Treats a str, unicode
    term as a single item.

    Parameters
    ----------
    term : any
        Term to iterate over.

    Yields
    ------
    any
        Items in the list representation of term.
    """
    if isinstance(term, str):
        yield term
    else:
        try:
            for t in term:
                yield t
        except:
            yield term


def render_pep440(vcs):
    """Convert git release tag into a form that is PEP440 compliant."""
    if vcs is None:
        return None
    tags = vcs.split('-')
    if len(tags) == 1:
        return tags[0]
    else:
        return tags[0] + '+' + '.'.join(tags[1:])


@staticmethod
def is_not_certain(fragment, certainty_threshold):
    """State if a fragment has been assigned with sufficient certainty

        Parameters
        ----------
        fragment : Fragment object
            Collection of images related to the same individual
        certainty_threshold : float
            Lower boundary in [0,1] for the certainty of a fragment

        Returns
        -------
        is_not_certain_flag : bool
            True if the fragment is assigned with high enough certainty

        """
    return fragment.certainty < certainty_threshold


@classmethod
def greater_than_or_equal_to(cls, a):
    """Returns interval of all values greater than or equal to the given value

        >>> print Interval.greater_than_or_equal_to(32)
        [32...)
        """
    return cls(lower_bound=a, lower_closed=True)


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


def getdest_input(linetype='TEL'):
    """
    Method collects user inputs for destination dialstring - TEL or SIP
    INPUTS: linetype as str ('TEL' or 'SIP')
    OUTPUT: Returns str
    """
    import re
    loop = True
    while loop:
        dest = input(f'Enter destination dialstring [{linetype}]: ')
        if dest != '':
            if linetype == 'TEL':
                res = re.match('\\d+', dest)
                if res:
                    loop = False
                else:
                    print(
                        f"Invalid input '{dest}' >> Expecting TEL(E.164) dialstring."
                        )
            elif linetype == 'SIP':
                res = re.match('([^@|\\s]+@[^@]+\\.[^@|\\s]+)', dest)
                if res:
                    loop = False
                else:
                    print(
                        f"Invalid input '{dest}' >> Expecting SIP URI dialstring."
                        )
        else:
            print(f"Empty input '{dest}' >> Expecting {linetype} dialstring.")
    return dest


def get_globus_id_type(uuid):
    """**Not implemented**
    Determine the type of resource a Globus UUID identifies.
    This utility is not comprehensive.

    Arguments:
        uuid (str): A Globus UUID.

    Returns:
        str: The type of resource identified. Types this utility can identify:

                * ``identity``: A user's identity in Globus Auth
                * ``group``: A Globus Group
                * ``endpoint``: A Globus Transfer Endpoint

                This utility cannot detect other types of UUID.
                If the UUID is not one of the above types, or is invalid, the return
                value will be ``unknown``.
    """
    raise NotImplementedError('get_globus_id_type currently not functional')


def zset_score_min_max_example():
    """ Example sorted set with min/max score pagination.
    """
    from uuid import uuid4
    from redis import StrictRedis
    from zato.redis_paginator import ZSetPaginator
    conn = StrictRedis()
    key = 'paginator:{}'.format(uuid4().hex)
    for x in range(1, 18):
        conn.zadd(key, x, chr(96 + x))
    p = ZSetPaginator(conn, key, 2, score_min=5, score_max=13)
    print(p.count)
    print(p.num_pages)
    print(p.page_range)
    page = p.page(3)
    print(page)
    print(page.object_list)
    conn.delete(key)


def mapping_constructor(mapping_type, loader, mapping):
    """Construct a mapping from the representation.

    :param mapping_type: the class of the mapping to construct, must accept a dictionary as a sole constructor argument
        to be compatible.
    :param loader: the yaml loader
    :type loader: :class:`yaml.loader.Loader`
    :param mapping: the mapping representation
    :return: the reconstructed mapping
    """
    yaml_node = loader.construct_mapping(mapping, deep=True)
    return mapping_type(yaml_node)


def getHierarchy(unique_name):
    """Returns a IHierarchy in the catalog with the given unique name."""


@classmethod
def docker(klass, container_id, shell, script, interval, deregister=None):
    """
        Invoke *script* packaged within a running docker container with
        *container_id* at a specified *interval* on the configured
        *shell* using the Docker Exec API.  Optional *register* after which a
        failing service will be automatically deregistered.
        """
    ret = {'docker_container_id': container_id, 'shell': shell, 'script':
        script, 'interval': interval}
    if deregister:
        ret['DeregisterCriticalServiceAfter'] = deregister
    return ret


def validate_type(arg, types):
    """
    >>> types = {'string': 'String'}
    >>> validate_type('string', types)
    'String'
    >>> try:
    ...     validate_type('bbb', types)
    ... except:
    ...     pass
    Error: Field type error, bbb
    """
    if arg not in types:
        print(f'Error: Field type error, {arg}')
        exit(1)
    return types.get(arg)


def applescriptify(s):
    """Escape string for insertion into an AppleScript string.

    .. versionadded:: 1.31

    Replaces ``"`` with `"& quote &"`. Use this function if you want

    to insert a string into an AppleScript script:
        >>> query = 'g "python" test'
        >>> applescriptify(query)
        'g " & quote & "python" & quote & "test'

    Args:
        s (unicode): Unicode string to escape.

    Returns:
        unicode: Escaped string

    """
    return s.replace(u'"', u'" & quote & "')


def assert_utility_signal(library, session, line):
    """Asserts or deasserts the specified utility bus signal.

    Corresponds to viAssertUtilSignal function of the VISA library.

    :param library: the visa library wrapped by ctypes.
    :param session: Unique logical identifier to a session.
    :param line: specifies the utility bus signal to assert. (Constants.UTIL_ASSERT*)
    :return: return value of the library call.
    :rtype: :class:`pyvisa.constants.StatusCode`
    """
    return library.viAssertUtilSignal(session, line)


def add_vbsclassifier(rule):
    """
        add_vbsclassifier

        Add an additional VBS classifier rule file

        @param rule: VBS classifier rule file
        @type rule: C{str}
        @return: None
        """


def my_callback(file_path):
    """Callback for new file"""
    print('New File Created: {:s}'.format(file_path))


def signal_delete_package_in_stripe(sender, **kwargs):
    """Signal: Delete the package in Stripe."""
    package = kwargs.get('instance')
    package.delete_in_stripe()


@staticmethod
def _create_request_url(url: str, params: dict=None):
    """
        Adds query params to the given url

        :param url: the url to extend
        :param params: query params as a keyed dictionary
        :return: the url including the given query params
        """
    if params:
        first_param = True
        for k, v in sorted(params.items(), key=lambda entry: entry[0]):
            if not v:
                continue
            if first_param:
                url += '?'
                first_param = False
            else:
                url += '&'
            url += '%s=%s' % (k, v)
    return url


def non_qualified_code(code):
    """
    Some codes, e.g. ISO 3166-2 subdivision codes, are compound and are formatted as
    "{country_code}-{subdivision_code}". For validation cases we often care about
    extracting the non-qualified subdivision code in such cases.

    """
    return code.split('-', 2)[1]


@classmethod
def fromcache(cls, cache, *args, **kwargs):
    """Initialize index using `cache` and update items.

        >>> cache = Cache()
        >>> index = Index.fromcache(cache, {'a': 1, 'b': 2, 'c': 3})
        >>> index.cache is cache
        True
        >>> len(index)
        3
        >>> 'b' in index
        True
        >>> index['c']
        3

        :param Cache cache: cache to use
        :param args: mapping or sequence of items
        :param kwargs: mapping of items
        :return: initialized Index

        """
    self = cls.__new__(cls)
    self._cache = cache
    self.update(*args, **kwargs)
    return self


@classmethod
def get_no_warning_args_default(cls):
    """Override to set default for --no-warning-args option."""
    return ()


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

    """
    pass


def merge_results(x, y):
    """
    Given two dicts, x and y, merge them into a new dict as a shallow copy.

    The result only differs from `x.update(y)` in the way that it handles list
    values when both x and y have list values for the same key. In which case
    the returned dictionary, z, has a value according to:
      z[key] = x[key] + z[key]

    :param x: The first dictionary
    :type x: :py:class:`dict`
    :param y: The second dictionary
    :type y: :py:class:`dict`
    :returns: The merged dictionary
    :rtype: :py:class:`dict`
    """
    z = x.copy()
    for key, value in y.items():
        if isinstance(value, list) and isinstance(z.get(key), list):
            z[key] += value
        else:
            z[key] = value
    return z


@classmethod
def trait_subclasses(cls, all=False):
    """ Returns a list of the immediate (or all) subclasses of this class.

        Parameters
        ----------
        all : bool
            Indicates whether to return all subclasses of this class. If
            False, only immediate subclasses are returned.

        """
    if not all:
        return cls.__subclasses__()
    return cls._trait_subclasses([])


def _zero_max_weight(fraction_read, c, gamma):
    """
    Get the weight ratio between ones and zeros.

    Parameters
    ----------
    beta:
        Exponent governing decay of 1's to 0's.
    delta:
        Asymptotic ratio for infinite number of samples.

    Returns
    -------
    float:
        Weight ratio between 1's and 0's
    """
    weight = 1 - (1 - c) * (1 - fraction_read) ** gamma
    return weight


def update_animation_flags():
    """Update animation flags

    """
    pass


def mapper(min_val, max_val, perc):
    """
    calculate relative position in delta min/max
    """
    x = abs(max_val - min_val) * perc
    if min_val < 0:
        return x - abs(min_val)
    else:
        return x + min_val


def tick2dayfrac(tick, nbTicks):
    """Conversion tick -> day fraction."""
    return tick / nbTicks


def with_leading_lower(example):
    """
    Changes the leading letter of the text of example `example` to uppercase.
    """
    text = example.text
    for i, c in enumerate(text):
        if not c.isspace():
            text = text[:i] + text[i].lower() + text[i + 1:]
            break
    example.text = text
    return example


def freedom(a):
    """
    return possible number of molecular placements
    """
    n = 1
    for i in range(len(a)):
        if a[i - 1] is a[i]:
            n *= 2
    return n


@staticmethod
def _find_next_eol(output, ind):
    """Find last newline before current position."""
    inext = ind + 1
    while inext < len(output):
        eolnext = output[inext].find('\n')
        if eolnext != -1:
            break
        inext += 1
    else:
        inext = len(output) - 1
        eolnext = len(output[-1]) - 1
    return inext, eolnext


def __call__(context):
    """The context provides a location that the vocabulary can make use of.
        """


def add_scheme_if_missing(url):
    """
    >>> add_scheme_if_missing("example.com/foo")
    'http://example.com/foo'
    >>> add_scheme_if_missing("https://example.com/foo")
    'https://example.com/foo'
    >>> add_scheme_if_missing("//example.com/foo")
    'http://example.com/foo'
    """
    if url.startswith('//'):
        url = 'http:' + url
    if '://' not in url:
        url = 'http://' + url
    return url


def lerp(t, x0, x1):
    """Linearly interpolate between x0 and x1."""
    return x0 + t * (x1 - x0)


@staticmethod
def _manipulatemessagetype(messagetype, inode):
    """ x12 also needs field from GS record to identify correct messagetype """
    return messagetype + inode.record.get('GS08', '')


def grab_collection_year(g):
    """Get collection year from Data_Collection section of proxychimp.Guts"""
    victim = g.pull_section('Data_Collection')[0]
    yr = None
    for ln in victim:
        if 'Collection_Year' in ln:
            ln_split = ln.split(':')
            yr = int(ln_split[-1])
    return yr


def get_environments_with_last_occurrence_date():
    """
        Returns a tuple of all environment and the dates of latest problem
        occurrences in those environments, sorted by those dates descendingly.
        """


def itoa(num, radix):
    """
    Convert int to a sts representation in an arbitrary base, up to 36.
    """
    result = ''
    while num > 0:
        result = '0123456789abcdefghijklmnopqrstuvwxyz'[num % radix] + result
        num //= radix
    return result


@classmethod
def _register_attribute(cls, attr):
    """ Resource subclasses will invoke this method to add a
        resource attribute

        """
    cls._attributes[attr.name] = attr


def _initialize_class_name_map():
    """
    Create a dictionary mapping each ObjectModel
    child to its name.  This is used for cerealizing
    dictionary objects back to ObjectModels
    """
    global _class_name_map
    from parselmouth.delivery import Cost
    from parselmouth.delivery import Goal
    from parselmouth.delivery import Stats
    from parselmouth.delivery import DeliveryMeta
    from parselmouth.delivery import Creative
    from parselmouth.delivery import LineItem
    from parselmouth.delivery import Campaign
    from parselmouth.targeting import TargetingData
    from parselmouth.targeting import AdUnit
    from parselmouth.targeting import Placement
    from parselmouth.targeting import Geography
    from parselmouth.targeting import Technology
    from parselmouth.targeting import DayPart
    from parselmouth.targeting import UserDomain
    from parselmouth.targeting import Custom
    from parselmouth.targeting import VideoContent
    from parselmouth.targeting import VideoPosition
    from parselmouth.targeting import TargetingCriterion
    _class_name_map = {'Cost': Cost, 'Goal': Goal, 'Stats': Stats,
        'DeliveryMeta': DeliveryMeta, 'Creative': Creative, 'LineItem':
        LineItem, 'Campaign': Campaign, 'TargetingData': TargetingData,
        'AdUnit': AdUnit, 'Placement': Placement, 'Geography': Geography,
        'Technology': Technology, 'DayPart': DayPart, 'UserDomain':
        UserDomain, 'Custom': Custom, 'VideoContent': VideoContent,
        'VideoPosition': VideoPosition, 'TargetingCriterion':
        TargetingCriterion}


def _col_widths(lines):
    """Return a list of maximum column widths"""
    widths = []
    for line in lines:
        for i, part in enumerate(line):
            while len(widths) <= i:
                widths.append(0)
            widths[i] = max(len(part), widths[i])
    return widths


def set_force_option(val=True):
    """set_force_option(val=True) -> None

    Set whether the interpreter should prompt to confirm dangerous actions.
    (True means don't.) This is called during setup if the --force option
    was supplied.
    """
    global is_force
    is_force = val


@staticmethod
def digitize(axis_value):
    """simplify any number down to -1, 0, or 1"""
    if axis_value == 0:
        return 0
    return axis_value / abs(axis_value)


def readbinStr(handle, leng=260):
    """Reads file handle by leng bytes and attempts to decode to utf-8."""
    rawbin = handle.read(leng)
    bin = rawbin.strip(b'\x00')
    return bin.decode('utf-8')


def _attributes(f, *args, **kwargs):
    """
        does the work of calling the function decorated by `attributes`
    """
    return f(*args, **kwargs)


@classmethod
def _stringify_action(cls, action):
    """ Convert Pyramid ACL action object to string. """
    action = cls.ACTIONS.get(action, action)
    return action.strip().lower()


def couch_url():
    """Return central couch url"""
    url = 'https://cmsweb.cern.ch/couchdb'
    return url


def version_constraint(version_range):
    """Convert a version_range to a version constraing string"""
    return f'>={version_range[0]},<{version_range[1]}'


def clean_quals(vec):
    """Extracts and cleans qualifier values from the vector of arguments.
    Qualifiers are generally usage or other notes such as "archaic",
    "colloquial", "chemistry", "british", etc.  There is no standard set
    of values for them and the set probably varies from language to
    language."""
    assert isinstance(vec, (list, tuple))
    for x in vec:
        assert isinstance(x, str)
    tags = []
    for i in range(len(vec)):
        x = vec[i]
        i += 1
        if x in ('en', 'fi'):
            print('clean_quals: WARNING: {} in vec: {}'.format(x, vec))
            continue
        while i < len(vec) - 1 and vec[-1] in ('usually', 'often', 'rarely',
            'strongly', 'extremely', 'including', 'chiefly', 'sometimes',
            'mostly', 'with', 'now'):
            x += ' ' + vec[i]
            i += 1
        while i < len(vec) - 2 and vec[i] in ('_', 'and', 'or'):
            x += ' ' + vec[i + 1]
            i += 2
        tags.append(x)
    return tags


@staticmethod
def _readMeta(fd):
    """Read meta array from the top of a file. Read lines until a blank line is reached.
        This function should ideally work for ALL versions of MetaArray.
        """
    meta = ''
    while True:
        line = fd.readline().strip()
        if line == '':
            break
        meta += line
    ret = eval(meta)
    return ret


def call_each_reversed(funcs: list, *args, **kwargs):
    """
    call each func from reversed func list.

    return the last func value or None if func list is empty.
    """
    ret = None
    for func in reversed(funcs):
        ret = func(*args, **kwargs)
    return ret


def extract(txt, begin, end, pos=0):
    """Extract the text between 'begin' and 'end' from 'txt'

    Args:
        txt: String to search in
        begin: First string to be searched for
        end: Second string to be searched for after 'begin'
        pos: Starting position for searches in 'txt'

    Returns:
        The string between the two search-strings 'begin' and 'end' beginning
        with position 'pos' in 'txt' as well as the position after 'end'.

        If at least one of 'begin' or 'end' is not found, None and the original
        value of 'pos' is returned

    Examples:
        extract("abcde", "b", "d")    -> "c" , 4
        extract("abcde", "b", "d", 3) -> None, 3
    """
    try:
        first = txt.index(begin, pos) + len(begin)
        last = txt.index(end, first)
        return txt[first:last], last + len(end)
    except (ValueError, TypeError, AttributeError):
        return None, pos


def cumulative_distribution(distribution):
    """Return normalized cumulative distribution from discrete distribution."""
    cdf = []
    cdf.append(0.0)
    psum = float(sum(distribution))
    for i in range(0, len(distribution)):
        cdf.append(cdf[i] + distribution[i] / psum)
    return cdf


def _filter_rule(args, rule):
    """Check if the given rule passes the filter specified in args.

    Args:
        args (Namespace): The arguments namespace
        rule (Rule): The rule to check

    Return:
        bool: True if the rule passes the filter (and should be included in output)
    """
    if args.pinned:
        return rule.get('auto_update') != True
    return True


def cols_to_cube_root(df, columns):
    """Convert data points to their cube root value so all values are between 0-1 and return new columns of prefixed data.

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

    Returns:
        Original dataframe with additional prefixed columns.
    """
    for col in columns:
        df['cube_root_' + col] = df[col] ** (1 / 3)
    return df


@staticmethod
def bin_bkdist(distance):
    """
        Discretise genomic distances

        :param distance: float

        :return:

        """
    if distance == -1:
        bin_distance = 'diff. chr.'
    elif distance == 0:
        bin_distance = '0'
    elif 1 < distance < 10000.0:
        bin_distance = '1-10 kb'
    elif 10000.0 < distance < 100000.0:
        bin_distance = '10-100 kb'
    elif 100000.0 < distance < 1000000.0:
        bin_distance = '0.1-1 Mb'
    elif 1000000.0 < distance < 10000000.0:
        bin_distance = '1-10 Mb'
    else:
        bin_distance = '>10 Mb'
    return bin_distance


def truncate_string_from_end(string: str, max_len: int) ->str:
    """If the string len is below the max_len, the function returns the same string.
	If the string is above the max len, the function returns only the last max_len characters plus '...' at the beginning."""
    if len(string) <= max_len:
        return string
    return f'Last {max_len} chars: "...{string[-max_len:]}"'


def get_station(args, input_file, stations):
    """Get latitude, longitude and name for each station"""
    count = 1
    with open(input_file) as stream:
        for line in stream:
            if count == 1:
                name = int(line.split(',')[0][12:])
                lat = float(line.split(',')[1][6:-1])
                lon = float(line.split(',')[2][5:-1])
            if count == 2:
                elevation = int(line.split(',')[0].split('=')[-1][2:7])
                qlty_ctrl = line.split(',')[-1].split('=')[-1].strip()
                break
            count += 1
    return lat, lon, name, elevation, qlty_ctrl


def namedtuple_asdict(namedtuple):
    """
    The same as ``namedtuple._adict()``.

    Parameters
    ----------
    namedtuple : collections.namedtuple
    The named tuple to get the dict of
    """
    return namedtuple._asdict()


def validate_options(namespace):
    """Validate any flattened request header option arguments."""
    try:
        start = namespace.start_range
        end = namespace.end_range
    except AttributeError:
        return
    else:
        namespace.ocp_range = None
        del namespace.start_range
        del namespace.end_range
        if start or end:
            start = start if start else 0
            end = end if end else ''
            namespace.ocp_range = 'bytes={}-{}'.format(start, end)


def group_assign(type: int=0):
    """Add selected bones to the chosen bone group

    :param type: Bone Group Index
    :type type: int
    """
    pass


@classmethod
def _msg_to_bytes(cls, msg, msg_id=None, **kwargs):
    """
        将报文对象转换为二进制数组（用于网络通讯）

        @param {object} msg - 报文对象（python对象，json.loads得到的对象）
        @param {string} msg_id=None - 主报文id（用于标明该报文业务类型）
        @param {**kwargs} kwargs - 转换参数，包括
            encoding='utf-8' - 字符编码
            has_sign_info=False - 是否带有签字验证信息（在json文档结尾），如果有，转换时加到字符串中
            sign_str='' - 当有签字验证信息时，验证信息字符串

        @returns {byte[]} - 二进制数组

        """
    if msg is None:
        return bytes()
    _str_ret = cls._msg_to_str(msg, msg_id=msg_id, **kwargs)
    _encoding = cls._get_para_from_kwargs('encoding', default_value='utf-8',
        kwargs=kwargs)
    _msg_bytes = bytes(_str_ret, _encoding)
    return _msg_bytes


def get_max_size_of_cache(connection: 'Connection') ->int:
    """
    Get the upper limit set in FlowDB for the cache size, in bytes.

    Parameters
    ----------
    connection : "Connection"

    Returns
    -------
    int
        Number of bytes in total available to cache tables

    """
    sql = 'SELECT cache_max_size()'
    return int(connection.fetch(sql)[0][0])


def ensure_required(rlist, required):
    """ Check which keys aren't present. """
    not_present = []
    for k in required:
        if k not in rlist:
            not_present.append(k)
    if len(not_present) != 0:
        print(' Skipping: following required fields not present:')
        for k in not_present:
            print('  %s' % k)
        return False
    return True


@staticmethod
def _from_db_object(zun_service, db_zun_service):
    """Converts a database entity to a formal object."""
    for field in zun_service.fields:
        setattr(zun_service, field, db_zun_service[field])
    zun_service.obj_reset_changes()
    return zun_service


def load_np_list(group):
    """ load a numpy list """
    np_list = []
    for key in sorted(group.keys()):
        data = group[key][:]
        np_list.append(data)
    return np_list


def add_edges(g, edges):
    """Add edges to the graph in place."""
    edges.apply(lambda e: g.add_edge(u=e['u_name'], v=e['v_name'], label=e[
        'label'], edge_class=e['edge_class']), axis=1)


@classmethod
def stripChars(cls, string, replaceWith='', notStripChars='', stripAlpha=
    True, stripNum=True, stripSpace=True, stripNewline=True, stripSpecial=True
    ):
    """Strip characters from a string based in the character type.
		"""
    ret = []
    for c in string:
        valid = True
        if c not in notStripChars:
            if c in cls.alpha:
                if stripAlpha:
                    valid = False
            elif c in cls.num:
                if stripNum:
                    valid = False
            elif c.isspace():
                if stripSpace:
                    valid = False
            elif c in cls.newlines:
                if stripNewline:
                    valid = False
            elif c in cls.special:
                if stripSpecial:
                    valid = False
            else:
                valid = False
        if valid:
            ret.append(c)
        else:
            ret.append(replaceWith)
    return ''.join(ret)


def deriv_v_r_func(*, Z_1, Z_2, Z_4, v_φ, ρ, a_0, dderiv_B_φ, B_θ,
    norm_kepler, X, v_r):
    """
    Compute the derivative of v_r
    """
    return (Z_1 * v_φ ** 2 * ρ * norm_kepler - 2 * Z_2 * Z_4 * a_0 *
        norm_kepler + dderiv_B_φ * a_0 * B_θ * (2 * v_φ * norm_kepler - Z_4 *
        X)) / (v_φ ** 2 * ρ * norm_kepler - Z_4 * a_0 * v_r)


def article_figure_09():
    """Figure 9 is  drawing in a word file,  this routine is just a marker
    to indicated that figure 9 has not been forgotten,
    figure from Walker and Indraratna (in press).

    References
    ----------
    .. [1] Walker, R.T.R. and Indraratna, B, (in press) "Moving loads on a
           viscoelastic foundation with special reference to railway
           transition zones". International Journal of Geomechanics.
    """
    print(
        'Figure 9 is  drawing in a word file.  This routine is just a marker to indicated that figure 9 has not been forgotten'
        )


def contact_matrix(d, radius, out=None):
    """calculate contacts from distance matrix

    Parameters
    ----------
    d : array-like
        distance matrix
    radius : float
        distance below which a contact is formed.
    out: array (optional)
        If `out` is supplied as a pre-allocated array of the correct
        shape then it is filled instead of allocating a new one in
        order to increase performance.

    Returns
    -------
    contacts : ndarray
        boolean array of formed contacts
    """
    if out is not None:
        out[:] = d <= radius
    else:
        out = d <= radius
    return out


def get_num_feats(data=None):
    """
    Returns the numerical features in a data set

    Parameters:
    -----------
        data: DataFrame or named Series

    Returns:
    -------
        List:
            A list of all the numerical features in a dataset.
    """
    if data is None:
        raise ValueError("data: Expecting a DataFrame or Series, got 'None'")
    num_features = data.select_dtypes(exclude=['object', 'datetime64']).columns
    return list(num_features)


def module_level_function(param1, param2=None, *args, **kwargs):
    """This is an example of a module level function.

    Function parameters should be documented in the ``Args`` section. The name
    of each parameter is required. The type and description of each parameter
    is optional, but should be included if not obvious.

    If \\*args or \\*\\*kwargs are accepted,
    they should be listed as ``*args`` and ``**kwargs``.

    The format for a parameter is::

        name (type): description
            The description may span multiple lines. Following
            lines should be indented. The "(type)" is optional.

            Multiple paragraphs are supported in parameter
            descriptions.

    Args:
        param1 (int): The first parameter.
        param2 (:obj:`str`, optional): The second parameter. Defaults to None.
            Second line of description should be indented.
        *args: Variable length argument list.
        **kwargs: Arbitrary keyword arguments.

    Returns:
        bool: True if successful, False otherwise.

        The return type is optional and may be specified at the beginning of
        the ``Returns`` section followed by a colon.

        The ``Returns`` section may span multiple lines and paragraphs.
        Following lines should be indented to match the first line.

        The ``Returns`` section supports any reStructuredText formatting,
        including literal blocks::

            {
                'param1': param1,
                'param2': param2
            }

    Raises:
        AttributeError: The ``Raises`` section is a list of all exceptions
            that are relevant to the interface.
        ValueError: If `param2` is equal to `param1`.

    """
    if param1 == param2:
        raise ValueError('param1 may not be equal to param2')
    return True


@staticmethod
def indices_to_bytes(indices, bits=11):
    """
        Converts indices to byte array
        :param indices:
        :param bits:
        :return:
        """
    ind_len = len(indices)
    barr = []
    cidx = 0
    carry = 0
    carry_bits = 0
    avail = bits
    while True:
        cb = 8 - carry_bits
        cons = min(cb, avail)
        carry <<= cons
        carry |= indices[cidx] >> avail - cons & (1 << cons) - 1
        carry_bits += cons
        avail -= cons
        if cb == cons:
            barr.append(carry)
            carry = 0
            carry_bits = 0
        if avail == 0:
            if cidx + 1 == ind_len:
                break
            cidx += 1
            avail = bits
    return bytes(barr)


def quaternion_real(quaternion):
    """Return real part of quaternion.

    >>> quaternion_real([3, 0, 1, 2])
    3.0

    """
    return float(quaternion[0])


def humanize_bitrate(bitrate):
    """Humanize bitrate from integer."""
    if bitrate is not None:
        for divisor, symbol in [(1000 ** 1, 'Kbps'), (1, 'bps')]:
            if bitrate >= divisor:
                break
        return f'{round(bitrate / divisor)} {symbol}'


def __getGraphAttributes__(dataframe):
    """
    Gets all available attributes from a sample dataframe, then repeatedly collects attributes to plot from the user until an empty string is received.
    Returns the list of attributes.
    """
    print('Plottable Attributes ==============================')
    for col in dataframe.columns:
        print('- ' + col)
    print('===================================================\n')
    attributes = []
    shouldGetInput = True
    while shouldGetInput:
        attribute = input('Attribute: ')
        if len(attribute) == 0:
            shouldGetInput = False
        else:
            attributes.append(attribute)
    return attributes


def destination_name(path, delimiter='__'):
    """
    Returns a cli option destination name from attribute path

    **Arguments**

    - path (`list`): attribute path
    - delimiter (`str`): delimiter for nested attributes

    **Returns**

    cli destination name (`str`)
    """
    return '{}'.format(delimiter.join(path))


def _list_from_data(data):
    """Get a new list of all the items in the list since the last
    special token, either an assigner or a list.
    Special token denoted by None, which cannot appear otherwise."""
    for index, item in enumerate(reversed(data)):
        if item is None:
            list_ = data[-index:len(data)]
            del data[-index:len(data)]
            return list_


@staticmethod
def get_value_of_key_from_list_dict(list_dict, selected_key):
    """
        Get value of key from list dict
        :param list_dict:
        :param selected_key:
        :return: list of values that have selected_key in each dict
        Ex: list_dict=[{'id': 1, 'v': 11},
                       {'id': 2, 'v': 22},
                       {'id': 3, 'v': 33}]
             selected_key='id'
          => return [1,2,3]
        """
    result_list = []
    for dict_item in list_dict:
        if selected_key in dict(dict_item).keys():
            result_list.append(dict_item.get(selected_key))
    return result_list


def register_handler(handler):
    """
    Install application-specific HDF5 image handler.

    :param handler: Handler object.
    """
    global _handler
    _handler = handler


def hasnode(node):
    """Returns a bool indicating if a node is known to this store.

        Implementations must only return True for full, binary node values:
        hex nodes, revision numbers, and partial node matches must be
        rejected.

        The null node is never present.
        """


@classmethod
def public_network(cls) ->'Network':
    """Get the :class:`Network` object representing the PUBLIC Network.

        :return: PUBLIC Network
        """
    return cls(cls.PUBLIC_NETWORK_PASSPHRASE)


@staticmethod
def DontVerifySegment(data):
    """
        DontVerifySegment may be used in fetch to skip validation of Data
        packets.
        """
    return True


@classmethod
def from_api_repr(cls, resource, client):
    """Factory:  construct a zone given its API representation

        :type resource: dict
        :param resource: zone resource representation returned from the API

        :type client: :class:`google.cloud.dns.client.Client`
        :param client: Client which holds credentials and project
                       configuration for the zone.

        :rtype: :class:`google.cloud.dns.zone.ManagedZone`
        :returns: Zone parsed from ``resource``.
        """
    name = resource.get('name')
    dns_name = resource.get('dnsName')
    if name is None or dns_name is None:
        raise KeyError(
            'Resource lacks required identity information:["name"]["dnsName"]')
    zone = cls(name, dns_name, client=client)
    zone._set_properties(resource)
    return zone


def get_jsonpath_val(json_obj, path_str):
    """Get json attribute value from a path.

  Args:
    json_obj: json object.
    path_str: attribute path as key1.key2.key3
  Returns:
    value of the given path, if not valid, return None.
  """
    keys = path_str.split('.')
    cur_val = None
    for cur_key in keys:
        if cur_key in json_obj:
            cur_val = json_obj[cur_key]
        else:
            cur_val = None
            break
    return cur_val


def rime_solver(slvr_cfg):
    """ Factory function that produces a RIME solver """
    from montblanc.impl.rime.tensorflow.RimeSolver import RimeSolver
    return RimeSolver(slvr_cfg)


@staticmethod
def match(source_registers, destination_registers):
    """
        Find maximum number of matches from source (previous destinations) to
        destination (current source) registers.

        Return list of two-tuples of matches (src_idx, dst_idx)
        """
    matched_pairs = []
    unmatched_dests = set(destination_registers)
    for dst_idx, dst in enumerate(destination_registers):
        for src_idx, src in enumerate(source_registers):
            if src.llvm_type == dst.llvm_type:
                matched_pairs.append((src_idx, dst_idx))
                unmatched_dests.discard(dst)
    return matched_pairs, unmatched_dests


@classmethod
def fatal_exception_message(typ, err) ->(str, None):
    """
		If the exception was fatal to the connection,
		what message should be given to the user?
		"""
    if typ.try_again(err):
        return None
    return getattr(err, 'strerror', '<strerror not present>')


def __parse_request_range(range_header_text):
    """ Return a tuple describing the byte range requested in a GET request
    If the range is open ended on the left or right side, then a value of None
    will be set.
    RFC7233: http://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7233.html#header.range
    Examples:
      Range : bytes=1024-
      Range : bytes=10-20
      Range : bytes=-999
    """
    left = None
    right = None
    if not range_header_text:
        return left, right
    range_header_text = range_header_text.strip()
    if not range_header_text.startswith('bytes'):
        return left, right
    components = range_header_text.split('=')
    if len(components) != 2:
        return left, right
    components = components[1].split('-')
    try:
        right = int(components[1])
    except:
        pass
    try:
        left = int(components[0])
    except:
        pass
    return left, right


def _test():
    """Run the doctests."""
    import doctest
    doctest.testmod()


def get_constants():
    """ Returns the object that implements IDriverConstants where the printer
        is going to get constant values from.
        """


def next_sol(sol, m_objs, H):
    """
    Create a new solution (sol) by incrementing the value of

        sol[m_objs-2] += 1

    and adjusting the last position of sol

        sol[m_objs-1] = H - sum(new_sol)

    The resulting solution (new_sol) can be invalid.

    Input
    sol         list, solution with m_objs integers
    m_objs      int, number of objectives
    H           int, granularity >= 2

    Output
    new_sol     list, a (possibly) valid solution
    """
    new_sol = [0] * m_objs
    for i in range(m_objs - 1):
        new_sol[i] = sol[i]
    new_sol[m_objs - 2] += 1
    new_sol[m_objs - 1] = H - sum(new_sol)
    return new_sol


def subscribe(requestor, service, nodeIdentifier, subscriber):
    """
        Called when a subscribe request has been received.

        @param requestor: The entity the request originated from.
        @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}
        @param service: The entity the request was addressed to.
        @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}
        @param nodeIdentifier: The identifier of the node to subscribe to.
        @type nodeIdentifier: C{unicode}
        @param subscriber: The entity to be subscribed.
        @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}
        @return: A deferred that fires with a
                 L{Subscription<wokkel.pubsub.Subscription>}.
        @rtype: L{Deferred<twisted.internet.defer.Deferred>}
        """


def append_real_ensemble(member, x):
    """
    Append an element to the an existing ensemble

    The uncertain number ``x`` must be elementary and have the
    same number of degrees of freedom as other members
    of the ensemble (not checked).

    """
    assert x.df == member._node.df
    assert x.is_elementary
    assert x._node.independent == False
    member._node.ensemble.add(x._node.uid)
    x._node.ensemble = member._node.ensemble


def GetExportPath(G2frame):
    """Determines the default location to use for writing files. Tries sequentially
    G2frame.LastExportDir and G2frame.LastGPXdir.

    :returns: a string containing the path to be used when writing files or '.'
      if none of the above are specified.
    """
    if G2frame.LastExportDir:
        return G2frame.LastExportDir
    elif G2frame.LastGPXdir:
        return G2frame.LastGPXdir
    else:
        return '.'


@staticmethod
def _default_next_char(particle):
    """
        Default next character implementation - linear progression through
        each character.
        """
    return particle.chars[(len(particle.chars) - 1) * particle.time //
        particle.life_time]


def delete_share():
    """Stop sharing a path"""
    raise NotImplementedError


def initialize_back_prop(AL, Y, AL_prime, Y_prime):
    """
    Initialize backward propagation

    Arguments:
    :param AL -- output of the forward propagation L_model_forward()... i.e. neural net predictions   (if regression)
                                                                 i.e. neural net probabilities (if classification)
          >> a numpy array of shape (n_y, m) where n_y = no. outputs, m = no. examples

    :param Y -- true "label" (classification) or "value" (regression)
         >> a numpy array of shape (n_y, m) where n_y = no. outputs, m = no. examples

    :param AL_prime -- the derivative of the last layer's activation output(s) w.r.t. the inputs x: AL' = d(AL)/dX
                >> a numpy array of size (n_y, n_x, m) where n_y = no. outputs, n_x = no. inputs, m = no. examples

    :param Y_prime -- the true derivative of the output(s) w.r.t. the inputs x: Y' = d(Y)/dX
               >> a numpy array of shape (n_y, n_x, m) where n_y = no. outputs, n_x = no. inputs, m = no. examples

    Returns:
    :return dAL -- gradient of the loss function w.r.t. last layer activations: d(L)/dAL
           >> a numpy array of shape (n_y, m)

    :return dAL_prime -- gradient of the loss function w.r.t. last layer activations derivatives: d(L)/dAL' where AL' = d(AL)/dX
                 >> a numpy array of shape (n_y, n_x, m)
    """
    n_y, _ = AL.shape
    Y = Y.reshape(AL.shape)
    dAL = AL - Y
    dAL_prime = AL_prime - Y_prime
    return dAL, dAL_prime


def intr(n):
    """Returns a correctly rounded integer"""
    return int(round(n))


@classmethod
def zero(cls, **kwd):
    """
        Return the zero polynomial.
        """
    return cls(**kwd)


def hide_link(url: str) ->str:
    """
    Hide URL (HTML only)
    Can be used for adding an image to a text message

    :param url:
    :return:
    """
    return f''


def p_class_name(p):
    """class_name : namespace_name
                  | NS_SEPARATOR namespace_name
                  | NAMESPACE NS_SEPARATOR namespace_name"""
    if len(p) == 2:
        p[0] = p[1]
    elif len(p) == 3:
        p[0] = p[1] + p[2]
    else:
        p[0] = p[1] + p[2] + p[3]


def _alphabetize_actions(arg_parser):
    """Alphabetize arg parser actions for the sake of nicer help printouts."""
    for g in arg_parser._action_groups:
        g._group_actions.sort(key=lambda opt: opt.dest)


def without(*things):
    """strip things from incoming things"""


def has_topic_models(args):
    """Returns whether some kind of topic model

    """
    return args.topic_model or args.topic_models or args.topic_model_tag


@staticmethod
def get_raw_units():
    """Include the settings for the units used by the instrument.

        The units are defined w.r.t. the SI units ('unit-fractions'; currently only units that are multiples of
        Si units can be used). For example, for current defined in mA, the value for the
        current unit-fraction will be 0.001.

        Returns: dictionary containing the unit-fractions for current, charge, and mass

        """
    raw_units = dict()
    raw_units['voltage'] = 1.0
    raw_units['current'] = 1.0
    raw_units['charge'] = 1.0
    raw_units['mass'] = 0.001
    raw_units['energy'] = 1.0
    return raw_units


def is_onion_url(url):
    """
    returns True/False depending on if a URL looks like a Tor hidden service
    (.onion) or not.
    This is designed to false as non-onion just to be on the safe-ish side,
    depending on your view point. It requires URLs like: http://domain.tld/,
    not http://domain.tld or domain.tld/.

    This can be optimized a lot.
    """
    try:
        url_parts = url.split('/')
        domain = url_parts[2]
        tld = domain.split('.')[-1]
        if tld == 'onion':
            return True
    except Exception:
        pass
    return False


def list_numbering_start(attrs):
    """extract numbering from list element attributes"""
    if 'start' in attrs:
        return int(attrs['start']) - 1
    else:
        return 0


@classmethod
def set_toolbox_path(cls):
    """Update the mimodd_tool_conf.xml file installed as part of the
        package with an absolute tool_path to the package xml wrappers."""
    with open(cls.tool_conf_file, 'r', encoding='utf-8') as sample:
        template = sample.readlines()[1:]
    with open(cls.tool_conf_file, 'w', encoding='utf-8') as out:
        out.write('<toolbox tool_path="{0}">\n'.format(cls.
            pkg_galaxy_data_path))
        out.writelines(template)


def set_uri(name, writecap, readcap=None, metadata=None, overwrite=True):
    """I add a child (by writecap+readcap) at the specific name. I return
        a Deferred that fires when the operation finishes. If overwrite= is
        True, I will replace any existing child of the same name, otherwise
        an existing child will cause me to return ExistingChildError. The
        child name must be a unicode string.

        The child caps could be for a file, or for a directory. If you have
        both the writecap and readcap, you should provide both arguments.
        If you have only one cap and don't know whether it is read-only,
        provide it as the writecap argument and leave the readcap as None.
        If you have only one cap that is known to be read-only, provide it
        as the readcap argument and leave the writecap as None.
        The filecaps are typically obtained from an IFilesystemNode with
        get_uri() and get_readonly_uri().

        If metadata= is provided, I will use it as the metadata for the named
        edge. This will replace any existing metadata. If metadata= is left
        as the default value of None, I will set ['mtime'] to the current
        time, and I will set ['ctime'] to the current time if there was not
        already a child by this name present. This roughly matches the
        ctime/mtime semantics of traditional filesystems.  See the
        "About the metadata" section of webapi.txt for futher information.

        If this directory node is read-only, the Deferred will errback with a
        NotWriteableError."""


def __call__(*args, **kwargs):
    """
        Function-like syntax to execute a dispatched call.
        """
    return args[0].execute(args[1:], kwargs)


def get_druggable_pockets(list_of_pockets):
    """Get a dict of PDB with a dict of Pockets object as entry, output a list of druggable pockets"""
    new_dict = {}
    for k in list_of_pockets.keys():
        new_dict[k] = {}
        for p in list_of_pockets[k].keys():
            if list_of_pockets[k][p].druggable == 'TRUE':
                new_dict[k][p] = list_of_pockets[k][p]
    key_to_del = []
    for k in new_dict.keys():
        if not new_dict[k]:
            key_to_del.append(k)
    for k in key_to_del:
        new_dict.pop(k)
    return new_dict


def freestyle_add_face_marks_to_keying_set():
    """Add the data paths to the Freestyle Face Mark property of selected polygons to the active keying set

    """
    pass


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

        :param SecondaryTeamRequestReminderDetails val:
        :rtype: TeamMergeRequestReminderExtraDetails
        """
    return cls('secondary_team', val)


@classmethod
def header_hash(cls, header):
    """
        Given a header return the hash for sibcoin.
        Need to download `x11_gost_hash` module
        Source code: https://github.com/ivansib/x11_gost_hash
        """
    import x11_gost_hash
    return x11_gost_hash.getPoWHash(header)


def InStr(data='', *strs):
    """
    Es-Valida si un string esta dentros de una lista de string

    En-Validate if a string is inside a string list

    test:

    >>> InStr("a","a","b","c")
    True
    >>> InStr("a","b","c")
    False
    """
    if len(strs) <= 0:
        return False
    for item in strs:
        if data == item:
            return True
    return False


def cumprod(array, *args, **kwargs):
    """
    Returns the cumulative product of array elements.

    See Also
    --------
    Array.cumprod
    """
    return array.cumprod(*args, **kwargs)


def __call__(cls, value, names=None, module=None, type=None):
    """Either returns an existing member, or creates a new enum class.

        This method is used both when an enum class is given a value to match
        to an enumeration member (i.e. Color(3)) and for the functional API
        (i.e. Color = Enum('Color', names='red green blue')).

        When used for the functional API: `module`, if set, will be stored in
        the new class' __module__ attribute; `type`, if set, will be mixed in
        as the first base class.

        Note: if `module` is not set this routine will attempt to discover the
        calling module by walking the frame stack; if this is unsuccessful
        the resulting class will not be pickleable.

        """
    if names is None:
        return cls.__new__(cls, value)
    return cls._create_(value, names, module=module, type=type)


def compute_intersection_length(A, B):
    """Compute the intersection length of two tuples.
    Args:
        A: a (speaker, start, end) tuple of type (string, float, float)
        B: a (speaker, start, end) tuple of type (string, float, float)

    Returns:
        a float number of the intersection between `A` and `B`
    """
    max_start = max(A[1], B[1])
    min_end = min(A[2], B[2])
    return max(0.0, min_end - max_start)


@classmethod
def get(cls, top, parent):
    """
        Get various attributes from the lldpAdjEp
        :param parent:
        :param top: the topSystem level json object
        :returns: list of Switch bridge domain
        """
    cls.check_parent(parent)
    result = []
    adjEp_data = top.get_subtree('lldpAdjEp', parent.attr['dn'])
    for adjEp_object in adjEp_data:
        adjEp = cls()
        adjEp._populate_from_attributes(adjEp_object['lldpAdjEp']['attributes']
            )
        adjEp.attr['dn'] = str(adjEp_object['lldpAdjEp']['attributes']['dn'])
        adjEp._parent = parent
        adjEp._parent.add_child(adjEp)
        result.append(adjEp)
    return result


@staticmethod
def __evaluate__(x_obj, y_obj):
    """Perform a not equal on int or float."""
    return x_obj != y_obj


def defaultSetAuthCookie(resp, cookie_name, cookie_value):
    """Set the authorisation cookie"""


def display_results_header(stats):
    """
    Nice results display.
    """
    print('\n Ping Sweep')
    print(' ==========')
    print(' target name: %s' % stats['host_name'])
    print(' ping count:  %d' % stats['count_send'])
    print(' timeout:     %d ms' % stats['timeout'])
    print(' pause time:  %d ms' % stats['time_pause'])
    print()
    head_A = '  Size (bytes)  |       Ping Times (ms)         | Lost Packets'
    head_B = ' Payload Packet |  min    avg    [std]     max  | All  T   C '
    print(head_A)
    print(head_B)
    head_C = ' ' + '-' * (len(head_B) - 1)
    print(head_C)


def calc_theoretical_noise_dr(imax, theoretical_noise, nsigma):
    """
    Calculates the theoretical noise dynamic range
    theoretical_noise (float): the theoretical noise of the observation
    returns (float): the theoretical noise dynamic range
    """
    theoretical_noise_dr = imax / (nsigma * theoretical_noise)
    return theoretical_noise_dr


def create_dns_str(dns=''):
    """
    Creates a Subject Alternative Name formatted string from a comma-separated string
    :return: comma-separated SAN formatted string
    """
    separator = ','
    formatted_dns = []
    for d in dns.split(separator):
        formatted_dns.append('DNS:' + d)
    return (separator + ' ').join(formatted_dns)


def p_is_reference(p):
    """is_reference : AND
                    | empty"""
    p[0] = p[1] is not None


def prep_filesize(file_size):
    """
    Convert file size to float.

    :param file_size: Number to parse.
    :type file_size: float
    """
    if file_size is None:
        file_size = 0.0
    fsize = float(file_size)
    return fsize


def close():
    """
        Close all pooled connections and disable the pool.
        """
    pass


def full_1d(length, fill_value, dtype, ctx):
    """Create a 1D tensor full of the fill_value.

    Parameters
    ----------
    shape : int
        The length of the vector.
    fill_value : int
        The filled value.
    dtype : data type
        It should be one of the values in the data type dict.
    ctx : context
        The device of the result tensor.

    Returns
    -------
    Tensor
        A result 1D tensor
    """
    pass


def _receive_release_rq(event):
    """Standard logging handler for receiving an A-RELEASE-RQ PDU."""
    pass


def _get_dict_from_protolongtolongmultimap(proto_map):
    """
    Convert the ProtoLongToLongMultiMap_pb2 type to a simple dict.
    """
    if len(proto_map.keys.elements) != len(proto_map.values):
        raise IndexError('array length mismatch')
    new_dict = {}
    for key, array_value in zip(proto_map.keys.elements, proto_map.values):
        value_list = []
        for value in array_value.elements:
            value_list.append(value)
        new_dict[key] = value_list
    return new_dict


def write_ubi_file(filename, ubilist):
    """ save 3x3 matrices into file """
    f = open(filename, 'w')
    for u in ubilist:
        f.write('%f %f %f\n' % (u[0][0], u[0][1], u[0][2]))
        f.write('%f %f %f\n' % (u[1][0], u[1][1], u[1][2]))
        f.write('%f %f %f\n\n' % (u[2][0], u[2][1], u[2][2]))
    f.close()


def get_quantum_numbers():
    """Return a set of iterators over the quantum numbers for the
        basis."""


def no_longer_stale():
    """
        Produce a new (or the original) object that is in the normal state
        and return it.

        :return: Another `IStaleAware`.
        """


def nokey(item):
    """
    Dummy function to apply to items without a key
    """
    return 'Unspecified'


def median(xs, sort=True):
    """Returns the median of an unsorted or sorted numeric vector.

    @param xs: the vector itself.
    @param sort: whether to sort the vector. If you know that the vector is
      sorted already, pass C{False} here.
    @return: the median, which will always be a float, even if the vector
      contained integers originally.
    """
    if sort:
        xs = sorted(xs)
    mid = int(len(xs) / 2)
    if 2 * mid == len(xs):
        return float(xs[mid - 1] + xs[mid]) / 2
    else:
        return float(xs[mid])


def boundary(value, minvalue, maxvalue):
    """Limit a value between a minvalue and maxvalue."""
    return min(max(value, minvalue), maxvalue)


def handle_import(destination_tree, src_entry):
    """ Add a missing import statement

    Args:
        destination_tree (ast): An ast generated from the destination file
        src_entry (ast node): An ast node found missing from the destination_tree

    """
    destination_tree.body.insert(0, src_entry)
    return destination_tree


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

    The ".dev0" means dirty.

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


def rm_lb_hyphens(plain_root, logger, ignore=['.json', '.log', '.err']):
    """
    Looks for a hyphen followed by whitespace or a line break.

    Reconstructs word and checks to see if the result exists in either
    WordNet or the OS's default spellchecker dictionary. If so,
    replaces fragments with reconstructed word.

    :param plain_root: The name of the directory containing plain-text
        files.
    :type plain_root: string

    :param logger: Logger that handles logging for the given directory.
    :type logger: Logger

    :param ignore: List of file extensions to ignore in the directory.
    :type ignore: list of strings, optional

    :returns: None
    """
    pass


def parse(lines):
    """
        Returns new object with this element which is trying to parse

        lines: list of lines to parse

        returns: tuple (ORGElement or its child, remaining_lines)

        remaining_lines - list of lines that are not parsed

        if parsing cannot be done then (None, lines) is returned
        """
    pass


def validate(job):
    """
    Perform user specific payload/job validation.

    :param job: job object.
    :return: Boolean (True if validation is successful).
    """
    return True


def get_user_by_email(email):
    """Returns user with given `email` or None if not found."""


@staticmethod
def pack(val):
    """Return a string representation of ``val``.

        Args:
            val: The :class:`datetime.date` object to convert.

        Returns:
            The ISO 8601-representation of ``val`` (``YYYY-MM-DD``).
        """
    return val.isoformat() if val is not None else None


def sortJobs(jobTypes, options):
    """ Return a jobTypes all sorted.
    """
    longforms = {'med': 'median', 'ave': 'average', 'min': 'min', 'total':
        'total', 'max': 'max'}
    sortField = longforms[options.sortField]
    if (options.sortCategory == 'time' or options.sortCategory == 'clock' or
        options.sortCategory == 'wait' or options.sortCategory == 'memory'):
        return sorted(jobTypes, key=lambda tag: getattr(tag, '%s_%s' % (
            sortField, options.sortCategory)), reverse=options.sortReverse)
    elif options.sortCategory == 'alpha':
        return sorted(jobTypes, key=lambda tag: tag.name, reverse=options.
            sortReverse)
    elif options.sortCategory == 'count':
        return sorted(jobTypes, key=lambda tag: tag.total_number, reverse=
            options.sortReverse)


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

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

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


def decode_response(client_message, to_object=None):
    """ Decode response from client message"""
    parameters = dict(response=None)
    parameters['response'] = client_message.read_bool()
    return parameters


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


def hhv(series, n):
    """
    求series在n个周期内的最高值

        注意: n为0的情况下, 或当n为有效值但当前的series序列元素个数不足n个, 函数返回 NaN 序列

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

        n (int): 周期

    Returns:
        pandas.Series: 最高值序列

    Example::

        from tqsdk import TqApi, TqSim, tafunc

        api = TqApi(TqSim())
        klines = api.get_kline_serial("CFFEX.IF1908", 24 * 60 * 60)
        hhv = tafunc.hhv(klines.high, 4)  # 求4个周期最高价的最大值, 即4周期高点(包含当前k线)
        print(list(hhv))
    """
    hhv_data = series.rolling(n).max()
    return hhv_data


@staticmethod
def _node(name: str, attribute: str):
    """
        Creates an node.

        :param name: The name of the node.
        :param attribute: The attributes.
        :return: A string to represents the node.
        """
    return '"{0}" [{1}]\n'.format(name, attribute)


def remap_dict(d, map):
    """
    Utility function to remap state dict keys according to var_map.
    """
    out = {}
    for new_key, key in map.iteritems():
        out[new_key] = d[key]
    return out


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

        :param RelocationBatchV2Result val:
        :rtype: RelocationBatchV2Launch
        """
    return cls('complete', val)


@classmethod
def calculate_acr(cls, is_extended, from_id, to_id, rtr_only=False, rtr_too
    =True):
    """
        Calculates ACR using CAN-ID range as parameter.

        :param bool is_extended: If True parameters from_id and to_id contains 29-bit CAN-ID.
        :param int from_id: First CAN-ID which should be received.
        :param int to_id: Last CAN-ID which should be received.
        :param bool rtr_only: If True only RTR-Messages should be received, and rtr_too will be ignored.
        :param bool rtr_too: If True CAN data frames and RTR-Messages should be received.
        :return: Value for ACR.
        :rtype: int
        """
    return (from_id & to_id) << 3 | (4 if rtr_only else 0
        ) if is_extended else (from_id & to_id) << 21 | (1048576 if
        rtr_only else 0)


def _are_compatible(left, right):
    """Return True if both arguments are compatible metadata versions.

    Parameters
    ----------
    left: MetadataVersion
    right: MetadataVersion
    """
    return left.major == right.major


def common_filters(marker=None, limit=None, sort_key=None, sort_dir=None,
    fields=None):
    """Generate common filters for any list request.

    :param marker: entity ID from which to start returning entities.
    :param limit: maximum number of entities to return.
    :param sort_key: field to use for sorting.
    :param sort_dir: direction of sorting: 'asc' or 'desc'.
    :param fields: a list with a specified set of fields of the resource
                   to be returned.
    :returns: list of string filters.
    """
    filters = []
    if isinstance(limit, int) and limit > 0:
        filters.append('limit=%s' % limit)
    if marker is not None:
        filters.append('marker=%s' % marker)
    if sort_key is not None:
        filters.append('sort_key=%s' % sort_key)
    if sort_dir is not None:
        filters.append('sort_dir=%s' % sort_dir)
    if fields is not None:
        filters.append('fields=%s' % ','.join(fields))
    return filters


@classmethod
def init_root(cls, info):
    """
        Creates a the root node of a channel tree.
        """
    return cls(info, None, None, None)


def _delitem_via_pathlist(external_dict, path_list, **kwargs):
    """
        y = {'c': {'b': 200}}
        _delitem_via_pathlist(y,['c','b'])
    """
    if 's2n' in kwargs:
        s2n = kwargs['s2n']
    else:
        s2n = 0
    if 'n2s' in kwargs:
        n2s = kwargs['n2s']
    else:
        n2s = 0
    this = external_dict
    for i in range(0, path_list.__len__() - 1):
        key = path_list[i]
        if n2s == 1:
            key = str(key)
        if s2n == 1:
            try:
                int(key)
            except:
                pass
            else:
                key = int(key)
        this = this.__getitem__(key)
    this.__delitem__(path_list[-1])
    return external_dict


def list_projects():
    """Return the list of available projects"""


def _gcd(a, b):
    """Calculate the greatest common divisor of a and b"""
    while b:
        a, b = b, a % b
    return a


def centralmoment(vi, k):
    """
    Converts raw distribution moments to central moments

    Parameters
    ----------
    vi : array
        The first four raw distribution moments
    k : int
        The central moment (0 to 4) to calculate (i.e., k=2 is the variance)

    Returns
    -------
    cm : scalar
        The central moment itself

    """
    if k == 0:
        ans = 1
    elif k == 1:
        ans = 0
    elif k == 2:
        ans = vi[2] - vi[1] ** 2
    elif k == 3:
        ans = vi[3] - 3 * vi[2] * vi[1] + 2 * vi[1] ** 3
    elif k == 4:
        ans = vi[4] - 4 * vi[3] * vi[1] + 6 * vi[2] * vi[1] ** 2 - 3 * vi[1
            ] ** 4
    else:
        print('Can only calculate central moments k = 0 to 4. Sorry.')
        ans = None
    return ans


@classmethod
def serialize(cls, value, *args, **kwargs):
    """Serialize a value to be exported

        `cls.serialize` should always return an unicode value, except for
        BinaryField
        """
    if value is None:
        value = ''
    return value


def generate_spliced_fasta(fasta_path, gtf_path, out_path):
    """Generate a spliced FASTA using the genome and GTF.

    This function assumes the order in which the chromosomes appear in the
    genome FASTA is identical to the order in which they appear in the GTF.
    Additionally, the GTF must be sorted by start position.
    The spliced FASTA contains entries of length 2 * (k - 1) for k = 31,
    centered around exon-exon splice junctions (any overlapping regions are
    collapsed).

    :param fasta_path: path to genomic FASTA file
    :type fasta_path: str
    :param gtf_path: path to GTF file
    :type gtf_path: str
    :param out_path: path to spliced FASTA to generate
    :type out_path: str

    :return: path to generated spliced FASTA
    :rtype: str
    """
    pass


def remove_prefix(text, prefix):
    """
    https://stackoverflow.com/questions/16891340/remove-a-prefix-from-a-string/16892491#16892491
    """
    return text[text.startswith(prefix) and len(prefix):]


def get_count_value(obj):
    """
    Returns count of child objects from LLDB value.

    :param lldb.SBValue obj: LLDB value object.
    :return: Count of child objects from LLDB value.
    :rtype: int | None
    """
    if obj is None:
        return None
    if obj.GetValue() is None or obj.GetValueAsUnsigned() == 0:
        return 0
    return obj.GetNumChildren()


def provider_parser(subparser):
    """Configure provider parser for Linode V4"""
    subparser.add_argument('--auth-token', help=
        'specify api key for authentication')


def parse_connection_string_libpq(connection_string):
    """parse a postgresql connection string as defined in
    http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING"""
    fields = {}
    while True:
        connection_string = connection_string.strip()
        if not connection_string:
            break
        if '=' not in connection_string:
            raise ValueError(
                'expecting key=value format in connection_string fragment {!r}'
                .format(connection_string))
        key, rem = connection_string.split('=', 1)
        if rem.startswith("'"):
            asis, value = False, ''
            for i in range(1, len(rem)):
                if asis:
                    value += rem[i]
                    asis = False
                elif rem[i] == "'":
                    break
                elif rem[i] == '\\':
                    asis = True
                else:
                    value += rem[i]
            else:
                raise ValueError('invalid connection_string fragment {!r}'.
                    format(rem))
            connection_string = rem[i + 1:]
        else:
            res = rem.split(None, 1)
            if len(res) > 1:
                value, connection_string = res
            else:
                value, connection_string = rem, ''
        fields[key] = value
    return fields


def solidsFluxPembNose(dp, db, emf, umf, us):
    """
    Calculates the solids entrainment flux for the surface of a bubbling bed
    with the bubble nose ejection model of Pemberton and Davidsion (Chem. Eng.
    Sci., 1986, 41, pp. 243-251). This model is suitable if there is a single
    bubble in the bed.

    Parameters
    ----------
    dp : float
        Particle diameter [m]
    db : float
        Bubble diameter [m]
    emf : float
        Void fraction at minimum fluidization [-]
    umf : float
        Minimum fluidization velocity [m/s]
    us : float
        Superficial gas velocity [m/s]

    Returns
    -------
    F0 : float
        Solids entrainment flux at the top of the bed [kg/m^2/s]
    """
    F0 = 3.0 * dp / db * (1 - emf) * (us - umf)
    return F0


@staticmethod
def supports_dry_runs():
    """ Do we support dry runs?

        Returns:
            bool: True
        """
    return True


def post_upgrade():
    """Post-upgrade checks."""
    pass


def derivate(f, a, d=10 ** -8, left=False):
    """
    estimate derivate
    :param f: function float -> float
    :param a: point
    :param d: little piece of increment
    :param left: if True, will derivate f from left (from right by default)
    :return:
    """
    return (f(a + d) - f(a)) / d if not left else (f(a) - f(a + d)) / d


def __call__(data, sw1, sw2):
    """Called to test data, sw1 and sw2 for error.

        @param data:       apdu response data
        @param sw1, sw2:   apdu data status words

        Derived classes must raise a L{smartcard.sw.SWException} upon error."""
    pass


@classmethod
def get_widget_error(cls, error, status, translate):
    """Get widget for a given error"""
    if hasattr(error, 'widget'):
        widget = error.widget
        if widget is not None:
            status.setdefault('widgets', []).append({'id': widget.id,
                'name': widget.name, 'label': translate(widget.label),
                'message': translate(error.message)})
        else:
            status.setdefault('messages', []).append({'message': translate(
                error.message)})
    else:
        status.setdefault('messages', []).append(translate(error.message))


def Distance(x, y, x0, y0):
    """
    Distance - returns the linear distance between 2 points

    Parameters
    ----------
        x: float or ndarray of floats
            x-coordinate of point1

        y: float or ndarray of floats
            y-coordinate of point1

        x0: float or ndarray of floats
            x-coordinate of point2

        y0: float or ndarray of floats
            y-coordinate of point2

    Returns
    -------
    return d
        d: float or ndarray of floats
            straight line distance between the 2 points

    N.B. all ndarrays must be the same size
    """
    d = ((x - x0) ** 2 + (y - y0) ** 2) ** 0.5
    return d


@classmethod
def is_valid(cls, *args):
    """Returns true if the arguments are valid cron pattern"""
    try:
        return bool(cls(*args))
    except (ValueError, KeyError):
        return False


def get(isamAppliance, id, check_mode=False, force=False):
    """
    Retrieve a Junction Mapping
    """
    return isamAppliance.invoke_get('Retrieve a Junction Mapping',
        '/wga/jmt_config/{0}'.format(id))


def skip_deleted_videos(item):
    """ filter func to filter-out deleted videos from list """
    return item['snippet']['title'] != 'Deleted video' and item['snippet'][
        'description'] != 'This video is unavailable.'


@classmethod
def from_dict(cls, obj):
    """Create an instance from a dict.

        Keys in the dict should match parameter names"""
    cls._check_keys(obj)
    return cls(**obj)


def find_between(s, first, last):
    """
    Find sting between two sub-strings
    Args:
        s: Main string
        first: first sub-string
        last: second sub-string
    Example find_between('[Hello]', '[', ']')  -> returns 'Hello'
    Returns:
        String between the first and second sub-strings, if any was found otherwise returns an empty string
    """
    try:
        start = s.index(first) + len(first)
        end = s.index(last, start)
        return s[start:end]
    except ValueError:
        return ''


def get_highest_task_parent(task=False):
    """
            Get the object containing the highest ITask object
            or the highest ITask object if task is True
        """


def pruneScope(target_scope, our_scope):
    """pruneScope(list A, list B) -> list

Given two lists of strings (scoped names), return a copy of list A
with any prefix it shares with B removed.

  e.g. pruneScope(['A', 'B', 'C', 'D'], ['A', 'B', 'D']) -> ['C', 'D']"""
    if not our_scope:
        return target_scope
    tscope = target_scope[:]
    i = 0
    while len(tscope) > 0 and i < len(our_scope) and tscope[0] == our_scope[i]:
        del tscope[0]
        i = i + 1
    return tscope


@classmethod
def pctNemaUnbalance(cls, Vph):
    """@return Nema unbalance"""
    VMag = [None] * 3
    _0 = True
    i = 0
    while True:
        if _0 is True:
            _0 = False
        else:
            i += 1
        if not i < 3:
            break
        VMag[i] = Vph[i].abs()
    VAvg = 0.0
    _1 = True
    i = 0
    while True:
        if _1 is True:
            _1 = False
        else:
            i += 1
        if not i < 3:
            break
        VAvg = VAvg + VMag[i]
    VAvg = VAvg / 3.0
    maxDiff = 0.0
    _2 = True
    i = 0
    while True:
        if _2 is True:
            _2 = False
        else:
            i += 1
        if not i < 3:
            break
        maxDiff = cls.Math.max(maxDiff, cls.Math.abs(VMag[i] - VAvg))
    if VAvg != 0.0:
        return maxDiff / VAvg * 100.0
    else:
        return 0


def create_url(token, url, customerid):
    """ Creates the url for sending data to NodePing

    Formats the url based on whether or not the
    customerid is None

    :type token: string
    :param token: Your NodePing API token
    :type url: string
    :param url: full URL to API excluding the token and/or custid
    :type customerid: string
    :param customerid: Optional subaccount ID for your account
    :return: URL that will be used for HTTP request
    :rtype: string
    """
    if '?' in url:
        token_str = '&token='
    else:
        token_str = '?token='
    if customerid:
        url = '{0}{1}{2}&customerid={3}'.format(url, token_str, token,
            customerid)
    else:
        url = '{0}{1}{2}'.format(url, token_str, token)
    return url


def obtain_neighbors(edges, point, num_neigh=3, step=1):
    """Investigates the directional neighbors of a pixel, searching
    for elements of a set into an image.

    Parameters
    ----------
    edges : array
        Binary input image representing the region edge.
    point : list
        Point coordinates of the central pixel.
    num_neigh : int, optional (default : 3)
        Number of neighbors to obtain in each side.
    step : int, optional (default : 1)
        Space given between one point and the other.

    Returns
    -------
    pts_neigh : list
        List containing the coordinates for each neighbor point
        contained in the edges image.
    """
    pts_neigh = []
    x_zero, y_zero = point
    idx = edges.index([x_zero, y_zero])
    pts_neigh.append([x_zero, y_zero])
    for num in range(num_neigh):
        pts_neigh.append(edges[idx - step * num])
        try:
            pts_neigh.append(edges[idx + step * num])
        except IndexError:
            aux_idx = len(edges) - 1 - idx
            pts_neigh.append(edges[aux_idx + step * num])
    return pts_neigh


@classmethod
def wordTooLong(cls, word, font, max_length, justify_chars=0):
    """test if a single word is too long to the displayed with the given font.
        @word: the word to check
        @font: the pygame.Font to use
        @max_length: the max length of the word
        @justify_chars: an integer that add a number of spaces at the worrd total length.
        @return: True if the word will be longer
        """
    return font.size(' ' * justify_chars + word)[0] > max_length


def stripnull(string):
    """Return string truncated at first null character.

    Clean NULL terminated C strings.

    >>> stripnull(b'string\\x00')
    b'string'

    """
    i = string.find(b'\x00')
    return string if i < 0 else string[:i]


def vertex_group_remove_from():
    """Remove the selected vertices from active or all vertex group(s)

    """
    pass


def layer_merge():
    """Merge the current layer with the layer below

    """
    pass


def add_once(function, action):
    """
    Filters TCL functions to avoid multiple instances
    of exactly identical functions in the script
    (just for aesthetics, honestly)
    :param function: a Function object that returns the TCL code (see library below)
    :param action: either Action or SimultaneousAction
    :return: str, TCL code
    """
    if function not in action.scene.functions:
        action.scene.functions.append(function)
        return function()
    else:
        return ''


def convert_to_codec_key(value):
    """
    Normalize code key value (encoding codecs must be lower case and must
    not contain any dashes).

    :param value: value to convert.
    """
    if not value:
        value = 'UTF-8'
    converted = value.replace('-', '_').lower()
    all_aliases = {'ascii': ['us_ascii', 'us', 'ansi_x3.4_1968', 'cp367',
        'csascii', 'ibm367', 'iso_ir_6', 'iso646_us', 'iso_646.irv:1991'],
        'utf-7': ['csunicode11utf7', 'unicode_1_1_utf_7',
        'unicode_2_0_utf_7', 'x_unicode_1_1_utf_7', 'x_unicode_2_0_utf_7'],
        'utf_8': ['unicode_1_1_utf_8', 'unicode_2_0_utf_8',
        'x_unicode_1_1_utf_8', 'x_unicode_2_0_utf_8'], 'utf_16': [
        'utf_16le', 'ucs_2', 'unicode', 'iso_10646_ucs2'], 'latin_1': [
        'iso_8859_1']}
    for key, aliases in all_aliases.items():
        if converted in aliases:
            return key
    return converted


def _int_or_str(c):
    """Return parameter as type integer, if possible
    otherwise as type string
    """
    try:
        return int(c)
    except ValueError:
        return c


def _setDefaults(configObj={}):
    """ set up the default parameters to run drizzle
        build,single,units,wt_scl,pixfrac,kernel,fillval,
        rot,scale,xsh,ysh,blotnx,blotny,outnx,outny,data
    """
    paramDict = {'build': True, 'single': True, 'in_units': 'cps', 'wt_scl':
        1.0, 'pixfrac': 1.0, 'kernel': 'square', 'fillval': 999.0, 'rot':
        0.0, 'scale': 1.0, 'xsh': 0.0, 'ysh': 0.0, 'blotnx': 2048, 'blotny':
        2048, 'outnx': 4096, 'outny': 4096, 'data': None, 'driz_separate':
        True, 'driz_combine': False}
    if len(configObj) != 0:
        for key in configObj.keys():
            paramDict[key] = configObj[key]
    return paramDict


def hex_to_rgb(x):
    """Convert a color hexcode to an rgb tuple.

    Example
    -------
    >>> rgb('#FFFFFF')
    (255, 255, 255)
    """
    if not (x.startswith('#') and len(x) == 7):
        raise ValueError('Invalid hex color')
    x = x.strip('#')
    try:
        return int(x[:2], 16), int(x[2:4], 16), int(x[4:], 16)
    except ValueError:
        raise ValueError('Invalid hex color')


def tensor(data, dtype=None):
    """Create a tensor given the data and data type.

    Parameters
    ----------
    data : input data
        The interface should at least support list and numpy array.
        The data is copied to a newly-allocated tensor.
    dtype : data type, optional
        It should be one of the values in the data type dict.
        If is none, the type should be inferred from data.

    Returns
    -------
    Tensor
        A framework-specific tensor.
    """
    pass


def chunk_list(list_to_chunk, chunk_size):
    """Yield successive chunks from a list."""
    for idx in range(0, len(list_to_chunk), chunk_size):
        yield list_to_chunk[idx:idx + chunk_size]


def _check_max_features(importances, max_features):
    """Interpret the max_features value"""
    n_features = len(importances)
    if max_features is None:
        max_features = n_features
    elif isinstance(max_features, int):
        max_features = min(n_features, max_features)
    elif isinstance(max_features, float):
        max_features = int(n_features * max_features)
    return max_features


def values():
    """Return the values of the mapping object.
        """


@staticmethod
def escape(text, quote=True):
    """
        Returns a string with special characters converted to HTML entities.

        :param str text: The string with optionally special characters.
        :param bool quote: If true the quotation mark characters, both double quote (") and single quote (')
                           characters are also translated.

        :rtype: str
        """
    text = text.replace('&', '&')
    text = text.replace('<', '<')
    text = text.replace('>', '>')
    if quote:
        text = text.replace('"', '"')
        text = text.replace("'", ''')
    return text


@staticmethod
def possible_string_format_functions(format_):
    """Iterate through possible string-derived format functions.

        A string can either be a format specifier for the format built-in,
        a new-style format string, or an old-style format string.

        This method is overridden in order to suppress printing the unit
        in each row since it is already at the top in the column header.
        """
    yield lambda format_, val: format(val.value, format_)
    yield lambda format_, val: format_.format(val.value)
    yield lambda format_, val: format_ % val.value


def bake_from_cache():
    """Bake from cache

    """
    pass


def powerset(L):
    """
    Constructs the power set, 'potenz Menge' of a given list.

    return list: of all possible subsets
    """
    import itertools
    pset = []
    for n in range(len(L) + 1):
        for sset in itertools.combinations(L, n):
            pset.append(sset)
    return pset


def convert_is_active(x) ->bool:
    """Convert string 'active' to bool."""
    return True if x == 'active' else False


def request_info(sid):
    """ Send info-req event to target session id ``sid``. """
    from x84.bbs import getsession
    session = getsession()
    session.send_event('route', (sid, 'info-req', session.sid))


def readable_keyword(s):
    """Return keyword with only the first letter in title case."""
    if s and not s.startswith('*') and not s.startswith('['):
        if s.count('.'):
            library, name = s.rsplit('.', 1)
            return library + '.' + name[0].title() + name[1:].lower()
        else:
            return s[0].title() + s[1:].lower()
    else:
        return s


@classmethod
def setup_instance(cls, remote):
    """Prepares an instance to mount this type of share."""
    pass


def number_to_html(number_as_string):
    """usage as ``number_to_html(num2str(1.023e-12)) == "'-1.0 x 10-12'"``"""
    s = number_as_string
    if s.find('e') > 0:
        if s.startswith('1e') or s.startswith('-1e'):
            s = s.replace('1e', '10')
        else:
            s = s.replace('e', ' x 10')
        s += ''
    return s


def _include_exclude(file_path, include=None, exclude=None):
    """Check if file matches one of include filters and not in exclude filter.

    :param file_path: Path to the file.
    :param include: Tuple containing patterns to which include from result.
    :param exclude: Tuple containing patterns to which exclude from result.
    """
    if exclude is not None and exclude:
        for pattern in exclude:
            if file_path.match(pattern):
                return False
    if include is not None and include:
        for pattern in include:
            if file_path.match(pattern):
                return True
        return False
    return True


def sign_x509(xml, key, certificate, algorithm=None, digest_algorithm=None,
    canonicalization_method=None):
    """Sign PSKC data using X.509 certificate and private key.

    xml: an XML document
    key: the private key in binary format
    certificate: the X.509 certificate
    """
    import signxml
    algorithm = algorithm or 'rsa-sha256'
    digest_algorithm = digest_algorithm or 'sha256'
    canonicalization_method = (canonicalization_method or signxml.
        XMLSignatureProcessor.default_c14n_algorithm)
    return signxml.XMLSigner(method=signxml.methods.enveloped,
        signature_algorithm=algorithm.rsplit('#', 1)[-1].lower(),
        digest_algorithm=digest_algorithm.rsplit('#', 1)[-1].lower(),
        c14n_algorithm=canonicalization_method).sign(xml, key=key, cert=
        certificate)


def get_property_in_hierarchy(sdo_props, mapping_property, prop_type='new_sdo'
    ):
    """if a mapping property (indexed by its name, which is key "property")
       if found as a key in sdo_props at a particular entity (e.g., Thing)
       then we've found it in the sdo, and grab it's description for use from
       the sdo. If we don't find it, we return the type as a "new_sdo"
    """
    for entity in sdo_props:
        if mapping_property['property'] in sdo_props[entity]:
            prop_type = entity
            name = mapping_property['property']
            desc = sdo_props[entity][name]['description']
            mapping_property['description'] = desc
            break
    return {'type': prop_type, 'property': mapping_property}


def screen_header(text: str, decor: str='=', max: int=79) ->str:
    """Return a header to be displayed on screen, by decorating ``text``."""
    text = str(text)
    available = max - len(text)
    if available > 3:
        text = '  ' + text + '  '
        available -= 4
    else:
        return text
    req_space = len(decor) * 2
    while available >= req_space:
        text = decor + text + decor
        available -= req_space
        if len(text) == available - len(decor):
            text += decor
            available -= len(decor)
    return text


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


@staticmethod
def find_neighbors_delaunay(pindex, triang):
    """
        Returns the indexes of points connected to ``pindex`` on the Gabriel
        chain subgraph of the Delaunay triangulation.
        """
    return triang.vertex_neighbor_vertices[1][triang.
        vertex_neighbor_vertices[0][pindex]:triang.vertex_neighbor_vertices
        [0][pindex + 1]]


def flash(message, type='message'):
    """Send a short message to the user."""


def binary_horner(poly, x):
    """
    Returns the binary polynomial :code:`poly` evaluated at point :code:`x`, using `Horner's
    method <https://en.wikipedia.org/wiki/Horner's_method>`_.  Any Python object supporting
    the operations of addition, subtraction, and multiplication may serve as the input point.
    """
    result = x - x
    for coefficient in reversed(poly.coefficients()):
        result *= x
        if coefficient:
            result += coefficient
    return result


@staticmethod
def get_parser_settings_key():
    """Return the key that contains the optional parser options in the `settings` input node."""
    return 'parser_options'


def set_session(session):
    """Sets the global TF session.
    """
    global _SESSION
    _SESSION = session


def int2tokens(num, tokens, negative_sign='-'):
    """
    Convert a group of tokens (within a given set) to a number.

    Items in the tokens set must not repeat/overlap.

    This is the inverse of `int2tokens()` given the same tokens set.

    Args:
        num (int): The input number to convert.
        tokens (Iterable[str]): The tokens to use for the representation.
            Items within the tokens set must not repeat or overlap.
        negative_sign (str): The symbol to use for negative numbers.
            The negative sign will be the first character of the
            representation.

    Returns:
        text (str): The integer represented.

    Examples:
        >>> [int2tokens(i, ('0', '1')) for i in range(10)]
        ['0', '1', '00', '01', '10', '11', '000', '001', '010', '011']
        >>> [int2tokens(i, ('a', 'b', 'c')) for i in range(10)]
        ['a', 'b', 'c', 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca']
        >>> [int2tokens(i, 'abc') for i in range(10)]
        ['a', 'b', 'c', 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca']
        >>> [int2tokens(i, ('po', 'ta')) for i in range(8)]
        ['po', 'ta', 'popo', 'pota', 'tapo', 'tata', 'popopo', 'popota']
        >>> int2tokens(161, ('po', 'ta'))
        'potapopopotata'
        >>> d = ('mo', 'no', 'ke')
        >>> all(n == tokens2int(int2tokens(n, d), d) for n in range(-999, 99))
        True

    See Also:
        letter2int(), int2letter(), tokens2int()
    """
    text = ''
    if num < 0:
        sign_text = negative_sign
        num = abs(num)
    else:
        sign_text = ''
    while num >= 0:
        text = tokens[num % len(tokens)] + text
        num = num // len(tokens) - 1
    return sign_text + text


def inverse(A=None, name=None, attr=None, out=None, **kwargs):
    """Compute the inverse of a matrix.
    Input is a tensor *A* of dimension *n >= 2*.

    If *n=2*, *A* is a square matrix. We compute:

      *out* = *A*\\ :sup:`-1`

    If *n>2*, *inverse* is performed separately on the trailing two dimensions
    for all inputs (batch mode).

    .. note:: The operator supports float32 and float64 data types only.

    Examples::

       Single matrix inverse
       A = [[1., 4.], [2., 3.]]
       inverse(A) = [[-0.6, 0.8], [0.4, -0.2]]

       Batch matrix inverse
       A = [[[1., 4.], [2., 3.]],
            [[1., 3.], [2., 4.]]]
       inverse(A) = [[[-0.6, 0.8], [0.4, -0.2]],
                     [[-2., 1.5], [1., -0.5]]]

    Defined in src/operator/tensor/la_op.cc:L919

    Parameters
    ----------
    A : Symbol
        Tensor of square matrix

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

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


@classmethod
def from_row(cls, row: tuple) ->'Station':
    """
        Instantiate a Station from a row of stations.sqlite3.
        """
    return cls(name=row[0], name_norm=row[1], sncf_id=row[3], sncf_tvs_id=
        row[4], latitude=row[5], longitude=row[6])


def _make_object_type_name(model):
    """
    SINGLE OBJECT QUERY TYPE NAME

    We need query type name. For example when we will query from graphql client end, we will be writing
    model name with lower and list with underscore or camelcase
    :param model:
    :return: a string name of query
    """
    return model.__name__.lower() + '_object'


def formula_2012_01_01(foyer_fiscal, period, parameters):
    """
        Plus-values 2012 entrant dans le calcul du revenu fiscal de référence
        """
    f3sa_2012 = foyer_fiscal('f3sa_2012', period)
    f3sj = foyer_fiscal('f3sj', period)
    f3sk = foyer_fiscal('f3sk', period)
    f3vc = foyer_fiscal('f3vc', period)
    f3vd_i = foyer_fiscal.members('f3vd', period)
    f3vf_i = foyer_fiscal.members('f3vf', period)
    f3vg = foyer_fiscal('f3vg', period)
    f3vi_i = foyer_fiscal.members('f3vi', period)
    f3vl = foyer_fiscal('f3vl', period)
    f3vm = foyer_fiscal('f3vm', period)
    f3vp = foyer_fiscal('f3vp', period)
    f3vt = foyer_fiscal('f3vt', period)
    f3vy = foyer_fiscal('f3vy', period)
    f3vz = foyer_fiscal('f3vz', period)
    f3we = foyer_fiscal('f3we', period)
    f3vi = foyer_fiscal.sum(f3vi_i)
    f3vd = foyer_fiscal.sum(f3vd_i)
    f3vf = foyer_fiscal.sum(f3vf_i)
    rpns_pvce_i = foyer_fiscal.members('rpns_pvce', period)
    rpns_pvce = foyer_fiscal.sum(rpns_pvce_i)
    return (f3sa_2012 + f3sj + f3sk + f3vc + f3vd + f3vf + f3vg + f3vi +
        f3vl + f3vm + f3vp + f3vt + f3vy + f3vz + f3we + rpns_pvce)


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

    The ".dev0" means dirty.

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


def parse_adl_path(adl_path):
    """ Returns tuple (store_name, object_key) """
    path_parts = adl_path.replace('adl://', '').split('/')
    store_name = path_parts[0].replace('.azuredatalakestore.net', '')
    object_key = '/'.join(path_parts[1:])
    return store_name, object_key


def write_output(matrix, base_fname=None, header='', suffix='', extension='dat'
    ):
    """
    Write output matrix with a nice format, to stdout and optionally a file.

    Parameters
    ----------

    matrix : encore.utils.TriangularMatrix
        Matrix containing the values to be printed

    base_fname : str
        Basic filename for output. If None, no files will be written, and
        the matrix will be just printed on standard output

    header : str
        Text to be written just before the matrix

    suffix : str
        String to be concatenated to basename, in order to get the final
        file name

    extension : str
        Extension for the output file

    """
    if base_fname is not None:
        fname = base_fname + '-' + suffix + '.' + extension
    else:
        fname = None
    matrix.square_print(header=header, fname=fname)


@staticmethod
def _identity(obj):
    """Return the given object.

        Args:
            obj: An object.

        Returns:
            The given object.
        """
    return obj