def get_network_interface_args(interface_index, interface_name):
    """Get QEMU command line arguments which add network interface.

    The arguments also instruct QEMU to capture packets on the interface. The
    packets are captured to file "link{interface_index}.pcap".

    :param interface_index: unique number for each interface
    :type interface_index: int
    :param interface_name: tap interface name
    :type interface_name: str
    :return: list of arguments
    :rtype: list(str)
    """
    packet_capture_filename = f'link{interface_index}.pcap'
    netdev_id = f'id_net{interface_index}'
    return ['-netdev',
        f'tap,id={netdev_id},ifname={interface_name},script=no,downscript=no',
        '-device', f'e1000,netdev={netdev_id}', '-object',
        f'filter-dump,id=id_dump{interface_index},netdev={netdev_id},file=' +
        packet_capture_filename]


def __call__(dirname, create=False):
    """Opens a `Maildir` folder at a given filesystem path.

        If `create` is ``True``, the folder will be created when it does not
        exist.  If `create` is ``False`` and the folder does not exist, an
        exception (``OSError``) will be raised.

        If path points to a file or an existing directory that is not a
        valid `Maildir` folder, an exception is raised regardless of the
        `create` argument.
        """


def base10tobase2(value, zfill=0):
    """
    This function converts from base 10 to base 2 in string format.  In
    addition, it takes a parameter for zero filling to pad out to a specific
    length.

    Note that the incoming number is converted to an int, and that if it is
    a negative number that the negative sign is added on to the total length,
    resulting in a string 1 char longer than the zfill specified.

    """
    new_value = []
    val = int(value)
    if val < 0:
        neg = True
        val *= -1
    else:
        neg = False
    if val == 0:
        new_value = ['0']
    while val > 0:
        new_value.append(str(val % 2))
        val = val / 2
    new_value.reverse()
    new_value_str = ''.join(new_value)
    if zfill:
        if len(new_value_str) > zfill:
            raise ValueError(
                """
            Base 2 version of %s is longer, %s, than the zfill limit, %s
            """
                 % (value, new_value_str, zfill))
        else:
            new_value_str = new_value_str.zfill(zfill)
    if neg:
        new_value_str = '-' + new_value_str
    return new_value_str


def get_termcolor_opts(dtype, _larch=None):
    """ get color options suitable for passing to
    larch's writer.write() for color output

    first argument should be string of
    'text', 'text2', 'error', 'comment'"""
    out = {'color': None}
    display = _larch.symtable._sys.display
    if display.use_color:
        out = getattr(display.colors, dtype, out)
    return out


def gen_upto_mark(it, pred):
    """Produce @nlines of output of input sequence @it until and including when predicate @pred is True."""
    for el in it:
        yield el
        if pred(el):
            it.close()


def embed_in_regex(string, regex_parts, index, as_string=True):
    """
    **Example usage**

    >>> from pytoolbox.unittest import asserts
    >>> asserts.equal(embed_in_regex('L', ['[a-z]', '[a-z]'], 0), (0, 'L[a-z]'))
    >>> asserts.equal(embed_in_regex('L', ['[a-z]', '[a-z]'], 1), (1, '[a-z]L'))
    >>> asserts.equal(embed_in_regex('L', ['[a-z]', '[a-z]'], 1, as_string=False), (1, ['[a-z]', 'L']))
    """
    regex = regex_parts[:]
    regex[index:index + len(string)] = string
    return index, ''.join(regex) if as_string else regex


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 format_obj(cls, obj):
    """Format object `obj` into the current class's preferred type
        (e.g., convert a dense matrix to sparse, or vice-versa, as appropriate)
        """
    raise NotImplementedError


@staticmethod
def validate(**kwargs):
    """Make consistent the input data for the visual."""
    return kwargs


def int_to_format(value, target_format):
    """Convert int to specified format"""
    if target_format == float:
        ret = float(value)
    elif target_format == str:
        ret = str(value)
    else:
        ret = value
    return ret


def getId():
    """Get the ID of the user.

        The ID can be used from Python to get the user from the user's
        UserDatabase.
        """


@staticmethod
def generate_logout(action):
    """
        Returns an HTML logout form.
        :param str action: Action to perform after submitting.
        :return str: Logout.
        """
    return (
        """
            <form method=post action=/{}>
                <input type="submit" name="log out" value="Logout">
            </form>
        """
        .format(action))


def FillFormWithValues(window, values_dict):
    """
    Fills a window with values provided in a values dictionary { element_key : new_value }

    :param window: (Window) The window object to fill
    :param values_dict: (Dict[Any:Any]) A dictionary with element keys as key and value is values parm for Update call
    """
    for element_key in values_dict:
        try:
            window.AllKeysDict[element_key].Update(values_dict[element_key])
        except Exception as e:
            print(
                'Problem filling form. Perhaps bad key?  This is a suspected bad key: {}'
                .format(element_key))


def remap_pos(node, cst_node, line):
    """
    remap the pos of a command substitution node `cst_node` to its parent node
    `node`
    """
    cst_str = line[slice(*cst_node.pos)]
    remapped_start = node.word.find(cst_str)
    remapped_end = remapped_start + len(cst_str)
    return remapped_start, remapped_end


def _TIME2STEPS(time):
    """Conversion from (float) time in seconds to milliseconds as int"""
    return int(time * 1000)


@staticmethod
def _next_index(s, index):
    """
        Convenience method for safely incrementing a string index
        """
    return index + 1 if index < len(s) else index


def get_val(source, extract=None, transform=None):
    """Extract a value from a source, transform and return it."""
    if extract is None:
        raw_value = source
    else:
        raw_value = extract(source)
    if transform is None:
        return raw_value
    else:
        return transform(raw_value)


def change_df_type():
    """
    1、pd.to_numeric(series)
    2、df['x'].astype(str)
    3、df = df.infer_objects()"""
    pass


def writeUVARI(v, theS):
    """Side effects s by writing v (an integer) to s using UVARI (big-endian)
    format. theS must have write(bytes) implemented."""
    by = bytearray()
    l = 0
    if v > 127:
        if v > 16383:
            l = 4
            by.append(192 | v >> 24 & 63)
            by.append(v >> 16 & 255)
            by.append(v >> 8 & 255)
            by.append(v & 255)
        else:
            l = 2
            by.append(128 | v >> 8 & 127)
            by.append(v & 255)
    else:
        l = 1
        by.append(v & 127)
    theS.write(by)


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 distance(parallax, parallax_error):
    """Computes distance from Gaia parallaxes using the Bayesian method of Bailer-Jones 2015.
    Input: parallax [mas], parallax error [mas]
    Output: distance [pc], 1-sigma uncertainty in distance [pc]
    """
    import numpy as np
    L = 1350
    parallax, parallax_error = parallax / 1000.0, parallax_error / 1000.0
    coeff = np.array([1.0 / L, -2, parallax / parallax_error ** 2, -(1.0 /
        parallax_error ** 2)])
    g = np.roots(coeff)
    reals = np.isreal(g)
    realsum = np.sum(reals)
    if realsum == 1:
        gd = np.real(g[np.where(reals)[0]])
    elif realsum == 3:
        if parallax >= 0:
            gd = np.min(g)
        elif parallax < 0:
            gd = g[np.where(g > 0)[0]]
    from scipy.optimize import brentq
    rmax = 1000000.0
    rmode = gd[0]
    M = rmode ** 2 * np.exp(-rmode / L) / parallax_error * np.exp(-1.0 / (2 *
        parallax_error ** 2) * (parallax - 1.0 / rmode) ** 2)
    lo = brentq(lambda x: 2 * np.log(x) - x / L - (parallax - 1.0 / x) ** 2 /
        (2 * parallax_error ** 2) + np.log(2) - np.log(M) - np.log(
        parallax_error), 0.001, rmode)
    hi = brentq(lambda x: 2 * np.log(x) - x / L - (parallax - 1.0 / x) ** 2 /
        (2 * parallax_error ** 2) + np.log(2) - np.log(M) - np.log(
        parallax_error), rmode, rmax)
    fwhm = hi - lo
    sigma = fwhm / 2.355
    return gd[0], sigma


def set_tol(value=1e-05):
    """Set Error Tolerance

    Set the tolerance for detriming if two numbers are simliar, i.e
    :math:`\\left|\\frac{a}{b}\\right| = 1 \\pm tolerance`

    Parameters
    ----------
    value: float
        The Value to set the tolerance to show be very small as it respresents the
        percentage of acceptable error in detriming if two values are the same.
    """
    global _tol
    if isinstance(value, float):
        _tol = value
    else:
        raise TypeError(type(value))


def shaderfx_move_down(shaderfx: str=''):
    """Move shaderfx down in the stack

    :param shaderfx: Shader, Name of the shaderfx to edit
    :type shaderfx: str
    """
    pass


def to_json(obj):
    """Utility method for converting an object to a json encoded string.

    Takes care of all the necessary setup.

    Args:
        obj (object): The object that should be encoded.

    Returns:
        str: The encoded version of the given object.
    """
    import jsonpickle
    jsonpickle.set_encoder_options('simplejson', sort_keys=True)
    return jsonpickle.encode(obj, unpicklable=False)


def psi_Na_OH_SO4_HMW84(T, P):
    """c-a-a': sodium hydroxide sulfate [HMW84]."""
    psi = -0.009
    valid = T == 298.15
    return psi, valid


def _set_class_module(module_class):
    """Initialize the module."""
    global _CLASS_MODULE
    _CLASS_MODULE = module_class


@classmethod
def isabreaker(cls, c, alist, esc):
    """ where we find char in c within a list alist that is not escaped by esc """
    for i, x in enumerate(alist):
        if c == x and alist[i - 1] != esc:
            return x
    return 0


def timediff(data):
    """Returns the array of the time differences of data."""
    return data[1:] - data[:-1]


def knife_tool(use_occlude_geometry: bool=True, only_selected: bool=False):
    """Cut new topology

    :param use_occlude_geometry: Occlude Geometry, Only cut the front most geometry
    :type use_occlude_geometry: bool
    :param only_selected: Only Selected, Only cut selected geometry
    :type only_selected: bool
    """
    pass


def CDLGAPSIDESIDEWHITE(df):
    """
    Up/Down-gap side-by-side white lines
    """


