def __call__(relchain, query, index, cache):
    """return boolean: whether to accept the given relchain.
        last relationship token in relchain is the most recent.
        query is original query that started the search.
        Used for the filter and targetFilter arguments of the IIndex query
        methods.  Cache is a dictionary that will be used throughout a given
        search."""


def set_fee_cache_time(seconds):
    """placeholder to ease the porting"""
    pass


def _format_eval_result(value, show_stdv=True):
    """Format metric string."""
    if len(value) == 4:
        return "%s's %s: %g" % (value[0], value[1], value[2])
    elif len(value) == 5:
        if show_stdv:
            return "%s's %s: %g + %g" % (value[0], value[1], value[2], value[4]
                )
        else:
            return "%s's %s: %g" % (value[0], value[1], value[2])
    else:
        raise ValueError('Wrong metric value')


@staticmethod
def to_green(data):
    """Hex color feed to green channel.
        :param int data: Color value, in hexadecimal.
        """
    return int(data[3], 16) * 16 + int(data[4], 16)


def charge_matrixelem(param_name, **kwargs):
    """Plot defaults for sweep_plotting.charge_matrixelem"""
    kwargs['xlabel'] = kwargs.get('xlabel') or param_name
    kwargs['ylabel'] = kwargs.get('ylabel') or '$|\\langle i |n| j \\rangle|$'
    return kwargs


def bytes2human(n):
    """
    Convert n bytes (as integer) to a human readable string.  Code was found
    online at activestate (see references).

    **Parameters**

        n: *int*
            The number of bytes.

    **Returns**

        n_in_str: *str*
            The bytes in string format.

    **References**

        - http://code.activestate.com/recipes/578019
    """
    symbols = 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)
    return '%sB' % n


def check_pt_data(*args):
    """Access stored Pressure Transducer data from the sensor limits and collected data to index and build an integer numpy array for sensor values that have exceeded the set bounds.

    Parameters
    ----------
    pt_limits : int numpy array
        Values for pressure transducer limits.
    pt_data : float numpy array
        Collected sensor data used to.

    Returns
    -------
    pt_input_data : numpy array
        numpy array of sensed pressure transducer values data.
    """
    limits = args[0].pt_limits
    pt = []
    for i in range(len(limits)):
        x = args[1][i] - limits[i]
        if x >= 0:
            pt.append(args[1][i])
        else:
            pt.append(0)
    return pt


def set_api_url_and_key(api_key, api_base_url=None):
    """
    Set the URL of the WakeBlaster API and its key that will be used for subsequent API calls.

    :param api_key: Access key for the WakeBlaster API provided to you by the WakeBlaster support team
    :param api_base_url: Base URL of all WakeBlaster HTTP requests. Default is the beta URL.
    """
    global _api_base_url, _api_key
    _api_base_url = api_base_url or 'https://beta.app.wakeblaster.net/api'
    _api_key = api_key


def lam2rgb(wav, gamma=0.8, output='norm'):
    """This converts a given wavelength of light to an
    approximate RGB colour value with edge attenuation.
    The wavelength must be given in nanometres in the
    range from 380 nm - 750 nm (789 THz - 400 THz).

    Adapted from: http://www.noah.org/wiki/Wavelength_to_RGB_in_Python
    Based on code by Dan Bruton
    http://www.physics.sfasu.edu/astro/color/spectra.html
    """
    wav = float(wav)
    if wav >= 380 and wav < 440:
        attenuation = 0.3 + 0.7 * (wav - 380) / (440 - 380)
        R = (-(wav - 440) / (440 - 380) * attenuation) ** gamma
        G = 0.0
        B = (1.0 * attenuation) ** gamma
    elif wav >= 440 and wav < 490:
        R = 0.0
        G = ((wav - 440) / (490 - 440)) ** gamma
        B = 1.0
    elif wav >= 490 and wav < 510:
        R = 0.0
        G = 1.0
        B = (-(wav - 510) / (510 - 490)) ** gamma
    elif wav >= 510 and wav < 580:
        R = ((wav - 510) / (580 - 510)) ** gamma
        G = 1.0
        B = 0.0
    elif wav >= 580 and wav < 645:
        R = 1.0
        G = (-(wav - 645) / (645 - 580)) ** gamma
        B = 0.0
    elif wav >= 645 and wav <= 750:
        attenuation = 0.3 + 0.7 * (750 - wav) / (750 - 645)
        R = (1.0 * attenuation) ** gamma
        G = 0.0
        B = 0.0
    else:
        R = 0.0
        G = 0.0
        B = 0.0
    if output == 'norm':
        return R, G, B
    elif output == 'hex':
        R *= 255
        R = max(0, min(round(R), 255))
        G *= 255
        G = max(0, min(round(G), 255))
        B *= 255
        B = max(0, min(round(B), 255))
        return '#{0:02x}{1:02x}{2:02x}'.format(R, G, B), (R, G, B)


def telemetry_is_enabled():
    """Default implementation for the ENABLE_TELEMETRY_FUNCTION setting."""
    return True


def getCiphers(filename, index, range=-1):
    """Returns a list of ciphers of encrypted data. Index is need for column specification
       Range is by default (-1), which implies that all ciphers from the column will be listed.
       If specified by a list, only ID's within the list will be considered."""
    if index > 0:
        CipherList = []
        with open(filename, 'rb') as f:
            next(f)
            if range == -1:
                for line in f:
                    CipherList.append((int(line.split()[index]), int(line.
                        split()[0])))
            else:
                for line in f:
                    if int(line.split(None, 1)[0]) in range:
                        CipherList.append((int(line.split()[index]), int(
                            line.split()[0])))
        return CipherList
    else:
        print('illegal index')


def constructCorpus(contigs, classMap, binary, target):
    """
    Construct a corpus, or body of training data for the decision tree, as well as the data under test.

    Args:
        contigs: A list of sidr.common.Contig objects with test variables.
        classMap: A dictionary mapping class names to their class id used by scikit-learn.
        binary: Set True to use "binary" (target/nontarget) classification for the model.
        target: The name of the target classification.
    Returns:
        corpus: A list of lists, containing the GC content, coverage, and class number.
        testdata: Data that was not classified by BLAST and will later be classified by the
            trained model.
        features: List of variables used by each contig.
    """
    corpus = []
    testdata = []
    features = []
    for contig in contigs:
        variableBuf = list(contig.variables.values())
        features = list(contig.variables.keys())
        if contig.classification:
            if binary:
                if contig.classification.lower() == target.lower():
                    variableBuf.append('target')
                    corpus.append(variableBuf)
                else:
                    variableBuf.append('nontarget')
                    corpus.append(variableBuf)
            else:
                variableBuf.append(contig.classification)
                corpus.append(variableBuf)
        else:
            variableBuf.insert(0, contig.contigid)
            testdata.append(variableBuf)
    return corpus, testdata, features


def identify_engine_thermostat_temperature(engine_temperature_regression_model
    ):
    """
    Identifies thermostat engine temperature and its limits [°C].

    :param engine_temperature_regression_model:
        The calibrated engine temperature regression model.
    :type engine_temperature_regression_model: ThermalModel

    :return:
        Engine thermostat temperature [°C].
    :rtype: float
    """
    return engine_temperature_regression_model.thermostat


@classmethod
def start_next_scene(cls):
    """
        Start next scene
        """
    cls.current_running_scene.start()
    cls.current_running_scene.scene_loop()


@classmethod
def get_unique_path_from_urlpath(cls, url_path):
    """
        Returns a unique path derived from the given url path taken from a Page object.

        We never change paths, even if a page has been moved in order to not confuse Pontoon.

        But this means that if pages are moved and a new one is created with the same slug in
        it's previous position, a path name clash could occur.
        """
    path = url_path.strip('/')
    path_suffix = 1
    try_path = path
    while cls.objects.filter(path=try_path).exists():
        try_path = f'{path}-{path_suffix}'
        path_suffix += 1
        if path_suffix > 100:
            raise Exception(f'Unable to find a unique path for: {url_path}')
    return try_path


def mapping(dictionary, mapping):
    """
    takes in a dictionary and a mapping which contains new key names,
    and returns a new dictionary with the updated key names, i.e.:
    dictionary = {'a': 1, 'b': 2, 'c': 3}
    mapping = {'a': 'aa', 'c': 'cc'}
    mapped_dictionary = mapping(dictionary, mapping)
    mapped_dictionary = {'aa': 1, b, 2, 'cc': 3}
    """
    mapped_dictionary = {}
    for key, value in dictionary.items():
        if key in list(mapping.keys()):
            new_key = mapping[key]
            if new_key in mapped_dictionary:
                if hasattr(value, 'any'):
                    if not value.any():
                        continue
                    if hasattr(mapped_dictionary, 'any'):
                        if value.any() and not mapped_dictionary[new_key].any(
                            ):
                            mapped_dictionary[new_key] = value
                        elif value.any() and mapped_dictionary[new_key].any():
                            mapped_dictionary[new_key] = value
                    elif value.any() and not mapped_dictionary[new_key].any():
                        mapped_dictionary[new_key] = value
                    elif value.any() and mapped_dictionary[new_key].any():
                        mapped_dictionary[new_key] = value
                elif not value:
                    continue
                elif value and not mapped_dictionary[new_key]:
                    mapped_dictionary[new_key] = value
                elif value and mapped_dictionary[new_key]:
                    mapped_dictionary[new_key] = value
            else:
                mapped_dictionary[new_key] = value
        else:
            mapped_dictionary[key] = value
    return mapped_dictionary


def get_model_field(schema, field):
    """Get the model field of a schema field

    :param Schema schema: a marshmallow schema
    :param str field: the name of the schema field
    :return str: the name of the field in the model
    """
    if schema._declared_fields.get(field) is None:
        raise Exception('{} has no attribute {}'.format(schema.__name__, field)
            )
    if schema._declared_fields[field].attribute is not None:
        return schema._declared_fields[field].attribute
    return field


def get_comma_separated_values(values):
    """Return the values as a comma-separated string"""
    if not isinstance(values, list) and not isinstance(values, tuple):
        values = [values]
    return ','.join(values)


def build_no_log_generator(container, log_args):
    """Return a generator that prints a warning about logs and waits for
    container to exit.
    """
    yield "WARNING: no logs are available with the '{}' log driver\n".format(
        container.log_driver)


@staticmethod
def bounding_box_overlap(line0, line1):
    """ Returns True if the bounding boxes of line0 and line1 intersect.
        Returns False otherwise, indicating a collision is impossible.

        Edge.bounding_box_overlap(np.arr[float(x4)], np.arr[float(x4)]) -> bool

        """
    x00, y00, x01, y01 = line0
    x10, y10, x11, y11 = line1
    x0_min = min(x00, x01)
    x0_max = max(x00, x01)
    x1_min = min(x10, x11)
    x1_max = max(x10, x11)
    if x0_max < x1_min or x1_max < x0_min:
        return False
    y0_min = min(y00, y01)
    y0_max = max(y00, y01)
    y1_min = min(y10, y11)
    y1_max = max(y10, y11)
    if y0_max < y1_min or y1_max < y0_min:
        return False
    return True


