def readTable(path, sep='\t', header=True, skipCommented=True, keys=[]):
    """Read a table in a file, and generate a list of strings per row.
	Skips rows starting with "#".

	sep (str): field separator.
	header (bool): presence of a header, to discard the first row.
	"""
    headerRead = False
    with open(path) as FILE:
        for line in FILE:
            if line[0] == '#' and skipCommented:
                continue
            elif header and not headerRead:
                if not keys:
                    keys = line.strip().split(sep)
                headerRead = True
                continue
            values = line.strip('\n').split(sep)
            if keys:
                if len(values) < len(keys):
                    raise Exception('Parsing error in file {}, line {}.'.
                        format(path, line))
                yield dict(zip(keys, values))
            else:
                yield values


def __hash__():
    """Get a unique identifier of the referenced object.
        """


def merge_dicts(*dict_args):
    """
    http://stackoverflow.com/questions/38987/how-to-merge-two-python-dictionaries-in-a-single-expression

    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result


def d2influx(data):
    """ transforms internal data (list of kv ) to influx data
    [
        {
            "_id": "<unique identity>",
            "_name": "<name of data source based on id>",
            "_source": "<source name>",
            "_ts": "<timestamp of the input values in rfc3339>",

            "field1": <value1 (float)>,
            ... ,
            "fieldX": <valueX (float)>
        }
    ]
    [
        {
            "measurement": "cpu_load_short",
            "tags": {
                "host": "server01",
                "region": "us-west"
            },
            "time": "2009-11-10T23:00:00Z",
            "fields": {
                "value": 0.64
            }
        }
    ]
    """
    ret = []
    for d in data:
        _id = str(d.pop('_id'))
        _name = d.pop('_name')
        _source = d.pop('_source')
        _ts = d.pop('_ts')
        for measurement, val in d.items():
            e = {'measurement': measurement, 'tags': {'source': _source,
                'id': _id, 'name': _name}, 'time': _ts, 'fields': {'value':
                val}}
            ret.append(e)
    return ret


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 project_apply():
    """Project edited image back onto the object

    """
    pass


def or_by_masks(df, masks):
    """Returns a sub-dataframe by the logical or over the given masks.

    Parameters
    ----------
    df : pandas.DataFrame
        The dataframe to take a subframe of.
    masks : list
        A list of pandas.Series of dtype bool, indexed identically to the given
        dataframe.

    Returns
    -------
    pandas.DataFrame
        The sub-dataframe resulting from applying the masks to the dataframe.

    Example
    -------
    >>> import pandas as pd
    >>> data = [[23, 'Jo'], [19, 'Mi'], [15, 'Di']]
    >>> df = pd.DataFrame(data, [1, 2, 3] , ['Age', 'Name'])
    >>> mask1 = pd.Series([False, True, True], df.index)
    >>> mask2 = pd.Series([False, False, True], df.index)
    >>> or_by_masks(df, [mask1, mask2])
       Age Name
    2   19   Mi
    3   15   Di
    """
    if len(masks) < 1:
        return df
    if len(masks) == 1:
        return df[masks[0]]
    overall_mask = masks[0] | masks[1]
    for mask in masks[2:]:
        overall_mask = overall_mask | mask
    return df[overall_mask]


def fill(use_beauty: bool=True):
    """Fill a selected edge loop with faces

    :param use_beauty: Beauty, Use best triangulation division
    :type use_beauty: bool
    """
    pass


def stress_temperature(t_air_24, t_opt=25.0, t_min=0.0, t_max=50.0):
    """
    Computes the stress for plants when it is too cold or hot

    .. math ::
        f=\\frac{T_{max}-T_{opt}}{T_{opt}-T_{min}}

    .. math ::
        s_{T}=\\frac{\\left(T_{a}-T_{min}\\right)\\left(T_{max}-T_{a}\\right)^{f}}
            {\\left(T_{opt}-T_{min}\\right)\\left(T_{max}-T_{opt}\\right)^{f}}

    Parameters
    ----------
    t_air_24 : float
        daily air temperature
        :math:`T_{a}`
        [C]
    t_opt : float
        optimum air temperature for plant growth
        :math:`T_{opt}`
        [C]
    t_min : float
        minimum air temperature for plant growth
        :math:`T_{min}`
        [C]
    t_max : float
        maximum air temperature for plant growth
        :math:`T_{max}`
        [C]

    Returns
    -------
    stress_temp : float
        stress factor for air temperature
        :math:`S_{T}`
        [-]

    Examples
    --------
    >>> import ETLook.stress as stress
    >>> stress.stress_temperature(15)
    0.83999999999999997
    >>> stress.stress_temperature(15, t_opt =20)
    0.9451080185178129
    >>> stress.stress_temperature(15, t_opt =20, t_min=10)
    0.79398148148148151
    >>> stress.stress_temperature(15, t_opt =20, t_min=10, t_max=30)
    0.75

    """
    f = (t_max - t_opt) / (t_opt - t_min)
    x = (t_air_24 - t_min) * (t_max - t_air_24) ** f
    y = (t_opt - t_min) * (t_max - t_opt) ** f
    stress = x / y
    stress = stress.clip(0, 1)
    return stress


def is_bytes(data):
    """
    Checks if the data given is a sequence of bytes

    And not a "text" type, that can be of multi-byte characters.
    Also, this does NOT mean a bytearray type.

    :param data: the instance to be checked if it falls under the definition
                 of an array of bytes.
    """
    return isinstance(data, bytes)


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

        :param DeviceDeleteOnUnlinkFailType val:
        :rtype: EventType
        """
    return cls('device_delete_on_unlink_fail', val)


def fill_coords(img, fn, color):
    """
    Fill pixels of an image with coordinates matching a filter function
    """
    for y in range(img.shape[0]):
        for x in range(img.shape[1]):
            yf = (y + 0.5) / img.shape[0]
            xf = (x + 0.5) / img.shape[1]
            if fn(xf, yf):
                img[y, x] = color
    return img


@classmethod
def check_support_ucannet(cls, hw_info_ex):
    """
        Checks whether the module supports the usage of USB-CANnetwork driver.

        :param HardwareInfoEx hw_info_ex:
            Extended hardware information structure (see method :meth:`get_hardware_info`).
        :return: True when the module does support the usage of the USB-CANnetwork driver, otherwise False.
        :rtype: bool
        """
    return cls.check_is_systec(hw_info_ex
        ) and cls.check_version_is_equal_or_higher(hw_info_ex.
        m_dwFwVersionEx, 3, 8)


def generate_presigned_url(ClientMethod=None, Params=None, ExpiresIn=None,
    HttpMethod=None):
    """
    Generate a presigned url given a client, its method, and arguments

    :type ClientMethod: string
    :param ClientMethod: The client method to presign for

    :type Params: dict
    :param Params: The parameters normally passed to
            ClientMethod.

    :type ExpiresIn: int
    :param ExpiresIn: The number of seconds the presigned url is valid
            for. By default it expires in an hour (3600 seconds)

    :type HttpMethod: string
    :param HttpMethod: The http method to use on the generated url. By
            default, the http method is whatever is used in the method's model.

    """
    pass


def bytes2NativeString(x, encoding='utf-8'):
    """
    Convert C{bytes} to a native C{str}.

    On Python 3 and higher, str and bytes
    are not equivalent.  In this case, decode
    the bytes, and return a native string.

    On Python 2 and lower, str and bytes
    are equivalent.  In this case, just
    just return the native string.

    @param x: a string of type C{bytes}
    @param encoding: an optional codec, default: 'utf-8'
    @return: a string of type C{str}
    """
    if isinstance(x, bytes) and str != bytes:
        return x.decode(encoding)
    return x


def get_prefix_name_from_path(path: str) ->str:
    """ Assume prefix-name to the last non-empty string after splitting along '/'
    """
    parts = path.split('/')
    for p in reversed(parts):
        if p:
            return p


def _get_widths(jstat_data=None, short_fields=False):
    """Function that returns the recommended field widths of the jstat output"""
    widths = dict()
    for field in jstat_data:
        max_width = max(list(map(len, list(map(str, jstat_data[field])))))
        field_width = len(field)
        if field_width > max_width:
            widths[field] = field_width
        else:
            widths[field] = max_width
    if short_fields:
        survivor_max = 6
        newgen_max = 6
        oldgen_max = 6
    else:
        survivor_max = max(widths['S0C'], widths['S1C'], widths['S0U'],
            widths['S1U'])
        newgen_max = max(widths['EC'], widths['EU'])
        oldgen_max = max(widths['OC'], widths['OU'])
    widths['OC'] = oldgen_max
    widths['OU'] = oldgen_max
    widths['EC'] = newgen_max
    widths['EU'] = newgen_max
    widths['S0C'] = survivor_max
    widths['S1C'] = survivor_max
    widths['S0U'] = survivor_max
    widths['S1U'] = survivor_max
    widths['EP'] = 6
    widths['OP'] = 6
    return widths


@property
def name(cls):
    """Return the configuration name of this plugin's class."""
    if cls.__name__ == 'Default':
        return cls.__module__
    return '{0.__module__}/{0.__name__}'.format(cls)


def CreateFont(font):
    """
    Creates a tuple of 7 :class:`wx.Font` attributes from the `font` input parameter.

    :param `font`: a :class:`wx.Font` instance.

    :returns: A tuple of 7 :class:`wx.Font` attributes from the `font` input parameter.
    """
    return font.GetPointSize(), font.GetFamily(), font.GetStyle(
        ), font.GetWeight(), font.GetUnderlined(), font.GetFaceName(
        ), font.GetEncoding()


def format(result):
    """Returns string representing the formatter result."""


def first(iterable):
    """
    Returns the first item returned by iterating over an iterable object.

    Example:

    >>> a = [1, 2, 3]
    >>> first(a)
    1
    """
    return next(iter(iterable))


def parse_github_url(some_url):
    """
    Takes in something that looks like a Github url in a requirements.txt
    file and returns the package name
    """
    if 'github' in some_url and 'opal' in some_url:
        package_name = some_url.split('@')[0].split('/')[-1]
        package_name = package_name.replace('.git', '')
        version = some_url.split('@')[-1].split('#')[0]
        return {package_name: version}