def xgcd(a, b):
    """
    Extented Euclid GCD algorithm.
    Return (x, y, g) : a * x + b * y = gcd(a, b) = g.
    """
    if a == 0:
        return 0, 1, b
    if b == 0:
        return 1, 0, a
    px, ppx = 0, 1
    py, ppy = 1, 0
    while b:
        q = a // b
        a, b = b, a % b
        x = ppx - q * px
        y = ppy - q * py
        ppx, px = px, x
        ppy, py = py, y
    return ppx, ppy, a


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

    The ".dev0" means dirty.

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


@classmethod
def _parse_xml_ports(cls, scanports_data):
    """
            Protected method parsing the list of scanned services from
            a targeted host. This protected method cannot be called directly
            with a string. A <ports/> tag can be directly passed to parse()
            and the below method will be called and return a list of nmap
            scanned services.

            :param scanports_data: <ports> XML tag from a nmap scan
            :type scanports_data: xml.ElementTree.Element or a string

            :return: list of NmapService
        """
    xelement = cls.__format_element(scanports_data)
    rdict = {'ports': [], 'extraports': None}
    for xservice in xelement:
        if xservice.tag == 'port':
            nport = cls._parse_xml_port(xservice)
            rdict['ports'].append(nport)
        elif xservice.tag == 'extraports':
            extraports = cls.__parse_extraports(xservice)
            rdict['extraports'] = extraports
    return rdict


@staticmethod
def __get_cpu_and_memory(resources):
    """
        Get CPU and MEMORY information from given resources object.

        :param resources: resources json object
        :return: cpu and memory
        """
    cpu = '-'
    memory = '-'
    for resource in resources:
        if resource['name'] == 'CPU':
            cpu = resource['integerValue'] / 1024
        elif resource['name'] == 'MEMORY':
            memory = resource['integerValue']
    return cpu, memory


def findRelationshipTokenSet(query):
    """Given a single dictionary of {indexName: token}, return a set (based
        on the btree family for relationships in the index) of relationship
        tokens that match it.  Intransitive."""


@staticmethod
def _to_config(field_name):
    """Convert a field name to a config key"""
    return field_name


def update_package_data(distribution):
    """update build_py options to get package_data changes"""
    build_py = distribution.get_command_obj('build_py')
    build_py.finalize_options()


def poke_16(library, session, address, data):
    """Write an 16-bit value from the specified address.

    Corresponds to viPoke16 function of the VISA library.

    :param library: the visa library wrapped by ctypes.
    :param session: Unique logical identifier to a session.
    :param address: Source address to read the value.
    :param data: value to be written to the bus.
    :return: return value of the library call.
    :rtype: :class:`pyvisa.constants.StatusCode`
    """
    return library.viPoke16(session, address, data)


def sort_wfs_components_current_station(wfs_component_labels_current_station,
    real_wfs_current_station, synth_wfs_current_station):
    """Function to sort current waveform components."""
    wfs_component_labels_current_station_sorted = list(
        wfs_component_labels_current_station)
    wfs_component_labels_current_station_sorted.sort()
    if wfs_component_labels_current_station_sorted == ['R', 'T', 'Z']:
        real_wfs_current_station_unsorted = list(real_wfs_current_station)
        synth_wfs_current_station_unsorted = list(synth_wfs_current_station)
        idx_tmp = wfs_component_labels_current_station.index('R')
        real_wfs_current_station[0] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[0] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('T')
        real_wfs_current_station[1] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[1] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('Z')
        real_wfs_current_station[2] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[2] = synth_wfs_current_station_unsorted[
            idx_tmp]
        wfs_component_labels_current_station = (
            wfs_component_labels_current_station_sorted)
    elif wfs_component_labels_current_station_sorted == ['L', 'Q', 'T']:
        real_wfs_current_station_unsorted = list(real_wfs_current_station)
        synth_wfs_current_station_unsorted = list(synth_wfs_current_station)
        idx_tmp = wfs_component_labels_current_station.index('L')
        real_wfs_current_station[0] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[0] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('Q')
        real_wfs_current_station[1] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[1] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('T')
        real_wfs_current_station[2] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[2] = synth_wfs_current_station_unsorted[
            idx_tmp]
        wfs_component_labels_current_station = (
            wfs_component_labels_current_station_sorted)
    elif wfs_component_labels_current_station_sorted == ['R-P', 'R-S',
        'T-P', 'T-S', 'Z-P', 'Z-S']:
        real_wfs_current_station_unsorted = list(real_wfs_current_station)
        synth_wfs_current_station_unsorted = list(synth_wfs_current_station)
        idx_tmp = wfs_component_labels_current_station.index('R-P')
        real_wfs_current_station[0] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[0] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('R-S')
        real_wfs_current_station[1] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[1] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('T-P')
        real_wfs_current_station[2] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[2] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('T-S')
        real_wfs_current_station[3] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[3] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('Z-P')
        real_wfs_current_station[4] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[4] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('Z-S')
        real_wfs_current_station[5] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[5] = synth_wfs_current_station_unsorted[
            idx_tmp]
        wfs_component_labels_current_station = (
            wfs_component_labels_current_station_sorted)
    elif wfs_component_labels_current_station_sorted == ['Z-P', 'R-P']:
        real_wfs_current_station_unsorted = list(real_wfs_current_station)
        synth_wfs_current_station_unsorted = list(synth_wfs_current_station)
        idx_tmp = wfs_component_labels_current_station.index('Z-P')
        real_wfs_current_station[0] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[0] = synth_wfs_current_station_unsorted[
            idx_tmp]
        idx_tmp = wfs_component_labels_current_station.index('Z-S')
        real_wfs_current_station[1] = real_wfs_current_station_unsorted[idx_tmp
            ]
        synth_wfs_current_station[1] = synth_wfs_current_station_unsorted[
            idx_tmp]
        wfs_component_labels_current_station = (
            wfs_component_labels_current_station_sorted)
    return (wfs_component_labels_current_station_sorted,
        real_wfs_current_station, synth_wfs_current_station)


def colorFromAngle(angle):
    """
    Converts numbers into colors for shading effects.
    """
    return int(230 * (angle / 450)), int(230 * (angle / 450)), 250


def format_query_params(request, config):
    """formats query parameters from config and attached to URL."""
    if 'query' in config['request'].keys():
        request['request']['url']['raw'] += config['request']['query']
        request['request']['url']['host'] = [request['request']['url']['raw']]
    return request