@classmethod
def from_solver(cls, solver_class, model, **kwargs):
    """
        Create solver from solver class and prepare run method.
        """
    meta = model._meta
    solver = solver_class(meta.diff_fn, y0=meta.y0, t0=meta.t0)
    return cls(solver, model, **kwargs)


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

        :param RelocationBatchErrorEntry val:
        :rtype: RelocationBatchResultEntry
        """
    return cls('failure', val)


def show_progress(epoch, step, n_epochs, n_steps, steps_in_epoch, loss):
    """
    print the current progress and loss
    :param epoch: current epoch
    :param step: current step
    :param n_epochs: number of epoch in training
    :param n_steps: number of steps in training
    :param steps_in_epoch: number of steps in one epoch
    :param loss: current loss
    """
    n_steps = n_steps if n_steps is not None else n_epochs * steps_in_epoch - 1
    steps_taken = epoch * steps_in_epoch + step
    progress = round(100 * steps_taken / n_steps, 2)
    print(
        f'\rprogress: {progress}%, epoch: {epoch}, step: {step}, loss: {loss}',
        end='')


@classmethod
def sharps(cls):
    """ Return a chromatic scale of sharps, starting with A

        >>> Note.sharps()  # doctest: +NORMALIZE_WHITESPACE
        [[Note(A)], [Note(A#)], [Note(B)], [Note(B#), Note(C)], [Note(C#)], [Note(D)],
         [Note(D#)], [Note(E)], [Note(E#), Note(F)], [Note(F#)], [Note(G)], [Note(G#)]]
        """
    ret = []
    for note, index in cls._chromatic_index_map.items():
        if 'b' not in note:
            if len(ret) == index:
                ret.append([cls(note)])
            else:
                ret[-1].append(cls(note))
    return ret


def escape(str):
    """Precede all special characters with a backslash."""
    out = ''
    for char in str:
        if char in '\\ ':
            out += '\\'
        out += char
    return out


@classmethod
def get(cls, entity_id, external_project_id=None, force_show_deleted=False,
    suppress_exception=False, session=None):
    """Get an entity or raise if it does not exist"""
    db_entity = cls.db_repo.get(entity_id, external_project_id=
        external_project_id, force_show_deleted=force_show_deleted,
        suppress_exception=suppress_exception, session=session)
    if db_entity:
        return cls()._from_db_object(db_entity)
    else:
        return None


def calculate_bucket_count_in_heap_with_height(k, h):
    """
    Calculate the number of buckets in a
    k-ary heap of height h.
    """
    assert h >= 0
    return (k ** (h + 1) - 1) // (k - 1)


@staticmethod
def run(instance, instances):
    """Enrich instance object with jump hosts."""
    return instance


def calculate_velocity(estimate, total_hours):
    """TODO: Docstring for calculate_velocity.

    :estimate: TODO
    :total_hours: TODO
    :returns: TODO

    """
    return round(estimate / float(total_hours), 2) if total_hours > 0 else 0


def is_aa_seq(file):
    """check input gene files to make sure they are amino acid sequences and not nucletotide sequences"""
    with open(file, 'r') as infile:
        all_count, atcg_count = 0, 0
        for line in infile:
            if line.startswith('>'):
                pass
            else:
                all_count += len(line)
                atcg_count += line.upper().count('A') + line.upper().count('T'
                    ) + line.upper().count('C') + line.upper().count('G')
        atcg_per = atcg_count / all_count
        if atcg_per > 0.7:
            return False
        else:
            return True


@classmethod
def get_friendly_name(cls):
    """Returns a human-readable name of the curve that can be
        used in messages."""
    return 'sensitivity-specificity plot'


@classmethod
def count(cls, **kwargs):
    """Like search, but only count the number of matches."""
    kwargs.setdefault('params', {})
    kwargs['params'].update({'search_type': 'count'})
    res = cls.search(raw_result=True, **kwargs)
    return res['hits']['total']


def dismount(filepath):
    """Dismount the volume at filepath, implemented via :meth:`Dir.dismount`

    :param filepath: anything accepted by :func:`dir`
    """
    return dir(filepath).dismount()


def levenshtein(a, b):
    """Calculates the Levenshtein distance between a and b.
    (Clever compact Pythonic implementation from hetland.org)"""
    n, m = len(a), len(b)
    if n > m:
        a, b = b, a
        n, m = m, n
    current = list(range(n + 1))
    for i in range(1, m + 1):
        previous, current = current, [i] + [0] * n
        for j in range(1, n + 1):
            add, delete = previous[j] + 1, current[j - 1] + 1
            change = previous[j - 1]
            if a[j - 1] != b[i - 1]:
                change = change + 1
            current[j] = min(add, delete, change)
    return current[n]


def reverse(vol, csum):
    """Yields a set of paths which reference a given checksum_path name."""


def get_geometry(lon, lat, size):
    """Returns a geo json geometry.

    Give lon, lat, and size in degrees.
    """
    geo_json_geometry = {'type': 'Polygon', 'coordinates': [[[lon - size /
        2, lat - size / 2], [lon - size / 2, lat + size / 2], [lon + size /
        2, lat + size / 2], [lon + size / 2, lat - size / 2], [lon - size /
        2, lat - size / 2]]]}
    return geo_json_geometry


def string_to_num(s: str):
    """Converts a string to an int/float

    Returns ``None`` if it can't be converted

    >>> string_to_num('5')
    5
    >>> string_to_num('5.2')
    5.2
    >>> string_to_num(10)
    10
    >>> string_to_num(10.1)
    10.1
    >>> string_to_num('this is not a string') is None
    True
    """
    if isinstance(s, (int, float)):
        return s
    if s.isdigit():
        return int(s)
    try:
        return float(s)
    except ValueError:
        return None


@staticmethod
def _user_callback_example(pkt_dict: dict) ->None:
    """
        This is an user_callback example method.
        It manages the pkt dictionary
        :param pkt_dict: The packet dictionary
        :return: None
        """
    return None


@staticmethod
def p_unit_type(p):
    """unit_type : EXTENDED_SI
                     | DERIVED"""
    p[0] = p[1]


def detach_classic_link_vpc(DryRun=None, InstanceId=None, VpcId=None):
    """
    Unlinks (detaches) a linked EC2-Classic instance from a VPC. After the instance has been unlinked, the VPC security groups are no longer associated with it. An instance is automatically unlinked from a VPC when it's stopped.
    See also: AWS API Documentation

    :example: response = client.detach_classic_link_vpc(
        DryRun=True|False,
        InstanceId='string',
        VpcId='string'
    )

    :type DryRun: boolean
    :param DryRun: Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation . Otherwise, it is UnauthorizedOperation .

    :type InstanceId: string
    :param InstanceId: [REQUIRED]
            The ID of the instance to unlink from the VPC.

    :type VpcId: string
    :param VpcId: [REQUIRED]
            The ID of the VPC to which the instance is linked.

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

    """
    pass


def string_keys_to_dict(key_strings, callback):
    """
    Maps each string in `key_strings` to `callback` function
    and return as a dict.
    """
    return dict.fromkeys(key_strings, callback)


@classmethod
def factory(cls, global_config, **local_config):
    """Used for paste app factories in paste.deploy config files.

        Any local configuration (that is, values under the [app:APPNAME]
        section of the paste config) will be passed into the `__init__` method
        as kwargs.

        A hypothetical configuration would look like:

            [app:wadl]
            latest_version = 1.3
            paste.app_factory = karbor.api.fancy_api:Wadl.factory

        which would result in a call to the `Wadl` class as

            import karbor.api.fancy_api
            fancy_api.Wadl(latest_version='1.3')

        You could of course re-implement the `factory` method in subclasses,
        but using the kwarg passing it shouldn't be necessary.

        """
    return cls(**local_config)


def dimensions_url_search(keywords_list_as_string):
    """Returns a valid keyword search URL for Dimensions"""
    q = (
        'https://app.dimensions.ai/discover/publication?search_text={}&search_type=kws&search_field=full_search'
        )
    from urllib.parse import quote
    s = quote(keywords_list_as_string)
    return q.format(s)


def yy():
    """Return calendar year as a 2 digit string"""


def get_jyutping_from_mor(mor):
    """
    Extract jyutping string from *mor*.
    """
    jyutping, _, _ = mor.partition('=')
    jyutping, _, _ = jyutping.partition('-')
    jyutping, _, _ = jyutping.partition('&')
    return jyutping


def history_append(text: str='', current_character: int=0,
    remove_duplicates: bool=False):
    """Append history at cursor position

    :param text: Text, Text to insert at the cursor position
    :type text: str
    :param current_character: Cursor, The index of the cursor
    :type current_character: int
    :param remove_duplicates: Remove Duplicates, Remove duplicate items in the history
    :type remove_duplicates: bool
    """
    pass


def wrap(command: bytes):
    """
    Wrap the given command into the padding bytes  and
    :param command: bytes
    :return: padded command: bytes
    """
    start = b'\x02'
    stop = b'\x03'
    return start + command + stop


def disable_warning_messages():
    """
    Disable warning message printing.
    """
    global warning_enabled
    warning_enabled = False


@classmethod
def transform(klass, input_value):
    """
        Transform input values to store into Froshki._data.

        klass.transform(input_value) -> value_to_store
        Override this method for customization.
        """
    return input_value


def validate_region_file(filename: str):
    """Checks if a file is a region file."""
    if filename[-4:].lower() != '.cnt' and filename[-4:].lower() != '.reg':
        raise ValueError('%s Failed validation: Not a region file' % filename)


def transpose_axes(data, axes, asaxes='CTZYX'):
    """Return data with its axes permuted to match specified axes.

    A view is returned if possible.

    >>> transpose_axes(numpy.zeros((2, 3, 4, 5)), 'TYXC', asaxes='CTZYX').shape
    (5, 2, 1, 3, 4)

    """
    for ax in axes:
        if ax not in asaxes:
            raise ValueError('unknown axis %s' % ax)
    shape = data.shape
    for ax in reversed(asaxes):
        if ax not in axes:
            axes = ax + axes
            shape = (1,) + shape
    data = data.reshape(shape)
    data = data.transpose([axes.index(ax) for ax in asaxes])
    return data


def apply_rule(word, remove_total, append_string):
    """
        Apply the stemming rule to the word
    """
    new_word_length = len(word) - remove_total
    word = word[0:new_word_length]
    if append_string:
        word += append_string
    return word


@staticmethod
def _format_size(num_bytes, binary=False, strip=True):
    """
        Format a number of bytes as a human readable size.

        Parameters
        ----------
        num_bytes : int
            The size to format.
        binary : bool, optional
            The base to group the number of bytes.
        strip : bool, optional
            If trailing zeros should be keeped or stripped.

        Returns
        -------
        str
            The human readable file size.
        """
    size_units = ['bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    if binary:
        base = 2 ** 10
    else:
        base = 10 ** 3
    for i, unit in reversed(list(enumerate(size_units))):
        divider = base ** i
        if num_bytes >= divider:
            formatted = '{:0.2f}'.format(num_bytes / divider, unit)
            if strip:
                formatted = formatted.rstrip('0').rstrip('.')
            formatted = '{} {}'.format(formatted, unit)
            return formatted
    return '0 {}'.format(size_units[0])


@staticmethod
def _headers():
    """Returns common headers for all requests (GET & POST) to the API"""
    headers = {'X-Auth-User-Id': '0', 'X-Auth-Session-Key': '0',
        'User-Agent': 'PowderToy/92.2 (WIN32; SSE3; M0) TPTPP/92.2.333R.0'}
    return headers


def find_roots(graph):
    """
    Identify all roots, where a root is a node that has no edges that point to
    it.

    :param graph: A networkx DiGraph.
    """
    instances = set(graph.nodes())
    if not instances:
        raise ValueError('graph contains no edges')
    for edge in graph.edges():
        if edge[1] in instances:
            instances.remove(edge[1])
    return instances


def _apply_properties(widget, properties={}):
    """Applies the specified properties to the widget.

    `properties` is a dictionary with key value pairs corresponding
    to the properties to be applied to the widget.
    """
    with widget.hold_sync():
        for key, value in properties.items():
            setattr(widget, key, value)


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

    Kristian B. Knudsen (kknu@berkeley.edu / kristianbknudsen@gmail.com)
    """
    Rs = params['Rs']
    R1 = params['R1']
    R2 = params['R2']
    R3 = params['R3']
    R4 = params['R4']
    R5 = params['R5']
    R6 = params['R6']
    R7 = params['R7']
    R8 = params['R8']
    R9 = params['R9']
    R10 = params['R10']
    R11 = params['R11']
    R12 = params['R12']
    R13 = params['R13']
    R14 = params['R14']
    R15 = params['R15']
    R16 = params['R16']
    R17 = params['R17']
    R18 = params['R18']
    R19 = params['R19']
    R20 = params['R20']
    R21 = params['R21']
    R22 = params['R22']
    R23 = params['R23']
    R24 = params['R24']
    R25 = params['R25']
    R26 = params['R26']
    R27 = params['R27']
    R28 = params['R28']
    R29 = params['R29']
    R30 = params['R30']
    R31 = params['R31']
    R32 = params['R32']
    R33 = params['R33']
    R34 = params['R34']
    R35 = params['R35']
    R36 = params['R36']
    R37 = params['R37']
    R38 = params['R38']
    R39 = params['R39']
    R40 = params['R40']
    R41 = params['R41']
    R42 = params['R42']
    R43 = params['R43']
    R44 = params['R44']
    R45 = params['R45']
    R46 = params['R46']
    R47 = params['R47']
    R48 = params['R48']
    R49 = params['R49']
    R50 = params['R50']
    R51 = params['R51']
    R52 = params['R52']
    R53 = params['R53']
    R54 = params['R54']
    R55 = params['R55']
    R56 = params['R56']
    R57 = params['R57']
    R58 = params['R58']
    R59 = params['R59']
    R60 = params['R60']
    R61 = params['R61']
    R62 = params['R62']
    R63 = params['R63']
    R64 = params['R64']
    R65 = params['R65']
    R66 = params['R66']
    R67 = params['R67']
    R68 = params['R68']
    R69 = params['R69']
    R70 = params['R70']
    R71 = params['R71']
    R72 = params['R72']
    R73 = params['R73']
    R74 = params['R74']
    R75 = params['R75']
    R76 = params['R76']
    R77 = params['R77']
    R78 = params['R78']
    R79 = params['R79']
    return Rs + R1 / (1 + w * 1.0j * t_values[0]) + R2 / (1 + w * 1.0j *
        t_values[1]) + R3 / (1 + w * 1.0j * t_values[2]) + R4 / (1 + w *
        1.0j * t_values[3]) + R5 / (1 + w * 1.0j * t_values[4]) + R6 / (1 +
        w * 1.0j * t_values[5]) + R7 / (1 + w * 1.0j * t_values[6]) + R8 / (
        1 + w * 1.0j * t_values[7]) + R9 / (1 + w * 1.0j * t_values[8]
        ) + R10 / (1 + w * 1.0j * t_values[9]) + R11 / (1 + w * 1.0j *
        t_values[10]) + R12 / (1 + w * 1.0j * t_values[11]) + R13 / (1 + w *
        1.0j * t_values[12]) + R14 / (1 + w * 1.0j * t_values[13]) + R15 / (
        1 + w * 1.0j * t_values[14]) + R16 / (1 + w * 1.0j * t_values[15]
        ) + R17 / (1 + w * 1.0j * t_values[16]) + R18 / (1 + w * 1.0j *
        t_values[17]) + R19 / (1 + w * 1.0j * t_values[18]) + R20 / (1 + w *
        1.0j * t_values[19]) + R21 / (1 + w * 1.0j * t_values[20]) + R22 / (
        1 + w * 1.0j * t_values[21]) + R23 / (1 + w * 1.0j * t_values[22]
        ) + R24 / (1 + w * 1.0j * t_values[23]) + R25 / (1 + w * 1.0j *
        t_values[24]) + R26 / (1 + w * 1.0j * t_values[25]) + R27 / (1 + w *
        1.0j * t_values[26]) + R28 / (1 + w * 1.0j * t_values[27]) + R29 / (
        1 + w * 1.0j * t_values[28]) + R30 / (1 + w * 1.0j * t_values[29]
        ) + R31 / (1 + w * 1.0j * t_values[30]) + R32 / (1 + w * 1.0j *
        t_values[31]) + R33 / (1 + w * 1.0j * t_values[32]) + R34 / (1 + w *
        1.0j * t_values[33]) + R35 / (1 + w * 1.0j * t_values[34]) + R36 / (
        1 + w * 1.0j * t_values[35]) + R37 / (1 + w * 1.0j * t_values[36]
        ) + R38 / (1 + w * 1.0j * t_values[37]) + R39 / (1 + w * 1.0j *
        t_values[38]) + R40 / (1 + w * 1.0j * t_values[39]) + R41 / (1 + w *
        1.0j * t_values[40]) + R42 / (1 + w * 1.0j * t_values[41]) + R43 / (
        1 + w * 1.0j * t_values[42]) + R44 / (1 + w * 1.0j * t_values[43]
        ) + R45 / (1 + w * 1.0j * t_values[44]) + R46 / (1 + w * 1.0j *
        t_values[45]) + R47 / (1 + w * 1.0j * t_values[46]) + R48 / (1 + w *
        1.0j * t_values[47]) + R49 / (1 + w * 1.0j * t_values[48]) + R50 / (
        1 + w * 1.0j * t_values[49]) + R51 / (1 + w * 1.0j * t_values[50]
        ) + R52 / (1 + w * 1.0j * t_values[51]) + R53 / (1 + w * 1.0j *
        t_values[52]) + R54 / (1 + w * 1.0j * t_values[53]) + R55 / (1 + w *
        1.0j * t_values[54]) + R56 / (1 + w * 1.0j * t_values[55]) + R57 / (
        1 + w * 1.0j * t_values[56]) + R58 / (1 + w * 1.0j * t_values[57]
        ) + R59 / (1 + w * 1.0j * t_values[58]) + R60 / (1 + w * 1.0j *
        t_values[59]) + R61 / (1 + w * 1.0j * t_values[60]) + R62 / (1 + w *
        1.0j * t_values[61]) + R63 / (1 + w * 1.0j * t_values[62]) + R64 / (
        1 + w * 1.0j * t_values[63]) + R65 / (1 + w * 1.0j * t_values[64]
        ) + R66 / (1 + w * 1.0j * t_values[65]) + R67 / (1 + w * 1.0j *
        t_values[66]) + R68 / (1 + w * 1.0j * t_values[67]) + R69 / (1 + w *
        1.0j * t_values[68]) + R70 / (1 + w * 1.0j * t_values[69]) + R71 / (
        1 + w * 1.0j * t_values[70]) + R72 / (1 + w * 1.0j * t_values[71]
        ) + R73 / (1 + w * 1.0j * t_values[72]) + R74 / (1 + w * 1.0j *
        t_values[73]) + R75 / (1 + w * 1.0j * t_values[74]) + R76 / (1 + w *
        1.0j * t_values[75]) + R77 / (1 + w * 1.0j * t_values[76]) + R78 / (
        1 + w * 1.0j * t_values[77]) + R79 / (1 + w * 1.0j * t_values[78])


def Lorentz1d(x, *p):
    """
    function to calculate a general one dimensional Lorentzian

    Parameters
    ----------
    x :     array-like
        coordinate(s) where the function should be evaluated
    p :     list
        list of parameters of the Lorentz-function
        [XCEN, FWHM, AMP, BACKGROUND]

    Returns
    -------
    array-like
        the value of the Lorentian described by the parameters p
        at position (x, y)

    """
    g = p[3] + p[2] / (1 + (2 * (x - p[0]) / p[1]) ** 2)
    return g


def sma(df, price, col, n):
    """
    Simple Moving Average (SMA) is an arithmetic moving average calculated by
    adding recent closing prices then dividing that by the number of time periods
    in the calculation average.

    SMA = (P_1 + ... + P_n) / n

    Parameters:
        df (pd.DataFrame): DataFrame which contain the asset price.
        price (string): the column name of the price of the asset.
        col (string): the column name for the n-day moving average results.
        n (int): the total number of periods.

    Returns:
        df (pd.DataFrame): Dataframe with n-day moving average of the asset calculated.

    Example Strategy:
    Bullish

    AND [Daily SMA(20,Daily Volume) > 40000]
    AND [Daily SMA(60,Daily Close) > 20]

    AND [Daily SMA(150,Daily Close) > 5 days ago Daily SMA(150,Daily Close)]
    AND [Daily EMA(5,Daily Close) > Daily EMA(35,Daily Close)]
    AND [Yesterday's Daily EMA(5,Daily Close) < Yesterday's Daily EMA(35,Daily Close)]
    AND [Daily Volume > Daily SMA(200,Daily Volume)]

    Bearish:

    AND [Daily SMA(20,Daily Volume) > 40000]
    AND [Daily SMA(60,Daily Close) > 20]

    AND [Daily SMA(150,Daily Close) < 5 days ago Daily SMA(150,Daily Close)]
    AND [Daily EMA(5,Daily Close) < Daily EMA(35,Daily Close)]
    AND [Yesterday's Daily EMA(5,Daily Close) > Yesterday's Daily EMA(35,Daily Close)]
    AND [Daily Volume > Daily SMA(200,Daily Volume)]

    Citation: https://school.stockcharts.com/doku.php?id=technical_indicators:moving_averages

    """
    df = df.copy()
    if df.shape[0] < n:
        df[col] = None
    else:
        df[col] = df[price].rolling(window=n).mean()
    return df


@staticmethod
def _get_name_from_dn(dn):
    """
        Get the instance name from the dn

        :param dn: string containing the distinguished name URL
        :return: string containing the name
        """
    name = dn.split('/dom-')[1].split('/')[0]
    return name


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

    """
    pass


def _remove_segment_line(params):
    """Remove annotation line from the view."""
    if params['segment_line'] is not None:
        params['segment_line'].remove()
        params['segment_line'] = None
        params['ax'].selector.active = True


@classmethod
def default_config(cls, **params):
    """
        Return a :class:`ParameterSet` object holding the default
        model configuration parameters, updated with any values passed on
        as keywords

        Parameters
        ----------
        **params :
            parameter values specified as key/value pairs
        """
    from pyRSD.rsdfit.parameters import Parameter, ParameterSet
    allowed = cls.allowable_kwargs
    model = cls()
    for name in allowed:
        params.setdefault(name, getattr(model, name))
    toret = ParameterSet()
    for name in params:
        toret[name] = Parameter(name=name, value=params[name])
    toret.tag = 'model'
    return toret


@classmethod
def get_month_year_in_slash_range(cls, match, ignore_wrong_years):
    """
        Get year(s) and month from slash range eg. 2007/08. If second value is between 1 and 12, take it as a month.

        Args:
            match (Match): Match object
            ignore_wrong_years (List[int]): Numbers identified as years that probably are not years

        Returns:
            Tuple[Optional[int], Optional[int], Optional[int]]: First year, first month, second year

        """
    first_year_str = match.group(1)
    first_year = int(first_year_str)
    if first_year in ignore_wrong_years:
        return None, None, None
    two_digits_str = match.group(3)
    if two_digits_str:
        two_digits = int(two_digits_str)
        if 1 <= two_digits <= 12:
            return first_year, two_digits, None
        else:
            second_year = int('%s%s' % (first_year_str[:2], two_digits_str))
            if second_year > first_year:
                return first_year, None, second_year
            else:
                ignore_wrong_years.append(first_year)
                return None, None, None
    else:
        return first_year, None, None


def updateStatus(update):
    """
    This function is a callback for the updates we do upon restarting the system.
    It checks whether or not the update completed successfully and if not it
    changes the state of the chute to stopped and adds a warning.
    :param update: The update object containing information about the chute that was created and whether it was successful or not.
    :type update: obj
    :returns: None
    """
    pass


def _attr_key(attr):
    """Return an appropriate key for an attribute for sorting

    Attributes have a namespace that can be either ``None`` or a string. We
    can't compare the two because they're different types, so we convert
    ``None`` to an empty string first.

    """
    return attr[0][0] or '', attr[0][1]


@classmethod
def lower(cls, string):
    """ return lowered and strip string"""
    return string.lower().strip()


def _check_bind_options(kw):
    """Check keyword options passed to dummy mailer ``.bind`` method
    for plausibility.

    Performs the same checks that :method:`Mailer.bind` does.

    """
    valid_options = 'default_sender', 'transaction_manager'
    invalid_options = set(kw.keys()).difference(valid_options)
    if invalid_options:
        raise ValueError('invalid options: %s' % ', '.join(sorted(
            invalid_options)))


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


def _find_associated_colorbar(obj):
    """A rather poor way of telling whether an axis has a colorbar associated: Check the
    next axis environment, and see if it is de facto a color bar; if yes, return the
    color bar object.
    """
    for child in obj.get_children():
        try:
            cbar = child.colorbar
        except AttributeError:
            continue
        if cbar is not None:
            return cbar
    return None


@staticmethod
def _needed_packages():
    """
        List of needed packages
        :return:
        """
    return []


def vapour_pressure_deficit(svp, vp):
    """
    Computes the vapour pressure deficit :math:`\\Delta_e` in [mbar]

    .. math ::
        \\Delta_e=e_s-e_a

    Parameters
    ----------
    svp : float
        saturated vapour pressure
        :math:`e_s`
        [mbar]
    vp : float
        actual vapour pressure
        :math:`e_a`
        [mbar]

    Returns
    -------
    vpd : float
       vapour pressure deficit
       :math:`\\Delta_e`
       [mbar]

    Examples
    --------
    >>> from ETLook import meteo
    >>> meteo.vapour_pressure_deficit(12.5, 5.4)
    7.1
    >>> meteo.vapour_pressure_deficit(vp=5.4, svp=12.3)
    6.9

    """
    vpd = svp - vp
    vpd[vpd < 0] = 0
    return vpd


def get_root(w):
    """
    Simple method to access root for a widget
    """
    next_level = w
    while next_level.master:
        next_level = next_level.master
    return next_level


def get_rms_bq(var):
    """
    Return the RMS base quality at this position
    """
    return var.INFO.get('BQ')


def email_contribution():
    """Return the email address to use for those who want to contribute."""
    return 'support@sympathyfordata.com'


def get_type():
    """A type name representative of the type across the plone system. More
        importantly it should be the name proper name and not the user
        friendly name."""


@staticmethod
def in_between(now, start, end):
    """Determine timing for schedules."""
    if start <= end:
        return start <= now < end
    return start <= now or now < end


def split(string, sep=' '):
    """Splits a string."""
    return string.split(sep)


def tiles_from_vid(pv_video, start_frame=0, end_frame=None):
    """
    A tile generator from a pyvision3 video object

    Parameters
    ----------
    pv_video: pyvision3 video
        You may want to use the size= option in the constructor
        of the video so that tile-sized images are generated
    start_frame: int
        Starting frame, defaults to 0
    end_frame: int
        Ending frame, defaults to None, meaning to use the
        complete duration of the video

    Returns
    -------
    A tile generator, yielding tuples like: (str(frame_num), image, None)
    """
    start_frame = 0 if start_frame < 0 else start_frame
    if start_frame != pv_video.current_frame_num:
        pv_video.seek_to(start_frame)
    for tile in pv_video:
        if end_frame is not None:
            if pv_video.current_frame_num > end_frame:
                raise StopIteration
        yield str(pv_video.current_frame_num), tile, None


def offset_name(offset):
    """Format an offset into a name."""
    return 'offset_{:X}'.format(offset.offset)


@staticmethod
def normalize_locale(locale):
    """
        Normalize locale
        Extracts language code from passed in locale string to be used later
        for dictionaries loading.

        :param locale:          string, locale (en, en_US)
        :return:                string, language code
        """
    import re
    match = re.match('^[a-z]+', locale.lower())
    if match:
        return match.group()


def left_justify(words, width):
    """
    Left justify words.

    :param words: list of words
    :type words : list
    :param width: width of each line
    :type width: int
    :return: left justified words as list
    """
    return ' '.join(words).ljust(width)


def metric_set_min(key, value):
    """Sets metric value if it is less that the current one.

    :param str|unicode key:

    :param int|long value:

    :rtype: bool
    """
    return False


def cpu_list_product(iterable):
    """returns the product of a list"""
    prod = 1
    for n in iterable:
        prod *= n
    return prod


def _is_iter(lst):
    """Is ``lst`` an iterator?
    """
    try:
        return list(lst)
    except:
        return False


@staticmethod
def _rem_clean(rem):
    """Strip, transform newlines, and escape '[' in string so it's
        acceptable as a remind entry."""
    return rem.strip().replace('\n', '%_').replace('[', '["["]')


def replace(node, **kw):
    """Equivalent to namedtuple's _replace.
    When **kw is empty simply returns node itself.

    >>> o = BinOp(Add(), NumberConstant(2), NumberConstant(3))
    >>> o2 = replace(o, op=Sub(), left=NumberConstant(3))
    >>> print(o, o2)
    (2 + 3) (3 - 3)
    """
    if kw:
        vals = dict(node)
        vals.update(**kw)
        return node.__class__(**vals)
    else:
        return node


def _past_month(m):
    """Subtract 1 from month."""
    if m == 1:
        return 12
    else:
        return m - 1


@classmethod
def get_format_string(cls):
    """See BzrDirFormat.get_format_string()."""
    return b'Bazaar-NG branch, format 5\n'


@classmethod
def merge(cls, intervals, merge_contiguous=False, **kwargs):
    """ merge a list of intervals and return a list of intervals

        By default, the intervals must be overlapping to be merged.  If you
        want to merge contiguous intervals, set merge_contiguous to True.
        """
    is_overlapping = cls.is_contiguous if merge_contiguous else cls.overlaps
    intervals = sorted(intervals, key=lambda x: (x.chrom, x.end))
    if len(intervals) > 1:
        done, todo = [intervals[0].copy(**kwargs)], intervals[1:]
        while todo:
            item = todo.pop(0).copy(**kwargs)
            while done and is_overlapping(item, done[-1]):
                item = done.pop().union(item, merge_contiguous=merge_contiguous
                    )
            done.append(item)
    else:
        done = intervals
    return done


@staticmethod
def process_sink_covariates(covariates):
    """Process sink covariates before saving them.

        This method is applied to the sink covariates before they are saved.
        The method can be used to compute derived covariates

        Parameters
        ----------
        covariates : float[]
            Covariates describing the attractiveness of sinks

        """
    return covariates


def subdivideEdge(G):
    """
    Given a graph G, returns a graph in which the
    edges of G are subdivided.

    INPUT
    G: A networkx graph

    OUTPUT
    Ge: The edge subdivision of G
    """
    Ge = G.copy()
    edges = G.edges()
    for edge in edges:
        Ge.remove_edge(*edge)
        Ge.add_node(str(edge))
        Ge.add_edge(edge[0], str(edge))
        Ge.add_edge(edge[1], str(edge))
    return Ge


def fprints_from_fprints_dict(fprints_dict, level=-1):
    """Get fingerprint at `level` from dict of level to fingerprint."""
    fprints_list = fprints_dict.get(level, fprints_dict[max(fprints_dict.
        keys())])
    return fprints_list


def pause():
    """
    overpython.pause()

    Will ask the user to press ENTER key and exits with code 64.
    overpython.returnf(0) will also do the same exact function.
    """
    print('Press the ENTER key to exit...')
    input()
    exit(64)


@staticmethod
def _noRepeat(pts):
    """Remove repeated points"""
    p0 = None
    for p in pts:
        if p != p0:
            yield p
            p0 = p


def mavfmt(field):
    """work out the struct format for a type"""
    map = {'float': 'f', 'double': 'd', 'char': 'c', 'int8_t': 'b',
        'uint8_t': 'B', 'uint8_t_mavlink_version': 'B', 'int16_t': 'h',
        'uint16_t': 'H', 'int32_t': 'i', 'uint32_t': 'I', 'int64_t': 'q',
        'uint64_t': 'Q'}
    if field.array_length:
        if field.type in ['char', 'int8_t', 'uint8_t']:
            return str(field.array_length) + 's'
        return str(field.array_length) + map[field.type]
    return map[field.type]


def path_list_is_parent(parent_pl, son_pl):
    """
        from xdict.utils import *
        path_list_is_parent(['a','b',''],['a','b','c'])
        path_list_is_parent(['a','b',''],['a','b','c',''])
        path_list_is_parent(['a','b',''],['a','b','c','d'])
        path_list_is_parent(['a','b',''],['a','b','c','d',''])

        path_list_is_parent(['','a','b'],['a','b','c'])
        path_list_is_parent(['','a','b'],['a','b','c',''])
        path_list_is_parent(['','a','b'],['a','b','c','d'])
        path_list_is_parent(['','a','b'],['a','b','c','d',''])

        path_list_is_parent(['a','b'],['a','b','c'])
        path_list_is_parent(['a','b'],['a','b',''])
        path_list_is_parent(['a','b'],['a','b','c',''])
        path_list_is_parent(['a','b'],['a','b','c','d'])
        path_list_is_parent(['a','b'],['a','b','c','d',''])

        path_list_is_parent(['a','b'],['a','b','c'])
        path_list_is_parent(['a','b'],['a','b','c',''])
        path_list_is_parent(['a','b'],['a','b','c','d'])
        path_list_is_parent(['a','b'],['a','b','c','d',''])
    """
    sl_len = son_pl.__len__()
    pl_len = parent_pl.__len__()
    if sl_len - 1 == pl_len:
        for i in range(0, pl_len):
            if parent_pl[i] == son_pl[i]:
                pass
            else:
                return False
        return True
    else:
        return False


def passProperty(image, to, properties):
    """ Pass properties from one image to another

    :param img_with: image that has the properties to tranpass
    :type img_with: ee.Image
    :param img_without: image that will recieve the properties
    :type img_without: ee.Image
    :param properties: properies to transpass
    :type properties: list
    :return: the image with the new properties
    :rtype: ee.Image
    """
    for prop in properties:
        p = image.get(prop)
        to = to.set(prop, p)
    return to


def get_args_pos(fparams) ->int:
    """Position in params of function of varargs, >= 0 if it's present, else -1.
    fparams is inspect.signature(f).parameters
        for some function f.

    Doctests:
    >>> import inspect
    >>> def f(a, b, c, x=8, **kwargs): pass
    >>> get_args_pos(inspect.signature(f).parameters)
    -1
    >>> def ff(a, b, *other_args, **kwargs): pass
    >>> get_args_pos(inspect.signature(ff).parameters)
    2
    >>> def fff(*args): pass
    >>> get_args_pos(inspect.signature(fff).parameters)
    0
    """
    for i, name in enumerate(fparams):
        param = fparams[name]
        if param.kind == param.VAR_POSITIONAL:
            return i
    return -1


@classmethod
def _has_element(cls, container, index):
    """Check to see if an index is in the container.

        Args:
            container (obj): Object that should be checked for index.
            index (obj): Index that should be checked for.

        Returns:
            bool: True if the index is in the container.

        """
    return index in container


def _is_fstype(fs_type):
    """
    Check if file system type is supported in module
    :param fs_type: file system type
    :return: True if fs_type is supported in this module, False otherwise
    """
    return fs_type in set(['ext2', 'ext3', 'ext4', 'fat32', 'fat16',
        'linux-swap', 'reiserfs', 'hfs', 'hfs+', 'hfsx', 'NTFS', 'ntfs', 'ufs']
        )


def add_selection_group(parser):
    """
    Add program selection arguments
    """
    group = parser.add_argument_group('Select Programs')
    group.add_argument('names', nargs='*', metavar='PROG', help=
        'Names of the programs to select')
    group.add_argument('-a', '--all', action='store_true', help=
        'select all programs')


def resource_url(resource, request, *elements, **kw):
    """
    This is a backwards compatibility function.  Its result is the same as
    calling::

        request.resource_url(resource, *elements, **kw)

    See :meth:`pyramid.request.Request.resource_url` for more information.
    """
    return request.resource_url(resource, *elements, **kw)


@classmethod
def can_solve(cls, filter_):
    """Tells if the solver is able to resolve the given filter.

        Arguments
        ---------
        filter_ : subclass of dataql.resources.BaseFilter
            The subclass or ``BaseFilter`` to check if it is solvable by the current solver class.

        Returns
        -------
        boolean
            ``True`` if the current solver class can solve the given filter, ``False`` otherwise.

        Example
        -------

        >>> FilterSolver.solvable_filters
        (<class 'dataql.resources.Filter'>,)
        >>> FilterSolver.can_solve(Filter(name='foo'))
        True
        >>> SliceSolver.can_solve(Filter(name='foo'))
        False

        """
    for solvable_filter in cls.solvable_filters:
        if isinstance(filter_, solvable_filter):
            return True
    return False


@classmethod
def from_fraction(cls, fraction, precision):
    """ A short way of constructing Intervals from a fraction. """
    return cls((fraction.numerator * 10 ** precision - 1) // fraction.
        denominator, (fraction.numerator * 10 ** precision + 1) // fraction
        .denominator, precision)


@staticmethod
def ones(shape, dtype=None):
    """Return a new tensor of given shape and type, filled with ones.

        Parameters
        ----------
        shape : int or sequence of ints
            Shape of the new tensor.
        dtype : data-type, optional
            The desired data-type for the tensor.
        """
    raise NotImplementedError


def lock_database_and_move(store_connection, blobhelper, ude, commit=True,
    committing_tid_int=None, after_selecting_tid=None):
    """
        Lock the database, choose the next TID, and move temporary
        data into its final place.

        This is used in two modes. In the usual case, *commit* will be
        true, and this method is called to implement the final step of
        ``tpc_finish``. In that case, this method is responsible for
        committing the transaction (using the *store_connection*
        provided). When *commit* is false, this method is effectively
        part of ``tpc_vote`` and must **not** commit.

        The *blobhelper* is the :class:`IBlobHelper`. This method is
        responsible for moving blob data into place if the blob data
        is stored on the server and there are blobs in this
        transaction. (Implementations that use stored procedures will
        probably not need this argument; it is here to be able to
        provide ``txn_has_blobs`` to
        :meth:`IObjectMover.move_from_temp`.)

        *ude* is a tuple of ``(username, description, extension)``.

        If *committing_tid_int* is None, then this method must lock
        the database and choose the next TID as if by calling
        :meth:`lock_database_and_choose_next_tid` (passing in the
        expanded *ude*); if it is **not** None, the database has
        already been locked and the TID selected.

        *after_selecting_tid* is a function of one argument, the
        committing integer TID. If it is proveded, it must be called
        once the TID has been selected and temporary data moved into
        place.

        Implementations are encouraged to do all of this work in as
        few calls to the database as possible with a stored procedure
        (ideally one call). The default implementation will use
        :meth:`lock_database_and_choose_next_tid`,
        :meth:`IObjectMover.move_from_temp`,
        :meth:`IObjectMover.update_current` and
        :meth:`ITransactionControl.commit_phase1` and
        :meth:`ITransactionControl.commit_phase2`.

        When committing, implementations are encouraged to exit any
        :meth:`critical phase <IDBDriver.enter_critical_phase_until_transaction_end>`
        in the most timely manner possible after ensuring that the commit
        request has been sent, especially if only one
        communication with the database is required that may block for an arbitrary
        time to get the lock.

        :return: A tuple ``(committing_tid_int, prepared_txn_id)``;
                 the *prepared_txn_id* is irrelevant if *commit* was
                 true.
        """


def is_binary(node):
    """Is the subtree under `node` a fully bifurcating tree?"""
    for x in node.preorder_internal_node_iter():
        if len(x.child_nodes()) != 2:
            return False
    return True


def printEvolutionInfo(evolution):
    """Function that prints all important parameters of the evolution.
    :param evolution: evolution object
    """
    print('> Simulation parameters')
    print(f'HDF file storage: {evolution.trajectoryFileName}')
    print(f'Trajectory Name: {evolution.trajectoryName}')
    if hasattr(evolution, '_t_end_initial_population'):
        print(
            f'Duration of evaluating initial population {evolution._t_end_initial_population - evolution._t_start_initial_population}'
            )
    if hasattr(evolution, '_t_end_evolution'):
        print(
            f'Duration of evolution {evolution._t_end_evolution - evolution._t_start_evolution}'
            )
    if evolution.model is not None:
        print(f'Model: {type(evolution.model)}')
        if hasattr(evolution.model, 'name'):
            if isinstance(evolution.model.name, str):
                print(f'Model name: {evolution.model.name}')
    print(f'Eval function: {evolution.evalFunction}')
    print(f'Parameter space: {evolution.paramInterval}')
    print('> Evolution parameters')
    print(f'Number of generations: {evolution.NGEN}')
    print(f'Initial population size: {evolution.POP_INIT_SIZE}')
    print(f'Population size: {evolution.POP_SIZE}')
    print(f'Crossover paramter: {evolution.CXP}')
    print(f'Selection paramter: {evolution.RANKP}')
    if len(evolution.comments) > 0:
        if isinstance(evolution.comments, str):
            print(f'Comments: {evolution.comments}')
        elif isinstance(evolution.comments, list):
            for c in evolution.comments:
                print(f'Comments: {c}')


def commutator(op_a, op_b, op_c=None, threshold=1e-12):
    """
    Compute commutator of `op_a` and `op_b` or
    the symmetric double commutator of `op_a`, `op_b` and `op_c`.

    See McWeeny chapter 13.6 Equation of motion methods (page 479)

    | If only `op_a` and `op_b` are provided:
    |     result = A\\*B - B\\*A;
    |
    | If `op_a`, `op_b` and `op_c` are provided:
    |     result = 0.5 \\* (2\\*A\\*B\\*C + 2\\*C\\*B\\*A - B\\*A\\*C - C\\*A\\*B - A\\*C\\*B - B\\*C\\*A)

    Args:
        op_a (WeightedPauliOperator): operator a
        op_b (WeightedPauliOperator): operator b
        op_c (Optional(WeightedPauliOperator)): operator c
        threshold (float): the truncation threshold

    Returns:
        WeightedPauliOperator: the commutator

    Note:
        For the final chop, the original codes only contain the paulis with real coefficient.
    """
    op_ab = op_a * op_b
    op_ba = op_b * op_a
    if op_c is None:
        res = op_ab - op_ba
    else:
        op_ac = op_a * op_c
        op_ca = op_c * op_a
        op_abc = op_ab * op_c
        op_cba = op_c * op_ba
        op_bac = op_ba * op_c
        op_cab = op_c * op_ab
        op_acb = op_ac * op_b
        op_bca = op_b * op_ca
        tmp = op_bac + op_cab + op_acb + op_bca
        tmp = 0.5 * tmp
        res = op_abc + op_cba - tmp
    res.simplify()
    res.chop(threshold)
    return res


@staticmethod
def format_fingerprint(fingerprint: str) ->str:
    """Format a PGP fingerprint into sections of 4 characters, separated by spaces."""
    string_parts = []
    for idx in range(0, 40, 4):
        string_parts.append(fingerprint[idx:idx + 4])
        if idx == 16:
            string_parts.append('')
    return ' '.join(string_parts)


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


@staticmethod
def _idxs2items(edge_node_table, arr):
    """For the given array, get all edges based on edge node table.

        :param edge_node_table: edge table to be used
        :param arr: a list of indexes to edge table
        :return: edges that correspond to the given index array
        """
    ret = []
    for i in arr:
        ret.append(edge_node_table[i])
    return ret


@staticmethod
def _resolve_param_duplicates(values, param_defn, _in):
    """ Resolve cases where query parameters are provided multiple times.
            The default behavior is to use the first-defined value.
            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
            `a` would be "1,2,3".
            However, if 'collectionFormat' is 'multi' then the duplicate values
            are concatenated together and `a` would be "1,2,3,4,5,6".
        """
    if param_defn.get('collectionFormat') == 'multi':
        return ','.join(values)
    return values[0]


@classmethod
def at(cls, cursor, after_token=False, tokens_with_position=False):
    """Create and init from a Cursor.

        The Runner is positioned so that yielding forward starts with the
        first complete token after the cursor's start position.

        Set after_token to True if you want to position the cursor after the
        token, so that it gets yielded when you go backward.

        If tokens_with_position is True, uses the tokens_with_position()
        method to get the tokens, else (by default), the tokens() method is
        used.

        """
    runner = cls(cursor.document, tokens_with_position)
    runner.set_position(cursor.start, after_token)
    return runner


def skewed_heteroscedastic_mean(X):
    """Theoretical mean."""
    mean = 4 * X * (1 - X) + X
    return mean


@staticmethod
def score(uri: str) ->int:
    """
        Returns a score value for the give uri. E.g. 0 for unlikely/unknown, 20 for yes, probalby thats the file format the reader can read.

        :param uri: str
        :return: int
        """
    return 0


def channels_group(name: str='NewGroup'):
    """Add selected F-Curves to a new group

    :param name: Name, Name of newly created group
    :type name: str
    """
    pass


def key_match(key1, key2):
    """determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
    For example, "/foo/bar" matches "/foo/*"
    """
    i = key2.find('*')
    if i == -1:
        return key1 == key2
    if len(key1) > i:
        return key1[:i] == key2[:i]
    return key1 == key2[:i]


def add_tags_to_resource(ResourceArn=None, TagList=None):
    """
    Adds or overwrites one or more tags for the specified AWS CloudHSM resource.
    Each tag consists of a key and a value. Tag keys must be unique to each resource.
    See also: AWS API Documentation

    :example: response = client.add_tags_to_resource(
        ResourceArn='string',
        TagList=[
            {
                'Key': 'string',
                'Value': 'string'
            },
        ]
    )

    :type ResourceArn: string
    :param ResourceArn: [REQUIRED]
            The Amazon Resource Name (ARN) of the AWS CloudHSM resource to tag.

    :type TagList: list
    :param TagList: [REQUIRED]
            One or more tags.
            (dict) --A key-value pair that identifies or specifies metadata about an AWS CloudHSM resource.
            Key (string) -- [REQUIRED]The key of the tag.
            Value (string) -- [REQUIRED]The value of the tag.

    :rtype: dict
    :return: {
        'Status': 'string'
    }

    """
    pass


@staticmethod
def defaultReceptionTimeout():
    """Returns the default reception timeout representing
        an empty symbol

        :return: the default reception timeout in milliseconds
        :rtype: :class:`int`
        """
    return 5000


@classmethod
def get_image_info(cls, name):
    """
        Gets an image's info.

        It is not required to prefix the name with ``File:``, but the extension is required.

        Parameters
        ----------
        name: :class:`str`
            The name of the image.

        Returns
        -------
        :class:`Image`
            The image's information.
        """
    gen = cls.get_images_info([name])
    return next(gen)


def initialize_preactivation_states(dense_outputs, obj):
    """Creates lists for `preactivation_states` dictionary."""
    for tensor in dense_outputs:
        layer_name = tensor.name.split('/')[0]
        obj.preactivation_states[layer_name] = []


def name_validator(data):
    """
    accept only all primaries new_primaries none
    """
    try:
        if (data == 'all' or data == 'primaries' or data == 'new_primaries' or
            data == 'none'):
            return data
        elif data == 'disable':
            return 'none'
        elif data == 'enable':
            return 'all'
        elif data == 'default':
            return None
        else:
            raise ValueError
    except ValueError:
        return 'Bad status value'


def __ne__(A, other):
    """Returns true if both objects are not equal"""
    return not A == other


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

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

    o: float odds, strictly positive

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


def writeBED(inBED, file_path):
    """
    Writes a bed dataframe into a bed file.
    Bed format: 'chrom','chromStart','chromEnd','name','score','strand'

    :param inBED: bed dataframe to be written.
    :param file_path: /path/to/file.bed

    :returns: nothing

    """
    inBED.to_csv(file_path, index=None, sep='\t', header=None)


def donate(args):
    """Consider a donation to the author."""
    print(
        'Please assist by implementing this command: support donations to the author.'
        )


def _vpd(es, ea):
    """Vapor pressure deficit

    Parameters
    ----------
    es : ee.Image or ee.Number
        Saturated vapor pressure [kPa].
    ea : ee.Image or ee.Number
        Actual vapor pressure [kPa].

    Returns
    -------
    ee.Image or ee.Number
        Vapor pressure deficit [kPa].

    """
    return es.subtract(ea).max(0)


def addCriterion(field, criterion_type):
    """Add a new search criterion.
        """


def get_client_ip(request):
    """
        Return the client IP address as a string.
    """
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        return x_forwarded_for.split(',')[0]
    return request.META.get('REMOTE_ADDR')


@staticmethod
def _negotiate(client_value, server_value):
    """Return the negotiated value between what the client has requested
        and the server has requested for how the two will communicate.

        :param int client_value:
        :param int server_value:
        :return: int

        """
    return min(client_value, server_value) or (client_value or server_value)


@classmethod
def _pack_weights(cls, model_params, placeholder):
    """Create a single list of weights to pass to the solver."""
    raise NotImplementedError


def get_route_name(route):
    """Returns route name."""
    name = route.split('/', 1)[-1]
    return name


def add_density_option_group(parser):
    """Adds the options needed to configure contours and density colour map.

    Parameters
    ----------
    parser : object
        ArgumentParser instance.
    """
    density_group = parser.add_argument_group(
        'Options for configuring the contours and density color map')
    density_group.add_argument('--density-cmap', type=str, default=
        'viridis', help=
        'Specify the colormap to use for the density. Default is viridis.')
    density_group.add_argument('--contour-color', type=str, default=None,
        help=
        'Specify the color to use for the contour lines. Default is white for density plots and black for scatter plots.'
        )
    density_group.add_argument('--use-kombine-kde', default=False, action=
        'store_true', help=
        "Use kombine's KDE for determining contours. Default is to use scipy's gaussian_kde."
        )
    return density_group


def binary_regex_search(prog):
    """Returns a function that returns 1 or 0 depending on regex search result.

    If regular expression compiled into prog is present in a string
    the result of calling the returned function with the string will be 1
    and 0 otherwise.

    >>> import regex as re
    >>> binary_regex_search(re.compile("12"))("12")
    1
    >>> binary_regex_search(re.compile("12"))("34")
    0
    """
    return lambda s: 1 if prog.search(s) else 0


def url():
    """Returns a string representing the location of this repo."""


def p_arregloD(p):
    """arregloD : '[' arregloE ']' ',' arregloD
                | '[' arregloE ']'
    """
    if len(p) > 4:
        if p[5][1] != p[2]:
            raise TypeError('Arrays in matrix must be of same size')
        p[0] = p[5][0] + 1, p[2]
    else:
        p[0] = 1, p[2]


def is_van(df):
    """Return if vehicle is a van, per NHTSA convention."""
    yr = df['YEAR']
    body = df['BODY_TYP']
    return yr.between(1975, 1981) & (body == 51) | yr.between(1982, 1990
        ) & body.isin([40, 41, 48, 49]) | (1991 <= yr) & body.isin([20, 21,
        22, 24, 25, 28, 29])


def text_paste():
    """Paste text from clipboard

    """
    pass


def are_skeleton_equal(sk1, sk2):
    """
    Test whether the two skeleton ``sk1`` and ``sk2`` are equals.

    EXAMPLES::

        sage: from surface_dynamics.flat_surfaces.origamis.origami_database import are_skeleton_equal
        sage: sk1 = {'table1': {'col1': {'sql': 'TEXT', 'unique': True}, 'col2': {'sql': 'INTEGER'}}}
        sage: sk2 = {'table1': {'col1': {'sql': 'TEXT', 'unique': True}, 'col2': {'sql': 'INTEGER', 'unique': False}}}
        sage: are_skeleton_equal(sk1,sk2)
        True
    """
    if set(sk1.keys()) != set(sk2.keys()):
        return False
    for table in sk1:
        v1 = sk1[table]
        v2 = sk2[table]
        if set(v1.keys()) != set(v2.keys()):
            return False
        for col in v1:
            w1 = v1[col]
            w2 = v2[col]
            if w1['sql'] != w2['sql']:
                return False
            if w1.get('index', False) != w2.get('index', False):
                return False
            if w1.get('unique', False) != w2.get('unique', False):
                return False
            if w1.get('primary_key', False) != w2.get('primary_key', False):
                return False
    return True


def _to_public_key(obj):
    """Convert obj a PublicKey object."""
    from .keys import PublicKey
    if isinstance(obj, PublicKey):
        return obj
    if isinstance(obj, str):
        return PublicKey.from_hex(obj)
    return PublicKey.from_bytes(obj)


@classmethod
def ones(cls, shape, dtype=float):
    """Return a new array of given shape and type, filled with ones."""
    raise NotImplementedError


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

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

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


def bpseq_output(seq, pairs, header_lines=None, removed=None):
    """Return sequence and structure information in bpseq format

    seq -- string of sequence characters, no validation
    pairs -- Pairs object or list of tuples
    header_lines -- list of header lines at the top of the file

    Return value is a formatted string
    """
    result = []
    if header_lines:
        result.extend(header_lines)
    partners = pairs.toPartners(len(seq))
    for idx, (seq_symbol, partner_idx) in enumerate(zip(seq, partners)):
        if partner_idx is None:
            partner_idx = -1
        result.append(' '.join(map(str, [idx + 1, seq_symbol, partner_idx +
            1])))
    if removed is not None:
        result.append('# REMOVED BASE PAIRS')
        partners = removed.toPartners(len(seq))
        for idx, (seq_symbol, partner_idx) in enumerate(zip(seq, partners)):
            if partner_idx is None:
                partner_idx = -1
            result.append(' '.join(map(str, [idx + 1, seq_symbol,
                partner_idx + 1])))
    return '\n'.join(result)


def _get_vel_mass(particles, selection=None):
    """Return velocity and mass for a selection.

    This is just for convenience since we are using this
    selection a lot.

    Parameters
    ----------
    particles : object like :py:class:`.Particles`
        This object represents the particles.
    selection : list of integers, optional
        A list with indices of particles to use in the calculation.

    Returns
    -------
    out[0] : numpy.array
        The velocities corresponding to the selection.
    out[1] : numpy.array, optional
        The masses corresponding to the selection.

    """
    if selection is None:
        vel = particles.vel
        mass = particles.mass
    else:
        vel = particles.vel[selection]
        mass = particles.mass[selection]
    return vel, mass


def _set_autocommit(connection):
    """Make sure a connection is in autocommit mode."""
    if hasattr(connection.connection, 'autocommit'):
        if callable(connection.connection.autocommit):
            connection.connection.autocommit(True)
        else:
            connection.connection.autocommit = True
    elif hasattr(connection.connection, 'set_isolation_level'):
        connection.connection.set_isolation_level(0)


def could_merge(df1, df2):
    """Naive check for whether DataFrames can merge"""
    memory = {}
    for column in df1.columns:
        memory[column] = True
    for column in df2.columns:
        if column in memory:
            return column
    return None


def _from_bytes(b):
    """
	Convert a string from bytes if it is not already a string.

	:param b: string to convert
	:type b: `str` or `bytes`

	:return: decoded string
	:rtype: str
	"""
    if isinstance(b, bytes):
        return b.decode('utf-8')
    return b


def quote(value):
    """Quote a string value."""
    res = ['"']
    for char in value:
        if char == '"':
            res.append('\\')
        res.append(char)
    res.append('"')
    return ''.join(res)


def function_args(function):
    """
    This will return a list of the non-keyword arguments
    :param function:    function to check arguments for
    :return:            list of arguments
    """
    try:
        return function.__code__.co_varnames
    except:
        return function.f_code.co_varnames


def get_class_parameters(cosmology):
    """
    Get CLASS parameters corresponding to an astropy cosmology model.
    """
    class_parameters = {}
    try:
        class_parameters['h'] = cosmology.h
        class_parameters['T_cmb'] = cosmology.Tcmb0.value
        class_parameters['Omega_b'] = cosmology.Ob0
        class_parameters['Omega_cdm'] = cosmology.Odm0 - cosmology.Onu0
        class_parameters['Omega_k'] = cosmology.Ok0
        class_parameters['Omega_scf'] = 0.0
        try:
            class_parameters['w0_fld'] = cosmology.w0
            class_parameters['wa_fld'] = 0.0
            class_parameters['Omega_Lambda'] = 0.0
        except AttributeError:
            class_parameters['Omega_fld'] = 0.0
        if cosmology.has_massive_nu:
            m_nu = cosmology.m_nu
            try:
                num_massive = len(m_nu)
            except TypeError:
                num_massive = 3
                m_nu = [num_massive * m_nu]
            if num_massive > 3:
                raise RuntimeError(
                    'Cannot calculate cosmology with >3 massive neutrinos.')
            m_ncdm = []
            for mass in m_nu:
                if mass > 0:
                    m_ncdm.append(repr(mass.value))
                else:
                    num_massive -= 1
            if num_massive > 0:
                class_parameters['m_ncdm'] = ','.join(m_ncdm)
        else:
            num_massive = 0
        class_parameters['N_ncdm'] = num_massive
        num_light = 3 - num_massive
        class_parameters['N_ur'] = 3.00641 - num_massive + num_light * (
            cosmology.Neff - 3.00641) / 3.0
    except AttributeError:
        raise ValueError('Cosmology is missing required attributes.')
    return class_parameters


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

        :param DeleteTeamInviteLinkDetails val:
        :rtype: EventDetails
        """
    return cls('delete_team_invite_link_details', val)


def validate_boolean(b):
    """Convert b to a boolean or raise a ValueError."""
    try:
        b = b.lower()
    except AttributeError:
        pass
    if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True):
        return True
    elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False):
        return False
    else:
        raise ValueError('Could not convert "%s" to boolean' % b)


def between(val, schema, min_val, max_val):
    """
    !~~between(min,max)
        corresponding integers in documents must be between min and max,
        included.
    """
    return min_val <= val <= max_val


def calculate_normalisation(slab_energy, slab_cations, bulk, area):
    """Normalises the slab energy relative to the bulk material.
    Thus allowing the different slab calculations to be compared.

    .. math::
        Energy = \\frac{1}{2A} \\Bigg( E_{MO}^{slab} -
        \\frac{nCat_{slab}}{nCat_{Bulk}} E_{MO}^{Bulk} \\Bigg)

    where Energy is the slab energy normalised to the
    bulk, :math:`E_{MO}^{slab}` is the DFT slab energy, :math:`nCat_{slab}`
     is the number of slab cations, :math:`nCat_{Bulk}` is the number of bulk
    cations, :math:`E_{MO}^{Bulk}` is the DFT bulk energy A is the surface
    area.

    Parameters
    ----------
    slab_energy : float
        Energy of the slab from DFT
    slab_cations : int
        Total number of cations in the slab
    bulk : dictionary
        Dictionary of bulk properties
    area : float
        Surface area

    Returns
    -------
    float:
        Constant normalising the slab energy to the bulk energy.
    """
    return (slab_energy - slab_cations / bulk['Cation'] * (bulk['Energy'] /
        bulk['F-Units'])) / (2 * area)


def _test():
    """perform internal tests."""
    import doctest
    doctest.testmod()


def get_grid(ntot):
    """
    Get a 2-d grid layout given the total number of plots

    returns nrow,ncol

    e.g.
       p1 p2

       p1 p2
       p3

       p1 p2
       p3 p4

       p1 p2 p3
       p4 p5

       etc.
    """
    from math import sqrt
    sq = int(sqrt(ntot))
    if ntot == sq * sq:
        return sq, sq
    elif ntot <= sq * (sq + 1):
        return sq, sq + 1
    else:
        return sq + 1, sq + 1


def create_log_group(awsclient, log_group_name):
    """Creates a log group with the specified name.

    :param log_group_name: log group name
    :return:
    """
    client_logs = awsclient.get_client('logs')
    response = client_logs.create_log_group(logGroupName=log_group_name)


def check_publish(publish):
    """ Convert the list of published variables to a set with unique elements.
    """
    if publish is None:
        publish = []
    elif isinstance(publish, str):
        publish = [publish]
    elif isinstance(publish, (list, tuple)):
        pass
    else:
        msg = (
            'The publish keyword should specify a string or a list of strings')
        raise RuntimeError(msg)
    return set(publish)


def fancy_time(build_time):
    """
    returns build time in human readable form

    :param build_time: total time taken for the build
    """
    seconds = build_time.seconds
    minutes = round(seconds / 60)
    hours = round(seconds / 60 / 60)
    days = build_time.days
    f_time = ''
    if days > 0:
        f_time = str(days)
        f_time = f_time + (' day' if days == 1 else ' days')
    elif hours > 0:
        f_time = str(hours)
        f_time = f_time + (' hour' if hours == 1 else ' hours')
    elif minutes > 0:
        f_time = str(minutes)
        f_time = f_time + (' minute' if minutes == 1 else ' minutes')
    elif seconds > 0:
        f_time = str(seconds)
        f_time = f_time + (' second' if seconds == 1 else ' seconds')
    else:
        f_time = 'zero time'
    return f_time


def init_manager_process(parent_logger, initializer=None, initargs=()):
    """
    Migrate the logger of the parent to the child. It will be a queue logger anyway.

    :param parent_logger: The logger from the parent
    :param initializer: Optional extra initializer
    :param initargs: Optional initializer arguments
    """
    global logger
    logger = parent_logger
    if initializer:
        initializer(*initargs)


@classmethod
def is_valid(cls, state_to_test):
    """Tests if a state is a valid one."""
    return state_to_test in cls.__dict__


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

        :param ShowcaseAddMemberDetails val:
        :rtype: EventDetails
        """
    return cls('showcase_add_member_details', val)


def get_addr_cell(text):
    """
    Возвращает адрес ячейки
    То есть из представления 'AZ12' выдается ('AZ', 12)

    :param text: полное строковое представление ячейки
    :type text: str
    """
    for i, s in enumerate(text):
        if s.isdigit():
            return text[:i], int(text[i:])
    else:
        raise ValueError('Addr cell is bad format value "%s"' % text)


def getIndent(line: str):
    """ get the indent part of a line of code """
    i = 0
    for i in range(len(line)):
        if line[i] != ' ' and line[i] != '\t':
            break
    indent = line[:i]
    return indent


def is_instance(obj):
    """
    Tests if obj is a class instance of any type.

    Parameters
    ----------
    obj : any
        Input object

    Returns
    -------
    out : bool
        Flag if obj is class instance or not
    """
    try:
        _ = obj.__dict__
        return True
    except AttributeError:
        return False


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 supportsWorkAddition():
    """Indicates if a given policy supports addition of new work"""
    return False


def zero_variance_flagger_and_cutter(df, useful_cols, cutter=True):
    """
    Function flags features with only one value (zero variance), and, if specified, culls these from the input dataframe (inplace)

    Parameters
    ----------
    df : pandas.DataFrame
        Desired features
    useful_cols : pandas.DataFrame
        Lookup table detailing desired features
    cutter : bool
        If true [default], df is modified to remove features with only one value

    Returns
    -------
    zero_variance_features : list
        List of features with zero variance
    useful_cols : pandas.DataFrame
        Returned unchanged if `cutter` == False, else the clipped features are removed
    """
    zero_variance_features = []
    for feature_name, feature in df.iteritems():
        if len(feature.value_counts()) == 1:
            zero_variance_features.append(feature_name)
    if cutter == True:
        print(
            f'Following features dropped for having zero variance: {zero_variance_features}'
            )
        df.drop(zero_variance_features, axis=1, inplace=True)
        useful_cols = useful_cols.loc[(~useful_cols.feature.isin(
            zero_variance_features)), :]
    return zero_variance_features, useful_cols


def _df_nans_not_allowed(df_name, df):
    """
    Internal function that raises an exception if a user passed a DataFrame
    with NANs when not allowed.
    """
    if df is None:
        raise TypeError('Expected DataFrame {}'.format(df_name))
    if df.isnull().values.any():
        raise TypeError('Found unexpected NaN values in DataFrame "{0}".'.
            format(df_name))


def virtual(func: 'callable'):
    """
    mark a function as "virtual", which means that this function can be override.
    any base class should use this or @abstractmethod to decorate all functions
    that can be (re)implemented by subclasses.
    """
    return func


def decode_string(v, encoding='utf-8'):
    """ Returns the given value as a Unicode string (if possible).
    """
    if isinstance(encoding, str):
        encoding = ((encoding,),) + (('windows-1252',), ('utf-8', 'ignore'))
    if isinstance(v, bytes):
        for e in encoding:
            try:
                return v.decode(*e)
            except:
                pass
        return v
    return str(v)


def split_args(args):
    """Split command line args in 3 groups:
    - head, containing the initial options
    - body, containing everything after head, up to the first option
    - tail, containing everything after body
    """
    head = []
    body = []
    tail = []
    for arg in args:
        if arg.startswith('-'):
            if body:
                tail.append(arg)
            else:
                head.append(arg)
        elif tail:
            tail.append(arg)
        else:
            body.append(arg)
    return head, body, tail


def channels_click(extend: bool=False):
    """Handle clicks to select NLA channels

    :param extend: Extend Select
    :type extend: bool
    """
    pass


def npv(pval, payarray, rate, fromdayone):
    """ npv - Net Present Value
    """
    for i, payment in enumerate(payarray):
        pval -= payment / pow(1 + rate / (12 * 100.0), fromdayone + i)
    return pval


def serialize(to_serialize, version, desc, iv) ->bytes:
    """This serializes the prepared header, prepending the version and the
    length of the following header.
    """
    return bytes([version >> 8, version & 255, len(desc)]
        ) + desc + iv + to_serialize


@staticmethod
def rename_key(old_key, new_key, commented_map, logger=None):
    """Rename a key in YAML file data that was loaded with the RoundTripLoader (e.g. that contains comments).

        Comments are retained for the renamed key. Order of keys is also maintained.

        Args:
            old_key: The existing key name you want to change.
            new_key: The new key name.
            commented_map: The YAML data CommentMap class (from yaml.load) with
                the key you want to change.
            logger: Optional logger instance which will be used to log this at
                the debug level.

        Returns the updated CommentedMap YAML dict. (Note that this method does not
        change the dict object (e.g. it's changed in place), you you most
        likely don't need to do anything with the returned dict.
        """
    if old_key == new_key or old_key not in commented_map:
        return commented_map
    key_list = list(commented_map.keys())
    for key in key_list:
        if key == old_key:
            if logger:
                logger.debug('Renaming key: %s: -> %s:', old_key, new_key)
            commented_map[new_key] = commented_map[old_key]
            try:
                commented_map.ca.items[new_key] = commented_map.ca.items.pop(
                    old_key)
            except KeyError:
                pass
            del commented_map[old_key]
        else:
            commented_map.move_to_end(key)
    return commented_map


@classmethod
def select(cls, symbol, start_date, end_date):
    """Method returns stock prices for current: ticker/symbol, start date, end date."""
    instance = cls(symbol, start_date, end_date)
    return instance.data


def is_iterable(obj):
    """
    Are we being asked to look up a list of things, instead of a single thing?
    We check for the `__iter__` attribute so that this can cover types that
    don't have to be known by this module, such as NumPy arrays.

    Strings, however, should be considered as atomic values to look up, not
    iterables. The same goes for tuples, since they are immutable and therefore
    valid entries.

    We don't need to check for the Python 2 `unicode` type, because it doesn't
    have an `__iter__` attribute anyway.
    """
    return hasattr(obj, '__iter__') and not isinstance(obj, str
        ) and not isinstance(obj, tuple)


def pytest_testnodeready(node):
    """ Test Node is ready to operate. """


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

    """
    pass


def print_overfit_metrics(df):
    """
    Method used to print the OverFit metrics. It basically adds a title and prints a DataFrame.
    :param df: (pandas DataFrame) OverFit metrics DataFrame
    """
    print('\n\n----------------------------------------------')
    print('OVERFIT METRICS')
    print('----------------------------------------------')
    print(df)


@staticmethod
def set_fold_trigger(block, val):
    """
        Set the block fold trigger flag (True means the block is a fold
        trigger).

        :param block: block to set
        :param val: value to set
        """
    if block is None:
        return
    state = block.userState()
    if state == -1:
        state = 0
    state &= 2080374783
    state |= int(val) << 26
    block.setUserState(state)


def dfa_nonemptiness_check(dfa: dict) ->bool:
    """ Checks if the input DFA is nonempty (i.e. if it recognizes a
    language except the empty one), returning True/False.

    An automaton A is nonempty if :math:`L(A) ≠ ∅`. L(A) is
    nonempty iff there are states :math:`s_0 and t ∈ F` such
    that t is connected to :math:`s_0`. Thus, automata
    nonemptiness is equivalent to graph reachability, where a
    breadth-first-search algorithm can construct in linear time
    the set of all states connected to initial state
    :math:`s_0`.
    A is nonempty iff this set intersects F nontrivially.

    :param dict dfa: input DFA.
    :return: *(bool)*, True if the DFA is nonempty, False otherwise
    """
    queue = [dfa['initial_state']]
    visited = set()
    visited.add(dfa['initial_state'])
    while queue:
        state = queue.pop(0)
        visited.add(state)
        for a in dfa['alphabet']:
            if (state, a) in dfa['transitions']:
                if dfa['transitions'][state, a] in dfa['accepting_states']:
                    return True
                if dfa['transitions'][state, a] not in visited:
                    queue.append(dfa['transitions'][state, a])
    return False


def isZeroToOne(value):
    """
    Utility function to confirm value(s) in range [0..1]
    """
    if isinstance(value, (list, tuple)):
        for each in value:
            if isinstance(each, (list, tuple)):
                for another in each:
                    if not 0 <= another <= 1:
                        return False
            elif not 0 <= each <= 1:
                return False
        return True
    if isinstance(value, (int, float)):
        return 0 <= value <= 1


def default_validators(item, context):
    """
    Check role and permission
    role and permission check result will be cached in context dict
    """
    from uliweb import functions, request
    roles = item.get('roles', [])
    perms = item.get('permissions', [])
    if roles or perms:
        if roles:
            con_roles = context.setdefault('roles', {})
            for x in roles:
                if x in con_roles:
                    flag = con_roles[x]
                else:
                    flag = functions.has_role(request.user, x)
                    con_roles[x] = flag
                if flag:
                    return flag
        if perms:
            con_perms = context.setdefault('permissions', {})
            for x in perms:
                if x in con_perms:
                    flag = con_perms[x]
                else:
                    flag = functions.has_permission(request.user, x)
                    con_perms[x] = flag
            if flag:
                return flag
    else:
        return True


def keyvault_is_recoverable(resource_groups):
    """

    version_added = 1.1
    """
    for resource in resource_groups:
        cmd = 'az resource show --id {}'.format(resource['id'])
        if not ('enableSoftDelete' == 'enabled' and 'enablePurgeProtection' ==
            'enabled'):
            print('fail')


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


@staticmethod
def preferencePages():
    """
        Returns all the preference pages used by this module.
        Must be overloaded.

        :returns: list of preference page classes
        """
    raise NotImplementedError()


@property
def is_impartial(G):
    """
        Whether the Surreal number is impartial or not. Only the Surreal 0 is impartial.

        Returns
        -------
        impartial : bool
            Whether this number is impartial.
        """
    return G._n == 0


def binary_reduce(reducer, binary_op, graph, lhs, rhs, lhs_data, rhs_data,
    out_size, lhs_map, rhs_map, out_map):
    """Perform binary operation between given data and reduce based on graph
    structure.

    Parameters
    ----------
    reducer : str
        Type of reduction: 'sum', 'max', 'min', 'mean', 'prod', 'none' (no
        reduction)
    binary_op : str
        Binary operation to perform, can be 'add', 'mul', 'sub', 'div'
    graph : GraphIndex
        The graph
    lhs : int
        The lhs target (src, dst, edge)
    rhs : int
        The rhs target (src, dst, edge)
    lhs_data : Tensor
        The lhs data
    rhs_data : Tensor
        The rhs data
    out_size : int
        Size of first dimension of output data
    lhs_map : tuple
        Two lhs id mapping arrays, one for forward pass, the other for backward
    rhs_map : tuple
        Two rhs id mapping arrays, one for forward pass, the other for backward
    out_map : tuple
        Two out id mapping arrays, one for forward pass, the other for backward

    Returns
    -------
    Tensor
        The result.
    """
    pass


def get_limit():
    """
    Canned response for limits for servers. Returns only the absolute limits
    """
    return {'limits': {'absolute': {'maxServerMeta': 40, 'maxPersonality':
        5, 'totalPrivateNetworksUsed': 0, 'maxImageMeta': 40,
        'maxPersonalitySize': 1000, 'maxSecurityGroupRules': -1,
        'maxTotalKeypairs': 100, 'totalCoresUsed': 5, 'totalRAMUsed': 2560,
        'totalInstancesUsed': 5, 'maxSecurityGroups': -1,
        'totalFloatingIpsUsed': 0, 'maxTotalCores': -1,
        'totalSecurityGroupsUsed': 0, 'maxTotalPrivateNetworks': 3,
        'maxTotalFloatingIps': -1, 'maxTotalInstances': 200,
        'maxTotalRAMSize': 256000}}}


@staticmethod
def _lowercase_first_letter(string):
    """
        Converts first letter of the string to lowercase

        :param string: initial string
        :return: initial string with first character in lowercase
        """
    if not string:
        return string
    return string[0].lower() + string[1:]


def _restore_coord_attrs(ds):
    """
    Put back coordinates attribute that
    to_netcdf and to_zarr didn't like.

    Parameters
    ----------
    ds: xarray.Dataset

    Returns
    -------
    ds: xarray.Dataset
    """
    for var in ds.variables:
        attrs = ds[var].attrs
        coordinates = attrs.pop('_coordinates', None)
        ds[var].attrs = attrs
        if coordinates is not None:
            ds[var].attrs['coordinates'] = coordinates
    return ds


def get_oct_digits(mode):
    """
    Separate a given integer into its three components
    """
    if not 0 <= mode <= 511:
        raise ValueError('expected a value between 000 and 777')
    return {'u': (mode & 448) >> 6, 'g': (mode & 56) >> 3, 'o': mode & 7}


def gettaskwithlabelid(labelid, api):
    """
    Returns a list of Task IDs found with given label-ID

    :param labelid: (str) label ID of label to search for
    :param api: (obj) todoist api
    :return: (list) found Task IDs
    """
    found = []
    for task in api.state['items']:
        if not isinstance(task['id'], str) and task['labels'] and not task[
            'is_deleted'] and not task['in_history'] and not getattr(task,
            'is_archived', 0):
            for label in task['labels']:
                if label == labelid:
                    found.append(task['id'])
    return found


def zigZagDecode(z):
    """ Reverses ZigZag encoding """
    return z >> 1 ^ -(z & 1)


def loopcut_slide(MESH_OT_loopcut=None, TRANSFORM_OT_edge_slide=None):
    """Cut mesh loop and slide it

    :param MESH_OT_loopcut: Loop Cut, Add a new loop between existing loops
    :param TRANSFORM_OT_edge_slide: Edge Slide, Slide an edge loop along a mesh
    """
    pass


def constraints_clear():
    """Clear all the constraints for the active Object only

    """
    pass


def transform_aabb(transform, aabb):
    """
    Apply a transformation to an axis aligned bounding box.

    The result is a new AABB in the same coordinate system as the original AABB.
    The new AABB contains all corner points of the original AABB after applying the given transformation.

    Args
        transform: The transformation to apply.
        x1:        The minimum x value of the AABB.
        y1:        The minimum y value of the AABB.
        x2:        The maximum x value of the AABB.
        y2:        The maximum y value of the AABB.
    Returns
        The new AABB as tuple (x1, y1, x2, y2)
    """
    x1, y1, x2, y2 = aabb
    points = transform.dot([[x1, x2, x1, x2], [y1, y2, y2, y1], [1, 1, 1, 1]])
    min_corner = points.min(axis=1)
    max_corner = points.max(axis=1)
    return [min_corner[0], min_corner[1], max_corner[0], max_corner[1]]


def mutex(container, *options):
    """ Given options must be mutually exclusive. """
    found = None
    for option in options:
        if container.get(option) is None:
            continue
        if found is not None:
            raise ValueError('options %s and %s are mutually exclusive' % (
                found, option))
        else:
            found = option


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


@classmethod
def initialized(cls):
    """Has an instance been created?"""
    return hasattr(cls, '_instance') and cls._instance is not None


def e_z(z, **cosmo):
    """The unitless Hubble expansion rate at redshift z.

    In David Hogg's (arXiv:astro-ph/9905116v4) formalism, this is
    equivalent to E(z), defined in his eq. 14.

    Modified (JBJ, 29-Feb-2012) to include scalar w parameter

    """
    if 'w' in cosmo:
        return (cosmo['omega_M_0'] * (1 + z) ** 3.0 + cosmo['omega_k_0'] *
            (1 + z) ** 2.0 + cosmo['omega_lambda_0'] * (1 + z) ** (1 +
            cosmo['w'])) ** 0.5
    else:
        return (cosmo['omega_M_0'] * (1 + z) ** 3.0 + cosmo['omega_k_0'] *
            (1 + z) ** 2.0 + cosmo['omega_lambda_0']) ** 0.5


def new_snr_chisq(snr, new_snr, chisq_dof, chisq_index=4.0, chisq_nhigh=3.0):
    """Returns the chi-square value needed to weight SNR into new SNR"""
    chisqnorm = (snr / new_snr) ** chisq_index
    if chisqnorm <= 1:
        return 1e-20
    return chisq_dof * (2 * chisqnorm - 1) ** (chisq_nhigh / chisq_index)