@classmethod
def serialize(cls, value):
    """
        Converts value to something serializable by :mod:`json`.

        :param value: value to convert
        :return: :mod:`json` serializable equivalent

        By default, returns ``value``, to pass straight to :mod:`json`

        .. warning::

            :meth:`serialize` and :meth:`deserialize` **are not** symetrical.

        **Example of serializing then deserializing a custom object**

        Let's create our own ``Color`` class we'd like to represent as a
        parameter.

        .. doctest::

            >>> class Color(object):
            ...     def __init__(self, r, g, b):
            ...         self.r = r
            ...         self.g = g
            ...         self.b = b
            ...
            ...     def __eq__(self, other):
            ...         return (
            ...             type(self) == type(other) and \\
            ...             self.r == other.r and \\
            ...             self.g == other.g and \\
            ...             self.b == other.b
            ...         )
            ...
            ...     def __repr__(self):
            ...         return "<Color: %i, %i, %i>" % (self.r, self.g, self.b)

            >>> from cqparts.params import Parameter
            >>> class ColorParam(Parameter):
            ...     _doc_type = ":class:`list`"  # for sphinx documentation
            ...     def type(self, value):
            ...         (r, g, b) = value
            ...         return Color(r, g, b)
            ...
            ...     @classmethod
            ...     def serialize(cls, value):
            ...         # the default serialize will fail, we know this
            ...         # because json.dumps(Color(0,0,0)) raises an exception
            ...         if value is None:  # parameter is nullable
            ...             return None
            ...         return [value.r, value.g, value.b]
            ...
            ...     @classmethod
            ...     def deserialize(cls, value):
            ...         # the de-serialized rgb list is good to pass to type
            ...         return value

        Note that ``json_deserialize`` does not return a ``Color`` instance.
        Intead, it returns a *list* to be used as an input to :meth:`cast`
        (which is ultimately passed to :meth:`type`)

        This is because when the values are deserialized, they're used as the
        default values for a newly created :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>` class.

        So now when we use them in a :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>`:

        .. doctest::

            >>> from cqparts.params import ParametricObject, Float
            >>> class MyObject(ParametricObject):
            ...     color = ColorParam(default=[127, 127, 127])  # default 50% grey
            ...     height = Float(10)

            >>> my_object = MyObject(color=[100, 200, 255])
            >>> my_object.color  # is a Color instance (not a list)
            <Color: 100, 200, 255>

        Now to demonstrate how a parameter goes in and out of being serialized,
        we'll create a ``test`` method that, doesn't do anything, except that
        it should *not* throw any exceptions from its assertions, or the call
        to :meth:`json.dumps`

        .. doctest::

            >>> import json

            >>> def test(value, obj_class=Color, param_class=ColorParam):
            ...     orig_obj = param_class().cast(value)
            ...
            ...     # serialize
            ...     if value is None:
            ...         assert orig_obj == None
            ...     else:
            ...         assert isinstance(orig_obj, obj_class)
            ...     serialized = json.dumps(param_class.serialize(orig_obj))
            ...
            ...     # show serialized value
            ...     print(serialized)  # as a json string
            ...
            ...     # deserialize
            ...     ds_value = param_class.deserialize(json.loads(serialized))
            ...     new_obj = param_class().cast(ds_value)
            ...
            ...     # now orig_obj and new_obj should be identical
            ...     assert orig_obj == new_obj
            ...     print("all good")

            >>> test([1, 2, 3])
            [1, 2, 3]
            all good
            >>> test(None)
            null
            all good

        These are used to serialize and deserialize :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>`
        instances, so they may be added to a catalogue, then re-created.

        To learn more, go to :meth:`ParametricObject.serialize() <cqparts.params.parametric_object.ParametricObject.serialize>`

        """
    return value


def getIconURL():
    """ Get the absolute URL of the icon for the object.

        o This method is used in the 'folder_contents' view to generate an
          appropriate icon for the items found in the folder.

        o If the content item does not define an attribute named "icon"
          return a "default" icon path (e.g., ``/misc_/dtmldoc.gif``, which is
          the icon used for DTML Documents).

        o Permission:  Public
        """


def DegreeDist(model, node_type='metabolites', bipartite=True):
    """ node_type = "metabolites" | "reactions" """
    rv = {}
    if 'met' in node_type:
        names = model.Metabolites()
    elif 'reac' in node_type:
        names = model.Reactions()
    for n in names:
        deg = model.Degree(n, bipartite=bipartite)
        if deg in rv.keys():
            rv[deg] = rv[deg] + 1
        else:
            rv[deg] = 1
    return rv


def format_device(dev):
    """
    Format a device for display.
    """
    copy_dev = dev.copy()
    for key in ('ip', 'replication_ip'):
        if ':' in copy_dev[key]:
            copy_dev[key] = '[' + copy_dev[key] + ']'
    return (
        'd%(id)sr%(region)sz%(zone)s-%(ip)s:%(port)sR%(replication_ip)s:%(replication_port)s/%(device)s_"%(meta)s"'
         % copy_dev)


def domain_from_hostname(hostname):
    """Return the canonical domain from a hostname, and if it's already a hostname, just return itself.

    >>> domain_from_hostname('tsunami')
    'tsunami.ocf.berkeley.edu'
    """
    if not hostname.endswith('.ocf.berkeley.edu'):
        return hostname + '.ocf.berkeley.edu'
    return hostname


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


@staticmethod
def _get_payload_template(params=None):
    """Construct payload template.

        Args:
            params: Additional params.

        Returns:
            dict: Return payload dict.
        """
    if not params:
        params = {}
    payload_template = {'method': '', 'params': params, 'jsonrpc': '2.0',
        'id': 0}
    return payload_template


def is_deletable_code(cell):
    """Returns whether or not cell is deletable"""
    if 'tags' in cell['metadata'] and 'include' in cell['metadata']['tags']:
        return False
    if 'tags' in cell['metadata'] and 'ignore' in cell['metadata']['tags']:
        return True
    elif len(cell['outputs']) > 0:
        for output in cell['outputs']:
            if 'data' in output and 'image/png' in output['data']:
                return False
    return True


def padl(text, n, c):
    """
    left pad of text with character c
    """
    text = str(text)
    return str(c) * (n - len(text)) + text


def bitmask(mask):
    """
    First element in `mask` is least-significant bit, last element is most-significant.
    """
    result = 0
    for index, x in enumerate(mask):
        result |= x << index
    return result


def get_version(request):
    """
    Computes the JSON-RPC version

    :param request: A request dictionary
    :return: The JSON-RPC version or None
    """
    if 'jsonrpc' in request:
        return 2.0
    elif 'id' in request:
        return 1.0
    return None


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 provider_parser(subparser):
    """Configure provider parser for Aurora"""
    subparser.add_argument('--auth-api-key', help=
        'specify API key for authentication')
    subparser.add_argument('--auth-secret-key', help=
        'specify the secret key for authentication')


def metadata_item_format(value):
    """Space-separated values in 'key=value' format."""
    try:
        data_name, data_value = value.split('=')
    except ValueError:
        message = (
            'Incorrectly formatted metadata. Argument values should be in the format a=b c=d'
            )
        raise ValueError(message)
    return {'name': data_name, 'value': data_value}


def remove_legend(ax=None):
    """Remove legend for axes or gca.

    See http://osdir.com/ml/python.matplotlib.general/2005-07/msg00285.html
    """
    from pylab import gca, draw
    if ax is None:
        ax = gca()
    ax.legend_ = None
    draw()


def _gen_param_code(name, doc, defaultValueStr):
    """
    Generates Python code for a shared param class.

    :param name: param name
    :param doc: param doc
    :param defaultValueStr: string representation of the default value
    :return: code string
    """
    template = """
    def set$Name(self, value):
        ""\"
        Sets the value of :py:attr:`$name`.
        ""\"
        return self._set($name=value)

    def get$Name(self):
        ""\"
        Gets the value of $name or its default value.
        ""\"
        return self.getOrDefault(self.$name)"""
    Name = name[0].upper() + name[1:]
    return template.replace('$name', name).replace('$Name', Name).replace(
        '$doc', doc).replace('$defaultValueStr', str(defaultValueStr))


def format_pattern(bit, pattern):
    """Return a string that is formatted with the given bit using either % or .format on the given pattern."""
    try:
        if '%' in pattern:
            return pattern % bit
    except:
        pass
    try:
        return pattern.format(bit)
    except:
        return pattern


def reveal():
    """Unhide all bones that have been tagged to be hidden in Pose Mode

    """
    pass


def add_simple_uvs():
    """Add cube map uvs on mesh

    """
    pass


def nest(flat_dict, separator='/'):
    """
    Converts a flat dictionary into a nested dictionary by splitting keys by a
    given separator.

    Args:
        flat_dict (dict): Flat dictionary.
        separator (str, optional): Field separator within given dictionary's
            keys. Default: '/'.

    Returns:
        dict: Nested dictionary.
    """
    output = {}
    for keys, val in flat_dict.items():
        split_keys = list(filter(lambda x: x != '', keys.split(separator)))
        cursor = output
        last = split_keys.pop()
        for key in split_keys:
            if key not in cursor:
                cursor[key] = {}
            if not isinstance(cursor[key], dict):
                msg = f"Duplicate key conflict. Key: '{key}'."
                raise KeyError(msg)
            cursor = cursor[key]
        cursor[last] = val
    return output


def lorenz(v):
    """
    Returns lorenz values to future plots
    Based on https://stackoverflow.com/questions/39512260/calculating-gini-coefficient-in-python-numpy
    """
    import numpy as np
    bins = np.linspace(0.0, 100.0, 11)
    total = float(np.sum(v))
    yvals = []
    for b in bins:
        bin_vals = v[v <= np.percentile(v, b)]
        bin_fraction = np.sum(bin_vals) / total * 100.0
        yvals.append(bin_fraction)
    pe_area = np.trapz(bins, x=bins)
    lorenz_area = np.trapz(yvals, x=bins)
    gini_val = (pe_area - lorenz_area) / float(pe_area)
    return bins, yvals, gini_val


def create_cube(bm: 'bmesh.types.BMesh', size: float, matrix:
    'mathutils.Matrix', calc_uvs: bool) ->dict:
    """Creates a cube.

    :param bm: The bmesh to operate on.
    :type bm: 'bmesh.types.BMesh'
    :param size: size of the cube
    :type size: float
    :param matrix: matrix to multiply the new geometry with
    :type matrix: 'mathutils.Matrix'
    :param calc_uvs: calculate default UVs
    :type calc_uvs: bool
    :return:  verts: output vertstype list of (bmesh.types.BMVert)
    """
    pass


def select_word():
    """Select word under cursor

    """
    pass


def uniqueItemIndex(pos=0):
    """Return an index iterator."""


@classmethod
def _seconds_to_minutes(cls, val, **kwargs):
    """
        converts a number of seconds to minutes
        """
    zero_value = kwargs.get('zero_value', 0)
    if val is not None:
        if val == zero_value:
            return 0
        return val / 60
    else:
        return 'Not Defined'


def f(i):
    """A fake task - in this case let just open a file and write a number to it"""
    f = open('%d.txt' % i, 'w')
    for k in range(1000000):
        f.write('%d * 10 = %d\n' % (i, 10 * i))
    f.close()


def parse_bdist_wininst(name):
    """Return (base,pyversion) or (None,None) for possible .exe name"""
    lower = name.lower()
    base, py_ver, plat = None, None, None
    if lower.endswith('.exe'):
        if lower.endswith('.win32.exe'):
            base = name[:-10]
            plat = 'win32'
        elif lower.startswith('.win32-py', -16):
            py_ver = name[-7:-4]
            base = name[:-16]
            plat = 'win32'
        elif lower.endswith('.win-amd64.exe'):
            base = name[:-14]
            plat = 'win-amd64'
        elif lower.startswith('.win-amd64-py', -20):
            py_ver = name[-7:-4]
            base = name[:-20]
            plat = 'win-amd64'
    return base, py_ver, plat


def strip_semicolon_from_word(sWord):
    """
    Removes trailing semicolon from a word:

        case;   => case
        entity; => entity

    Parameters:

      sWord: (string)

    Returns: (string)
    """
    if ';' == sWord[-1]:
        return sWord[0:-1]
    return sWord


def fmodifier_paste(only_active: bool=True, replace: bool=False):
    """Add copied F-Modifiers to the selected F-Curves

    :param only_active: Only Active, Only paste F-Modifiers on active F-Curve
    :type only_active: bool
    :param replace: Replace Existing, Replace existing F-Modifiers, instead of just appending to the end of the existing list
    :type replace: bool
    """
    pass