def next_regular(target):
    """Finds the next regular number greater than or equal to target.

    Regular numbers are composites of the prime factors 2, 3, and 5.
    Also known as 5-smooth numbers or Hamming numbers, these are the optimal
    size for inputs to fast-fourier transforms (FFTPACK).

    Parameters
    ----------
    target : positive int

    Returns
    -------
    match : int

    Notes
    -----
    This function was taken from the scipy.signal.signaltools module.
    See http://scipy.org/scipylib/
    """
    if target <= 6:
        print(target)
        return target
    if not target & target - 1:
        return target
    match = float('inf')
    p5 = 1
    while p5 < target:
        p35 = p5
        while p35 < target:
            quotient = -(-target // p35)
            p2 = 2 ** (quotient - 1).bit_length()
            N = p2 * p35
            if N == target:
                return N
            elif N < match:
                match = N
            p35 *= 3
            if p35 == target:
                return p35
        if p35 < match:
            match = p35
        p5 *= 5
        if p5 == target:
            return p5
    if p5 < match:
        match = p5
    return match


def get_oldest_compatible_version(config):
    """Return the current oldest compatible version of the config.

    :return: current oldest compatible config version or 0 if not defined
    """
    return config.get('CONFIG_VERSION', {}).get('OLDEST_COMPATIBLE', 0)


@classmethod
def is_editable(cls, title):
    """
        Can this title be edited at the moment?
        Only returns `True` if there is no open request at the moment.
        :type title: Title
        :rtype: bool
        """
    if not title.publisher_is_draft:
        return False
    current_request = cls.get_current_request(title)
    if current_request is None:
        return True
    return current_request.is_closed()


def format_range(var_middle, var_end, minimum, maximum, exclusiveMinimum,
    exclusiveMaximum):
    """
    Formats an mathematical description of a range, for example, ``0 ≤
    x ≤ 2``.

    Parameters
    ----------
    var_middle : str or None
        The string to put in the middle of an expression, such as
        the ``x`` in ``0 ≤ x ≤ 2``.

    var_end : str or None
        The string to put at one end of a single comparision, such as
        the ``x`` in ``x ≤ 0``.

    minimum : number
        The minimum value.

    maximum : number
        The maximum value.

    exclusiveMinimum : bool
        If `True`, the range excludes the minimum value.

    exclusiveMaximum : bool
        If `True`, the range excludes the maximum value

    Returns
    -------
    expr : str
        The formatted range expression
    """
    if minimum is not None and maximum is not None:
        part = '{0} '.format(minimum)
        if exclusiveMinimum:
            part += '<'
        else:
            part += '≤'
        part += ' {0} '.format(var_middle)
        if exclusiveMaximum:
            part += '<'
        else:
            part += '≤'
        part += ' {0}'.format(maximum)
    elif minimum is not None:
        if var_end is not None:
            part = '{0} '.format(var_end)
        else:
            part = ''
        if exclusiveMinimum:
            part += '> {0}'.format(minimum)
        else:
            part += '≥ {0}'.format(minimum)
    elif maximum is not None:
        if var_end is not None:
            part = '{0} '.format(var_end)
        else:
            part = ''
        if exclusiveMaximum:
            part += '< {0}'.format(maximum)
        else:
            part += '≤ {0}'.format(maximum)
    else:
        return None
    return part


def _unsigned_zero(dtype):
    """
    Given a numpy dtype, finds its "zero" point, which is exactly in the
    middle of its range.
    """
    assert dtype.kind == 'u'
    return 1 << dtype.itemsize * 8 - 1


def GetScaledEventPosition(event, dc, scaling):
    """
    Function that calculates the nearest point of the grid defined by scaling for the given point
    """
    pos = event.GetLogicalPosition(dc)
    if scaling:
        pos.x = round(pos.x / scaling[0]) * scaling[0]
        pos.y = round(pos.y / scaling[1]) * scaling[1]
    return pos


def height_from_foot_length(segment_length):
    """
    Calculates body height based on the foot length

    args:
        segment_length (float): length of foot

    Returns:
        float: total body height
    """
    if segment_length <= 0:
        raise ValueError('segment_length must be > 0')
    return segment_length / 0.152


def add_mask(name: str='Mask'):
    """Add a mask node to the current node editor

    :param name: Name, Data-block name to assign
    :type name: str
    """
    pass


def flatten_sequence(sequence, isinstance=isinstance, StringTypes=
    StringTypes, SequenceTypes=SequenceTypes, do_flatten=do_flatten):
    """Flatten a sequence to a non-nested list.

    Same as flatten(), but it does not handle the single scalar
    case. This is slightly more efficient when one knows that
    the sequence to flatten can not be a scalar.
    """
    result = []
    for item in sequence:
        if isinstance(item, StringTypes) or not isinstance(item, SequenceTypes
            ):
            result.append(item)
        else:
            do_flatten(item, result)
    return result


def create_game_session(FleetId=None, AliasId=None,
    MaximumPlayerSessionCount=None, Name=None, GameProperties=None,
    CreatorId=None, GameSessionId=None, IdempotencyToken=None):
    """
    Creates a multiplayer game session for players. This action creates a game session record and assigns an available server process in the specified fleet to host the game session. A fleet must have an ACTIVE status before a game session can be created in it.
    To create a game session, specify either fleet ID or alias ID and indicate a maximum number of players to allow in the game session. You can also provide a name and game-specific properties for this game session. If successful, a  GameSession object is returned containing game session properties, including a game session ID with the custom string you provided.
    By default, newly created game sessions allow new players to join. Use  UpdateGameSession to change the game session's player session creation policy.
    See also: AWS API Documentation

    :example: response = client.create_game_session(
        FleetId='string',
        AliasId='string',
        MaximumPlayerSessionCount=123,
        Name='string',
        GameProperties=[
            {
                'Key': 'string',
                'Value': 'string'
            },
        ],
        CreatorId='string',
        GameSessionId='string',
        IdempotencyToken='string'
    )

    :type FleetId: string
    :param FleetId: Unique identifier for a fleet to create a game session in. Each request must reference either a fleet ID or alias ID, but not both.

    :type AliasId: string
    :param AliasId: Unique identifier for an alias associated with the fleet to create a game session in. Each request must reference either a fleet ID or alias ID, but not both.

    :type MaximumPlayerSessionCount: integer
    :param MaximumPlayerSessionCount: [REQUIRED]
            Maximum number of players that can be connected simultaneously to the game session.

    :type Name: string
    :param Name: Descriptive label that is associated with a game session. Session names do not need to be unique.

    :type GameProperties: list
    :param GameProperties: Set of developer-defined properties for a game session. These properties are passed to the server process hosting the game session.
            (dict) --Set of key-value pairs containing information a server process requires to set up a game session. This object allows you to pass in any set of data needed for your game. For more information, see the Amazon GameLift Developer Guide .
            Key (string) -- [REQUIRED]TBD
            Value (string) -- [REQUIRED]TBD

    :type CreatorId: string
    :param CreatorId: Unique identifier for a player or entity creating the game session. This ID is used to enforce a resource protection policy (if one exists) that limits the number of concurrent active game sessions one player can have.

    :type GameSessionId: string
    :param GameSessionId: This parameter is no longer preferred. Please use ``IdempotencyToken`` instead. Custom string that uniquely identifies a request for a new game session. Maximum token length is 48 characters. If provided, this string is included in the new game session's ID. (A game session ID has the following format: arn:aws:gamelift:region::gamesession/fleet ID/custom ID string or idempotency token .)

    :type IdempotencyToken: string
    :param IdempotencyToken: Custom string that uniquely identifies a request for a new game session. Maximum token length is 48 characters. If provided, this string is included in the new game session's ID. (A game session ID has the following format: arn:aws:gamelift:region::gamesession/fleet ID/custom ID string or idempotency token .)

    :rtype: dict
    :return: {
        'GameSession': {
            'GameSessionId': 'string',
            'Name': 'string',
            'FleetId': 'string',
            'CreationTime': datetime(2015, 1, 1),
            'TerminationTime': datetime(2015, 1, 1),
            'CurrentPlayerSessionCount': 123,
            'MaximumPlayerSessionCount': 123,
            'Status': 'ACTIVE'|'ACTIVATING'|'TERMINATED'|'TERMINATING'|'ERROR',
            'GameProperties': [
                {
                    'Key': 'string',
                    'Value': 'string'
                },
            ],
            'IpAddress': 'string',
            'Port': 123,
            'PlayerSessionCreationPolicy': 'ACCEPT_ALL'|'DENY_ALL',
            'CreatorId': 'string'
        }
    }

    """
    pass


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 disableSciShortcut(obj, keyseq):
    """Disable Scintilla action shortcuts

	If `obj` is an :any:`eye.widgets.editor.Editor` and `keyseq` is a shortcut triggering a Scintilla editor action,
	the shortcut is disabled.
	This function only works for internal editor actions, like `PyQt5.Qsci.QsciCommand.Undo`.

	See :any:`QsciCommand`. The reverse function is :any:`setSciShortcut`.
	"""
    assert keyseq.count() == 1
    qcmd = obj.standardCommands().boundTo(keyseq[0])
    if qcmd is not None:
        qcmd.setKey(0)


def to_whole_minutes(seconds):
    """Divide `seconds` by 60 to convert to whole minutes."""
    minutes = seconds // 60
    return minutes


def _schema_from_verb(verb, partial=False):
    """Return an instance of schema for given verb."""
    from .verbs import Verbs
    return getattr(Verbs, verb)(partial=partial)


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

        :param PaperDocRevertDetails val:
        :rtype: EventDetails
        """
    return cls('paper_doc_revert_details', val)


@classmethod
def from_mapping(cls, x0, x1):
    """ Create an STTransform from the given mapping

        See `set_mapping` for details.

        Parameters
        ----------
        x0 : array-like
            Start.
        x1 : array-like
            End.

        Returns
        -------
        t : instance of STTransform
            The transform.
        """
    t = cls()
    t.set_mapping(x0, x1)
    return t


@classmethod
def getQtDesignerPluginInfo(cls):
    """Returns pertinent information in order to be able to build a valid
        QtDesigner widget plugin.

        The dictionary returned by this method should contain *at least* the
        following keys and values:

            - 'module' : a string representing the full python module name (ex.: 'taurus.qt.qtgui.base')
            - 'icon' : a string representing valid resource icon (ex.: 'designer:combobox.png')
            - 'container' : a bool telling if this widget is a container widget or not.

        This default implementation returns the following dictionary:

            { 'module'    : 'taurus.qt.qtgui.base',
              'group'     : 'Taurus Widgets',
              'icon'      : 'logos:taurus.svg',
              'container' : False }

        :return: (dict) a map with pertinent designer information"""
    return {'group': 'Taurus Widgets', 'icon': 'logos:taurus.png',
        'container': False}


def myPenetrance(geno):
    """A three-locus heterogeneity penetrance model"""
    if sum(geno) < 2:
        return 0
    else:
        return sum(geno) * 0.1


def getByteCount(value: int) ->int:
    """Calculate the number of bytes required to represent value

    :value: value to check. Non-negative
    :returns: number of bytes to represent the number

    """
    assert value >= 0
    if 0 == value:
        return 1
    return (value.bit_length() + 7) // 8


def onetime():
    """ The estimated one time expense
        """


def relevant_paths(root_dir, only_title, only_part):
    """We may want to filter the paths we search in to those relevant to a
    particular cfr title/part. Most index entries encode this as their first
    two path components"""
    prefix_path = root_dir.path
    for sub_entry in root_dir.sub_entries():
        suffix_path = sub_entry.path[len(prefix_path):]
        if only_title and suffix_path[0] != str(only_title):
            continue
        if only_part and suffix_path[1] != str(only_part):
            continue
        yield sub_entry


def _recspe(slow_spec, freqs, T):
    """
    Applied a correction factor to the spectrum of a slow-measured variable
    based on the response-time T

    Parameters
    -----------
    freqs: numpy.array
        frequencies
    slow_spec: numpy.array
        the spectrum
    T: float
        the response-time
    """
    import numpy as np
    assert len(slow_spec) == len(freqs)
    return slow_spec * (1.0 + 4.0 * np.pi ** 2.0 * freqs ** 2.0 * T ** 2.0)


@staticmethod
def _string_bytes_bytearray_as_bytes(src: 'typing.Union[str, bytes, bytearray]'
    ) ->bytes:
    """Get bytes string from string/bytes/bytearray union.

        :param src: source string or bytes-like object
        :return: Byte string
        :rtype: bytes
        :raises TypeError: unexpected source type.
        """
    if isinstance(src, bytes):
        return src
    if isinstance(src, bytearray):
        return bytes(src)
    if isinstance(src, str):
        return src.encode('utf-8')
    raise TypeError(
        f'{src!r} has unexpected type: not conform to Union[str, bytes, bytearray]'
        )


def get_resource_body(resource):
    """Get a full version of the resource's body
    """
    try:
        digest = resource.get_structured_body()
    except AttributeError:
        digest = resource
    return digest


def meta(f):
    """Decorator to make a :class:`VExternal` method an external meta method.

    Example use::

        class MyClass(VExternal):
            @meta
            def my_meta_method(self, *args, **kargs):
                pass

    """
    f.meta = True
    f.meta_name = None
    return f


def etree_get_text(ele):
    """     <Why need itertext? >
        >>>html_text = 'TEXT
TAIL'
        >>>root = etree.HTML(html_text)
        >>>eles = root.xpath("//html/body")
        >>>eles[0].text
        'TEXT'
        >>>eles[0].tail == None
        True
        >>> nvbody.etree_get_text(eles[0])
        'TEXTTAIL'
        >>>
        >>>
        >>> eles = root.xpath("//html/body/br")
        >>> eles[0].text == None
        True
        >>> eles[0].tail
        'TAIL'
        >>> nvbody.etree_get_text(eles[0])
        ''
    >>>
    """
    it = ele.itertext()
    texts = list(it)
    text = ''
    for i in range(0, texts.__len__()):
        text = text + texts[i]
    return text


def __call__():
    """Check the adapted assignment manager. Will raise Unathorized if
        something fishy is going on.
        """


def percentage_format(value, decimal=2):
    """
	Format number as percentage
	"""
    formatStr = '{:.' + str(decimal) + '%}'
    return formatStr.format(value)


def parse_species(species_data):
    """Iterate over list of species at each site."""
    parsed_species_data = []
    quality_list = []
    for species in species_data:
        if species['@AirQualityBand'] != 'No data':
            species_dict = {}
            species_dict['description'] = species['@SpeciesDescription']
            species_dict['code'] = species['@SpeciesCode']
            species_dict['quality'] = species['@AirQualityBand']
            species_dict['index'] = species['@AirQualityIndex']
            species_dict['summary'
                ] = f"{species_dict['code']} is {species_dict['quality']}"
            parsed_species_data.append(species_dict)
            quality_list.append(species_dict['quality'])
    return parsed_species_data, quality_list


def register_instances_with_load_balancer(LoadBalancerName=None, Instances=None
    ):
    """
    Adds the specified instances to the specified load balancer.
    The instance must be a running instance in the same network as the load balancer (EC2-Classic or the same VPC). If you have EC2-Classic instances and a load balancer in a VPC with ClassicLink enabled, you can link the EC2-Classic instances to that VPC and then register the linked EC2-Classic instances with the load balancer in the VPC.
    Note that RegisterInstanceWithLoadBalancer completes when the request has been registered. Instance registration takes a little time to complete. To check the state of the registered instances, use  DescribeLoadBalancers or  DescribeInstanceHealth .
    After the instance is registered, it starts receiving traffic and requests from the load balancer. Any instance that is not in one of the Availability Zones registered for the load balancer is moved to the OutOfService state. If an Availability Zone is added to the load balancer later, any instances registered with the load balancer move to the InService state.
    To deregister instances from a load balancer, use  DeregisterInstancesFromLoadBalancer .
    For more information, see Register or De-Register EC2 Instances in the Classic Load Balancer Guide .
    See also: AWS API Documentation

    Examples
    This example registers the specified instance with the specified load balancer.
    Expected Output:

    :example: response = client.register_instances_with_load_balancer(
        LoadBalancerName='string',
        Instances=[
            {
                'InstanceId': 'string'
            },
        ]
    )

    :type LoadBalancerName: string
    :param LoadBalancerName: [REQUIRED]
            The name of the load balancer.

    :type Instances: list
    :param Instances: [REQUIRED]
            The IDs of the instances.
            (dict) --The ID of an EC2 instance.
            InstanceId (string) --The instance ID.

    :rtype: dict
    :return: {
        'Instances': [
            {
                'InstanceId': 'string'
            },
        ]
    }

    """
    pass


def obj_box_coord_upleft_butright_to_centroid(coord):
    """Convert one coordinate [x1, y1, x2, y2] to [x_center, y_center, w, h].
    It is the reverse process of ``obj_box_coord_centroid_to_upleft_butright``.

    Parameters
    ------------
    coord : list of 4 int/float
        One coordinate.

    Returns
    -------
    list of 4 numbers
        New bounding box.

    """
    if len(coord) != 4:
        raise AssertionError('coordinate should be 4 values : [x1, y1, x2, y2]'
            )
    x1, y1, x2, y2 = coord
    w = x2 - x1
    h = y2 - y1
    x_c = x1 + w / 2.0
    y_c = y1 + h / 2.0
    return [x_c, y_c, w, h]


def __hash__(G):
    """
        Define the hash of a Surreal as the hash of its value.

        Returns
        -------
        hash : str
            The hash of G.
        """
    return hash(G._n)


def _dxt_mask_set(swizzler_mask, log_c, log_x, log_y, log_z, c_mask, x_mask,
    y_mask, z_mask):
    """THIS FUNCTION WILL SWIZZLE AN ARRAY OF X,
    Y, Z, AND CHANNEL OFFSETS TOGETHER SO THAT
    ALL PIXELS PER DXT TEXEL ARE ADJACENT.

    MAKES IT SO THE FIRST BITS ARE THE CHANNEL AXIS,
    NEXT TWO BITS ARE THE X AXIS, AND THE NEXT 2 BITS
    ARE THE Y AXIS. THE REMAINDER OF THE X BITS ARE NEXT,
    FOLLOWED BY THE REMAINDER OF THE Y BITS, FOLLOWED BY
    THE REMAINDER OF THE Z BITS"""
    tmp_x = log_x
    tmp_y = log_y
    if tmp_x > 2:
        tmp_x = 2
    if tmp_y > 2:
        tmp_y = 2
    c_mask.extend([0] * log_c)
    x_mask.extend([log_c] * tmp_x)
    y_mask.extend([log_c + tmp_x] * tmp_y)
    z_mask.extend([log_c + tmp_x + tmp_y] * log_z)
    x_mask.extend([log_c + tmp_y + log_z] * (log_x - tmp_x))
    y_mask.extend([log_c + log_x + log_z] * (log_y - tmp_y))


def pytest_html_results_table_header(cells):
    """ Called after building results table header. """


def get_records(ShardIterator=None, Limit=None):
    """
    Gets data records from an Amazon Kinesis stream's shard.
    Specify a shard iterator using the ShardIterator parameter. The shard iterator specifies the position in the shard from which you want to start reading data records sequentially. If there are no records available in the portion of the shard that the iterator points to,  GetRecords returns an empty list. Note that it might take multiple calls to get to a portion of the shard that contains records.
    You can scale by provisioning multiple shards per stream while considering service limits (for more information, see Streams Limits in the Amazon Kinesis Streams Developer Guide ). Your application should have one thread per shard, each reading continuously from its stream. To read from a stream continually, call  GetRecords in a loop. Use  GetShardIterator to get the shard iterator to specify in the first  GetRecords call.  GetRecords returns a new shard iterator in NextShardIterator . Specify the shard iterator returned in NextShardIterator in subsequent calls to  GetRecords . Note that if the shard has been closed, the shard iterator can't return more data and  GetRecords returns null in NextShardIterator . You can terminate the loop when the shard is closed, or when the shard iterator reaches the record with the sequence number or other attribute that marks it as the last record to process.
    Each data record can be up to 1 MB in size, and each shard can read up to 2 MB per second. You can ensure that your calls don't exceed the maximum supported size or throughput by using the Limit parameter to specify the maximum number of records that  GetRecords can return. Consider your average record size when determining this limit.
    The size of the data returned by  GetRecords varies depending on the utilization of the shard. The maximum size of data that  GetRecords can return is 10 MB. If a call returns this amount of data, subsequent calls made within the next 5 seconds throw ProvisionedThroughputExceededException . If there is insufficient provisioned throughput on the shard, subsequent calls made within the next 1 second throw ProvisionedThroughputExceededException . Note that  GetRecords won't return any data when it throws an exception. For this reason, we recommend that you wait one second between calls to  GetRecords ; however, it's possible that the application will get exceptions for longer than 1 second.
    To detect whether the application is falling behind in processing, you can use the MillisBehindLatest response attribute. You can also monitor the stream using CloudWatch metrics and other mechanisms (see Monitoring in the Amazon Kinesis Streams Developer Guide ).
    Each Amazon Kinesis record includes a value, ApproximateArrivalTimestamp , that is set when a stream successfully receives and stores a record. This is commonly referred to as a server-side timestamp, whereas a client-side timestamp is set when a data producer creates or sends the record to a stream (a data producer is any data source putting data records into a stream, for example with  PutRecords ). The timestamp has millisecond precision. There are no guarantees about the timestamp accuracy, or that the timestamp is always increasing. For example, records in a shard or across a stream might have timestamps that are out of order.
    See also: AWS API Documentation

    :example: response = client.get_records(
        ShardIterator='string',
        Limit=123
    )

    :type ShardIterator: string
    :param ShardIterator: [REQUIRED]
            The position in the shard from which you want to start sequentially reading data records. A shard iterator specifies this position using the sequence number of a data record in the shard.

    :type Limit: integer
    :param Limit: The maximum number of records to return. Specify a value of up to 10,000. If you specify a value that is greater than 10,000, GetRecords throws InvalidArgumentException .

    :rtype: dict
    :return: {
        'Records': [
            {
                'SequenceNumber': 'string',
                'ApproximateArrivalTimestamp': datetime(2015, 1, 1),
                'Data': b'bytes',
                'PartitionKey': 'string'
            },
        ],
        'NextShardIterator': 'string',
        'MillisBehindLatest': 123
    }

    """
    pass


def state_utility(ufuncs, state):
    """computes utility for a state"""
    utility = 0
    for attr, value in state.items():
        if attr in ufuncs:
            utility += ufuncs[attr](state[attr])
    return utility


def raw_poly_to_mask(poly):
    """
    There's not currently much metadata attached to masks, but this is
    around if we ever decide that we need to implement more
    complicated masking schemes.

    In particular, we might want to store also whether the interior
    or exterior is the masked region, but this is functionally achieved
    for now with the `invert` flag in other functions.

    :param poly: Polygon implementing a masked region.
    :return:
    """
    return {'poly': poly}


def volume_frustum(s1, s2, height):
    """
    Calculates the volume of a frustum given the base and top areas, and height.
    """
    return height / 3 * (s1 + s2 + (s1 * s2) ** 0.5)


def prefixed_userid(request):
    """In Kinto users ids are prefixed with the policy name that is
    contained in Pyramid Multiauth.
    If a custom authn policy is used, without authn_type, this method returns
    the user id without prefix.
    """
    authn_type = getattr(request, 'authn_type', None)
    if authn_type is not None:
        return f'{authn_type}:{request.selected_userid}'


def _get_code_cell_str_list(notebook_data_dict):
    """
    Get a list of code cell strings.

    Parameters
    ----------
    notebook_data_dict : dict
        A dictionary of notebook data.

    Returns
    -------
    code_str_list : list of str
        A list of code cell strings.
    """
    code_str_list = []
    has_key = 'cells' in notebook_data_dict
    if not has_key:
        return []
    cells_list = notebook_data_dict['cells']
    for cell_dict in cells_list:
        cell_type = cell_dict['cell_type']
        if cell_type != 'code':
            continue
        source_list = cell_dict['source']
        source = ''.join(source_list)
        code_str_list.append(source)
    return code_str_list


@classmethod
def all_channel(cls):
    """A :class:`Permissions` with all channel-specific permissions set to
        ``True`` and the guild-specific ones set to ``False``. The guild-specific
        permissions are currently:

        - manage_guild
        - kick_members
        - ban_members
        - administrator
        - change_nickname
        - manage_nicknames
        """
    return cls(871890001)


def gen_html_comments(comment_text):
    """Add a HTML comment block.

    Args:
      comment_text (string): The text in the comment.

    Returns: The HTML comment with the given text.

    """
    return '<!-- ' + comment_text + ' -->'


def validateArguments(terms):
    """Does some preliminary argument validatation, such as checking fo matching
    braces and braces."""
    bracketCount = 0
    for term in terms:
        if term == '[':
            bracketCount += 1
        elif term == ']':
            bracketCount -= 1
    if bracketCount:
        print('rpn:  mismatched brackets (count: {})'.format(bracketCount))
        return False
    parenCount = 0
    for term in terms:
        if term == '(':
            parenCount += 1
        elif term == ')':
            parenCount -= 1
    if parenCount:
        print('rpn:  mismatched parenthesis (count: {})'.format(parenCount))
        return False
    braceCount = 0
    for term in terms:
        if term == '{':
            braceCount += 1
        elif term == '}':
            braceCount -= 1
    if braceCount:
        print('rpn:  mismatched braces (count: {})'.format(braceCount))
        return False
    return True


def maybe_mongo(uri):
    """
    Check whether arg should be regarded as MongoDB

    Prameters
    ---------
    uri: obj
       Argument to be distinguished

    Returns
    -------
    bool: maybe_mongo
    """
    try:
        import pymongo
    except ImportError:
        return False
    if isinstance(uri, (pymongo.mongo_client.MongoClient, pymongo.
        collection.Collection)):
        msg = (
            'To initialize MongoBackend, pymongo Database instance must be provided, given: {}{}'
            )
        raise ValueError(msg.format(uri, type(uri)))
    elif isinstance(uri, pymongo.database.Database):
        return True
    elif not isinstance(uri, str):
        return False
    return uri.startswith('mongodb://')


def update_parameter(store, name, value):
    """Updates the parameter in the database.

    The callsite should convert the value properly
    """
    store.execute(
        """UPDATE parameter_data
                    SET field_value = ?
                    WHERE field_name = ?"""
        , (value, name))


def calc_M(S, L):
    """ Calculate multipliers of the extensions

    Parameters
    ----------
    L : pandas.DataFrame or numpy.array
        Leontief input output table L
    S : pandas.DataFrame or numpy.array
        Direct impact coefficients

    Returns
    -------
    pandas.DataFrame or numpy.array
        Multipliers M
        The type is determined by the type of D.
        If DataFrame index/columns as D

    """
    return S.dot(L)


def update_sub(x, decrement):
    """Update the value of `x` by subtracting `decrement`.

    # Arguments
        x: A `Variable`.
        decrement: A tensor of same shape as `x`.

    # Returns
        The variable `x` updated.
    """
    raise NotImplementedError(
        'MXNet Backend: Update operations are not supported yet.')


def set_constant(s, constant, value, time=None, date=None):
    """
    Set a constant value.
    """
    constant.add_value(s, value, time=time, date=date)


def kwargs_to_string(kwargs):
    """
    Given a set of kwargs, turns them into a string which can then be passed to a command.
    :param kwargs: kwargs from a function call.
    :return: outstr: A string, which is '' if no kwargs were given, and the kwargs in string format otherwise.
    """
    outstr = ''
    for arg in kwargs:
        outstr += ' -{} {}'.format(arg, kwargs[arg])
    return outstr


def is_published(post):
    """returns True/False based on `published` metadata in post"""
    return post and 'published' in post.meta and post.meta['published'] is True


def is_special_method(name):
    """
    Tests if a callable name is a special Python method (has a :code:`'__'`
    prefix and suffix)

    :param name: Callable name
    :type  name: string

    :rtype: boolean
    """
    return name.startswith('__')


def circle_radius(cs):
    """Compute the ``CS`` attribute into a circle radius in osu! pixels.

    Parameters
    ----------
    cs : float
        The circle size.

    Returns
    -------
    radius : float
        The radius in osu! pixels.
    """
    return 512 / 16 * (1 - 0.7 * (cs - 5) / 5)


def datetime_to_dir_date(dt):
    """
    Takes format of directory '%Y-%m-%d' and converts to datetime"""
    return dt.strftime('%Y-%m-%d')


@classmethod
def _message_id(cls, message, require_id):
    """Validate the message is a dictionary and return its ID.

        Raise an error if the message is invalid or the ID is of an
        invalid type.  If it has no ID, raise an error if require_id
        is True, otherwise return None.
        """
    raise NotImplementedError


def disassociate_web_acl(ResourceArn=None):
    """
    Removes a web ACL from the specified resource.
    See also: AWS API Documentation

    :example: response = client.disassociate_web_acl(
        ResourceArn='string'
    )

    :type ResourceArn: string
    :param ResourceArn: [REQUIRED]
            The ARN (Amazon Resource Name) of the resource from which the web ACL is being removed.

    :rtype: dict
    :return: {}

    """
    pass


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


def transform_results(results, func):
    """Transform a list of (timestamp,value) pairs by applying a function to the
    value."""
    try:
        for i in range(len(results)):
            results[i][1] = func(results[i][1])
    except TypeError:
        return func(results)
    return results


def getRecentPosts(blogid, username, password, num):
    """Return 'num' recent posts to specified blog,

        returns a struct: The three basic elements are title, link and
        description. For blogging tools that don't support titles and links,
        the description element holds what the Blogger API refers to as
        'content'.
        """


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


def _es_delete_indexes(current_search):
    """Delete all registered Elasticsearch indexes."""
    list(current_search.delete(ignore=[404]))


def insertMany(dbCursor, table, dataDict, arrayFields, scalarFields=None):
    """Insert multiple rows into the specified table of a database.
    Should raise an exception if it fails--does it do so reliably?

    Inputs:
    - dbCursor: database cursor
    - table: name of table
    - dataDict: dict of field name: value entries
    - arrayFields: a list of fields to add whose values are arrays;
        every array must have the same length;
        one row will be added for each array element
    - scalarFields: a list of fields to add whose values are scalars;
        these fields will have the same value for every added row

    Returns the number of rows added.
    """
    scalarFields = scalarFields or []
    numEntries = 0
    for fieldName in arrayFields:
        if numEntries:
            if len(dataDict[fieldName]) != numEntries:
                raise ValueError('arrays must have matching length')
        else:
            numEntries = len(dataDict[fieldName])
    if numEntries == 0:
        return 0
    listOfLists = [([dataDict[fieldName]] * numEntries) for fieldName in
        scalarFields] + [dataDict[fieldName] for fieldName in arrayFields]
    zippedList = zip(*listOfLists)
    allFields = scalarFields + arrayFields
    fieldListStr = ', '.join(allFields)
    sArry = ('%s, ' * len(allFields))[:-2]
    sqlCmd = 'insert into %s (%s) values (%s)' % (table, fieldListStr, sArry)
    dbCursor.executemany(sqlCmd, zippedList)
    return numEntries


def unpack_data(data):
    """
    Unpack data to the tuple.

    Parameters
    ----------
    data : ndarray
        An ndarray with (n, 3)-shape.

    Returns
    -------
    tuple
        A tuple made of three (n, 1)-shaped ndarrays.
    """
    return data[:, (0)], data[:, (1)], data[:, (2)]


def load_cryptography_hazmat_bindings__padding(finder, module):
    """the cryptography module requires the _cffi_backend module (loaded implicitly)"""
    finder.IncludeModule('_cffi_backend')


def render_pep440_pre(pieces):
    """TAG[.post.devDISTANCE] -- No -dirty.

    Exceptions:
    1: no tags. 0.post.devDISTANCE
    """
    if pieces['closest-tag']:
        rendered = pieces['closest-tag']
        if pieces['distance']:
            rendered += '.post.dev%d' % pieces['distance']
    else:
        rendered = '0.post.dev%d' % pieces['distance']
    return rendered


def indices(df):
    """Returns the list of named indices of the dataframe, ignoring any unnamed index."""
    a = list(df.index.names)
    return a if a != [None] else []


def generateColumnName(variable, visit, instance):
    """Generate a column name for the given variable, visit and instance.

    :arg variable: Integer variable ID
    :arg visit:    Visit number
    :arg instance: Instance number
    """
    return '{}-{}.{}'.format(variable, visit, instance)


@staticmethod
def filtering(queryset, query_dict):
    """
        function to apply the pre search condition to the queryset to narrow
        down the queryset's size

        :param queryset: Django Queryset: queryset of all objects
        :param query_dict: dict: contains selected_related, filter and other
          customized filter functions
        :return: queryset: result after applying the pre search condition dict
        """
    for key, value in query_dict.items():
        assert hasattr(queryset, key
            ), 'Parameter query_dict contains non-existent attribute.'
        if isinstance(value, list):
            queryset = getattr(queryset, key)(*value)
        elif isinstance(value, dict):
            queryset = getattr(queryset, key)(**value)
        else:
            queryset = getattr(queryset, key)(value)
    return queryset


def parse_like_term(term):
    """
        Parse search term into (operation, term) tuple. Recognizes operators
        in the beginning of the search term. Case insensitive is the default.

        * = case sensitive (can precede other operators)
        ^ = starts with
        = = exact

        :param term:
            Search term
    """
    case_sensitive = term.startswith('*')
    if case_sensitive:
        term = term[1:]
    if term.startswith('^'):
        oper = 'startswith'
        term = term[1:]
    elif term.startswith('='):
        oper = 'exact'
        term = term[1:]
    else:
        oper = 'contains'
    if not case_sensitive:
        oper = 'i' + oper
    return oper, term


def precip_36(code: str, unit: str='in') ->str:
    """
    Translates a 5-digit 3 and 6-hour precipitation code
    """
    return (
        f'Precipitation in the last 3 hours: {int(code[1:3])} {unit}. - 6 hours: {int(code[3:])} {unit}.'
        )


def _internal_function(parameter):
    """
    Describe here what this function does,
    its input parameters, and what it returns.
    """
    return parameter.upper()


def mse_func(target, mse_input):
    """Return error of interpolation.

    This function returns eval_numeric()the mean squared error for two sequences of
    numeric values.

    """
    counter = 0
    error = []
    while counter < len(target):
        error.append(abs(target[counter] - mse_input[counter]) ** 2)
        counter = counter + 1
    ave_error = sum(error) / len(target)
    return ave_error


@classmethod
def content_available_lifecycle_environments(cls, options):
    """List the lifecycle environments not attached to the capsule."""
    cls.command_sub = 'content available-lifecycle-environments'
    result = cls.execute(cls._construct_command(options), output_format='csv')
    return result


def uninstall(context):
    """Uninstall script"""


@classmethod
def _create_outerjoin(cls, left, right, onclause=None, full=False):
    """Return an ``OUTER JOIN`` clause element.

        The returned object is an instance of :class:`_expression.Join`.

        Similar functionality is also available via the
        :meth:`_expression.FromClause.outerjoin()` method on any
        :class:`_expression.FromClause`.

        :param left: The left side of the join.

        :param right: The right side of the join.

        :param onclause:  Optional criterion for the ``ON`` clause, is
          derived from foreign key relationships established between
          left and right otherwise.

        To chain joins together, use the :meth:`_expression.FromClause.join`
        or
        :meth:`_expression.FromClause.outerjoin` methods on the resulting
        :class:`_expression.Join` object.

        """
    return cls(left, right, onclause, isouter=True, full=full)


def _export_iter_entries(tree, subdir, skip_special=True):
    """Iter the entries for tree suitable for exporting.

    :param tree: A tree object.
    :param subdir: None or the path of an entry to start exporting from.
    :param skip_special: Whether to skip .bzr files.
    :return: iterator over tuples with final path, tree path and inventory
        entry for each entry to export
    """
    if subdir == '':
        subdir = None
    if subdir is not None:
        subdir = subdir.rstrip('/')
    entries = tree.iter_entries_by_dir()
    for path, entry in entries:
        if path == '':
            continue
        if skip_special and path.startswith('.bzr'):
            continue
        if path == subdir:
            if entry.kind == 'directory':
                continue
            final_path = entry.name
        elif subdir is not None:
            if path.startswith(subdir + '/'):
                final_path = path[len(subdir) + 1:]
            else:
                continue
        else:
            final_path = path
        if not tree.has_filename(path):
            continue
        yield final_path, path, entry


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 luminosity_ratio(fractional_lum):
    """Return luminosity ratio S=L2/L1."""
    return fractional_lum / (1 - fractional_lum)


def penalize(x, upper, lower):
    """
	produces a penalty relative to how much x is above the upper or below lower bound. maximum value is 2
	:param x:
	:param upper:
	:param lower:
	:return:
	"""
    if lower is not None and upper is not None and lower > upper:
        lower, upper = upper, lower
    u = 0
    l = 0
    if upper is not None and x > upper:
        u += 1 - 1 / ((x - upper) ** 2 + 1)
    if lower is not None and x < lower:
        l += 1 - 1 / ((x - lower) ** 2 + 1)
    return u + l


def send_notification():
    """Method to add send a notification
        """


def in_hm3(var):
    """
    Return whether the variant was part of HapMap3
    """
    return var.INFO.get('H3')


def mcu(pounds: float, lovibond: float, gallons: float) ->float:
    """
    Determines Malt Color Unit (MCU).

    Parameters
    ----------
    pounds : float
        Weight in pounds.
    lovibond : float
        Color of malt in degrees lovibond.
    gallons : float
        Water volume in gallons.

    Returns
    -------
    float or None
        Malt Color Unit.
    """
    if gallons != 0:
        return pounds * lovibond / gallons
    else:
        return


@classmethod
def all_classes(cls):
    """
        Return a list of class of backend type
        """
    return list(cls.classes_iterator())


def _fmt(x: complex) ->str:
    """ Format a complex number as a coordinate pair string. Remove trailing zeros to reduce file size. """
    return f'{x.real:.4g},{x.imag:.4g}'


def find_section(section_name, table):
    """
    seek into the csv table to a section ( section_name match 1st field )
    return the matching row without first field
    """
    fields = [None]
    while fields[0] != section_name:
        fields = table.pop(0)
    return fields[1:]


def _to_seconds(td):
    """Convert a timedelta to seconds"""
    return td.seconds + td.days * 24 * 60 * 60


def _latex_float(f, format='.3g'):
    """ http://stackoverflow.com/a/13490601
    """
    float_str = '{{0:{0}}}'.format(format).format(f)
    if 'e' in float_str:
        base, exponent = float_str.split('e')
        return '{0}\\times 10^{{{1}}}'.format(base, int(exponent))
    else:
        return float_str


def decode(token):
    """Un-escape special characters in a token from a path representation.

    :param str token: The token to decode
    :return: The decoded string
    :rtype: str
    """
    return token.replace('\\/', '/').replace('\\\\', '\\')


@staticmethod
def create(version):
    """Return a new instance for *version*, which can be either `'1.0'`
        or `'2.0'`."""
    clsname = 'JsonRpcV{}'.format(version.rstrip('.0'))
    cls = globals()[clsname]
    return cls(version)


def kth_root(n: int, k: int) ->int:
    """
    Calculates the `k`-th integer root of `n`.

    Parameters:
        n (int): Integer.
        k (int): Root (e.g. 2).

    Returns:
        int: `k`-th integer root of `n

    Examples:
        >>> from samson.math.general import kth_root
        >>> kth_root(1000, 3)
        10

        >>> kth_root(129, 7)
        3

    References:
        https://stackoverflow.com/questions/23621833/is-cube-root-integer
    """
    lb, ub = 0, n
    while lb < ub:
        guess = (lb + ub) // 2
        if pow(guess, k) < n:
            lb = guess + 1
        else:
            ub = guess
    return lb


@staticmethod
def metadata_id(item):
    """Extracts the identifier from a Bugzilla item."""
    return item['bug_id'][0]['__text__']


@staticmethod
def save_file(title='Save File', start_directory=None, filters=None):
    """
        Function that shows save file DCC native dialog
        :param title: str
        :param start_directory: str
        :param filters: str
        :return: str
        """
    raise NotImplementedError('save_file() function is not implemented')


def prettyTimeDelta(seconds):
    """
    Pretty-print seconds to human readable string 1d 1h 1m 1s
    """
    seconds = int(seconds)
    days, seconds = divmod(seconds, 86400)
    hours, seconds = divmod(seconds, 3600)
    minutes, seconds = divmod(seconds, 60)
    s = [(days, 'd'), (hours, 'h'), (minutes, 'm'), (seconds, 's')]
    s = filter(lambda x: x[0] != 0, s)
    return ' '.join(map(lambda x: '{}{}'.format(*x), s))


def psi_Ca_K_Cl_HMW84(T, P):
    """c-c'-a: calcium potassium chloride [HMW84]."""
    psi = -0.025
    valid = T == 298.15
    return psi, valid


@classmethod
def serialize_attributions(cls, attributions, resolve_pronouns=False):
    """
        This accepts an iterable of Attribution objects, and produces
        an HTML page that visualizes them.
        """
    dom, body = cls.prepare_dom()
    for attribution in attributions:
        attribution_element = cls.get_attribution_element(attribution,
            resolve_pronouns)
        body.appendChild(attribution_element)
    return dom.toprettyxml(indent='  ')


def add_script_data(req, data={}, **kwargs):
    """Add data to be made available in javascript scripts as global variables.

    The keys in `data` and the keyword argument names provide the names of the
    global variables. The values are converted to JSON and assigned to the
    corresponding variables.
    """
    script_data = req.chrome.setdefault('script_data', {})
    script_data.update(data)
    script_data.update(kwargs)


def remove_doubles(threshold: float=0.02, use_unselected: bool=False):
    """Selected UV vertices that are within a radius of each other are welded together

    :param threshold: Merge Distance, Maximum distance between welded vertices
    :type threshold: float
    :param use_unselected: Unselected, Merge selected to other unselected vertices
    :type use_unselected: bool
    """
    pass


def set_prefs(prefs):
    """This function is called before opening the project"""
    prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', '.hg',
        '.svn', '_svn', '.git']
    prefs['save_objectdb'] = True
    prefs['compress_objectdb'] = False
    prefs['automatic_soa'] = True
    prefs['soa_followed_calls'] = 0
    prefs['perform_doa'] = True
    prefs['validate_objectdb'] = True
    prefs['max_history_items'] = 32
    prefs['save_history'] = True
    prefs['compress_history'] = False
    prefs['indent_size'] = 4
    prefs['extension_modules'] = []
    prefs['import_dynload_stdmods'] = True
    prefs['ignore_syntax_errors'] = False
    prefs['ignore_bad_imports'] = False


def pks_from_iterable(iterable, unique_output=False):
    """
    Return pks list based on iterable
    :param iterable: list of django model objects OR django queryset
    :param unique_output: if True returned list will be unique
    :return: list of int
    """
    pks = list()
    for obj in iterable:
        try:
            pks.append(int(getattr(obj, 'pk', obj)))
        except (TypeError, ValueError):
            raise TypeError(
                'Iterable %s is not any of Queryset, list with django Model objects or ints'
                 % iterable)
    return list(set(pks)) if unique_output else pks


def __str__():
    """Read the stored checksum or 'n/a'
        """


def set_omero_login_hook(fn):
    """Set the function to be called when a login to Omero is needed.

    """
    global __omero_login_fn
    __omero_login_fn = fn


def left_arrow_path(x, y, offset):
    """ x,y is the final point
    """
    d = [('m', x + 2 * offset, y), (-offset, 0), (0, offset), (-offset, -
        offset), (offset, -offset), (0, offset), 'z']
    return d


def predict_shape(major_axis, minor_axis):
    """ This function predicts whether the object detected is circle or ellispeIt is the short axis of the ellipse
    It returns number of circles or the ellipse in the image
    Arguments:
    major_axis = It is the long axis of the ellipse
    minor_axis = It is the short axis of the ellipse    """
    circular_particle = 0
    ellipsoidal_particle = 0
    for i in range(len(major_axis)):
        x = 0.1 * major_axis[i] + major_axis[i]
        y = major_axis[i] - 0.1 * major_axis[i]
        if minor_axis[i] <= x and minor_axis[i] >= y:
            circular_particle += 1
        else:
            ellipsoidal_particle += 1
    return circular_particle, ellipsoidal_particle


@staticmethod
def __convert_key(expression):
    """Converts keys in YAML that reference other keys.
        """
    if type(expression) is str and len(expression) > 2 and expression[1
        ] == '!':
        expression = eval(expression[2:-1])
    return expression


@classmethod
def is_valid_base_for_new(cls, base, monolingual):
    """Check whether base is valid."""
    raise NotImplementedError()


def getType(v):
    """

	Easily obtain a variable's type without delving into its parameters.

	Parameters
	----------
	v : :obj:`variable`
		Variable to inspect.

	Returns
	-------
	str
		Type of variable.

	"""
    return type(v).__name__
    pass


def is_good_response(resp):
    """
    Returns True if the response seems to be HTML, False otherwise.
    """
    content_type = resp.headers['Content-Type'].lower()
    return (resp.status_code == 200 and content_type is not None and
        content_type.find('html') > -1)


def divide_slice(initial_slice, n_slices):
    """Create a set of smaller slices from an original slice.

    Parameters
    ----------
    initial_slice : :py:class:`slice`
        A slice which must have `start` and `stop` set.
    n_slices : int
        Number of slices to produce.

    Yields
    ------
    :py:class:`slice`
        Slices which when combined would be equivalent to `initial_slice`.
    """
    pos = start = initial_slice.start
    stop = initial_slice.stop
    chunk = (stop - start) // n_slices
    n_larger = (stop - start) % n_slices
    for _ in range(n_larger):
        yield slice(pos, pos + chunk + 1)
        pos += chunk + 1
    for _ in range(n_slices - n_larger):
        yield slice(pos, pos + chunk)
        pos += chunk


def announce(*a) ->None:
    """Make this message stand out from all the noise in the console."""
    print('******** ', *a)


def validate_matrix_shape(name, shape, nrows, ncols, nobs):
    """
    Validate the shape of a possibly time-varying matrix, or raise an exception

    Parameters
    ----------
    name : str
        The name of the matrix being validated (used in exception messages)
    shape : array_like
        The shape of the matrix to be validated. May be of size 2 or (if
        the matrix is time-varying) 3.
    nrows : int
        The expected number of rows.
    ncols : int
        The expected number of columns.
    nobs : int
        The number of observations (used to validate the last dimension of a
        time-varying matrix)

    Raises
    ------
    ValueError
        If the matrix is not of the desired shape.
    """
    ndim = len(shape)
    if ndim not in [2, 3]:
        raise ValueError(
            'Invalid value for %s matrix. Requires a 2- or 3-dimensional array, got %d dimensions'
             % (name, ndim))
    if not shape[0] == nrows:
        raise ValueError(
            'Invalid dimensions for %s matrix: requires %d rows, got %d' %
            (name, nrows, shape[0]))
    if not shape[1] == ncols:
        raise ValueError(
            'Invalid dimensions for %s matrix: requires %d columns, got %d' %
            (name, ncols, shape[1]))
    if nobs is None and not (ndim == 2 or shape[-1] == 1):
        raise ValueError(
            'Invalid dimensions for %s matrix: time-varying matrices cannot be given unless `nobs` is specified (implicitly when a dataset is bound or else set explicity)'
             % name)
    if ndim == 3 and nobs is not None and not shape[-1] in [1, nobs]:
        raise ValueError(
            'Invalid dimensions for time-varying %s matrix. Requires shape (*,*,%d), got %s'
             % (name, nobs, str(shape)))


def _set_item(x_train, x_test, column: str, value: list, train_length: int,
    test_length: int):
    """
    Utility function for __setitem__ for determining which input is for which dataset
    and then sets the input to the new column for the correct dataset.

    Parameters
    ----------
    x_train : Dataframe
        Training Data

    x_test : Dataframe
        Testing Data

    column : str
        New column name

    value : list
        List of values for new column

    train_length : int
        Length of training data

    test_length : int
        Length of training data
    """
    if len(value) == train_length and len(value) == test_length:
        x_train[column] = value
        x_test[column] = value
    elif len(value) == train_length:
        x_train[column] = value
    else:
        x_test[column] = value
    return x_train, x_test


@staticmethod
def _normalize_inputs(framework, data, project) ->tuple:
    """
        Normalize constructor inputs

        A :class:`ProjectFramework` is constructed against a particular framework
        and data. For convenience, these can be specified by passing in a Project
        containing the framework and data. This function takes in all of the inputs
        provided to the constructor (whether making a blank instance or reading a
        spreadsheet) and returns the framework and data. The order of precedence is

        - If separate framework or data is provided, it will be used
        - Otherwise, they will be drawn from the project

        So for example, a project and data could be provided, in which case the framework
        would come from the project and the data would come from the explicit argument
        (even if the project also contained data).

        :param framework: Optionally a :class:`ProjectFramework` instance
        :param data: Optionally a :class:`ProjectData` instance
        :param project: Optionally a :class:`Project` instance
        :return: Tuple containing ``(framework,data)``

        """
    if (framework is None and project is None or data is None and project is
        None):
        errormsg = (
            'To read in a ProgramSet, please supply one of the following sets of inputs: (a) a Framework and a ProjectData, (b) a Project.'
            )
        raise Exception(errormsg)
    if framework is None:
        if project.framework is None:
            errormsg = (
                'A Framework was not provided, and the Project has not been initialized with a Framework'
                )
            raise Exception(errormsg)
        else:
            framework = project.framework
    if data is None:
        if project.data is None:
            errormsg = 'Project data has not been loaded yet'
            raise Exception(errormsg)
        else:
            data = project.data
    return framework, data


def normalize_minmax(array, array_min, array_max, cols=[]):
    """
    Normalizes columns of the array to between 0 and 1 using min-max
    normalization.

    Parameters
    ----------
    array : numpy.array
        The array to normalize.
    array_min : numpy.array
        Array containing minimum values of each column.
    array_max : numpy.array
        Array containing maximum values of each column.
    cols : list
        The columns to normalize. If the list is empty (default),
        all columns will be normalized.

    Returns
    -------
    numpy.array
        The normalized array.

    Note
    ----
    You can use :py:func:`~get_minmax` function to get :code:`array_min`
    and :code:`array_max` parameters.
    """
    normalized_array = array.astype(float)
    all_normalized = (array - array_min) / (array_max - array_min)
    if len(cols) == 0:
        normalized_array = all_normalized
    elif array.ndim == 1:
        normalized_array[cols] = all_normalized[cols]
    else:
        normalized_array[:, (cols)] = all_normalized[:, (cols)]
    return normalized_array


def get_parent_main_window(widget):
    """Returns a reference to the ElectrumWindow this widget belongs to."""
    from .main_window import ElectrumWindow
    for _ in range(100):
        if widget is None:
            return None
        if not isinstance(widget, ElectrumWindow):
            widget = widget.parentWidget()
        else:
            return widget
    return None


def smart_project(angle_limit: float=66.0, island_margin: float=0.0,
    user_area_weight: float=0.0, use_aspect: bool=True, stretch_to_bounds:
    bool=True):
    """This script projection unwraps the selected faces of a mesh (it operates on all selected mesh objects, and can be used to unwrap selected faces, or all faces)

    :param angle_limit: Angle Limit, Lower for more projection groups, higher for less distortion
    :type angle_limit: float
    :param island_margin: Island Margin, Margin to reduce bleed from adjacent islands
    :type island_margin: float
    :param user_area_weight: Area Weight, Weight projections vector by faces with larger areas
    :type user_area_weight: float
    :param use_aspect: Correct Aspect, Map UVs taking image aspect ratio into account
    :type use_aspect: bool
    :param stretch_to_bounds: Stretch to UV Bounds, Stretch the final output to texture bounds
    :type stretch_to_bounds: bool
    """
    pass


def get_glyph_name(character_map, unicode_value):
    """Get the name of the glyph from the unicode value"""
    return character_map[unicode_value]


def plot_freq(dataframe, y_log=False, x='token', figsize=(15, 10), fontsize=14
    ):
    """Plot a sorted histogram of work frequencies

    Args:
        dataframe (pandas dataframe): frequency of tokens, typically with colnames ["token","frequency"]
        y_log (bool): should there be a log scale on the y axis
        x (str): name of the columns with the tokens (i.e. words)
        figsize (tuple):
        fontsize (int):

    Returns:
        barplot: plot

    """
    p = dataframe.plot.bar(x=x, figsize=figsize, fontsize=fontsize)
    if y_log:
        p.set_yscale('log', nonposy='clip')
    return p


def extract_end_label(oLine):
    """
    Returns the end label.

    Parameters:

       oLine: (line object)

    Returns: (one element or empty list of strings)
    """
    word = oLine.line.replace(';', '').split()[-1]
    lower = word.lower()
    if lower == 'end' or lower == 'generate' or lower == 'process':
        return []
    return [word]


def add_figure(**kwargs):
    """ Adds a figure to the output file manifest. Automatically adds the tags 'type:fig extension:json'
    %
    %   ADDFIGURE(p) writes a JSON file from a plotlyfig object p (see
    %   figure.m example file in octue-app-matlab).
    %
    %   ADDFIGURE(data, layout) writes a JSON file from data and layout
    %   structures, which must be compliant with plotly spec, using MATLAB's native
    %   json encoder (2017a and later).
    %
    %   ADDFIGURE(..., tags) adds a string of tags to the figure to help the
    %   intelligence system find it. These are appended to the automatically added
    %   tags identifying it as a file.
    %
    %   uuid = ADDFIGURE(...) Returns the uuid string of the created figure,
    %   allowing you to find and refer to it from anywhere (e.g. report templates or
    %   in hyperlinks to sharable figures).

    % Generate a unique filename and default tags
    % TODO generate on the octue api so that the figure can be trivially registered
    % in the DB and rendered
    uuid = octue.utils.genUUID;
    key = [uuid '.json'];
    name = fullfile(octue.get('OutputDir'), [uuid '.json']);
    tags = 'type:fig extension:json ';

    % Parse arguments, appending tags and generating json
    % TODO validate inputs, parse more elegantly, and accept cases where the data
    % and layout keys are part of the structure or not.
    if nargin == 1
        str = plotly_json(varargin{1});

    elseif (nargin == 2) && (isstruct(varargin{2}))
        data = varargin{1};
        layout = varargin{2};
        str = jsonencode({data, layout});

    elseif (nargin == 2)
        str = plotly_json(varargin{1});
        tags = [tags varargin{2}];

    elseif nargin == 3
        data = varargin{1};
        layout = varargin{2};
        str = jsonencode({data, layout});
        tags = [tags varargin{3}];

    end

    % Write the file
    fid = fopen(name, 'w+');
    fprintf(fid, '%s', str);
    fclose(fid);

    % Append it to the output manifest
    file = octue.DataFile(name, key, uuid, tags);
    octue.get('OutputManifest').Append(file)

    end

    function str = plotly_json(p)
    %PLOTLY_JSON extracts json data from a plotlyfig object.

    jdata = m2json(p.data);
    jlayout = m2json(p.layout);
    str = sprintf('{"data": %s, "layout": %s}', escapechars(jdata), escapechars(jlayout));

    end
    """
    uuid = None
    return uuid


def makeID(citation, nodeType):
    """Makes the id, of the correct type for the network"""
    if nodeType != 'full':
        return getattr(citation, nodeType)
    else:
        return citation.ID()


def julian_century(jd_local):
    """Returns the Julian Century with Julian Day, julian_local."""
    days_century = 2451545
    day_per_century = 36525
    for i in range(2451545, 0, -36525):
        if jd_local < i:
            days_century = i - day_per_century
        else:
            break
    julian_cent = (jd_local - days_century) / day_per_century
    return julian_cent


def keylist2str(keylist):
    """Convert keylist to a string representation.

    :param keylist: keylist to be converted
    :type keylist: list
    :return: string representation
    :rtype: str
    """
    return ''.join(map(lambda x: "['" + str(x) + "']", keylist))


def is_conflicting(fsm, eqclass, gamma):
    """
    Return whether the given equivalence class for gamma is conflicting or not.

    fsm -- the model
    eqclass -- a BDD representing a set of states/inputs pairs
    gamma -- a set of agents of fsm

    eqclass must be a distributed knowledge based equivalence class.

    """
    si = fsm.pick_one_state_inputs(eqclass)
    ngamma_cube = fsm.bddEnc.inputsCube - fsm.inputs_cube_for_agents(gamma)
    return (eqclass - (eqclass & si.forsome(fsm.bddEnc.statesCube |
        ngamma_cube))).isnot_false()


@staticmethod
def set_slope_class(elt, value):
    """ Set attribute class iaw positive or negative slope. """
    if abs(value) < 0.005:
        elt.attrib['class'] = 'stable'
    elif value > 0:
        elt.attrib['class'] = 'increase'
    else:
        elt.attrib['class'] = 'decrease'


@classmethod
def detected_releasers(cls):
    """
        Returns all of the releasers that are compatible with the project.
        """
    releasers_cls = filter(lambda r: r.detect(), cls.releasers())
    releasers = map(lambda r: r(), releasers_cls)
    return releasers


def __init__(context):
    """Adapts a label root.
        """


def _is_secure_boot(instance_info_caps, node_caps):
    """Extract node secure boot property"""
    return 'true' == str(instance_info_caps.get('secure_boot', node_caps.
        get('secure_boot', 'false'))).lower()


def _has_single_child(section):
    """Does the section have only one child ?"""
    return len(section.children()) == 1


def _CCMP_immediate(cpu, reg_op, imm_op, nzcv_op):
    """
        CCMP (immediate).

        :param reg_op: register.
        :param imm_op: immediate.
        :param nzcv_op: immediate.
        """
    cpu._ccmp_imm_reg(reg_op, imm_op, nzcv_op, imm=True)


def _setDefaults(configObj={}):
    """set up the default parameters to run drizzle
       build,single,units,wt_scl,pixfrac,kernel,fillval,
       rot,scale,xsh,ysh,blotnx,blotny,outnx,outny,data

       Used exclusively for unit-testing, if any are defined.

    """
    paramDict = {'build': True, 'single': True, 'stepsize': 10, 'in_units':
        'cps', 'wt_scl': 1.0, 'pixfrac': 1.0, 'kernel': 'square', 'fillval':
        999.0, 'maskval': None, 'rot': 0.0, 'scale': 1.0, 'xsh': 0.0, 'ysh':
        0.0, 'blotnx': 2048, 'blotny': 2048, 'outnx': 4096, 'outny': 4096,
        'data': None, 'driz_separate': True, 'driz_combine': False}
    if len(configObj) != 0:
        for key in configObj.keys():
            paramDict[key] = configObj[key]
    return paramDict


def p_slice_item(p):
    """ slice_item : expression
                   | proper_slice """
    p[0] = p[1]


def _pprint(params):
    """Pretty print the dictionary 'params'."""
    params_list = list()
    for i, (k, v) in enumerate(params):
        if type(v) is float:
            this_repr = '{}={:.4f}'.format(k, v)
        else:
            this_repr = '{}={}'.format(k, v)
        params_list.append(this_repr)
    return params_list


def properties_context_change(context: str=''):
    """Jump to a different tab inside the properties editor

    :param context: Context
    :type context: str
    """
    pass


def set_current_bus(bus):
    """Sets the current bus."""
    global __bus
    __bus = bus


def delta_seconds(before, after):
    """Return the difference between two timing objects.

    Compute the difference in seconds between two date, time, or
    datetime objects (as a float, to microsecond resolution).
    """
    delta = after - before
    try:
        return delta.total_seconds()
    except AttributeError:
        return delta.days * 24 * 3600 + delta.seconds + float(delta.
            microseconds) / 10 ** 6


def ec2_instances(*args, **kwargs):
    """
    Returns a list of instances for the specified filters.
    """
    from fabulaws.ec2 import EC2Service
    return EC2Service().instances(*args, **kwargs)


@classmethod
def presenceIndicator(cls):
    """
        The key that is guaranteed to be present in the return value of binaryToAttributes().
        Assuming that binaryToAttributes() is used with SDB's PutAttributes, the return value of
        this method could be used to detect the presence/absence of an item in SDB.
        """
    return u'numChunks'


def addAttachment(filename, content, mime_type):
    """
           Adds an attachment to this message
        """


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 obj_to_dic(obj):
    """
    将 obj 对象的属性封装成 dict
    :param obj: [obj]
    :return:
    """
    res = dict(obj.__dict__)
    res.pop('_sa_instance_state', None)
    return res


def rect(theWhere, theX, theY, theWidth, theHeight, theBorderColor,
    theFillingColor=4278190080):
    """
	Display a filled rectangle.

	Parameters
	----------
	theWhere: np.ndarray
		image/frame where the component should be rendered.
	theX: int
		position X where the component should be placed.
	theY: int
		position Y where the component should be placed.
	theWidth: int
		width of the rectangle.
	theHeight: int
		height of the rectangle.
	theBorderColor: uint
		color of rectangle's border in the format `0xRRGGBB`, e.g. `0xff0000` for red.
	theFillingColor: uint
		color of rectangle's filling in the format `0xAARRGGBB`, e.g. `0x00ff0000` for red, `0xff000000` for transparent filling.

	See Also
	----------
	image()
	"""
    print('This is wrapper function to help code autocompletion.')


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 _syscal_write_electrode_coords(fid, spacing, N):
    """helper function that writes out electrode positions to a file descriptor

    Parameters
    ----------
    fid: file descriptor
        data is written here
    spacing: float
        spacing of electrodes
    N: int
        number of electrodes
    """
    fid.write('# X Y Z\n')
    for i in range(0, N):
        fid.write('{0} {1} {2} {3}\n'.format(i + 1, i * spacing, 0, 0))


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


@property
def model_name(cls):
    """Return this model's name."""
    return cls.__name__


def torch_installed():
    """
    Checks that *pytorch* is available.
    """
    try:
        import torch
        return True
    except ImportError:
        return False


def is_number(value):
    """is_number determines if the value for a field is numeric
    """
    if isinstance(value, int):
        return True
    if isinstance(value, float):
        return True
    return False


def combine_gene_pos(hybridizations_infos, converted_positions, hybridization):
    """
    Gather info about the imaging at each hybridization.

    This function creates a dictionary where for each hybridization
    are shown the genes and number of positions imaged for each
    gene. This function will be useful to created distribution lists
    for running parallel processing of the datasets.

    Parameters:
    -----------

    hybridizations_infos: dict
        Dictionary with parsed Hybridizations metadata
    converted_positions: dict
        Dictionary with the coords of the images for all hybridization.
        The coords are a list of floats
    hybridization: str
        Selected hybridization to process

    Returns:
    -----------

    genes_and_positions: dict
        Dictionary where for each hybridization, the genes and number of
        positions imaged for each gene are showed.
    """
    genes_and_positions = dict()
    for gene in hybridizations_infos[hybridization].keys():
        genes_and_positions[gene] = list(converted_positions[hybridization]
            .keys())
    return genes_and_positions


@classmethod
def factory(cls, out_dir, groups_dict):
    """
        Generate dictionary of MultiYearGroup objects for all groups in groups

        Parameters
        ----------
        out_dir : str
            Output directory, used for Pipeline handling
        groups_dict : dict
            Dictionary of group parameters, parsed from multi-year config file

        Returns
        -------
        groups : dict
            Dictionary of MultiYearGroup objects for each group in groups
        """
    groups = {}
    for name, kwargs in groups_dict.items():
        groups[name] = cls(name, out_dir, **kwargs)
    return groups


def get_ancestor_ids(cur, node):
    """
    Return an iterator that yields the ID of every element while
    traversing from ``node`` to the root node.

    :param node:
    :type node: Node or uuid4
    """
    sql = """
        SELECT
          ancestor
        FROM
          ancestors
        WHERE
          node=%s;
    """
    cur.execute(sql, (str(node),))
    for result in cur:
        yield str(result['ancestor'])