def interpret_line(line, splitter=','):
    """
    Split text into arguments and parse each of them to an appropriate format (int, float or string)
    Args:
        line:
        splitter:
    Returns: list of arguments
    """
    parsed = list()
    elms = line.split(splitter)
    for elm in elms:
        try:
            el = int(elm)
        except Exception as ex1:
            try:
                el = float(elm)
            except Exception as ex2:
                el = elm.strip()
        parsed.append(el)
    return parsed


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 extract_templates(cls, file_=None, source=None, tag=None, is_re=False,
    ignore_mark=False, export=False):
    """Extract template.

        # @:adhoc_template_check:@ -mark
        A template ...
        # @:adhoc_template_check:@

        # @:adhoc_template_check:@ -other
        Another interleaved
        # @:adhoc_template_check:@

        # @:adhoc_template_check:@ -mark
        continued
        # @:adhoc_template_check:@

        >>> AdHoc.extract_templates(
        ...     tag=AdHoc.section_tag("adhoc_template_check"))
                A template ...
                continued
                Another interleaved

        >>> rt_section = AdHoc.get_templates(
        ...     __file__, None,
        ...     tag=AdHoc.section_tag("adhoc_run_time_section"),
        ...     ignore_mark=True)
        >>> rt_section = ''.join(rt_section.values())

        .. >>> printf(rt_section)
        """
    file_, source, tag, is_re = cls.std_template_param(file_, source, tag,
        is_re)
    templates = cls.get_templates(file_, source, tag, is_re=is_re,
        ignore_mark=ignore_mark)
    sv_extract_warn = cls.extract_warn
    cls.extract_warn = True
    for outf, template in sorted(templates.items()):
        if outf.startswith('-'):
            outf = '-'
        if outf == '-' and export:
            continue
        xfile = cls.check_xfile(outf, cls.extract_dir)
        if xfile is not None:
            cls.write_source(xfile, template)
    cls.extract_warn = sv_extract_warn


@staticmethod
def fileExtension():
    """Return the extension used for the file on disc representing this
        resource """
    return '.dashboard'


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 check_section(node, section, keys=None):
    """Validate keys in a section"""
    if keys:
        for key in keys:
            if key not in node:
                raise ValueError('Missing key %r inside %r node' % (key,
                    section))


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


def _float_or_none(x, digits=3):
    """ Helper function to format a variable that can be a float or None"""
    if x is None:
        return str(x)
    fmtstr = '{0:.{digits}g}'.format(x, digits=digits)
    return fmtstr.format(x)


def getExceptionMessage(exceptionDetails: dict) ->str:
    """Get exception message from `exceptionDetails` object."""
    exception = exceptionDetails.get('exception')
    if exception:
        return exception.get('description') or exception.get('value')
    message = exceptionDetails.get('text', '')
    stackTrace = exceptionDetails.get('stackTrace', dict())
    if stackTrace:
        for callframe in stackTrace.get('callFrames'):
            location = str(callframe.get('url', '')) + ':' + str(callframe.
                get('lineNumber', '')) + ':' + str(callframe.get(
                'columnNumber'))
            functionName = callframe.get('functionName', '<anonymous>')
            message = message + f'\n    at {functionName} ({location})'
    return message


def read_file(filename, mode='r'):
    """write_file will open a file, "filename" and write content, "content"
    and properly close the file
    """
    with open(filename, mode) as filey:
        content = filey.readlines()
    return content


@classmethod
def generic_model(cls, site_class, **kwds):
    """Use generic model parameters based on site class.

        Parameters
        ----------
        site_class: str
            Site classification. Possible options are:
             * Geomatrix AB
             * Geomatrix CD
             * USGS AB
             * USGS CD
             * USGS A
             * USGS B
             * USGS C
             * USGS D

            See the report for definitions of the Geomatrix site
            classication. USGS site classification is based on :math:`V_{s30}`:

            =========== =====================
            Site Class  :math:`V_{s30}` (m/s)
            =========== =====================
            A           >750 m/s
            B           360 to 750 m/s
            C           180 to 360 m/s
            D           <180 m/s
            =========== =====================

        Returns
        -------
        DepthDependToroVelVariation
            Initialized :class:`DepthDependToroVelVariation` with generic parameters.
        """
    p = dict(cls.PARAMS[site_class])
    p.update(kwds)
    if 'depth' not in kwds:
        p['depth'] = [0, 15]
        p['ln_std'] = [0.25, 0.15]
    return cls(**p)


def psi_Cs_Na_Cl_PK74(T, P):
    """c-c'-a: caesium sodium chloride [PK74]."""
    psi = -0.003
    valid = T == 298.15
    return psi, valid


def _add_title(title, marker):
    """Return a title for a basemodels docstring."""
    return ['', title, marker * len(title)]


def normalize_multiline(line):
    """Normalize multiline-related code that will cause syntax error.

    This is for purposes of checking syntax.

    """
    if line.startswith('def ') and line.rstrip().endswith(':'):
        return line + ' pass'
    elif line.startswith('return '):
        return 'def _(): ' + line
    elif line.startswith('@'):
        return line + 'def _(): pass'
    elif line.startswith('class '):
        return line + ' pass'
    elif line.startswith(('if ', 'elif ', 'for ', 'while ')):
        return line + ' pass'
    return line


def replace(tpl, ind, var):
    """
    (TUPLE FUNCTION)
    Replace tpl[ind] with var
    """
    tpl = list(tpl)
    if type(ind) == str:
        ind = tpl.index(ind)
    tpl[ind] = var
    return tuple(tpl)


def test_cab(archive, compression, cmd, verbosity, interactive):
    """Test a CAB archive."""
    return [cmd, '-t', archive]


def resetForm():
    """Reset any cached data because underlying content may have changed
        """


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 merged_tagged_value_dict(iface, name):
    """Look up the tagged value 'name' in schema and all its bases, assuming
    that the value under 'name' is a dict. Return a dict that consists of
    all dict items, with those from more-specific interfaces overriding those
    from more-general ones.
    """
    tv = {}
    for iface in reversed(iface.__iro__):
        tv.update(iface.queryTaggedValue(name, {}))
    return tv


def setitems(items):
    """
    Takes a dict `items` and writes its key/val to the config.
    """
    for key, val in items.items():
        set(key, val)


def lineno(obj):
    """Tries to obtain a line number from the code"""
    try:
        return obj.lineno
    except AttributeError:
        return 0


@classmethod
def get_version(cls, settings, path):
    """Generate the version string to be used in static URLs.

        ``settings`` is the `Application.settings` dictionary and ``path``
        is the relative location of the requested asset on the filesystem.
        The returned value should be a string, or ``None`` if no version
        could be determined.

        .. versionchanged:: 3.1
           This method was previously recommended for subclasses to override;
           `get_content_version` is now preferred as it allows the base
           class to handle caching of the result.
        """
    abs_path = cls.get_absolute_path(settings['static_path'], path)
    return cls._get_cached_version(abs_path)


def parse_pubstatus_node(node):
    """ Parse pubstatus node

    Parameters
    ----------
    node : XML node or None

    Returns
    -------
    str or None
    """
    if node is not None:
        return node.text


@classmethod
def from_dict(cls, config):
    """Return a Module from the config dictionary"""
    return cls(**config)


def indent_text(string, indent_level=2):
    """Indent every line of text in a newline-delimited string"""
    indented_lines = []
    indent_spaces = ' ' * indent_level
    for line in string.split('\n'):
        indented_lines.append(indent_spaces + line)
    return '\n'.join(indented_lines)


def obv(df, price='close', volume='volume', col='obv'):
    """
    On Balance Volume (OBV) measures buying and selling pressure as a cumulative indicator, adding volume on up days and subtracting it on down days
    The On Balance Volume (OBV) line is simply a running total of positive and negative volume.
    A period's volume is positive when the close is above the prior close and is negative when the close is below the prior close.

    The On Balance Volume (OBV) is a cumulative total of the up and down volume.
    When the close is higher than the previous close, the volume is added to
    the running total, and when the close is lower than the previous close,
    the volume is subtracted from the running total.

    Parameters:
        df (pd.DataFrame): DataFrame which contain the asset price.
        price (string): the column name of the price of the asset.
        volume (string): the column name of the volume of the asset.
        obv (string): the column name for the on balance volume values.

    Returns:
        df (pd.DataFrame): Dataframe with obv of the asset calculated.

    Sample Strategy:
    Bullish:
        AND [Daily SMA(60,Daily Volume) > 100000]
        AND [Daily SMA(60,Daily Close) > 10]

        AND [Daily Close < Daily SMA(65,Daily Close)]
        AND [Daily AccDist > Daily AccDist Signal (65)]
        AND [Daily OBV > Daily OBV Signal(65)]
        AND [Daily Close < Daily SMA(20,Daily Close)]
        AND [Daily AccDist > Daily AccDist Signal (20)]
        AND [Daily OBV > Daily OBV Signal(20)]

    Bearish:

        AND [Daily SMA(60,Daily Volume) > 100000]
        AND [Daily SMA(60,Daily Close) > 10]

        AND [Daily Close > Daily SMA(65,Daily Close)]
        AND [Daily AccDist < Daily AccDist Signal (65)]
        AND [Daily OBV < Daily OBV Signal(65)]
        AND [Daily Close > Daily SMA(20,Daily Close)]
        AND [Daily AccDist < Daily AccDist Signal (20)]
        AND [Daily OBV < Daily OBV Signal(20)]

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

    """
    df['diff'] = df[price].diff()
    df = df.fillna(1)
    df.loc[df['diff'] > 0, col + '_sign'] = 1
    df.loc[df['diff'] < 0, col + '_sign'] = -1
    df.loc[df['diff'] == 0, col + '_sign'] = 0
    volume_sign = df[volume] * df[col + '_sign']
    df[col] = volume_sign.cumsum()
    df.drop(['diff', col + '_sign'], axis=1, inplace=True)
    return df


def as_utf8(s):
    """ensure utf8 bytes"""
    if not isinstance(s, bytes):
        s = s.encode('utf8')
    return s


@staticmethod
def _get_or_add_member_to_xml(clsdict):
    """
        Add the enum -> xml value mapping to the enumeration class state
        """
    if '_member_to_xml' not in clsdict:
        clsdict['_member_to_xml'] = dict()
    return clsdict['_member_to_xml']


def ellipsize(s, max_length=60):
    """
    >>> print(ellipsize(u'lorem ipsum dolor sit amet', 40))
    lorem ipsum dolor sit amet
    >>> print(ellipsize(u'lorem ipsum dolor sit amet', 20))
    lorem ipsum dolor...
    """
    if len(s) > max_length:
        ellipsis = '...'
        return s[:max_length - len(ellipsis)] + ellipsis
    else:
        return s


def searchGroupsByRequest(request):
    """Search for groups matching a set of criteria found in a request.

        This method will look remove any obvious values from the request
        which are not search criteria. It will also remove any fields
        which have an empty string value.
        """


def __get_latest_server_os_object(nova, server):
    """
    Returns a server with a given id
    :param nova: the Nova client
    :param server: the domain VmInst object
    :return: the list of servers or None if not found
    """
    return nova.servers.get(server.id)


def add_namespace_to_cmd(cmd, namespace=None):
    """Add an optional namespace to the command."""
    return ['ip', 'netns', 'exec', namespace] + cmd if namespace else cmd


def convert_dict_to_array(data):
    """Convert a dict-based format to an array."""
    items = []
    nmap = {}
    index = 0
    nodes = data.get('nodes', ())
    rels = data.get('rels', ())
    for nindex, node in enumerate(nodes):
        items.append(node)
        nmap[nindex] = index
        index += 1
    for rel in enumerate(rels):
        items.append(rel)
        rel['start'] = nmap[rel['start']]
        rel['end'] = nmap[rel['end']]
    return data


def byteorder(filename):
    """Check the byteorder of a given file.

    Args:
        filename (str): Filename of a tiff image.

    Returns:
        str: '<' for little endian, '>' for big endian.
    """
    with open(filename, 'rb') as handle:
        tmp = {b'II': '<', b'MM': '>'}[handle.read(2)]
        return tmp


def convert_temperature_int(value):
    """Convert the integer temperature value to signed."""
    return int(value) - 100


def calculate_score(points, max_bytes, total_buttons, buttons, bytes):
    """Calculates the score for a level.

    points: the points assigned for solving the level (based on difficulty)
    max_bytes: the maximum number of bytes for the level
    total_buttons: the number of white buttons on the level
    buttons: the number of white buttons pressed
    bytes: the number of bytes actually used
    """
    if buttons == total_buttons and bytes <= max_bytes:
        return points * max_bytes // bytes
    assert buttons < total_buttons or bytes > max_bytes
    points_per_button = 0
    if bytes <= max_bytes:
        points_per_button = points // (2 * total_buttons)
    if max_bytes < bytes <= 2 * max_bytes:
        points_per_button = points * (2 * max_bytes - bytes) // (2 *
            max_bytes * total_buttons)
    return buttons * points_per_button


def is_empty(dict_obj):
    """
    query if a dict is empty

    :param dict_obj: the to be tested dictionary
    :return: True, if it is empty, False if not empty
    """
    if isinstance(dict_obj, dict):
        if len(list(dict_obj.items())) <= 0:
            return True
        else:
            switch = True
            for k, v in list(dict_obj.items()):
                if v is None:
                    pass
                else:
                    switch = False
            return switch
    else:
        return False


def getBuilderNames():
    """Return a list of the names of all Builders on which this set will
        do builds.

        @returns: list of names via Deferred"""


def process_rules(value):
    """
        This should implement the rules logic.

        """
    raise NotImplementedError


def dup_shift(f, a, K):
    """
    Evaluate efficiently Taylor shift ``f(x + a)`` in ``K[x]``.

    Examples
    ========

    >>> R, x = ring('x', ZZ)

    >>> R.dup_shift(x**2 - 2*x + 1, ZZ(2))
    x**2 + 2*x + 1

    """
    f, n = list(f), len(f) - 1
    for i in range(n, 0, -1):
        for j in range(i):
            f[j + 1] += a * f[j]
    return f


def rpc_asynchronous(method):
    """Decorator to declare an asynchronous RPC command.

    :func:`rpc_command` must also be used for this to make effect. The order in
    which both decorators are applied is not important."""
    method.is_asynchronous = True
    return method


@classmethod
def getTimezone(cls):
    """Returns the pytz timezone for the market session."""
    return cls.timezone


def restrict_injection(n):
    """Take the first child's data."""
    if n.child[0] is not None:
        if n.child[0].data is not None:
            return n.child[0].data.copy()


def convert_ip_port(ip):
    """
    Get ip and port, but extract port from ip if ip was as ip:port
    :param ip:
    :return: (ip, port)
    """
    port = 5658
    if ':' in ip:
        ip, port = ip.split(':')
    return ip, port


@classmethod
def validate(cls, value):
    """
        Raise |ValueError| if *value* is not an assignable value.
        """
    if value not in cls._valid_settings:
        raise ValueError('%s not a member of %s enumeration' % (value, cls.
            __name__))


def change_frame(frame: int=0):
    """Interactively change the current frame number

    :param frame: Frame
    :type frame: int
    """
    pass


def get_subclasses(cls):
    """
    Recursively finds all subclasses of the current class.
    Like Python's __class__.__subclasses__(), but recursive.
    Returns a list containing all subclasses.

    @type cls: object
    @param cls: A Python class.
    @rtype: list(object)
    @return: A list containing all subclasses.
    """
    result = set()
    path = [cls]
    while path:
        parent = path.pop()
        for child in parent.__subclasses__():
            if not '.' in str(child):
                continue
            if child not in result:
                result.add(child)
                path.append(child)
    return result


def control_valve_choke_P_g(xT, gamma, P1=None, P2=None):
    """Calculates either the upstream or downstream pressure at which choked
    flow though a gas control valve occurs, given either a set upstream or
    downstream pressure. Implements an analytical solution of
    the needed equations from the full function
    :py:func:`~.size_control_valve_g`. A singularity arises as `xT` goes to 1
    and `gamma` goes to 1.4.

    .. math::
        P_1 = - \\frac{7 P_{2}}{5 \\gamma x_T - 7}

    .. math::
        P_2 = \\frac{P_{1}}{7} \\left(- 5 \\gamma x_T + 7\\right)

    Parameters
    ----------
    xT : float, optional
        Pressure difference ratio factor of a valve without fittings at choked
        flow [-]
    gamma : float
        Specific heat capacity ratio [-]
    P1 : float, optional
        Absolute pressure upstream of the valve [Pa]
    P2 : float, optional
        Absolute pressure downstream of the valve [Pa]

    Returns
    -------
    P_choke : float
        Pressure at which a choke occurs in the gas valve [Pa]

    Notes
    -----
    Extremely cheap to compute.

    Examples
    --------
    >>> control_valve_choke_P_g(1, 1.3, 1E5)
    7142.857142857143
    >>> control_valve_choke_P_g(1, 1.3, P2=7142.857142857143)
    100000.0
    """
    if P2 is None:
        ans = P2 = P1 * (-5.0 * gamma * xT + 7.0) / 7.0
    elif P1 is None:
        ans = P1 = -7.0 * P2 / (5.0 * gamma * xT - 7.0)
    else:
        raise Exception('Either P1 or P2 needs to be specified')
    return ans


def change_regularity(element, family):
    """
    For a given finite element, return the corresponding space
    specified by 'family'.
    """
    return element.reconstruct(family=family)


def iterBigFile(textfile, offset=0, size=None, maxSize=400, headSize=40,
    tailSize=None):
    """
    Yield lines from file textfile. If the size to read is bigger
    than maxSize then yield the first lines until headSize bytes, then
    yield None, then yield the last lines from tailSize bytes to the end.
    """
    if size is None:
        textfile.seek(0, 2)
        sizeKb = (textfile.tell() - offset) / 1024
    else:
        sizeKb = size
    headSizeB = headSize * 1024
    tailSizeB = (tailSize or headSize) * 1024
    textfile.seek(offset)
    if 0 < maxSize < sizeKb:
        for line in textfile.read(headSizeB).split('\n'):
            yield line + '\n'
        yield None
        textfile.seek(sizeKb * 1024 - tailSizeB)
    for line in textfile:
        yield line


def select_linked(extend: bool=False):
    """Select all UV vertices linked to the active UV map

    :param extend: Extend, Extend selection rather than clearing the existing selection
    :type extend: bool
    """
    pass


def stream_is_unidirectional(stream_id: int) ->bool:
    """
    Returns True if the stream is unidirectional.
    """
    return bool(stream_id & 2)


def sequence(value):
    """Return tuple containing value if value is not a sequence.

    >>> sequence(1)
    (1,)
    >>> sequence([1])
    [1]

    """
    try:
        len(value)
        return value
    except TypeError:
        return value,


def _pipe_segment_with_colons(align, colwidth):
    """Return a segment of a horizontal line with optional colons which
    indicate column's alignment (as in `pipe` output format)."""
    w = colwidth
    if align in ['right', 'decimal']:
        return '-' * (w - 1) + ':'
    elif align == 'center':
        return ':' + '-' * (w - 2) + ':'
    elif align == 'left':
        return ':' + '-' * (w - 1)
    else:
        return '-' * w


def write(cal, file=None):
    """Write a calendar to an ICS file.

    Args:
        cal: calendar to write to the file
        file: file to write the calendar in

    """
    file.write(cal.to_ical().decode('utf-8'))


def p_expression_lnot(p):
    """expression : LNOT expression"""
    p[0] = not p[1]


def root_signature_provider(signature_dict, key_id, _key, _data):
    """Root signature provider used to return signatures created remotely.

    Args:
        - signature_dict(dict): Dict where key is key_id and value is signature
        - key_id(str): Key id from targets metadata file
        - _key(securesystemslib.formats.RSAKEY_SCHEMA): Key info
        - _data(dict): Data to sign (already signed remotely)

    Returns:
        Dictionary that comforms to `securesystemslib.formats.SIGNATURE_SCHEMA`

    Raises:
        - KeyError: If signature for key_id is not present in signature_dict
    """
    from binascii import hexlify
    return {'keyid': key_id, 'sig': hexlify(signature_dict.get(key_id)).
        decode()}


def num_urls_in_units_dict(units_dict):
    """
    Counts the number of urls in a all_units dict, it ignores subtitles from
    its counting.
    """
    num_urls = 0
    for units in units_dict.values():
        for unit in units:
            for video in unit.videos:
                num_urls += int(video.video_youtube_url is not None)
                num_urls += int(video.available_subs_url is not None)
                num_urls += int(video.sub_template_url is not None)
                num_urls += len(video.mp4_urls)
            num_urls += len(unit.resources_urls)
    return num_urls


def generate_correlation_id():
    """
    Creates a new ``correlation_id`` for requests.

    Increments the ``last_id`` value so each generated ID is unique for
    this machine and process.
    """
    global last_id
    last_id += 1
    return last_id


def arg_eval(arg):
    """Evaluate an argument."""
    try:
        return eval(arg)
    except:
        return arg


def warning_on_one_line(message, category, filename, lineno, file=None,
    line=None):
    """User warning formatter"""
    return '{}:{}: {}: {}\n'.format(filename, lineno, category.__name__,
        message)


def list_domain_names():
    """
    Lists all search domains owned by an account.
    See also: AWS API Documentation

    :example: response = client.list_domain_names()

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

    """
    pass


def _relabel_nodes_integers(g):
    """A helper function that relabels nodes in a graph/network using
    consecutive integer ids starting from 0. The relabeled ids are
    ordered following the original alphabetical order as the original
    node labels.

    Parameters
    ----------
    g : NetworkX Graph or DiGraph
        The original network of which the nodes are to be relabeled.

    Returns
    -------
    NetworkX Graph or DiGraph
        A new network with nodes relabeled.
    rev_mapping : dict
        A mapping from the new node ids (integers) to the original node
        labels.

    See Also
    --------
    networkx.relabel.relabel_nodes
    """
    mapping = dict()
    rev_mapping = dict()
    for i, node in enumerate(sorted(g.nodes())):
        mapping[node] = i
        rev_mapping[i] = node
    from networkx import relabel_nodes
    return relabel_nodes(g, mapping), rev_mapping


@classmethod
def fromkeys(cls, iterable, value=None):
    """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
        and values equal to v (which defaults to None).

        """
    d = cls()
    for key in iterable:
        d[key] = value
    return d


def unpack_header_kw(hdus, keywords, try_first=0):
    """ Looks up keyword values in FITS headers. Iterates over
    extensions until keyword is found, else returns False

    Can look up single keyword or several at once

    hdus - HDUList, exposure headers
    keywords - string or list, keywords to look up
    try_first - header index to look up first

    returns
    ----
    vals - single parameter value or list of parameter values
    """
    vals = []
    kws = [keywords] if not isinstance(keywords, list) else keywords
    for kw in kws:
        for hdu_ind in set([try_first, *range(len(hdus))]):
            try:
                hdu = hdus[hdu_ind]
                vals.append(hdu.header[kw])
                break
            except (IndexError, KeyError):
                pass
        else:
            vals.append(False)
    if not isinstance(keywords, list):
        return vals[0]
    return vals


def pitch2hz(p, beta=12, ref_frq=440.0):
    """Convert pitch to frequency.

    Parameters
    ----------
    p : np.ndarray, float
        midi pitch
    beta : int
        equal divisions of the octave
    ref_frq : float, optional
        Description

    Returns
    -------
    frq : np.ndarray, float
        frequency
    """
    return 2 ** ((p - 69) / beta) * ref_frq


def flag_callback():
    """JS callback for the flagging button

    Returns
    -------
    code : :obj:`str`
    """
    code = """
            //sources: list of all different sources for the different antennas and available sources
            //n_sources: number of sources
            //flagging: status of flag_data

            let n_sources =  uf_sources.length;

            if (cb_obj.active.includes(0)){
                for (let i=0; i<n_sources; i++){
                    uf_sources[i].data.y1 = f_sources[i].data.iy1;
                    uf_sources[i].data.y2 = f_sources[i].data.iy2;
                    uf_sources[i].change.emit();
                }
            }
            else{
                for (let i=0; i<n_sources; i++){
                    uf_sources[i].data.y1 = f_sources[i].data.y1;
                    uf_sources[i].data.y2 = f_sources[i].data.y2;
                    uf_sources[i].change.emit();
                }

            }
           """
    return code


@classmethod
def read_dataframe(cls, dataframe, wildtype, **kwargs):
    """Construct a GenotypePhenotypeMap from a dataframe."""
    df = dataframe
    self = cls(wildtype, df.genotypes, df.phenotypes, stdeviations=df.
        stdeviations, n_replicates=df.n_replicates, **kwargs)
    return self


def _clean_lc(lc):
    """ Perform Lightkurve operations on object.

    Performes basic cleaning of a light curve, removing nans, outliers,
    median filtering etc.

    Parameters
    ----------
    lc : Lightkurve.LightCurve instance
        Lightkurve object to be cleaned

    Returns
    -------
    lc : Lightkurve.LightCurve instance
        The cleaned Lightkurve object

    """
    lc = lc.remove_nans().normalize().flatten().remove_outliers()
    return lc


@classmethod
def register_transformation(cls, src, target, action=None):
    """Register a transformation from class src to class target using function action.

        :param src: source function
        :param target: target function
        :param action: transformation function
        """
    cls.transformations[target].append((src, action))


def is_special(ip_address):
    """Determine if the address is SPECIAL
       Note: This is super bad, improve it
    """
    special = {'224.0.0.251': 'multicast_dns', 'ff02::fb': 'multicast_dns'}
    return special[ip_address] if ip_address in special else False


def onInitialize():
    """
        Called before forking the process.
        """


def umf_ergun(dp, ep, mu, phi, rhog, rhos):
    """
    Determine minimum fluidization velocity from particle and gas properties.
    This approach is based on the Ergun pressure drop equation for a bed of
    particles. Refer to Equations 18 and 19 in Chapter 3 of Kunii and Levenspiel
    [2]_,

    Parameters
    ----------
    dp : float
        Diameter of bed particle [m]
    ep : float
        Void fraction of the bed [-]
    mu : float
        Viscosity of gas [kg/ms]
    phi : float
        Sphericity of bed particle [-]
    rhog : float
        Density of gas [kg/m³]
    rhos : float
        Density of bed particle [kg/m³]

    Returns
    -------
    umf : float
        Minimum fluidization velocity [m/s]

    Example
    -------
    >>> umf_ergun(0.0005, 0.46, 3.6e-5, 0.86, 0.44, 2500)
    0.1488

    References
    ----------
    .. [2] Daizo Kunii and Octave Levenspiel. Fluidization Engineering.
       Butterworth-Heinemann, 2nd edition, 1991.
    """
    g = 9.81
    K1 = 1.75 / (ep ** 3 * phi)
    K2 = 150 * (1 - ep) / (ep ** 3 * phi ** 2)
    a = K2 / (2 * K1)
    b = 1 / K1
    Ar = dp ** 3 * rhog * (rhos - rhog) * g / mu ** 2
    Re = (a ** 2 + b * Ar) ** 0.5 - a
    umf = Re * mu / (rhog * dp)
    return umf


def copy_reduce(reducer, graph, target, in_data, out_size, in_map, out_map):
    """Copy target data and perform reduce based on graph structure.

    Parameters
    ----------
    reducer : str
        Type of reduction: be 'sum', 'max', 'min', 'mean', 'prod', 'none' (no
        reduction)
    graph : GraphIndex
        The graph
    target : int
        The input target (src, dst, edge)
    in_data : Tensor
        The input data
    out_size : int
        Size of first dimension of output data
    in_map : tuple
        Two input id mapping arrays, one for forward, the other for backward
    out_map : tuple
        Two output id mapping arrays, one for forward, the other for backward

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


def get_host_info(node_info, host):
    """
    Simple callback that takes the node info from `/_cluster/nodes` and a
    parsed connection information and return the connection information. If
    `None` is returned this node will be skipped.

    Useful for filtering nodes (by proximity for example) or if additional
    information needs to be provided for the :class:`~elasticsearch.Connection`
    class. By default master only nodes are filtered out since they shouldn't
    typically be used for API operations.

    :arg node_info: node information from `/_cluster/nodes`
    :arg host: connection information (host, port) extracted from the node info
    """
    attrs = node_info.get('attributes', {})
    if attrs.get('data', 'true') == 'false' and attrs.get('client', 'false'
        ) == 'false' and attrs.get('master', 'true') == 'true':
        return None
    return host


def log(harn, msg):
    """
        Logs an info message. Alias of :func:LogMixin.info

        Args:
            msg (str): an info message to log
        """
    harn.info(msg)


def get_shortest_path_distance_old(planner, origin, destination):
    """
    This function calculates the distance of the shortest path connecting
    origin and destination using A* search with distance heuristic.
    Args:
        planner: Global route planner
        origin (tuple): Tuple containing x, y co-ordinates of start position
        destination (tuple): (x, y) co-coordinates of destination position

    Returns:
        The shortest distance from origin to destination along a feasible path

    """
    graph, _ = planner.build_graph()
    path = planner.path_search(origin, destination)
    distance = 0.0
    if len(path) > 0:
        first_node = graph.nodes[path[0]]['vertex']
        distance = planner.distance(origin, first_node)
        for i in range(1, len(path)):
            distance += planner.distance(graph.nodes[path[i - 1]]['vertex'],
                graph.nodes[path[i]]['vertex'])
    return distance


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

        :param UserDeleteEmailsResult val:
        :rtype: UserDeleteResult
        """
    return cls('success', val)


def page_HTML(title, *tokens, **kw):
    """ Convenience function returning an '<HTML>' token for a page.
      Keyword parameters:
      `content_type`: "http-equiv" Content-Type, default: "text/html; charset=UTF-8".
      `head_tokens`: optional extra markup tokens for the HEAD section.
      `body_attrs`: optional attributes for the BODY section tag.
  """
    content_type = kw.pop('content_type', 'text/html; charset=UTF-8')
    head_tokens = kw.pop('head_tokens', ())
    body_attrs = kw.pop('body_attrs', {})
    if kw:
        raise ValueError('unexpected keywords: %r' % (kw,))
    body = ['BODY', body_attrs]
    body.extend(tokens)
    head = ['HEAD', ['META', {'http-equiv': 'Content-Type', 'content':
        content_type}], '\n', ['TITLE', title], '\n']
    head.extend(head_tokens)
    return ['HTML', head, body]


def options():
    """
    Return a sorted list of dicts, each containing the keys "name", "code" and
    "exceptions". These should be used to build a user interface for customers
    to declare their country of residence. If their declared country of
    residence includes any exceptions, the user must be presented with an option
    to select their residence as residing in an area with a VAT exception.

    The country codes and names are from ISO 3166-1.

    :return:
        A list of dicts objects each with the keys "name", "code" and
        "exceptions"
    """
    return [{'name': 'Afghanistan', 'code': 'AF', 'exceptions': []}, {
        'name': 'Åland Islands', 'code': 'AX', 'exceptions': []}, {'name':
        'Albania', 'code': 'AL', 'exceptions': []}, {'name': 'Algeria',
        'code': 'DZ', 'exceptions': []}, {'name': 'American Samoa', 'code':
        'AS', 'exceptions': []}, {'name': 'Andorra', 'code': 'AD',
        'exceptions': []}, {'name': 'Angola', 'code': 'AO', 'exceptions': [
        ]}, {'name': 'Anguilla', 'code': 'AI', 'exceptions': []}, {'name':
        'Antarctica', 'code': 'AQ', 'exceptions': []}, {'name':
        'Antigua and Barbuda', 'code': 'AG', 'exceptions': []}, {'name':
        'Argentina', 'code': 'AR', 'exceptions': []}, {'name': 'Armenia',
        'code': 'AM', 'exceptions': []}, {'name': 'Aruba', 'code': 'AW',
        'exceptions': []}, {'name': 'Australia', 'code': 'AU', 'exceptions':
        []}, {'name': 'Austria', 'code': 'AT', 'exceptions': ['Jungholz',
        'Mittelberg']}, {'name': 'Azerbaijan', 'code': 'AZ', 'exceptions':
        []}, {'name': 'Bahamas', 'code': 'BS', 'exceptions': []}, {'name':
        'Bahrain', 'code': 'BH', 'exceptions': []}, {'name': 'Bangladesh',
        'code': 'BD', 'exceptions': []}, {'name': 'Barbados', 'code': 'BB',
        'exceptions': []}, {'name': 'Belarus', 'code': 'BY', 'exceptions':
        []}, {'name': 'Belgium', 'code': 'BE', 'exceptions': []}, {'name':
        'Belize', 'code': 'BZ', 'exceptions': []}, {'name': 'Benin', 'code':
        'BJ', 'exceptions': []}, {'name': 'Bermuda', 'code': 'BM',
        'exceptions': []}, {'name': 'Bhutan', 'code': 'BT', 'exceptions': [
        ]}, {'name': 'Bolivia, Plurinational State of', 'code': 'BO',
        'exceptions': []}, {'name': 'Bonaire, Sint Eustatius and Saba',
        'code': 'BQ', 'exceptions': []}, {'name': 'Bosnia and Herzegovina',
        'code': 'BA', 'exceptions': []}, {'name': 'Botswana', 'code': 'BW',
        'exceptions': []}, {'name': 'Bouvet Island', 'code': 'BV',
        'exceptions': []}, {'name': 'Brazil', 'code': 'BR', 'exceptions': [
        ]}, {'name': 'British Indian Ocean Territory', 'code': 'IO',
        'exceptions': []}, {'name': 'Brunei Darussalam', 'code': 'BN',
        'exceptions': []}, {'name': 'Bulgaria', 'code': 'BG', 'exceptions':
        []}, {'name': 'Burkina Faso', 'code': 'BF', 'exceptions': []}, {
        'name': 'Burundi', 'code': 'BI', 'exceptions': []}, {'name':
        'Cambodia', 'code': 'KH', 'exceptions': []}, {'name': 'Cameroon',
        'code': 'CM', 'exceptions': []}, {'name': 'Canada', 'code': 'CA',
        'exceptions': []}, {'name': 'Cabo Verde', 'code': 'CV',
        'exceptions': []}, {'name': 'Cayman Islands', 'code': 'KY',
        'exceptions': []}, {'name': 'Central African Republic', 'code':
        'CF', 'exceptions': []}, {'name': 'Chad', 'code': 'TD',
        'exceptions': []}, {'name': 'Chile', 'code': 'CL', 'exceptions': []
        }, {'name': 'China', 'code': 'CN', 'exceptions': []}, {'name':
        'Christmas Island', 'code': 'CX', 'exceptions': []}, {'name':
        'Cocos (Keeling) Islands', 'code': 'CC', 'exceptions': []}, {'name':
        'Colombia', 'code': 'CO', 'exceptions': []}, {'name': 'Comoros',
        'code': 'KM', 'exceptions': []}, {'name': 'Congo', 'code': 'CG',
        'exceptions': []}, {'name': 'Congo, the Democratic Republic of the',
        'code': 'CD', 'exceptions': []}, {'name': 'Cook Islands', 'code':
        'CK', 'exceptions': []}, {'name': 'Costa Rica', 'code': 'CR',
        'exceptions': []}, {'name': "Côte d'Ivoire", 'code': 'CI',
        'exceptions': []}, {'name': 'Croatia', 'code': 'HR', 'exceptions':
        []}, {'name': 'Cuba', 'code': 'CU', 'exceptions': []}, {'name':
        'Curaçao', 'code': 'CW', 'exceptions': []}, {'name': 'Cyprus',
        'code': 'CY', 'exceptions': []}, {'name': 'Czech Republic', 'code':
        'CZ', 'exceptions': []}, {'name': 'Denmark', 'code': 'DK',
        'exceptions': []}, {'name': 'Djibouti', 'code': 'DJ', 'exceptions':
        []}, {'name': 'Dominica', 'code': 'DM', 'exceptions': []}, {'name':
        'Dominican Republic', 'code': 'DO', 'exceptions': []}, {'name':
        'Ecuador', 'code': 'EC', 'exceptions': []}, {'name': 'Egypt',
        'code': 'EG', 'exceptions': []}, {'name': 'El Salvador', 'code':
        'SV', 'exceptions': []}, {'name': 'Equatorial Guinea', 'code': 'GQ',
        'exceptions': []}, {'name': 'Eritrea', 'code': 'ER', 'exceptions':
        []}, {'name': 'Estonia', 'code': 'EE', 'exceptions': []}, {'name':
        'Ethiopia', 'code': 'ET', 'exceptions': []}, {'name':
        'Falkland Islands (Malvinas)', 'code': 'FK', 'exceptions': []}, {
        'name': 'Faroe Islands', 'code': 'FO', 'exceptions': []}, {'name':
        'Fiji', 'code': 'FJ', 'exceptions': []}, {'name': 'Finland', 'code':
        'FI', 'exceptions': []}, {'name': 'France', 'code': 'FR',
        'exceptions': []}, {'name': 'French Guiana', 'code': 'GF',
        'exceptions': []}, {'name': 'French Polynesia', 'code': 'PF',
        'exceptions': []}, {'name': 'French Southern Territories', 'code':
        'TF', 'exceptions': []}, {'name': 'Gabon', 'code': 'GA',
        'exceptions': []}, {'name': 'Gambia', 'code': 'GM', 'exceptions': [
        ]}, {'name': 'Georgia', 'code': 'GE', 'exceptions': []}, {'name':
        'Germany', 'code': 'DE', 'exceptions': ['Büsingen am Hochrhein',
        'Heligoland']}, {'name': 'Ghana', 'code': 'GH', 'exceptions': []},
        {'name': 'Gibraltar', 'code': 'GI', 'exceptions': []}, {'name':
        'Greece', 'code': 'GR', 'exceptions': ['Mount Athos']}, {'name':
        'Greenland', 'code': 'GL', 'exceptions': []}, {'name': 'Grenada',
        'code': 'GD', 'exceptions': []}, {'name': 'Guadeloupe', 'code':
        'GP', 'exceptions': []}, {'name': 'Guam', 'code': 'GU',
        'exceptions': []}, {'name': 'Guatemala', 'code': 'GT', 'exceptions':
        []}, {'name': 'Guernsey', 'code': 'GG', 'exceptions': []}, {'name':
        'Guinea', 'code': 'GN', 'exceptions': []}, {'name': 'Guinea-Bissau',
        'code': 'GW', 'exceptions': []}, {'name': 'Guyana', 'code': 'GY',
        'exceptions': []}, {'name': 'Haiti', 'code': 'HT', 'exceptions': []
        }, {'name': 'Heard Island and McDonald Islands', 'code': 'HM',
        'exceptions': []}, {'name': 'Holy See (Vatican City State)', 'code':
        'VA', 'exceptions': []}, {'name': 'Honduras', 'code': 'HN',
        'exceptions': []}, {'name': 'Hong Kong', 'code': 'HK', 'exceptions':
        []}, {'name': 'Hungary', 'code': 'HU', 'exceptions': []}, {'name':
        'Iceland', 'code': 'IS', 'exceptions': []}, {'name': 'India',
        'code': 'IN', 'exceptions': []}, {'name': 'Indonesia', 'code': 'ID',
        'exceptions': []}, {'name': 'Iran, Islamic Republic of', 'code':
        'IR', 'exceptions': []}, {'name': 'Iraq', 'code': 'IQ',
        'exceptions': []}, {'name': 'Ireland', 'code': 'IE', 'exceptions':
        []}, {'name': 'Isle of Man', 'code': 'IM', 'exceptions': []}, {
        'name': 'Israel', 'code': 'IL', 'exceptions': []}, {'name': 'Italy',
        'code': 'IT', 'exceptions': ["Campione d'Italia", 'Livigno']}, {
        'name': 'Jamaica', 'code': 'JM', 'exceptions': []}, {'name':
        'Japan', 'code': 'JP', 'exceptions': []}, {'name': 'Jersey', 'code':
        'JE', 'exceptions': []}, {'name': 'Jordan', 'code': 'JO',
        'exceptions': []}, {'name': 'Kazakhstan', 'code': 'KZ',
        'exceptions': []}, {'name': 'Kenya', 'code': 'KE', 'exceptions': []
        }, {'name': 'Kiribati', 'code': 'KI', 'exceptions': []}, {'name':
        "Korea, Democratic People's Republic of", 'code': 'KP',
        'exceptions': []}, {'name': 'Korea, Republic of', 'code': 'KR',
        'exceptions': []}, {'name': 'Kosovo, Republic of', 'code': 'XK',
        'exceptions': []}, {'name': 'Kuwait', 'code': 'KW', 'exceptions': [
        ]}, {'name': 'Kyrgyzstan', 'code': 'KG', 'exceptions': []}, {'name':
        "Lao People's Democratic Republic", 'code': 'LA', 'exceptions': []},
        {'name': 'Latvia', 'code': 'LV', 'exceptions': []}, {'name':
        'Lebanon', 'code': 'LB', 'exceptions': []}, {'name': 'Lesotho',
        'code': 'LS', 'exceptions': []}, {'name': 'Liberia', 'code': 'LR',
        'exceptions': []}, {'name': 'Libya', 'code': 'LY', 'exceptions': []
        }, {'name': 'Liechtenstein', 'code': 'LI', 'exceptions': []}, {
        'name': 'Lithuania', 'code': 'LT', 'exceptions': []}, {'name':
        'Luxembourg', 'code': 'LU', 'exceptions': []}, {'name': 'Macao',
        'code': 'MO', 'exceptions': []}, {'name':
        'Macedonia, the former Yugoslav Republic of', 'code': 'MK',
        'exceptions': []}, {'name': 'Madagascar', 'code': 'MG',
        'exceptions': []}, {'name': 'Malawi', 'code': 'MW', 'exceptions': [
        ]}, {'name': 'Malaysia', 'code': 'MY', 'exceptions': []}, {'name':
        'Maldives', 'code': 'MV', 'exceptions': []}, {'name': 'Mali',
        'code': 'ML', 'exceptions': []}, {'name': 'Malta', 'code': 'MT',
        'exceptions': []}, {'name': 'Marshall Islands', 'code': 'MH',
        'exceptions': []}, {'name': 'Martinique', 'code': 'MQ',
        'exceptions': []}, {'name': 'Mauritania', 'code': 'MR',
        'exceptions': []}, {'name': 'Mauritius', 'code': 'MU', 'exceptions':
        []}, {'name': 'Mayotte', 'code': 'YT', 'exceptions': []}, {'name':
        'Mexico', 'code': 'MX', 'exceptions': []}, {'name':
        'Micronesia, Federated States of', 'code': 'FM', 'exceptions': []},
        {'name': 'Moldova, Republic of', 'code': 'MD', 'exceptions': []}, {
        'name': 'Monaco', 'code': 'MC', 'exceptions': []}, {'name':
        'Mongolia', 'code': 'MN', 'exceptions': []}, {'name': 'Montenegro',
        'code': 'ME', 'exceptions': []}, {'name': 'Montserrat', 'code':
        'MS', 'exceptions': []}, {'name': 'Morocco', 'code': 'MA',
        'exceptions': []}, {'name': 'Mozambique', 'code': 'MZ',
        'exceptions': []}, {'name': 'Myanmar', 'code': 'MM', 'exceptions':
        []}, {'name': 'Namibia', 'code': 'NA', 'exceptions': []}, {'name':
        'Nauru', 'code': 'NR', 'exceptions': []}, {'name': 'Nepal', 'code':
        'NP', 'exceptions': []}, {'name': 'Netherlands', 'code': 'NL',
        'exceptions': []}, {'name': 'New Caledonia', 'code': 'NC',
        'exceptions': []}, {'name': 'New Zealand', 'code': 'NZ',
        'exceptions': []}, {'name': 'Nicaragua', 'code': 'NI', 'exceptions':
        []}, {'name': 'Niger', 'code': 'NE', 'exceptions': []}, {'name':
        'Nigeria', 'code': 'NG', 'exceptions': []}, {'name': 'Niue', 'code':
        'NU', 'exceptions': []}, {'name': 'Norfolk Island', 'code': 'NF',
        'exceptions': []}, {'name': 'Northern Mariana Islands', 'code':
        'MP', 'exceptions': []}, {'name': 'Norway', 'code': 'NO',
        'exceptions': []}, {'name': 'Oman', 'code': 'OM', 'exceptions': []},
        {'name': 'Pakistan', 'code': 'PK', 'exceptions': []}, {'name':
        'Palau', 'code': 'PW', 'exceptions': []}, {'name':
        'Palestine, State of', 'code': 'PS', 'exceptions': []}, {'name':
        'Panama', 'code': 'PA', 'exceptions': []}, {'name':
        'Papua New Guinea', 'code': 'PG', 'exceptions': []}, {'name':
        'Paraguay', 'code': 'PY', 'exceptions': []}, {'name': 'Peru',
        'code': 'PE', 'exceptions': []}, {'name': 'Philippines', 'code':
        'PH', 'exceptions': []}, {'name': 'Pitcairn', 'code': 'PN',
        'exceptions': []}, {'name': 'Poland', 'code': 'PL', 'exceptions': [
        ]}, {'name': 'Portugal', 'code': 'PT', 'exceptions': ['Azores',
        'Madeira']}, {'name': 'Puerto Rico', 'code': 'PR', 'exceptions': []
        }, {'name': 'Qatar', 'code': 'QA', 'exceptions': []}, {'name':
        'Réunion', 'code': 'RE', 'exceptions': []}, {'name': 'Romania',
        'code': 'RO', 'exceptions': []}, {'name': 'Russian Federation',
        'code': 'RU', 'exceptions': []}, {'name': 'Rwanda', 'code': 'RW',
        'exceptions': []}, {'name': 'Saint Barthélemy', 'code': 'BL',
        'exceptions': []}, {'name':
        'Saint Helena, Ascension and Tristan da Cunha', 'code': 'SH',
        'exceptions': []}, {'name': 'Saint Kitts and Nevis', 'code': 'KN',
        'exceptions': []}, {'name': 'Saint Lucia', 'code': 'LC',
        'exceptions': []}, {'name': 'Saint Martin (French part)', 'code':
        'MF', 'exceptions': []}, {'name': 'Saint Pierre and Miquelon',
        'code': 'PM', 'exceptions': []}, {'name':
        'Saint Vincent and the Grenadines', 'code': 'VC', 'exceptions': []},
        {'name': 'Samoa', 'code': 'WS', 'exceptions': []}, {'name':
        'San Marino', 'code': 'SM', 'exceptions': []}, {'name':
        'Sao Tome and Principe', 'code': 'ST', 'exceptions': []}, {'name':
        'Saudi Arabia', 'code': 'SA', 'exceptions': []}, {'name': 'Senegal',
        'code': 'SN', 'exceptions': []}, {'name': 'Serbia', 'code': 'RS',
        'exceptions': []}, {'name': 'Seychelles', 'code': 'SC',
        'exceptions': []}, {'name': 'Sierra Leone', 'code': 'SL',
        'exceptions': []}, {'name': 'Singapore', 'code': 'SG', 'exceptions':
        []}, {'name': 'Sint Maarten (Dutch part)', 'code': 'SX',
        'exceptions': []}, {'name': 'Slovakia', 'code': 'SK', 'exceptions':
        []}, {'name': 'Slovenia', 'code': 'SI', 'exceptions': []}, {'name':
        'Solomon Islands', 'code': 'SB', 'exceptions': []}, {'name':
        'Somalia', 'code': 'SO', 'exceptions': []}, {'name': 'South Africa',
        'code': 'ZA', 'exceptions': []}, {'name':
        'South Georgia and the South Sandwich Islands', 'code': 'GS',
        'exceptions': []}, {'name': 'South Sudan', 'code': 'SS',
        'exceptions': []}, {'name': 'Spain', 'code': 'ES', 'exceptions': [
        'Canary Islands', 'Ceuta', 'Melilla']}, {'name': 'Sri Lanka',
        'code': 'LK', 'exceptions': []}, {'name': 'Sudan', 'code': 'SD',
        'exceptions': []}, {'name': 'Suriname', 'code': 'SR', 'exceptions':
        []}, {'name': 'Svalbard and Jan Mayen', 'code': 'SJ', 'exceptions':
        []}, {'name': 'Swaziland', 'code': 'SZ', 'exceptions': []}, {'name':
        'Sweden', 'code': 'SE', 'exceptions': []}, {'name': 'Switzerland',
        'code': 'CH', 'exceptions': []}, {'name': 'Syrian Arab Republic',
        'code': 'SY', 'exceptions': []}, {'name':
        'Taiwan, Province of China', 'code': 'TW', 'exceptions': []}, {
        'name': 'Tajikistan', 'code': 'TJ', 'exceptions': []}, {'name':
        'Tanzania, United Republic of', 'code': 'TZ', 'exceptions': []}, {
        'name': 'Thailand', 'code': 'TH', 'exceptions': []}, {'name':
        'Timor-Leste', 'code': 'TL', 'exceptions': []}, {'name': 'Togo',
        'code': 'TG', 'exceptions': []}, {'name': 'Tokelau', 'code': 'TK',
        'exceptions': []}, {'name': 'Tonga', 'code': 'TO', 'exceptions': []
        }, {'name': 'Trinidad and Tobago', 'code': 'TT', 'exceptions': []},
        {'name': 'Tunisia', 'code': 'TN', 'exceptions': []}, {'name':
        'Turkey', 'code': 'TR', 'exceptions': []}, {'name': 'Turkmenistan',
        'code': 'TM', 'exceptions': []}, {'name':
        'Turks and Caicos Islands', 'code': 'TC', 'exceptions': []}, {
        'name': 'Tuvalu', 'code': 'TV', 'exceptions': []}, {'name':
        'Uganda', 'code': 'UG', 'exceptions': []}, {'name': 'Ukraine',
        'code': 'UA', 'exceptions': []}, {'name': 'United Arab Emirates',
        'code': 'AE', 'exceptions': []}, {'name': 'United Kingdom', 'code':
        'GB', 'exceptions': ['Akrotiri', 'Dhekelia']}, {'name':
        'United States', 'code': 'US', 'exceptions': []}, {'name':
        'United States Minor Outlying Islands', 'code': 'UM', 'exceptions':
        []}, {'name': 'Uruguay', 'code': 'UY', 'exceptions': []}, {'name':
        'Uzbekistan', 'code': 'UZ', 'exceptions': []}, {'name': 'Vanuatu',
        'code': 'VU', 'exceptions': []}, {'name':
        'Venezuela, Bolivarian Republic of', 'code': 'VE', 'exceptions': []
        }, {'name': 'Viet Nam', 'code': 'VN', 'exceptions': []}, {'name':
        'Virgin Islands, British', 'code': 'VG', 'exceptions': []}, {'name':
        'Virgin Islands, U.S.', 'code': 'VI', 'exceptions': []}, {'name':
        'Wallis and Futuna', 'code': 'WF', 'exceptions': []}, {'name':
        'Western Sahara', 'code': 'EH', 'exceptions': []}, {'name': 'Yemen',
        'code': 'YE', 'exceptions': []}, {'name': 'Zambia', 'code': 'ZM',
        'exceptions': []}, {'name': 'Zimbabwe', 'code': 'ZW', 'exceptions': []}
        ]


def p_idfobject(p):
    """idfobject : objectname SEMICOLON"""
    p[0] = [p[1]]


def length_from_str(src):
    """A simple restriction of integer:

    <xs:simpleType name="Length">
            <xs:restriction base="xs:integer">
                    <xs:maxInclusive value="32767"/>
                    <xs:minInclusive value="-32768"/>
            </xs:restriction>
    </xs:simpleType>"""
    value = int(src)
    if value < -32768 or value > 32767:
        raise ValueError('Value exceeds bounds for Length: %i' % value)
    return value


@staticmethod
def is_valid(control_instance, *args, **kwargs):
    """ Method to check if the new control values are correct.

        If the new list controls values are not correct, the backroung
        color of each control in the list will be red.

        Parameters
        ----------
        control_instance: QFrame (mandatory)
            the control widget we want to validate

        Returns
        -------
        valid: bool
            True if the control values are valid,
            False otherwise
        """
    valid = True
    return valid


@classmethod
def duration(cls):
    """
        Duration of the temporal value, that is, ``'SequenceSet'``.
        """
    return 'SequenceSet'


def hash_string(some_string):
    """Calculate the human-readable SHA256 hash of a string.

    Parameters
    ----------
    some_string : str, required
        String to be hashed.

    Returns
    -------
    String of 64 hexadecimal characters.

    """
    import hashlib
    return hashlib.sha256(some_string.encode()).hexdigest()


def strip_blank_lines(l):
    """Remove leading and trailing blank lines from a list of lines"""
    while l and not l[0].strip():
        del l[0]
    while l and not l[-1].strip():
        del l[-1]
    return l


def dict_pack(d_files, d_names, d_crop, d_inftemp, d_temp, d_plate):
    """
    Function is used within the auto_crop function to  crop using the inputs
    given by the user.

    Parameters:
    -----------
    d_files : dictonary
        contains the raw file in the requested folder

    d_names : dictonary
        Contains all the names of the files in the requested folder

    d_crop : dictonary
        Contains the cropped versions of the files in the folder

    d_inftemp : dictonary
        Contins all of the inflection points of the files in the folder

    Returns
    --------
    d_all : dictonary
        Nested dictionary of all of the needed dictonary

    """
    d_all = {'d_files': d_files, 'd_names': d_names, 'd_crop': d_crop,
        'd_inftemp': d_inftemp, 'd_temp': d_temp, 'd_plate': d_plate}
    return d_all


def compare(a, b):
    """Return -1/0/1 if a is less/equal/greater than b."""
    return 0 if a == b else 1 if a > b else -1 if a < b else None


def complementary_iof(principal, complementary_iof_fee=0.0038):
    """Complementary IOF tax over the principal.

    If :math:`s` is the principal and :math:`I^{**}` is the complementary IOF
    fee, then the due complementary IOF tax over the principal is

    .. math::

        s\\ I^{**}.

    Parameters
    ----------
    principal: float, required
        The loan principal, which is the basis for the complementary IOF tax.
    complementary_iof_fee: float, required
        Aliquot applied over the principal. Its value is defined by law.
    """
    return float(principal * complementary_iof_fee)


def make_vector(dim, init_value):
    """
    Return a list of dim copies of init_value
    """
    return [init_value] * dim


def tree_for_key(key, context=None):
    """the lookup tree for *key*."""


@classmethod
def __factory(cls, data):
    """
        This factory makes that any returned value is a measure
        instead of a float.
        """
    return cls(data)


def strip_chars(subdomain_df):
    """Strip *.'s and www.'s"""
    subdomain_df = subdomain_df.str.lower()
    subdomain_df = subdomain_df.str.replace('www.', '')
    subdomain_df = subdomain_df.str.replace('\\*.', '')
    return subdomain_df


def create_scatter_legend(axi, color_labels, class_names, show=False, **kwargs
    ):
    """Generate a legend for a scatter plot with class labels.

    Parameters
    ----------
    axi : object like :class:`matplotlib.axes.Axes`
        The axes we will add the legend for.
    color_labels : dict of objects like :class:`numpy.ndarray`
        Colors for the different classes.
    color_names : dict of strings
        Names for the classes.
    show : boolean, optional
        If True, we will add the legend here.
    kwargs : dict, optional
        Additional arguments passed to the scatter method. Used
        here to get a consistent styling.

    Returns
    -------
    patches : list of objects like :class:`matplotlib.artist.Artist`
        The items we will create a legend for.
    labels : list of strings
        The labels for the legend.

    """
    patches, labels = [], []
    for key, val in color_labels.items():
        patches.append(axi.scatter([], [], color=val, **kwargs))
        if class_names is not None:
            label = class_names.get(key, key)
        else:
            label = key
        labels.append(label)
    if show:
        axi.legend(patches, labels)
    return patches, labels


@classmethod
def input(cls, port, contact):
    """
        Get the NodeID string for a support input.

        :param port: the desired port (1..6)
        :param contact: the desired contact at the port (1..2)
        :return: the node id string
        """
    return getattr(cls, 'in_{}_{}'.format(port, contact))


def iter_dict_differences(a, b):
    """
    Returns a generator yielding all the keys that have values that differ between each dictionary.
    """
    common_keys = set(a).union(b)
    for k in common_keys:
        a_value = a.get(k)
        b_value = b.get(k)
        if a_value != b_value:
            yield k, (a_value, b_value)


def _neighbor_switch(G, w, unsat, h_node_residual, avoid_node_id=None):
    """ Releases one free stub for ``w``, while preserving joint degree in G.

    Parameters
    ----------
    G : NetworkX graph
        Graph in which the neighbor switch will take place.
    w : integer
        Node id for which we will execute this neighbor switch.
    unsat : set of integers
        Set of unsaturated node ids that have the same degree as w.
    h_node_residual: dictionary of integers
        Keeps track of the remaining stubs  for a given node.
    avoid_node_id: integer
        Node id to avoid when selecting w_prime.

    Notes
    -----
    First, it selects *w_prime*, an  unsaturated node that has the same degree
    as ``w``. Second, it selects *switch_node*, a neighbor node of ``w`` that
    is not  connected to *w_prime*. Then it executes an edge swap i.e. removes
    (``w``,*switch_node*) and adds (*w_prime*,*switch_node*). Gjoka et. al. [1]
    prove that such an edge swap is always possible.

    References
    ----------
    .. [1] M. Gjoka, B. Tillman, A. Markopoulou, "Construction of Simple
       Graphs with a Target Joint Degree Matrix and Beyond", IEEE Infocom, '15
    """
    if avoid_node_id is None or h_node_residual[avoid_node_id] > 1:
        w_prime = next(iter(unsat))
    else:
        iter_var = iter(unsat)
        while True:
            w_prime = next(iter_var)
            if w_prime != avoid_node_id:
                break
    w_prime_neighbs = G[w_prime]
    for v in G[w]:
        if v not in w_prime_neighbs and v != w_prime:
            switch_node = v
            break
    G.remove_edge(w, switch_node)
    G.add_edge(w_prime, switch_node)
    h_node_residual[w] += 1
    h_node_residual[w_prime] -= 1
    if h_node_residual[w_prime] == 0:
        unsat.remove(w_prime)


def tracks_add(above_selected: bool=False):
    """Add NLA-Tracks above/after the selected tracks

    :param above_selected: Above Selected, Add a new NLA Track above every existing selected one
    :type above_selected: bool
    """
    pass


def disable():
    """Disables custom exception handling"""
    global ENABLED
    ENABLED = False


def NTM(Iref, wind_speed):
    """
    Additional evaluator - evaluates turbulence intensity according to IEC edition 3 normal turbulence model

    :param Iref: Reference turbulence intensity in percent according to turbine class
    :param wind_speed: 10-minute mean wind speed in m/s
    :returns: Turbulence intensity in percent
    """
    return Iref * (0.75 * wind_speed + 5.6) / wind_speed


@staticmethod
def shiftl(steps, val):
    """Shift left as a function. For use in functional patterns."""
    return val << steps


def datetime_to_utc_datetime_iso8601(datetime, day_granularity=False):
    """ Convert a datetime into its iso8601 UTC date.

        Parameters:
            datetime: Datetime to convert.
            day_granularity: Apply the day granularity

        Returns:
            Converted date (string).

    """
    datetime = datetime.replace(microsecond=0)
    result = datetime.isoformat() + 'Z'
    if day_granularity:
        result = result[:-10]
    return result


def has(cls):
    """
    Check whether *cls* is a class with ``attrs`` attributes.

    :param type cls: Class to introspect.
    :raise TypeError: If *cls* is not a class.

    :rtype: bool
    """
    return getattr(cls, '__attrs_attrs__', None) is not None


def lag(x, y, samps):
    """
    Lag x samps to the left and
    lag y samps to the right.
    samps must be even.
    If samps is negative x shifted to the right and y to the left.
    This process truncates trace length by samps and preserves centrality.
    Therefore windowing must be used after this process
    to ensure even trace lengths when measuring splitting.
    """
    if samps == 0:
        return x, y
    if samps > 0:
        return x[samps:], y[:-samps]
    else:
        return x[:samps], y[-samps:]


@classmethod
def find(cls, db, token, *, kind=None):
    """Find a token object by value.

        Returns None if not found.

        `kind='user'` only returns API tokens for users
        `kind='service'` only returns API tokens for services
        """
    prefix_match = cls.find_prefix(db, token)
    if kind == 'user':
        prefix_match = prefix_match.filter(cls.user_id != None)
    elif kind == 'service':
        prefix_match = prefix_match.filter(cls.service_id != None)
    elif kind is not None:
        raise ValueError("kind must be 'user', 'service', or None, not %r" %
            kind)
    for orm_token in prefix_match:
        if orm_token.match(token):
            return orm_token


def assert_fortran_mat(*mats):
    """Check if the input ndarrays are all proper Fortran matrices."""
    for mat in mats:
        if mat is not None and (mat.shape[0] > 1 or mat.shape[1] > 1
            ) and not mat.flags['F_CONTIGUOUS']:
            raise ValueError('Input matrix must be Fortran contiguous')


def intersperse_l(delimiter, iterable):
    """put the delimiter on the left of every element of iterable"""
    it = iter(iterable)
    for x in it:
        yield delimiter
        yield x


def unravel_index(i, shape, order='C'):
    """Rewrite of np.unravel_index that allows shape to have more than 32
    dimensions.

    numpy arrays cannot be of dimension larger than 32. to avoid issues and
    unecessary dependencies we just cut out numpy entirely
    """
    cumulative_sizes = []
    j = 1
    for size in shape[::-1]:
        j *= int(size)
        cumulative_sizes.append(j)
    if cumulative_sizes[-1] <= i:
        raise ValueError('Requested index outside of range.')
    cumulative_sizes = cumulative_sizes[::-1]
    indexes = []
    j = i
    for size in cumulative_sizes[1:]:
        indexes.append(j // size)
        j = j % size
    indexes.append(j)
    if order == 'C':
        pass
    elif order == 'F':
        indexes = indexes[::-1]
    else:
        raise ValueError('Expected "C" or "F" for "order" kwarg.')
    return indexes


def manage_changeProperties(REQUEST=None, **kw):
    """Change existing object properties.

        Change object properties by passing either a REQUEST object or
        name=value parameters
        """


def active_roles(account, days_back):
    """ Returns query for finding active roles (since days_back value). """
    query_string = f"""SELECT DISTINCT useridentity.sessioncontext.sessionissuer.arn
        FROM behold
        WHERE account = '{account}'
        AND useridentity.type = 'AssumedRole'
        AND from_iso8601_timestamp(eventtime) > date_add('day', -{days_back}, now());"""
    return query_string, f'athena_results/active_roles/{account}'


def resource_name(obj_type):
    """
    Transforms an object type into a resource name

    :param obj_type:
        The object type, i.e. ``user`` or ``user_reference``
    :returns: The name of the resource, i.e. the last part of the URL for the
        resource's index URL
    :rtype: str
    """
    if obj_type.endswith('_reference'):
        obj_type = obj_type[:obj_type.index('_reference')]
    if obj_type.endswith('y'):
        return obj_type[:-1] + 'ies'
    else:
        return obj_type + 's'


def main():
    """Run when called as a module."""
    raise RuntimeError('This module is not meant to be run by itself.')


def reflow(text):
    """
    Reformat CJK text according to its punctuation.

    Given a string, this function will reformat ("reflow") the text so that
    words and terms are not broken apart between lines. The function first
    strips out any leading margins as used by CBETA texts. It then adds an
    extra space following any short lines that might stand alone. Then it
    reformats the text according to horizontal spacing and punctuation.

    CBETA margin format: X01n0020_p0404a01(00)║

    """
    starters = '「『\u3000\t'
    enders = '：，；。？！」』.;:?!'
    specials = starters + enders + '\x1f'
    new_str = ''
    prev_c = '\x1f'
    for line in text.split('\n'):
        if '║' in line:
            line = line.split('║', 1)[-1]
        if line.startswith('\u3000') and len(line) < 17:
            line += '\u3000'
        for cur_c in line:
            if prev_c in enders and cur_c not in enders:
                new_str += '\n'
            elif cur_c in starters and prev_c not in specials:
                new_str += '\n'
            new_str += cur_c
            prev_c = cur_c
    if len(new_str) > 0 and new_str[-1] != '\n':
        new_str += '\n'
    return new_str


def upload_chunk(url, dat, start, stop, total, content_type, session):
    """Upload a chunk of a file"""
    res = session.put(url=url, data=dat, headers={'Content-Length': str(
        stop - start), 'Content-Type': content_type, 'Content-Range':
        'bytes {start}-{stop}/{total}'.format(start=start, stop=stop - 1,
        total=total)})
    return res


def add_inner_blocks(blocks):
    """Process a list of blocks by adding all closures and inner classes as
    top-level blocks.
    """
    new_blocks = []
    all_blocks = blocks[:]
    while all_blocks:
        block = all_blocks.pop()
        new_blocks.append(block)
        for inner_block in ('closures', 'inner_classes'):
            for i_block in getattr(block, inner_block, ()):
                named = i_block._replace(name=block.name + '.' + i_block.name)
                all_blocks.append(named)
                for meth in getattr(named, 'methods', ()):
                    m_named = meth._replace(classname=named.name)
                    all_blocks.append(m_named)
    return new_blocks


def discard(token):
    """Discard the workflow matched to the given `token`.

        :param token: A token matching a pending event with a type of
            'registration'.
        :raises LookupError: when no workflow is associated with the token.
        """


@classmethod
def default(cls):
    """Returns the default (0) value for this Enumeration.

        Returns:
            CFXEnum: The default value for this CFXEnum.
        """
    return next(iter(cls))


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

        :param ShowcasePostCommentType val:
        :rtype: EventType
        """
    return cls('showcase_post_comment', val)


@staticmethod
def sanitize(uri=''):
    """
        Sanitize the uri.

        The sanitize method returns a sanitized version of the string passed to it.

        Parameters
        ----------
        uri: str
            The uri location string.

        Returns
        -------
        str
            Returns a sanitized uri string.
        """
    if uri:
        uri = uri.replace('\\', '/')
    return uri


@classmethod
def _format_results_to_hdict(cls, obj, results, translator, hdict_row):
    """Convert hdict row to translator format for hdict.

        results - table row entries from subtables of a translator.
        translator - is the translator to convert obj.
        hdict_row - all the value fields of an hdict populated in a dict.
        """
    field_translators = translator[cls.FIELD_TRANSLATORS]
    table = translator[cls.TABLE_NAME]
    id_col = translator.get(cls.ID_COL)
    parent_key = translator.get(cls.PARENT_KEY)
    new_row = []
    for fieldtranslator in field_translators:
        col = fieldtranslator.get(cls.COL, fieldtranslator[cls.FIELDNAME])
        if col in hdict_row:
            new_row.append(hdict_row[col])
    if id_col:
        h = cls._compute_id(id_col, obj, new_row)
        new_row = (h,) + tuple(new_row)
    elif parent_key:
        h = None
        parent_col_name = translator.get(cls.PARENT_COL_NAME, cls.
            PARENT_KEY_COL_NAME)
        new_row = (hdict_row[parent_col_name],) + tuple(new_row)
    else:
        h = None
        new_row = tuple(new_row)
    results.append((table, new_row))
    return results, h


@classmethod
def forget(cls, db):
    """Forget cache for database."""
    cls._cache.pop(db, None)


def write_headers_titlecase(headers, write):
    """Monkey-patch h11 header handling.

    See https://github.com/python-hyper/h11/issues/31 for the details. Essentially SkyQ box is
    not RFC compliant as regards case-insensitive headers, so this patch forces the headers to
    comply with SkyQ's braindead implementation.
    """
    for name, value in headers:
        if name == b'host':
            write(b'%s: %s\r\n' % (name.title(), value))
    for name, value in headers:
        if name == b'upgrade':
            write(b'%s: %s\r\n' % (name.title(), value.lower()))
        elif name != b'host':
            write(b'%s: %s\r\n' % (name.title(), value))
    write(b'\r\n')


def parse_ref_settings(s, l, t):
    """
    [delete: cascade]
    """
    result = {}
    if 'update' in t:
        result['on_update'] = t['update'][0]
    if 'delete' in t:
        result['on_delete'] = t['delete'][0]
    if 'comment' in t:
        result['comment'] = t['comment'][0]
    return result