def make_custom_region_dict(seed_dict):
    """
    constructs a dictionary of location - item pairs for useful regions which
    are not already defined in the logs
    """
    s = seed_dict
    custom_regions = {'Kakariko': {'Kakariko Tavern': s['Light World'][
        'Kakariko Tavern'], 'Chicken House': s['Light World'][
        'Chicken House'], 'Kakariko Well - Top': s['Light World'][
        'Kakariko Well - Top'], 'Kakariko Well - Left': s['Light World'][
        'Kakariko Well - Left'], 'Kakariko Well - Middle': s['Light World']
        ['Kakariko Well - Middle'], 'Kakariko Well - Right': s[
        'Light World']['Kakariko Well - Right'], 'Kakariko Well - Bottom':
        s['Light World']['Kakariko Well - Bottom'], "Blind's Hideout - Top":
        s['Light World']["Blind's Hideout - Top"], "Blind's Hideout - Left":
        s['Light World']["Blind's Hideout - Left"],
        "Blind's Hideout - Right": s['Light World'][
        "Blind's Hideout - Right"], "Blind's Hideout - Far Left": s[
        'Light World']["Blind's Hideout - Far Left"],
        "Blind's Hideout - Far Right": s['Light World'][
        "Blind's Hideout - Far Right"], 'Bottle Merchant': s['Light World']
        ['Bottle Merchant']}, 'South Shore': {'Floodgate Chest': s[
        'Light World']['Floodgate Chest'], 'Sunken Treasure': s[
        'Light World']['Sunken Treasure'], 'Mini Moldorm Cave - Far Left':
        s['Light World']['Mini Moldorm Cave - Far Left'],
        'Mini Moldorm Cave - Left': s['Light World'][
        'Mini Moldorm Cave - Left'], 'Mini Moldorm Cave - Right': s[
        'Light World']['Mini Moldorm Cave - Right'],
        'Mini Moldorm Cave - Far Right': s['Light World'][
        'Mini Moldorm Cave - Far Right'], 'Mini Moldorm Cave - NPC': s[
        'Light World']['Mini Moldorm Cave - NPC'], 'Ice Rod Cave': s[
        'Light World']['Ice Rod Cave']}, 'Zora Area': {
        'Waterfall Fairy - Left': s['Light World']['Waterfall Fairy - Left'
        ], 'Waterfall Fairy - Right': s['Light World'][
        'Waterfall Fairy - Right'], 'King Zora': s['Light World'][
        'King Zora'], "Zora's Ledge": s['Light World']["Zora's Ledge"]},
        'Saha Hut': {"Sahasrahla's Hut - Left": s['Light World'][
        "Sahasrahla's Hut - Left"], "Sahasrahla's Hut - Middle": s[
        'Light World']["Sahasrahla's Hut - Middle"],
        "Sahasrahla's Hut - Right": s['Light World'][
        "Sahasrahla's Hut - Right"]}, 'Village Of Outcasts': {
        'C-Shaped House': s['Dark World']['C-Shaped House'], 'Chest Game':
        s['Dark World']['Chest Game'], 'Brewery': s['Dark World']['Brewery'
        ]}, 'TT First Four': {"Thieves' Town - Big Key Chest": s[
        'Thieves Town']["Thieves' Town - Big Key Chest"],
        "Thieves' Town - Ambush Chest": s['Thieves Town'][
        "Thieves' Town - Ambush Chest"], "Thieves' Town - Map Chest": s[
        'Thieves Town']["Thieves' Town - Map Chest"],
        "Thieves' Town - Compass Chest": s['Thieves Town'][
        "Thieves' Town - Compass Chest"]}, 'Hookshot Cave': {
        'Hookshot Cave - Bottom Right': s['Dark World'][
        'Hookshot Cave - Bottom Right'], 'Hookshot Cave - Bottom Left': s[
        'Dark World']['Hookshot Cave - Bottom Left'],
        'Hookshot Cave - Top Right': s['Dark World'][
        'Hookshot Cave - Top Right'], 'Hookshot Cave - Top Left': s[
        'Dark World']['Hookshot Cave - Top Left']}, 'Superbunny Cave': {
        'Superbunny Cave - Top': s['Dark World']['Superbunny Cave - Top'],
        'Superbunny Cave - Bottom': s['Dark World'][
        'Superbunny Cave - Bottom']}, 'North Dark World': {'Bumper Cave': s
        ['Dark World']['Bumper Cave'], 'Graveyard Ledge': s['Light World'][
        'Graveyard Ledge']}, 'Smith Sequence': {'Blacksmith': s[
        'Dark World']['Blacksmith'], 'Purple Chest': s['Dark World'][
        'Purple Chest']}, 'Pyramid Fairy': {'Pyramid Fairy - Left': s[
        'Dark World']['Pyramid Fairy - Left'], 'Pyramid Fairy - Right': s[
        'Dark World']['Pyramid Fairy - Right']}, 'Waterfall Fairy': {
        'Waterfall Fairy - Left': s['Light World']['Waterfall Fairy - Left'
        ], 'Waterfall Fairy - Right': s['Light World'][
        'Waterfall Fairy - Right']}, 'Hype Cave': {'Hype Cave - Top': s[
        'Dark World']['Hype Cave - Top'], 'Hype Cave - Middle Right': s[
        'Dark World']['Hype Cave - Middle Right'],
        'Hype Cave - Middle Left': s['Dark World'][
        'Hype Cave - Middle Left'], 'Hype Cave - Bottom': s['Dark World'][
        'Hype Cave - Bottom'], 'Hype Cave - NPC': s['Dark World'][
        'Hype Cave - NPC']}, 'Mire Shed': {'Mire Shed - Left': s[
        'Dark World']['Mire Shed - Left'], 'Mire Shed - Right': s[
        'Dark World']['Mire Shed - Right']}, 'TR Mimic': {
        'Turtle Rock - Chain Chomps': s['Turtle Rock'][
        'Turtle Rock - Chain Chomps'], 'Turtle Rock - Compass Chest': s[
        'Turtle Rock']['Turtle Rock - Compass Chest'],
        'Turtle Rock - Roller Room - Left': s['Turtle Rock'][
        'Turtle Rock - Roller Room - Left'],
        'Turtle Rock - Roller Room - Right': s['Turtle Rock'][
        'Turtle Rock - Roller Room - Right'], 'Turtle Rock - Big Chest': s[
        'Turtle Rock']['Turtle Rock - Big Chest'],
        'Turtle Rock - Big Key Chest': s['Turtle Rock'][
        'Turtle Rock - Big Key Chest'], 'Turtle Rock - Crystaroller Room':
        s['Turtle Rock']['Turtle Rock - Crystaroller Room'],
        'Turtle Rock - Eye Bridge - Bottom Left': s['Turtle Rock'][
        'Turtle Rock - Eye Bridge - Bottom Left'],
        'Turtle Rock - Eye Bridge - Bottom Right': s['Turtle Rock'][
        'Turtle Rock - Eye Bridge - Bottom Right'],
        'Turtle Rock - Eye Bridge - Top Left': s['Turtle Rock'][
        'Turtle Rock - Eye Bridge - Top Left'],
        'Turtle Rock - Eye Bridge - Top Right': s['Turtle Rock'][
        'Turtle Rock - Eye Bridge - Top Right'], 'Turtle Rock - Boss': s[
        'Turtle Rock']['Turtle Rock - Boss'], 'Mimic Cave': s[
        'Death Mountain']['Mimic Cave']}, 'Sphere One Standard': {
        'Lost Woods Hideout': s['Light World']['Lost Woods Hideout'],
        'Mushroom': s['Light World']['Mushroom'], 'Sanctuary': s[
        'Hyrule Castle']['Sanctuary'], 'Sewers - Secret Room - Left': s[
        'Hyrule Castle']['Sewers - Secret Room - Left'],
        'Sewers - Secret Room - Middle': s['Hyrule Castle'][
        'Sewers - Secret Room - Middle'], 'Sewers - Secret Room - Right': s
        ['Hyrule Castle']['Sewers - Secret Room - Right'],
        'Sewers - Dark Cross': s['Hyrule Castle']['Sewers - Dark Cross'],
        'Hyrule Castle - Boomerang Chest': s['Hyrule Castle'][
        'Hyrule Castle - Boomerang Chest'], 'Hyrule Castle - Map Chest': s[
        'Hyrule Castle']['Hyrule Castle - Map Chest'],
        "Hyrule Castle - Zelda's Cell": s['Hyrule Castle'][
        "Hyrule Castle - Zelda's Cell"], "Link's Uncle": s['Hyrule Castle']
        ["Link's Uncle"], 'Secret Passage': s['Hyrule Castle'][
        'Secret Passage'], 'Kakariko Tavern': s['Light World'][
        'Kakariko Tavern'], 'Chicken House': s['Light World'][
        'Chicken House'], 'Kakariko Well - Top': s['Light World'][
        'Kakariko Well - Top'], 'Kakariko Well - Left': s['Light World'][
        'Kakariko Well - Left'], 'Kakariko Well - Middle': s['Light World']
        ['Kakariko Well - Middle'], 'Kakariko Well - Right': s[
        'Light World']['Kakariko Well - Right'], 'Kakariko Well - Bottom':
        s['Light World']['Kakariko Well - Bottom'], "Blind's Hideout - Top":
        s['Light World']["Blind's Hideout - Top"], "Blind's Hideout - Left":
        s['Light World']["Blind's Hideout - Left"],
        "Blind's Hideout - Right": s['Light World'][
        "Blind's Hideout - Right"], "Blind's Hideout - Far Left": s[
        'Light World']["Blind's Hideout - Far Left"],
        "Blind's Hideout - Far Right": s['Light World'][
        "Blind's Hideout - Far Right"], 'Bottle Merchant': s['Light World']
        ['Bottle Merchant'], 'Floodgate Chest': s['Light World'][
        'Floodgate Chest'], 'Sunken Treasure': s['Light World'][
        'Sunken Treasure'], 'Mini Moldorm Cave - Far Left': s['Light World'
        ]['Mini Moldorm Cave - Far Left'], 'Mini Moldorm Cave - Left': s[
        'Light World']['Mini Moldorm Cave - Left'],
        'Mini Moldorm Cave - Right': s['Light World'][
        'Mini Moldorm Cave - Right'], 'Mini Moldorm Cave - Far Right': s[
        'Light World']['Mini Moldorm Cave - Far Right'],
        'Mini Moldorm Cave - NPC': s['Light World'][
        'Mini Moldorm Cave - NPC'], 'Ice Rod Cave': s['Light World'][
        'Ice Rod Cave'], "Sahasrahla's Hut - Left": s['Light World'][
        "Sahasrahla's Hut - Left"], "Sahasrahla's Hut - Middle": s[
        'Light World']["Sahasrahla's Hut - Middle"],
        "Sahasrahla's Hut - Right": s['Light World'][
        "Sahasrahla's Hut - Right"], 'Eastern Palace - Compass Chest': s[
        'Eastern Palace']['Eastern Palace - Compass Chest'],
        'Eastern Palace - Cannonball Chest': s['Eastern Palace'][
        'Eastern Palace - Cannonball Chest'], 'Eastern Palace - Map Chest':
        s['Eastern Palace']['Eastern Palace - Map Chest'], "Aginah's Cave":
        s['Light World']["Aginah's Cave"]}}
    return custom_regions


def _multiple_choice_validate(s: str, len_options: int):
    """Validates the option chosen is valid.

    Args:
        s: Value to validate.
        len_options: Number of possible options for the user.

    Raises:
        ValueError: If the answer is not valid.
    """
    if not s:
        raise ValueError('Please enter a value between {} and {}'.format(1,
            len_options + 1))
    if not str.isnumeric(s):
        raise ValueError('Please enter a numeric value')
    if 1 <= int(s) <= len_options + 1:
        return
    else:
        raise ValueError('Please enter a value between {} and {}'.format(1,
            len_options + 1))


@staticmethod
def density(r, sigma0, r_core):
    """
        rho(r) =  2/pi * Sigma_crit R_c**3 * (R_c**2 + r**2)**(-2)

        :param r: radius (angular scale)
        :param sigma0: convergence in the core
        :param r_core: core radius
        :return: density at radius r
        """
    return 1.0 / 2 * sigma0 * r_core ** 2 * (r_core ** 2 + r ** 2) ** (-3.0 / 2
        )


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


def rebuild_proxy():
    """Rebuild all selected proxies and timecode indices using the job system

    """
    pass


@classmethod
def generate_from_events(cls, id_, events, committed=True, apply_map=None):
    """
        Return an aggregate from applying the supplied events and apply_map

        Parameters:
        apply_map -- A dict of event_type keys to handler functions
        id_ -- unique identity; required because an aggregate must have identity
               in order to have events associated
        events -- The events to apply
        committed -- If True then the events are added as if committed
        """
    apply_map = apply_map or cls.get_apply_map()
    aggregate = cls.generate(id_)
    return aggregate.apply_events(events, committed=committed, apply_map=
        apply_map)


@staticmethod
def _tune_heartbeat_timeout(client_value, server_value):
    """ Determine heartbeat timeout per AMQP 0-9-1 rules

        Per https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf,

        > Both peers negotiate the limits to the lowest agreed value as follows:
        > - The server MUST tell the client what limits it proposes.
        > - The client responds and **MAY reduce those limits** for its
            connection

        If the client specifies a value, it always takes precedence.

        :param client_value: None to accept server_value; otherwise, an integral
            number in seconds; 0 (zero) to disable heartbeat.
        :param server_value: integral value of the heartbeat timeout proposed by
            broker; 0 (zero) to disable heartbeat.

        :returns: the value of the heartbeat timeout to use and return to broker
        :rtype: int
        """
    if client_value is None:
        timeout = server_value
    else:
        timeout = client_value
    return timeout


def floatable(value):
    """Check if a value can be converted to a float"""
    try:
        float(value)
        return True
    except ValueError:
        return False


def partition_payload(data, key, thresh):
    """
    Yield partitions of a payload

    e.g. with a threshold of 2:

    { "dataElements": [1, 2, 3] }
    -->
    { "dataElements": [1, 2] }
       and
    { "dataElements": [3] }

    :param data: the payload
    :param key: the key of the dict to partition
    :param thresh: the maximum value of a chunk
    :return: a generator where __next__ is a partition of the payload
    """
    data = data[key]
    for i in range(0, len(data), thresh):
        yield {key: data[i:i + thresh]}


@classmethod
def order_and_label(cls, t):
    """Order and label of a discrete type.

        Cf. :meth:`Profile.order_and_label`.

        Examples
        --------
            >>> ProfileNoisyDiscrete.order_and_label(('abc', 0.5, 0.01))
            ('abc', '$r(abc, u_b = 0.5 ± 0.01)$')
            >>> ProfileNoisyDiscrete.order_and_label(('abc', 0.5))
            ('abc', '$r(abc, u_b \\\\simeq 0.5)$')
            >>> ProfileNoisyDiscrete.order_and_label('a~b>c')
            ('a~b>c', '$r(a\\\\sim b>c)$')
        """
    if isinstance(t, tuple):
        if len(t) == 3:
            return t[0], '$r(%s, u_%s = %s ± %s)$' % (t[0], t[0][1], t[1], t[2]
                )
        else:
            return t[0], '$r(%s, u_%s \\simeq %s)$' % (t[0], t[0][1], t[1])
    else:
        return cls.order_and_label_weak(t)


def _div(lhs=None, rhs=None, out=None, name=None, **kwargs):
    """Divides arguments element-wise.

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

    Parameters
    ----------
    lhs : NDArray
        first input
    rhs : NDArray
        second input

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

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.
    """
    return 0,


def rgb_to_ansi(r, g, b):
    """
    Convert an rgb color to ansi color
    """
    r, g, b = int(r), int(g), int(b)
    if r == g & g == b:
        if r < 8:
            return int(16)
        if r > 248:
            return int(230)
        return int(round((r - 8) / 247 * 24) + 232)
    to_ansi_range = lambda a: int(round(a / 51.0))
    r_in_range = to_ansi_range(r)
    g_in_range = to_ansi_range(g)
    b_in_range = to_ansi_range(b)
    ansi = 16 + 36 * r_in_range + 6 * g_in_range + b_in_range
    return int(ansi)


def delete_job_queue(jobQueue=None):
    """
    Deletes the specified job queue. You must first disable submissions for a queue with the  UpdateJobQueue operation and terminate any jobs that have not completed with the  TerminateJob .
    It is not necessary to disassociate compute environments from a queue before submitting a DeleteJobQueue request.
    See also: AWS API Documentation

    Examples
    This example deletes the GPGPU job queue.
    Expected Output:

    :example: response = client.delete_job_queue(
        jobQueue='string'
    )

    :type jobQueue: string
    :param jobQueue: [REQUIRED]
            The short name or full Amazon Resource Name (ARN) of the queue to delete.

    :rtype: dict
    :return: {}

    """
    pass


def write_to_bed(peak_df, output_fname):
    """
    Write a peak dataframe to BED-6 format
    """
    peak_df.iloc[:, :6].to_csv(output_fname, sep='\t', index=None, header=None)


def p_case_statement(t):
    """case_statement : CASE value COLON"""
    t[0] = [t[2]]


def _pack_image(pixels):
    """Do create 2d list of pixels and return the list."""
    packed_pixels = []
    pixel_length = pixels[0]
    for i in range(0, len(pixels[1]), pixel_length):
        packed_pixels.append(tuple(pixels[1][i:i + pixel_length]))
    return packed_pixels


def get_stroke_freq(Ax, Az, fs_a, nperseg, peak_thresh, stroke_ratio=None):
    """Determine stroke frequency to use as a cutoff for filtering

    Args
    ----
    Ax: numpy.ndarray, shape (n,)
        x-axis accelermeter data (longitudinal)
    Ay: numpy.ndarray, shape (n,)
        x-axis accelermeter data (lateral)
    Az: numpy.ndarray, shape (n,)
        z-axis accelermeter data (dorso-ventral)
    fs_a: float
        sampling frequency (i.e. number of samples per second)
    nperseg: int
        length of each segment (i.e. number of samples per frq. band in PSD
        calculation. Default to 512 (scipy.signal.welch() default is 256)
    peak_thresh: float
        PSD power level threshold. Only peaks over this threshold are returned.

    Returns
    -------
    cutoff_frq: float
        cutoff frequency of signal (Hz) to be used for low/high-pass filtering
    stroke_frq: float
        frequency of dominant wavelength in signal
    stroke_ratio: float

    Notes
    -----
    During all descents and ascents phases where mainly steady swimming occurs.
    When calculated for the whole dive it may be difficult to differentiate the
    peak at which stroking rate occurs as there are movements than
    only steady swimming

    Here the power spectra is calculated of the longitudinal and dorso-ventral
    accelerometer signals during descents and ascents to determine the dominant
    stroke frequency for each animal in each phase

    This numpy samples per f segment 512 and a sampling rate of fs_a.

    Output: S is the amount of power in each particular frequency (f)
    """
    import numpy
    from . import dsp
    from . import utils
    from .plots import plotdsp
    stroke_axes = [(0, 'x', 'dorsa-ventral', Ax), (2, 'z', 'lateral', Az)]
    cutoff_frqs = list()
    stroke_frqs = list()
    stroke_ratios = list()
    for i, i_alph, name, data in stroke_axes:
        frqs, S, _, _ = dsp.calc_PSD_welch(data, fs_a, nperseg)
        delta = S.max() / 1000
        max_ind, min_ind = dsp.simple_peakfinder(range(len(S)), S, delta)
        max0 = max_ind[0]
        try:
            min_ind[0]
        except Exception:
            stroke_ratio = 0.4
        stroke_frq = frqs[max0]
        title = 'PSD - {} axis (n={}), {}'.format(i_alph, i, name)
        plotdsp.plot_welch_peaks(frqs, S, max_ind, title=title)
        cutoff_frq = utils.recursive_input('cutoff frequency', float)
        cutoff_frqs.append(cutoff_frq)
        stroke_frqs.append(stroke_frq)
        stroke_ratios.append(stroke_ratio)
    cutoff_frq = float(numpy.mean(cutoff_frqs))
    stroke_frq = float(numpy.mean(stroke_frqs))
    try:
        stroke_ratio = float(numpy.mean(stroke_ratios))
    except Exception:
        stroke_ratio = None
    return cutoff_frq, stroke_frq, stroke_ratio


def _parse_timezone_element(timezone_element):
    """returns a dict representation of a timezone etree element (either
    defaultTimeZone or daylightSavingsTimeZone)
    """
    return {'abbreviation': timezone_element.attrib.get('zoneAbbreviation'),
        'offset': timezone_element.attrib.get('zoneOffset')}


@classmethod
def _from_et(cls, root, parent):
    """
        Create a :class:`Grid` from a :code:`grid` element.

        :param root: The element tree tree to parse.
        :param parent: :class:`EagleFilePart` that should hold the resulting :class:`EagleFilePart`
        :rtype: :class:`Grid`
        """
    n = cls()
    n._init_from_et(root, parent)
    return n


def scale_plot_size(factor=1.5):
    """Scale plot size in jupyter notebook."""
    import matplotlib as mpl
    default_dpi = mpl.rcParamsDefault['figure.dpi']
    mpl.rcParams['figure.dpi'] = default_dpi * factor


def get_fields_from_model(model_class):
    """Returns all fields, including inherited fields but ignoring M2M fields."""
    return model_class._meta.fields


def calc_R25(R, temp):
    """
    Adjust measured BPB absorption ratio for temperature.

    Eq 16 of Nand & Ellwood (2018, doi:10.1002/lom3.10253)

    Form:
    R25 = R * (1 + A * (25 - temp))

    A = 6.774e-3 +/- 0.9e-5

    Parameters
    ----------
    R : array_like
        Measured Base/Acid absorption ratio.
    temp : array_like
        Temperature of measurement (C)

    Returns
    -------
    array_like : Temperature corrected absorption
    """
    A = 0.006774
    return R * (1 + A * (25 - temp))


def is_valid():
    """`True` if the container still knows this session."""


def downgrade():
    """Downgrade database."""


def dropname(ss, li):
    """drop names from a list of strings,
    names to drop are in space delimeted list
    does not change original list
    """
    newli = li[:]
    for item in ss.split():
        newli.remove(item)
    return newli


def link(address):
    """Link this user to the given IAddress.

        Raises AddressAlreadyLinkedError if this IAddress is already linked to
        another user.
        """


@classmethod
def sc_params(cls, options=None):
    """List all smart class parameters."""
    cls.command_sub = 'sc-params'
    return cls.execute(cls._construct_command(options), output_format='json')


@classmethod
def subscription_attach(cls, options=None):
    """Attach a subscription to host

        Usage::

            hammer host subscription attach [OPTIONS]

        Options::

            --host HOST_NAME                  Name to search by
            --host-id HOST_ID                 Host ID
            --quantity Quantity               Quantity of this subscriptions to
                                              add. Defaults to 1
            --subscription-id SUBSCRIPTION_ID ID of subscription
        """
    cls.command_sub = 'subscription attach'
    return cls.execute(cls._construct_command(options))


def profit(N, X, p, q, s):
    """
    Calcule le profit.

    @param      N       nombre de poulets vendus
    @param      X       nombre de poulets achetés
    @param      p       prix d'achat
    @param      q       prix de vente
    @param      s       prix soldé
    @return             profit
    """
    if X <= N:
        return X * (q - p)
    else:
        return X * (s - p) + N * (q - s)


def url(request):
    """ Returns the url to be used for the notification
        """


def get_testdata_path(tag_model):
    """Get path to sample data directory for given tag model"""
    import os
    tag_model = tag_model.upper().replace('-', '').replace('_', '')
    sample_path = os.path.join('../datasets/{}'.format(tag_model))
    if not os.path.isdir(sample_path):
        raise FileNotFoundError('No sample dataset found for tag {}.'.
            format(tag_model))
    return sample_path


def get_pil_version():
    """Get the PIL/Pillow version, or None if it is unavailable.
    """
    try:
        __import__('PIL', fromlist=[str('Image')])
        return 0,
    except ImportError:
        return None


def truncate(string, limit=1000):
    """
    Truncate the string to the limit number of
    characters
    """
    if len(string) > limit:
        return string[:limit - 20] + '...' + string[-17:]
    else:
        return string


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


def bool2int(val):
    """
    Funkcja zamienia wartość boolową 0 lub 1

    true -> 1
    false -> 0
    """
    return 1 if val else 0


def getHost():
    """
        Similar to getPeer, but returns an address describing this side of the
        connection.

        @return: An L{IAddress} provider.
        """


def text_content(context):
    """XPath Extension function to return a node text content."""
    return context.context_node.xpath('string()').strip()


def _evaluate_gear_box_torque_in(min_engine_on_speed, gear_box_torque,
    gear_box_speed_in, gear_box_speed_out, gear_box_efficiency_parameters):
    """
    Calculates torque required according to the temperature profile [N*m].
    """
    tgb, es, ws = gear_box_torque, gear_box_speed_in, gear_box_speed_out
    par = gear_box_efficiency_parameters
    if tgb < 0 < es and ws > 0:
        return (par['gbp01'] * tgb - par['gbp10'] * ws - par['gbp00']
            ) * ws / es
    elif es > min_engine_on_speed and ws > min_engine_on_speed:
        return (tgb - par['gbp10'] * es - par['gbp00']) / par['gbp01']
    return 0


def dict_keys(data, return_string=False):
    """Get sorted keys from dictionary given.

    If ``return_string`` argument is set to True, returns keys joined by
    commas.

    :param dict data:
    :param bool return_string:
    """
    keys = list(data.keys())
    keys.sort()
    if return_string:
        return ','.join(keys)
    return keys


def add_descriptive_metadata(schema, mapper):
    """Add "title" and "description" metadata to `schema` if found on
    `mapper`.
    """
    for keyword in ('title', 'description'):
        if keyword not in schema:
            value = getattr(mapper, keyword, None)
            if value is not None:
                schema[keyword] = value
    return schema


def print_decorate(msg, expr):
    """
    Helper function to make a print decoration around lambda expression. It will print `msg`, and then return
    the result of `expr`. If it typically used in expressions like
    `lambda x: print_decorate("Processing {}".format(x), do_smth_with(x))`
    :param msg: Message to print
    :param expr: Expression to compute
    :return: expr
    """
    print(msg)
    return expr


def hasVersion(id, state):
    """Return true if a version exists with the specific workflow state.
        """


def best_path2(paths):
    """Compute the optimal path from the nxm warping paths matrix."""
    m = paths
    path = []
    r, c = m.shape
    r -= 1
    c -= 1
    v = m[r, c]
    path.append((r - 1, c - 1))
    while r > 1 or c > 1:
        r_c, c_c = r, c
        if r >= 1 and c >= 1 and m[r - 1, c - 1] <= v:
            r_c, c_c, v = r - 1, c - 1, m[r - 1, c - 1]
        if r >= 1 and m[r - 1, c] <= v:
            r_c, c_c, v = r - 1, c, m[r - 1, c]
        if c >= 1 and m[r, c - 1] <= v:
            r_c, c_c, v = r, c - 1, m[r, c - 1]
        path.append((r_c - 1, c_c - 1))
        r, c = r_c, c_c
    path.reverse()
    return path


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

        :param str val:
        :rtype: DeleteSecondaryEmailResult
        """
    return cls('cannot_remove_primary', val)


def _upgrade_state_dict(state):
    """Helper for upgrading old model checkpoints."""
    from fairseq import models, registry, tasks
    if 'optimizer_history' not in state:
        state['optimizer_history'] = [{'criterion_name':
            'CrossEntropyCriterion', 'best_loss': state['best_loss']}]
        state['last_optimizer_state'] = state['optimizer']
        del state['optimizer']
        del state['best_loss']
    if 'epoch' in state and 'extra_state' not in state:
        state['extra_state'] = {'epoch': state['epoch'], 'batch_offset':
            state['batch_offset'], 'val_loss': state['val_loss']}
        del state['epoch']
        del state['batch_offset']
        del state['val_loss']
    if 'optimizer' in state['optimizer_history'][-1]:
        state['last_optimizer_state'] = state['optimizer_history'][-1][
            'optimizer']
        for optim_hist in state['optimizer_history']:
            del optim_hist['optimizer']
    if 'optimizer_name' not in state['optimizer_history'][-1]:
        state['optimizer_history'][-1]['optimizer_name'] = 'FairseqNAG'
    if 'lr_scheduler_state' not in state['optimizer_history'][-1]:
        state['optimizer_history'][-1]['lr_scheduler_state'] = {'best':
            state['optimizer_history'][-1]['best_loss']}
        del state['optimizer_history'][-1]['best_loss']
    if 'num_updates' not in state['optimizer_history'][-1]:
        state['optimizer_history'][-1]['num_updates'] = 0
    if hasattr(state['args'], 'max_positions') and not hasattr(state['args'
        ], 'max_source_positions'):
        state['args'].max_source_positions = state['args'].max_positions
        state['args'].max_target_positions = state['args'].max_positions
    if 'train_iterator' not in state['extra_state']:
        state['extra_state']['train_iterator'] = {'epoch': state[
            'extra_state']['epoch'], 'iterations_in_epoch': state[
            'extra_state'].get('batch_offset', 0)}
    if not hasattr(state['args'], 'task'):
        state['args'].task = 'translation'
    registry.set_defaults(state['args'], tasks.TASK_REGISTRY[state['args'].
        task])
    registry.set_defaults(state['args'], models.ARCH_MODEL_REGISTRY[state[
        'args'].arch])
    for registry_name, REGISTRY in registry.REGISTRIES.items():
        choice = getattr(state['args'], registry_name, None)
        if choice is not None:
            cls = REGISTRY['registry'][choice]
            registry.set_defaults(state['args'], cls)
    return state


def isOverlap(interval1, interval2):
    """
    Is there any overlap of the two specified intervals?

    :param interval1:
    :param interval2:

    :return: True if the intervals overlap in any way.
    """
    if max(interval1.value) >= min(interval2.value) and max(interval1.value
        ) <= max(interval2.value):
        return True
    elif min(interval1.value) <= max(interval2.value) and min(interval1.value
        ) >= min(interval2.value):
        return True
    elif min(interval2.value) <= max(interval1.value) and min(interval2.value
        ) >= min(interval1.value):
        return True
    return False


def parse_hosts(hosts):
    """
  Parse the -h/--host argument.

  All things that accept -h handle it in the same way. The rules:

  * --host is repeatable:

      -h host1 -h host2 -h host3

  * --host can be a list of comma-delimited hosts:

      -h host1,host2,host3 -h host4,host5

  * --hosts can be given a name, which will be printed in the logs in lieu
    of long hostnames, which helps reduce the column count

      -h host1=zaybxcwd-01.mycompany.com,host2=zaybxcwd-02.mycompany.com

  * --hosts can be a filename containing a list of hosts with each line
    formatted as described above.

    The '#' character may be used in the file for comments, and blank lines
    are ignored.

      -h @myhosts.txt
  """
    res = []
    for host in hosts:
        if host[0] == '@':
            path = host[1:]
            with open(path) as pathf:
                for line in pathf:
                    line = line.strip()
                    if not line or line[0] == '#':
                        continue
                    res.append(line)
        elif ',' in host:
            res.extend(host.rstrip(',').split(','))
        else:
            res.append(host)
    hosts = res
    res = []
    for host in hosts:
        if '=' in host:
            name, host = host.split('=', 1)
            res.append(name.strip(), host.strip())
        else:
            res.append((host, host))
    return res


def write_anki_table(conn, table_name, new_records, do_commit=True):
    """

    :param sqlite3.Connection conn:
    :param 'notes'|'cards' table_name:
    :param iter of OrderedDict new_records:
    :param bool do_commit:
    :return:
    """
    for new_record in new_records:
        conn.execute('INSERT INTO {} ({}) VALUES ({})'.format(table_name,
            ','.join(new_record.keys()), ','.join(['?' for _ in range(len(
            new_record))])), tuple(new_record.values()))
    if do_commit:
        conn.commit()


def resolve_attribute(name, bases, default=None):
    """Find the first definition of an attribute according to MRO order."""
    for base in bases:
        if hasattr(base, name):
            return getattr(base, name)
    return default


def multi_string(val):
    """Put a string together with delimiter if has more than one value"""
    if isinstance(val, (list, tuple)):
        return '\\'.join(val)
    else:
        return val


@staticmethod
def clip(tensor, a_min=None, a_max=None):
    """Clip the values of a tensor to within an interval.

        Given an interval, values outside the interval are clipped to the interval
        edges.  For example, if an interval of ``[0, 1]`` is specified, values
        smaller than 0 become 0, and values larger than 1 become 1.

        Not more than one of `a_min` and `a_max` may be `None`.

        Parameters
        ----------
        tensor : tl.tensor
            The tensor.
        a_min : scalar, optional
            Minimum value. If `None`, clipping is not performed on lower bound.
        a_max : scalar, optional
            Maximum value. If `None`, clipping is not performed on upper bound.

        Returns
        -------
        tensor
        """
    raise NotImplementedError


def mod_switch(x, q, rq):
    """ Modulus switching (rounding to a different discretization of the Torus)
    :param x: value to round (integer)
    :param q: input modulus (integer)
    :param rq: output modulus (integer)
    """
    return int(round(1.0 * rq * x / q) % rq)


def splitdataset(dataset, axis, value):
    """
    该函数用来根据 data[axis] = value 划分数据集
    """
    ret = []
    for i in dataset:
        if i[axis] == value:
            p = i[:axis]
            p.extend(i[axis + 1:])
            ret.append(p)
    return ret


@staticmethod
def _parse_numbers(value):
    """If string value can be represented as number, method will return it as int or float, else untouched."""
    try:
        conv_float = float(value)
        if conv_float - int(conv_float) == 0:
            value = int(conv_float)
        else:
            value = conv_float
    except ValueError:
        return value
    return value


def permission_settings(permission=None):
    """Return user-role permission settings.

        If 'permission' is passed to the method then only the settings for
        'permission' is returned.
        """


def multi_str_replace(s, tup_list):
    """
    performs mutltiple consecutive replacements on one string

    tup_list: list of 2-tuples [(old1, new1), (old2, new2), ...]

    returns result string
    """
    for a, b in tup_list:
        s = s.replace(a, b)
    return s


def _as_Ks(Ks=None, k=None, nu=1e-06, g=9.81):
    """
    Return the saturated hydraulic conductivity, computed from the instrinsic
    permeability if necessary.

    Parameters
    ----------
    Ks : float, optional
        :math:`K_S`, the saturated hydraulic conductivity. Must be positive. If
        neither `Ks` nor `k` are given, the saturated hydraulic conductivity is
        assumed to be 1.
    k : float, optional
        Intrinsic permeability of the porous medium. Can be given in place of
        `Ks`, which results in the saturated hydraulic conductivity being
        computed using :math:`K_S = kg/\\nu`. Must be positive.
    nu : float, optional
        :math:`\\nu`, the kinematic viscosity of the wetting fluid. Only used if
        `k` is passed instead of `Ks`. Must be positive. Defaults to 1e-6,
        approximately the kinematic viscosity of water at 20°C in SI units.
    g : float, optional
        Magnitude of the gravitational acceleration. Only used if `k` is passed
        instead of `Ks`. Must be positive. Defaults to 9.81, the gravity of
        Earth in SI units.

    Returns
    -------
    Ks : float
        :math:`K_S`, the saturated hydraulic conductivity
    """
    if Ks is not None:
        if k is not None:
            raise TypeError('cannot pass both Ks and k')
        if Ks <= 0:
            raise ValueError('Ks must be positive')
        return Ks
    elif k is not None:
        if k <= 0:
            raise ValueError('k must be positive')
        if nu <= 0:
            raise ValueError('nu must be positive')
        if g <= 0:
            raise ValueError('g must be positive')
        return g * k / nu
    else:
        return 1


def get_event_selectors(TrailName=None):
    """
    Describes the settings for the event selectors that you configured for your trail. The information returned for your event selectors includes the following:
    For more information, see Logging Data and Management Events for Trails in the AWS CloudTrail User Guide .
    See also: AWS API Documentation

    :example: response = client.get_event_selectors(
        TrailName='string'
    )

    :type TrailName: string
    :param TrailName: [REQUIRED]
            Specifies the name of the trail or trail ARN. If you specify a trail name, the string must meet the following requirements:
            Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)
            Start with a letter or number, and end with a letter or number
            Be between 3 and 128 characters
            Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are invalid.
            Not be in IP address format (for example, 192.168.5.4)
            If you specify a trail ARN, it must be in the format:
            arn:aws:cloudtrail:us-east-1:123456789012:trail/MyTrail

    :rtype: dict
    :return: {
        'TrailARN': 'string',
        'EventSelectors': [
            {
                'ReadWriteType': 'ReadOnly'|'WriteOnly'|'All',
                'IncludeManagementEvents': True|False,
                'DataResources': [
                    {
                        'Type': 'string',
                        'Values': [
                            'string',
                        ]
                    },
                ]
            },
        ]
    }

    :returns:
    Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)
    Start with a letter or number, and end with a letter or number
    Be between 3 and 128 characters
    Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are invalid.
    Not be in IP address format (for example, 192.168.5.4)

    """
    pass


def _recolumn(tmy3_dataframe):
    """
    Rename the columns of the TMY3 DataFrame.

    Parameters
    ----------
    tmy3_dataframe : DataFrame
    inplace : bool
        passed to DataFrame.rename()

    Returns
    -------
    Recolumned DataFrame.
    """
    raw_columns = (
        'ETR (W/m^2),ETRN (W/m^2),GHI (W/m^2),GHI source,GHI uncert (%),DNI (W/m^2),DNI source,DNI uncert (%),DHI (W/m^2),DHI source,DHI uncert (%),GH illum (lx),GH illum source,Global illum uncert (%),DN illum (lx),DN illum source,DN illum uncert (%),DH illum (lx),DH illum source,DH illum uncert (%),Zenith lum (cd/m^2),Zenith lum source,Zenith lum uncert (%),TotCld (tenths),TotCld source,TotCld uncert (code),OpqCld (tenths),OpqCld source,OpqCld uncert (code),Dry-bulb (C),Dry-bulb source,Dry-bulb uncert (code),Dew-point (C),Dew-point source,Dew-point uncert (code),RHum (%),RHum source,RHum uncert (code),Pressure (mbar),Pressure source,Pressure uncert (code),Wdir (degrees),Wdir source,Wdir uncert (code),Wspd (m/s),Wspd source,Wspd uncert (code),Hvis (m),Hvis source,Hvis uncert (code),CeilHgt (m),CeilHgt source,CeilHgt uncert (code),Pwat (cm),Pwat source,Pwat uncert (code),AOD (unitless),AOD source,AOD uncert (code),Alb (unitless),Alb source,Alb uncert (code),Lprecip depth (mm),Lprecip quantity (hr),Lprecip source,Lprecip uncert (code),PresWth (METAR code),PresWth source,PresWth uncert (code)'
        )
    new_columns = ['ETR', 'ETRN', 'GHI', 'GHISource', 'GHIUncertainty',
        'DNI', 'DNISource', 'DNIUncertainty', 'DHI', 'DHISource',
        'DHIUncertainty', 'GHillum', 'GHillumSource', 'GHillumUncertainty',
        'DNillum', 'DNillumSource', 'DNillumUncertainty', 'DHillum',
        'DHillumSource', 'DHillumUncertainty', 'Zenithlum',
        'ZenithlumSource', 'ZenithlumUncertainty', 'TotCld', 'TotCldSource',
        'TotCldUncertainty', 'OpqCld', 'OpqCldSource', 'OpqCldUncertainty',
        'DryBulb', 'DryBulbSource', 'DryBulbUncertainty', 'DewPoint',
        'DewPointSource', 'DewPointUncertainty', 'RHum', 'RHumSource',
        'RHumUncertainty', 'Pressure', 'PressureSource',
        'PressureUncertainty', 'Wdir', 'WdirSource', 'WdirUncertainty',
        'Wspd', 'WspdSource', 'WspdUncertainty', 'Hvis', 'HvisSource',
        'HvisUncertainty', 'CeilHgt', 'CeilHgtSource', 'CeilHgtUncertainty',
        'Pwat', 'PwatSource', 'PwatUncertainty', 'AOD', 'AODSource',
        'AODUncertainty', 'Alb', 'AlbSource', 'AlbUncertainty',
        'Lprecipdepth', 'Lprecipquantity', 'LprecipSource',
        'LprecipUncertainty', 'PresWth', 'PresWthSource', 'PresWthUncertainty']
    mapping = dict(zip(raw_columns.split(','), new_columns))
    return tmy3_dataframe.rename(columns=mapping)


def normalize_prefix(path):
    """Add trailing slash to prefix if it is not present

    >>> normalize_prefix("somepath")
    'somepath/'
    >>> normalize_prefix("somepath/")
    'somepath/'
    """
    if path is None or path is '' or path is '/':
        return None
    elif path.endswith('/'):
        return path
    else:
        return path + '/'


def file_asset(class_obj: type) ->type:
    """
    Decorator to annotate the FileAsset class. Registers the decorated class
    as the FileAsset known type.
    """
    assert isinstance(class_obj, type), 'class_obj is not a Class'
    global _file_asset_resource_type
    _file_asset_resource_type = class_obj
    return class_obj


def create_notify_payload(host, nt, usn, location=None, al=None, max_age=None):
    """
    Create a NOTIFY packet using the given parameters.
    Returns a bytes object containing a valid NOTIFY request.

    The NOTIFY request is different between IETF SSDP and UPnP SSDP.
    In IETF, the 'location' and 'al' fields serve the same purpose, and can be
    provided together (if so, they should point to the same location) or not at
    all.
    In UPnP, the 'location' field MUST be provided, and 'al' is ignored.
    Sending both 'location' and 'al' is the more widely supported option. It
    does not, however, mean that all SSDP implementations would accept a packet
    with both. Therefore the option to send just one of these fields (or none at
    all) is supported.
    If in doubt, send both. If your notifications go ignored, opt to not send 'al'.

    Parameters
    ----------
    host : str
        The address (IP + port) that the NOTIFY will be sent about.
        This is usually a multicast address.
    nt : str
        Notification type. Indicates which device is sending the notification.
    usn : str
        Unique identifier for the service. Usually this will be composed of a
        UUID or any other universal identifier.
    location : str
        A URL for more information about the service. This parameter is only valid
        when sending a UPnP SSDP packet.
    al : str
        Similar to 'location', but only supported on IETF SSDP, not UPnP.
    max_age : int
        Amount of time in seconds that the NOTIFY packet should be cached by
        clients receiving it. In UPnP, this header is required.
    """
    if max_age is not None and not isinstance(max_age, int):
        raise ValueError('max_age must by of type: int')
    data = (
        'NOTIFY * HTTP/1.1\r\nHOST:{}\r\nNT:{}\r\nNTS:ssdp:alive\r\nUSN:{}\r\n'
        .format(host, nt, usn))
    if location is not None:
        data += 'LOCATION:{}\r\n'.format(location)
    if al is not None:
        data += 'AL:{}\r\n'.format(al)
    if max_age is not None:
        data += 'Cache-Control:max-age={}\r\n'.format(max_age)
    return data.encode('utf-8')


def opposite_condition(dim, i, j):
    """
    encode the equality `x_i = -x_j`

    EXAMPLES::

        sage: from flatsurf.geometry.l_infinity_delaunay_cells import \\
        ....:     opposite_condition, sign_and_norm_conditions

        sage: eq1 = opposite_condition(2, 0, 1)
        sage: eq2 = opposite_condition(2, 1, 0)

        sage: ieqs1 = sign_and_norm_conditions(2, 0, 1)
        sage: ieqs2 = sign_and_norm_conditions(2, 1, -1)

        sage: sorted(Polyhedron(eqns=[eq1], ieqs=ieqs1).vertices_list())
        [[0, 0], [1, -1]]
        sage: sorted(Polyhedron(eqns=[eq1,eq2], ieqs=ieqs1).vertices_list())
        [[0, 0], [1, -1]]
        sage: sorted(Polyhedron(eqns=[eq1,eq2], ieqs=ieqs1+ieqs2).vertices_list())
        [[0, 0], [1, -1]]
    """
    l = [0] * (dim + 1)
    l[i + 1] = 1
    l[j + 1] = 1
    return l


@staticmethod
def remover(fn):
    """Tag the method as the collection remover.

        The remover method is called with one positional argument: the value
        to remove. The method will be automatically decorated with
        :meth:`removes_return` if not already decorated::

            @collection.remover
            def zap(self, entity): ...

            # or, equivalently
            @collection.remover
            @collection.removes_return()
            def zap(self, ): ...

        If the value to remove is not present in the collection, you may
        raise an exception or return None to ignore the error.

        If the remove method is internally instrumented, you must also
        receive the keyword argument '_sa_initiator' and ensure its
        promulgation to collection events.

        """
    fn._sa_instrument_role = 'remover'
    return fn


def _andlist(ss, sep=', ', seplast=', and ', septwo=' and '):
    """Comma-separate a list of strings according to English rules.

    Enforces the Oxford comma.
    """
    if len(ss) <= 1:
        return ''.join(ss)
    if len(ss) == 2:
        return septwo.join(ss)
    return sep.join(ss[:-1]) + seplast + ss[-1]


@classmethod
def get_graph_property(cls, graph, property_name):
    """ Get a graph property value
        :param graph: The graph
        :param property_name: The name of the property
        :return: The value of the graph porperty
        """
    return graph.graph[property_name]


def chip_id_simple(g, position):
    """
    Generates an easy-to-read chip id based on the position (excluding 0, 1, and 255)
    Chip ids increase by increments of 1 at each node position in y and 10 at each
    node position in x (works for max of 8x8 grid)

    """
    return (position[0] * 10 + position[1]) % 253 + 2


def persecond_to_sccm(Q):
    """Convert particle per second to sccm."""
    return Q / 4.477962e+17


def change_log_root_dir(root_dir, update_log_dir=False, add_timestamp=True):
    """Change the directory for the output log files.

    > *Input arguments*

    * `root_dir` (*type:* `str`): New output log directory.
    * `update_log_dir` (*type:* `bool`, *default:* `False`):
    Update current global path for log directory.
    * `add_timestamp` (*type:* `bool`, *default:* `True`): Add timestamp
    to the directory folder name.
    """
    global PCG_LOG_DIR_ROOT
    PCG_LOG_DIR_ROOT = root_dir
    if update_log_dir:
        update_log_dir(add_timestamp)


def dfs_edges_upstream_attributes_iter(G, source=None, attribute=None):
    """
    Produce edge attributes in a depth-first-search (DFS) traversing
    upstream and terminating each search leg when finding an edge having a
    non-null attribute.

    Based on Networkx dfs source
    """
    if source is None:
        nodes = G
    else:
        nodes = [source]
    visited = set()
    for start in nodes:
        if start in visited:
            continue
        visited.add(start)
        stack = [(iter(G.pred[start]), start)]
        while stack:
            parents, child = stack[-1]
            try:
                parent = next(parents)
                edge = G[parent][child]
                if edge[attribute] is not None:
                    yield parent, child, edge
                else:
                    stack.append((iter(G.pred[parent]), parent))
                if parent not in visited:
                    visited.add(parent)
            except StopIteration:
                stack.pop()


def error_message(context, msg):
    """
  Cannot remember, maybe I was starting to setup a logging facility?
  :param context: The runner's instance
  :param msg:
  :return:
  """
    return msg


@classmethod
def check_suffix(cls, *suffixes):
    """
        Check file type compatibility

        Check if the I/O class is compatible with any of the
        given suffixes (i.e. file formats/extensions).
        """
    for suffix in suffixes:
        if suffix in cls.SUFFIXES:
            return True
    return False


def sibseq(node):
    """
        | Get the sequence-number of siblings(share the same parent)

        :param  lxml.etree._Element node:
            lxml-etree-element
        :return int:
            the sequence-number of siblings

        ::

            html_str = ""\"

b0

b1

b2

b3

l0

l1

l2

l3

            ""\"

            root = LXHTML(html_str)
            ele = engine.xpath(root,"//body/div-out-1/div",2)
            ele.text
            # 'b2'
            engine.sibseq(ele)
            # 2

    """
    p = node.getparent()
    if p == None:
        return 0
    else:
        childs = p.getchildren()
        total = childs.__len__()
        for i in range(0, total):
            if node == childs[i]:
                curr_seq = i
                return curr_seq
            else:
                pass


def refr_idx_300ppm_co2(lbda_mu=0.3):
    """Get refractive index of air using eq. of Peck and Reeder, 1972

    Uses either of two parametrisations for wavelengths above or below 0.23
    microns using parametrisations from `Peck and Reeder, 1972, Dispersion of
    air <https://www.osapublishing.org/josa/abstract.cfm?uri=josa-62-8-958>`_.

    Parameters
    ----------
    lbda_mu : float or ndarray
        wavelength in microns

    Returns
    -------
    float
        refractive index
    """
    if lbda_mu >= 0.23:
        return 1 + (5791817 / (238.0185 - (1 / lbda_mu) ** 2) + 167909 / (
            57.362 - (1 / lbda_mu) ** 2)) * 10 ** -8
    else:
        return 1 + (8060.51 + 2480990 / (132.274 - (1 / lbda_mu) ** 2) +
            17455.7 / (39.32957 - (1 / lbda_mu) ** 2)) * 10 ** -8


def annotate(s, xy, ax=None):
    """
    function for plot annotation
    """
    binx = xy[0]
    biny = xy[1]
    ax.text(binx, biny, s, bbox=dict(facecolor='white', alpha=1.0),
        horizontalalignment='center', verticalalignment='center', transform
        =ax.transAxes)


def problem_to_filename(problem_name: str) ->str:
    """Converts a problem name to a filename"""
    return problem_name.lower().replace(' ', '-')


def _print_items(report, key, writer):
    """print out issues or fixes
    report: report dictionary
    key: 'issues' | 'fixes'
    writer: function
    """
    try:
        items = report[key]
    except KeyError:
        return
    items_found = len(items)
    if items_found == 0:
        writer(f'No {key} found!')
        writer('---')
        return
    writer(f'{items_found} {key} found:')
    has_oids = True
    if type(items) == list:
        for item in items:
            if type(item) == int:
                writer(f'    ObjectID {item}')
            else:
                has_oids = False
                writer(f'    {item}')
    else:
        for oid in items:
            writer(f'    ObjectID {oid}: {items[oid]}')
    if has_oids:
        writer(f'\nSelect statement to view {key} in ArcGIS:')
        statement = f"OBJECTID IN ({', '.join([str(oid) for oid in items])})"
        writer(statement)
    writer('---')


def open_file_browser(path):
    """Opens a file browser at the specified path."""
    import subprocess
    subprocess.Popen(['xdg-open', path])


def output_precision(prec=None):
    """Get or set the output precision.

    Package default is 4.  Do nothing is prec is None.

    Returns: default precision.

    >>> default_format("%.*f")
    '%.*f'
    >>> print mg(2, 'm2').sqrt()
    1.4142 m
    >>> output_precision(6)
    6
    >>> print mg(2, 'm2').sqrt()
    1.414214 m
    >>> output_precision(4)
    4
    """
    global _prn_prec
    if prec is not None:
        _prn_prec = prec
    return _prn_prec


def _humanize_size(nbytes):
    """Transform given number of bytes to human readable unit."""
    suffix = None
    for suffix in ['B', 'KB', 'MB', 'GB']:
        if nbytes < 1024:
            break
        nbytes /= 1024
    humanized = '{:.2f}'.format(nbytes).rstrip('0').rstrip('.')
    return '{} {}'.format(humanized, suffix)


def get_invalid_model_def_path_message() ->str:
    """
    get_invalid_model_def_path_message is used by get_all_file_entries to generate an appropriate
    error message to display when a user tries to create an experiment using a model definition
    contained in a directory whose name conflicts with the Determined package name
    (i.e. "determined").

    The function is also used in test_cli.py::test_create_reject_bad_path.
    """
    return (
        'A model definition cannot be contained in a directory named "determined"'
        )


def ignore_global_phase(statevec):
    """Multiple e^-iθ to `statevec` where θ is a phase of first non-zero element.

    Args:
        statevec np.array: Statevector.

    Returns:
        np.array: `statevec` is returned.
    """
    for q in statevec:
        if abs(q) > 1e-07:
            ang = abs(q) / q
            statevec *= ang
            break
    return statevec


def retry_argument_spec(spec=None):
    """Creates an argument spec for working with retrying"""
    arg_spec = dict(retries=dict(type='int'), retry_pause=dict(type='float',
        default=1))
    if spec:
        arg_spec.update(spec)
    return arg_spec


def is_string_like(obj):
    """Check if obj is string."""
    try:
        obj + ''
    except (TypeError, ValueError):
        return False
    return True


def analyze_portfolio(file):
    """ analyze portfolio (TBD) """
    pass


def do_float(value, default=0.0):
    """Convert the value into a floating point number. If the
    conversion doesn't work it will return ``0.0``. You can
    override this default using the first parameter.
    """
    try:
        return float(value)
    except (TypeError, ValueError):
        return default


@classmethod
def create(cls, mapping):
    """
        Create a mapping object
        @param cls:
        @type cls:
        @param mapping: mapping object or properties dict
        @type mapping: pylastica.doc_type.Mapping or dict
        @return:
        @rtype: pylastica.doc_type.Mapping
        """
    if isinstance(mapping, dict):
        mapping_object = cls()
        mapping_object.set_properties(mapping)
    else:
        mapping_object = mapping
    assert isinstance(mapping_object, cls), 'Invalid object type'
    return mapping_object


def set_level(request, level):
    """
    Sets the minimum level of messages to be recorded, returning ``True`` if
    the level was recorded successfully.

    If set to ``None``, the default level will be used (see the ``get_level``
    method).
    """
    if not hasattr(request, '_messages'):
        return False
    request._messages.level = level
    return True


def build_content_type(format, encoding='utf-8'):
    """
    Appends character encoding to the provided format if not already present.
    """
    if 'charset' in format:
        return format
    if format in ('application/json', 'text/javascript'):
        return format
    return '%s; charset=%s' % (format, encoding)


def gen_concatenate(iterators):
    """
Chain a sequence of iterators together into a single sequence.
"""
    for it in iterators:
        yield from it


def is_variable(term):
    """Test whether a Term represents a variable.

    :param term: term to check
    :return: True if the expression is a variable
    """
    return term is None or type(term) == int or term.is_var()


def zero_diag(Q):
    """
    Copy of Q altered such that diagonal entries are all 0.
    """
    Q_nodiag = Q.copy()
    for ii in range(Q.shape[0]):
        Q_nodiag[ii, ii] = 0
    return Q_nodiag


def check_num_rows_of_parameter_array(param_array, correct_num_rows, title):
    """
    Ensures that `param_array.shape[0]` has the correct magnitude. Raises a
    helpful ValueError if otherwise.

    Parameters
    ----------
    param_array : ndarray.
    correct_num_rows : int.
        The int that `param_array.shape[0]` should equal.
    title : str.
        The 'name' of the param_array whose shape is being checked.

    Results
    -------
    None.
    """
    if param_array.shape[0] != correct_num_rows:
        msg = '{}.shape[0] should equal {}, but it does not'
        raise ValueError(msg.format(title, correct_num_rows))
    return None


def _parse_integrator(int_method):
    """parse the integrator method to pass to C"""
    if int_method.lower() == 'rk4_c':
        int_method_c = 1
    elif int_method.lower() == 'rk6_c':
        int_method_c = 2
    elif int_method.lower() == 'symplec4_c':
        int_method_c = 3
    elif int_method.lower() == 'symplec6_c':
        int_method_c = 4
    elif int_method.lower() == 'dopr54_c':
        int_method_c = 5
    elif int_method.lower() == 'dop853_c':
        int_method_c = 6
    else:
        int_method_c = 0
    return int_method_c


def acceleration_fma(force, mass):
    """Usage: acceleration_fma(force of object, mass of object)"""
    return force / mass


def paths_calculate(start_frame: int=1, end_frame: int=250):
    """Calculate motion paths for the selected objects

    :param start_frame: Start, First frame to calculate object paths on
    :type start_frame: int
    :param end_frame: End, Last frame to calculate object paths on
    :type end_frame: int
    """
    pass


def centroid(im, gyx, method='weighted'):
    """Method to centroid on a target used different methods

    Parameters
    ----------
    im : array, mandatory
        image
    gyx : tuple, mandatory
        initial guess coordinates (y, x)
    method : str, optional, default: `weighted`, choices: [`weighted`,
        `peak`, `comet`]
        method to use for finding centroid

    Returns
    -------
    tuple, (y,x) image coordinates

    Examples
    --------
    >>> from astropy.io import fits
    >>> from sbpy.imageanalysis import centroid # doctest: +SKIP
    >>> hdu = fits.open('test.fits') # doctest: +SKIP
    >>> cyx = centroid(hdu[0].data, (21, 45)) # doctest: +SKIP

    not yet implemented

    """


def _convert(convert_func, geonames, keys):
    """Convert values in a list of geonames.

    :param convert_func: Function to run on key values.
    :param geonames: Parsed list of geonames returned from the API.
    :param keys: List of keys that should be converted, if they exist
                 in a geoname.
    :returns: The same list of geonames, with values converted.
    """
    for geoname in geonames:
        for key in keys:
            if key in geoname:
                geoname[key] = convert_func(geoname[key])
    return geonames


def update_hints(obj, data):
    """Update the hints on the root-node of a workflow. Usually, schedule
    hints are fixed per function. Sometimes a user may want to set hints
    manually on a specific promised object. :func:`update_hints` uses the
    `update` method on the hints dictionary with `data` as its argument.

    :param obj: a :py:class:`PromisedObject`.
    :param data: a :py:class:`dict` containing additional hints.

    The hints are modified, in place, on the node. All workflows that contain
    the node are affected."""
    root = obj._workflow.root
    obj._workflow.nodes[root].hints.update(data)


@staticmethod
def is_time_prefix(s):
    """ Given a string, determine if it is in the format of a prefix """
    days = 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'
    return s[:3] in days


def walsh_percent_effect_remaining(minutes, action_duration):
    """ Give percent of insulin remaining for IOB calculations.
        This curve is only included for the purposes of running glucose
        activity tests

        Arguments:
        minutes -- minutes after insulin delivery
        dia -- duration of insulin action, in hours
    """
    if minutes <= 0:
        return 1
    if minutes >= action_duration * 60:
        return 0
    dia = round(action_duration)
    if dia < 3:
        dia = 3
    elif dia > 6:
        dia = 6
    minutes = minutes * dia / action_duration
    if dia == 3:
        return -3.203e-09 * pow(minutes, 4) + 1.354e-06 * pow(minutes, 3
            ) - 0.0001759 * pow(minutes, 2) + 0.0009255 * minutes + 0.99951
    if dia == 4:
        return -3.31e-10 * pow(minutes, 4) + 2.53e-07 * pow(minutes, 3
            ) - 5.51e-05 * pow(minutes, 2) - 0.0009086 * minutes + 0.9995
    if dia == 5:
        return -2.95e-10 * pow(minutes, 4) + 2.32e-07 * pow(minutes, 3
            ) - 5.55e-05 * pow(minutes, 2) + 0.000449 * minutes + 0.993
    if dia == 6:
        return -1.493e-10 * pow(minutes, 4) + 1.413e-07 * pow(minutes, 3
            ) - 4.095e-05 * pow(minutes, 2) + 0.0006365 * minutes + 0.997
    raise RuntimeError


def reformat_version(version):
    """Hack to reformat old versions ending on '-alpha' to match pip format."""
    if version.endswith('-alpha'):
        return version.replace('-alpha', 'a0')
    return version.replace('-alpha', 'a')


def delete_message(message_id):
    """Remove the given message from the store.

        If the referenced message is missing from the message store, the
        operation is ignored.

        :param message: The Message-ID of the message to delete from the store.
        """


def progress_message(gen_all):
    """Decide progress bar message based on gen_all flag"""
    if gen_all:
        return 'Generating Transforms'
    else:
        return 'Stabilizing'


@classmethod
def get_available_releases(cls, public=None):
    """ Get the available releases

        Parameters:
            public (bool):
                If True, only return public data releases
        """
    cfgs = cls.list_available_configs()
    releases = []
    for i in cfgs:
        if public and not i.startswith('dr'):
            continue
        b = i.split('.cfg', 1)[0]
        if 'dr' in b or 'mpl' in b:
            releases.append(b.upper())
        elif 'work' in b and 'WORK' not in releases:
            releases.append('WORK')
    return releases


@staticmethod
def from_param(this):
    """(INTERNAL) ctypes parameter conversion method.
        """
    if this is None:
        return None
    return this._as_parameter_


@classmethod
def from_connections(cls, connections):
    """
        Alternate constructor accepting `.Connection` objects.

        .. versionadded:: 2.0
        """
    group = cls()
    group.extend(connections)
    return group


def bin2str(b):
    """
    Binary to string.
    """
    ret = []
    for pos in range(0, len(b), 8):
        ret.append(chr(int(b[pos:pos + 8], 2)))
    return ''.join(ret)


def _f_lcs(llcs, m, n):
    """
    Computes the LCS-based F-measure score
    Source: http://research.microsoft.com/en-us/um/people/cyl/download/papers/
    rouge-working-note-v1.3.1.pdf

    :param llcs: Length of LCS
    :param m: number of words in reference summary
    :param n: number of words in candidate summary
    :returns float: LCS-based F-measure score
    """
    r_lcs = llcs / m
    p_lcs = llcs / n
    beta = p_lcs / r_lcs
    num = (1 + beta ** 2) * r_lcs * p_lcs
    denom = r_lcs + beta ** 2 * p_lcs
    return num / denom


def delete():
    """DELETE /items/{id}"""


def _donothing_func(*args, **kwargs):
    """Perform no good and no bad"""
    pass


@staticmethod
def is_distinct(sol_list, sol):
    """
        Check if x is distinct from each solution in seta.

        :param seta: a list
        :param x: a Solution object
        :return: True or False
        """
    for ins in sol_list:
        if sol.is_equal(ins):
            return False
    return True


def package_root(varmap):
    """Return correct directory for the root package.

    The "root" package is the one where modules which do not
    belong to a package are located (see the distutils docs).
    This function should not need to be called directly in
    your actual setup script, but it can be useful for testing.
    Note that it looks for a ``package_root`` setup var, which
    can be used as a shortcut if your "root" package is not in
    the standard place (which is your setup script directory),
    rather than having to declare a ``package_dir`` dictionary
    with a ``''`` key.
    """
    try:
        return varmap['package_dir']['']
    except KeyError:
        try:
            result = varmap['package_root']
        except KeyError:
            return '.'
        else:
            dirmap = varmap.setdefault('package_dir', {})
            if '' not in dirmap:
                dirmap[''] = result
            return result


@staticmethod
def _fill_data(data, ntd, time_key):
    """Fill this time unit with git log information for all files."""
    chkin = ntd.commithash
    for status, filename in ntd.files:
        data[time_key][filename][chkin] = status


def create_projects(project_details_df, conn_target):
    """
    Create projects on the target server, based on project details from a source server.
    :param DataFrame project_details_df: the project details DataFrame
    :param class conn_target: the target server connection
    :return: list of HTTP responses
    """
    responses = []
    for index, project in project_details_df.iterrows():
        response = conn_target.create_project(project_name=project[
            'source_project_name'], project_description=project[
            'source_project_description'], content_permissions=project[
            'contentPermissions'], parent_project_id=None)
        responses.append(response)
    return responses


def mapped_to_chromosome(chrom):
    """
    Returns true if mapped to, eg, chr1 or X;
    false if mapped to other contig, eg GL*, MT*, hs*, M*
    """
    if chrom[0:2] in ['GL', 'MT', 'hs', 'NC'] or chrom[0:1] == 'M':
        return False
    return True


def gpencil_material_preset_add(name: str='', remove_name: bool=False,
    remove_active: bool=False):
    """Add or remove grease pencil material preset

    :param name: Name, Name of the preset, used to make the path name
    :type name: str
    :param remove_name: remove_name
    :type remove_name: bool
    :param remove_active: remove_active
    :type remove_active: bool
    """
    pass


@staticmethod
def _content_length(line):
    """Extract the content length from an input line."""
    if line.startswith(b'Content-Length: '):
        _, value = line.split(b'Content-Length: ')
        value = value.strip()
        try:
            return int(value)
        except ValueError:
            raise ValueError('Invalid Content-Length header: {}'.format(value))
    return None


def provider_parser(subparser):
    """Generate subparser for exoscale"""
    subparser.add_argument('--auth-key', help=
        'specify API key for authentication')
    subparser.add_argument('--auth-secret', help=
        'specify API secret for authentication')


def current_line(text):
    """Return a ( <cpu number>, ( <move1>, ... ) ) tuple from text.

    If the first word of text is digits it is the CPU number.  Otherwise set
    the CPU number to None.

    """
    t = text.split(maxsplit=1)
    if t[0].isdigit():
        return t[0], ' '.join(t[1:])
    else:
        return None, text


def urljoin(server_url, path):
    """Return the url concatenation of server_url and path."""
    return server_url.rstrip('/') + '/' + path.lstrip('/')


def is_middleware(target):
    """Mostly for internal use, this function returns True if *target* is
    a valid face middleware.

    Middlewares can be functions wrapped with the
    :func:`face_middleware` decorator, or instances of a user-created
    type, as long as it's a callable following face's signature
    convention and has the ``is_face_middleware`` attribute set to
    True.
    """
    if callable(target) and getattr(target, 'is_face_middleware', None):
        return True
    return False


def Song_Xu(Re, sphericity=1.0, S=1.0):
    """Calculates drag coefficient of a particle using the method in
    [1]_. Developed with data for spheres, cubes, and cylinders. Claims 3.52%
    relative error for 0.001 < Re < 100 based on 336 tests data.

    .. math::
        C_d = \\frac{24}{Re\\phi^{0.65}S^{0.3}}\\left(1 + 0.35Re\\right)^{0.44}

    Parameters
    ----------
    Re : float
        Particle Reynolds number of the sphere using the surrounding fluid
        density and viscosity, [-]
    sphericity : float, optional
        Sphericity of the particle
    S : float, optional
        Ratio of equivalent sphere area and the projected area in the particle
        settling direction [-]

    Returns
    -------
    Cd : float
        Drag coefficient of particle [-]

    Notes
    -----
    Notable as its experimental data and analysis is included in their
    supporting material.

    Examples
    --------
    >>> Song_Xu(30.)
    2.3431335190092444

    References
    ----------
    .. [1] Song, Xianzhi, Zhengming Xu, Gensheng Li, Zhaoyu Pang, and Zhaopeng
       Zhu. "A New Model for Predicting Drag Coefficient and Settling Velocity
       of Spherical and Non-Spherical Particle in Newtonian Fluid." Powder
       Technology 321 (November 2017): 242-50.
       doi:10.1016/j.powtec.2017.08.017.
    """
    return 24 / (Re * sphericity ** 0.65 * S ** 0.3) * (1 + 0.35 * Re) ** 0.44


def mkdir(name):
    """Create a directory.
        """


def check_raster_bases(sys):
    """Return a list of all raster that have no basis."""
    rasters_wo_bases = []
    for sname, system in sys.items():
        for rname, raster in system.items():
            try:
                raster.basis_column()
            except KeyError:
                if sname:
                    rasters_wo_bases.append("'{}'/'{}'".format(sname, rname))
                else:
                    rasters_wo_bases.append("'{}'".format(rname))
    return rasters_wo_bases


def slice(obj, keys=[], skip=[], full=False):
    """ return a slice of an object. """
    from madz.object import Object
    o = Object()
    if not keys:
        keys = obj.keys()
    for key in keys:
        if key in skip:
            continue
        if not full and key.startswith('_'):
            continue
        val = obj.get(key, None)
        if val and 'keys' in dir(val):
            o[key] = slice(val)
        else:
            o[key] = val
    return o


def Moody(Re, eD):
    """Calculates Darcy friction factor using the method in Moody (1947)
    as shown in [1]_ and originally in [2]_.

    .. math::
        f_f = 1.375\\times 10^{-3}\\left[1+\\left(2\\times10^4\\frac{\\epsilon}{D} +
        \\frac{10^6}{Re}\\right)^{1/3}\\right]

    Parameters
    ----------
    Re : float
        Reynolds number, [-]
    eD : float
        Relative roughness, [-]

    Returns
    -------
    fd : float
        Darcy friction factor [-]

    Notes
    -----
    Range is Re >= 4E3 and Re <= 1E8; eD >= 0 < 0.01.

    Examples
    --------
    >>> Moody(1E5, 1E-4)
    0.01809185666808665

    References
    ----------
    .. [1] Winning, H. and T. Coole. "Explicit Friction Factor Accuracy and
       Computational Efficiency for Turbulent Flow in Pipes." Flow, Turbulence
       and Combustion 90, no. 1 (January 1, 2013): 1-27.
       doi:10.1007/s10494-012-9419-7
    .. [2] Moody, L.F.: An approximate formula for pipe friction factors.
       Trans. Am. Soc. Mech. Eng. 69,1005-1006 (1947)
    """
    return 4 * (0.001375 * (1 + (20000.0 * eD + 1000000.0 / Re) ** (1 / 3.0)))


def viaCombusta(obj):
    """ Returns if an object is in the Via Combusta. """
    return 195 < obj.lon < 225


def secondYAxis(requestContext, seriesList):
    """
    Graph the series on the secondary Y axis.
    """
    for series in seriesList:
        series.options['secondYAxis'] = True
        series.name = 'secondYAxis(%s)' % series.name
    return seriesList


def tors_eps(universe, seg, i):
    """Epsilon backbone dihedral

    The dihedral is computed based on position atoms for resid `i`.

    Parameters
    ----------
    universe : Universe
         :class:`~MDAnalysis.core.universe.Universe` containing the trajectory
    seg : str
        segment id for base
    i : int
        resid of the first base

    Returns
    -------
    epsilon : float
        torsion angle in degrees

    .. versionadded:: 0.7.6
    """
    e = universe.select_atoms(" atom {0!s} {1!s} C4' ".format(seg, i),
        " atom {0!s} {1!s} C3' ".format(seg, i), " atom {0!s} {1!s} O3' ".
        format(seg, i), ' atom {0!s} {1!s} P    '.format(seg, i + 1))
    epsilon = e.dihedral.value() % 360
    return epsilon


def is_reserved_name(name):
    """Tests if name is reserved

    Names beginning with 'xml' are reserved for future standardization"""
    if name:
        return name[:3].lower() == 'xml'
    else:
        return False


def nlz(x):
    """ Get the number of leadings zeros in a 32 bit word.

    >>> nlz (0)
    32
    >>> nlz (0x1)
    31
    >>> nlz (0xFF)
    24
    >>> nlz (0xFFFFFFFF)
    0

    See: http://www.hackersdelight.org/hdcodetxt/nlz.c.txt

    See: [Warren2013]_ pages 99ff
    """
    n = 32
    for shift in (16, 8, 4, 2, 1):
        y = x >> shift
        if y != 0:
            n = n - shift
            x = y
    return n - x


def get_spacetrack_sv(tle):
    """
    Place a text file of Spacetrack GPS TLEs into a dictionary with keys of the form 'PRN xx' for the SV of interest

    :param tle: Path to two line element set file
    :return: dict
    """
    gps_sv_dict = {}
    ns = 'NAVSTAR'
    with open(tle, 'rt') as tf:
        for line in tf:
            if ns in line:
                prn = line[line.find(ns):line.find('(') - 1]
                prn = prn.replace(ns, 'PRN')
            elif line[0] == '1':
                tle_ln1 = line.strip('\n')
            elif line[0] == '2':
                tle_ln2 = line.strip('\n')
                gps_sv_dict.update({prn: (tle_ln1, tle_ln2)})
            else:
                UserWarning('File structure incorrect')
                break
    return gps_sv_dict


def operator(op):
    """
    Returns a function which performs comparision operations
    """
    if op == '==':
        return lambda x, y: x == y
    if op == '!=':
        return lambda x, y: x != y
    if op == '<=':
        return lambda x, y: x <= y
    if op == '>=':
        return lambda x, y: x >= y
    if op == '<':
        return lambda x, y: x < y
    if op == '>':
        return lambda x, y: x > y
    raise Exception('operator %s not found' % op)


def choose_words(words):
    """
        Submit the final words.

        This should be called when the user is finished typing in the code,
        and terminates the code-entry process.  It does not return anything,
        but will cause the Wormhole's ``w.get_code()`` to fire, and initiates
        the wormhole connection process.

        It accepts a string like "purple-sausages", without the leading
        nameplate (which must have been submitted to ``choose_nameplate()``
        earlier) or its hyphen.  If ``choose_nameplate()`` was not called
        first, this will raise ``MustChooseNameplateFirstError``.

        This may only be called once, otherwise ``AlreadyChoseWordsError``
        will be raised.

        :param str words: the 'words' portion of the wormhole code

        :return: None
        """


def StyleSheet():
    """ A lazy importer for the Enaml StyleSheet class.

    """
    from enaml.styling import StyleSheet
    return StyleSheet


def slim_aggregates(aggregates):
    """"slim version of the region aggregates, minimizing NoData and verbose naming"""
    slimmed_aggregates = []
    for aggregate in aggregates:
        verbose_keys = list(aggregate.keys())
        for verbose_key in verbose_keys:
            slim_key = verbose_key.split('_')[0]
            aggregate[slim_key] = aggregate.pop(verbose_key)
        datetime = aggregate['datetime']
        aggregate['Date'] = datetime.split('T')[0] + 'Z'
        aggregate.pop('datetime', None)
        slimmed_aggregates.append(aggregate)
    return slimmed_aggregates


def init_variables_from_state_dict(sess, state_dict, ignore_extra=True):
    """
    Initialize model variables from state dictionary.

    Parameters
    ----------
    sess: Session
        A Session to use to load the weights.
    state_dict : dict
        Dictionary with values of model variables.
    ignore_extra : bool, default True
        Whether to silently ignore parameters from the file that are not present in this Module.
    """
    from .models.model_store import init_variables_from_state_dict
    init_variables_from_state_dict(sess=sess, state_dict=state_dict,
        ignore_extra=ignore_extra)


@classmethod
def add(cls, wrd):
    """ Add an adjective """
    cls.ADJECTIVES.add(wrd)


def is_exon(string):
    """Does the string contains 'exon' preceded or not by spaces.

    :param string: The string to be tested.

    :Example:

    >>> from pygtftk.utils import is_exon
    >>> assert is_exon("Exon") and is_exon("exon")

    """
    if string.lower().strip() == 'exon':
        return True
    return False


def GetSCC(TaskMapping, TaskGraph):
    """
	Return list of Strongly Connected Component cliques.
	"""
    return tuple()


def ceil(data=None, name=None, attr=None, out=None, **kwargs):
    """Returns element-wise ceiling of the input.

    The ceil of the scalar x is the smallest integer i, such that i >= x.

    Example::

       ceil([-2.1, -1.9, 1.5, 1.9, 2.1]) = [-2., -1.,  2.,  2.,  3.]

    The storage type of ``ceil`` output depends upon the input storage type:

       - ceil(default) = default
       - ceil(row_sparse) = row_sparse
       - ceil(csr) = csr

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

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

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

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


def _tiAction(gr, ev):
    """Event handler for text input action"""
    try:
        if ev.unicode == '\r':
            gr.canvas.config(command=gr).bubble('onaction', ev)
    except:
        pass


@staticmethod
def standard(model, **kwargs):
    """
        Create standard model of molecular evolution.

        Parameters
        ----------

         model : str
            Model to create. See list of available models below
         **kwargs:
            Key word arguments to be passed to the model

        **Available models**

        - JC69:

          Jukes-Cantor 1969 model. This model assumes equal frequencies
          of the nucleotides and equal transition rates between nucleotide states.
          For more info, see: Jukes and Cantor (1969).
          Evolution of Protein Molecules. New York: Academic Press. pp. 21-132.
          To create this model, use:

          :code:`mygtr = GTR.standard(model='jc69', mu=<my_mu>, alphabet=<my_alph>)`

          :code:`my_mu` - substitution rate (float)

          :code:`my_alph` - alphabet (str: :code:`'nuc'` or  :code:`'nuc_nogap'`)

        - K80:

          Kimura 1980 model. Assumes equal concentrations across nucleotides, but
          allows different rates between transitions and transversions. The ratio
          of the transversion/transition rates is given by kappa parameter.
          For more info, see
          Kimura (1980),  J. Mol. Evol. 16 (2): 111-120. doi:10.1007/BF01731581.
          Current implementation of the model does not account for the gaps.

          :code:`mygtr = GTR.standard(model='k80', mu=<my_mu>, kappa=<my_kappa>)`

          :code:`mu` - overall substitution rate (float)

          :code:`kappa` - ratio of transversion/transition rates (float)

        - F81:

          Felsenstein 1981 model. Assumes non-equal concentrations across nucleotides,
          but the transition rate between all states is assumed to be equal. See
          Felsenstein (1981), J. Mol. Evol. 17  (6): 368-376. doi:10.1007/BF01734359
          for details.

          :code:`mygtr = GTR.standard(model='F81', mu=<mu>, pi=<pi>, alphabet=<alph>)`

          :code:`mu` -  substitution rate  (float)

          :code:`pi`  - : nucleotide concentrations (numpy.array)

          :code:`alphabet' -  alphabet to use. (:code:`'nuc'` or  :code:`'nuc_nogap'`)

        - HKY85:

          Hasegawa, Kishino and Yano 1985 model. Allows different concentrations of the
          nucleotides (as in F81) + distinguishes between transition/transversion substitutions
          (similar to K80). Link:
          Hasegawa, Kishino, Yano (1985), J. Mol. Evol. 22 (2): 160-174. doi:10.1007/BF02101694

          Current implementation of the model does not account for the gaps

          :code:`mygtr = GTR.standard(model='HKY85', mu=<mu>, pi=<pi>, kappa=<kappa>)`

          :code:`mu` -  substitution rate  (float)

          :code:`pi`  - : nucleotide concentrations (numpy.array)

          :code:`kappa` - ratio of transversion/transition rates (float)

        - T92:

          Tamura 1992 model. Extending Kimura  (1980) model for the case where a
          G+C-content bias exists. Link:
          Tamura K (1992),  Mol.  Biol. Evol. 9 (4): 678-687.  DOI: 10.1093/oxfordjournals.molbev.a040752

          Current implementation of the model does not account for the gaps

          :code:`mygtr = GTR.standard(model='T92', mu=<mu>, pi_GC=<pi_gc>, kappa=<kappa>)`

          :code:`mu` -  substitution rate  (float)

          :code:`pi_GC`  - : relative GC content

          :code:`kappa` - ratio of transversion/transition rates (float)

        - TN93:

          Tamura and Nei 1993. The model distinguishes between the two different types of
          transition: (A <-> G) is allowed to have a different rate to (C<->T).
          Transversions have the same rate. The frequencies of the nucleotides are allowed
          to be different. Link: Tamura, Nei (1993), MolBiol Evol. 10 (3): 512-526.
          DOI:10.1093/oxfordjournals.molbev.a040023

          :code:`mygtr = GTR.standard(model='TN93', mu=<mu>, kappa1=<k1>, kappa2=<k2>)`

          :code:`mu` -  substitution rate  (float)

          :code:`kappa1`  - relative A<-->C, A<-->T, T<-->G and G<-->C rates (float)

          :code:`kappa` - relative C<-->T rate (float)

          .. Note::
                Rate of A<-->G substitution is set to one. All other rates
                (kappa1, kappa2) are specified relative to this rate

        """
    from .nuc_models import JC69, K80, F81, HKY85, T92, TN93
    from .aa_models import JTT92
    if model.lower() in ['jc', 'jc69', 'jukes-cantor', 'jukes-cantor69',
        'jukescantor', 'jukescantor69']:
        model = JC69(**kwargs)
    elif model.lower() in ['k80', 'kimura80', 'kimura1980']:
        model = K80(**kwargs)
    elif model.lower() in ['f81', 'felsenstein81', 'felsenstein1981']:
        model = F81(**kwargs)
    elif model.lower() in ['hky', 'hky85', 'hky1985']:
        model = HKY85(**kwargs)
    elif model.lower() in ['t92', 'tamura92', 'tamura1992']:
        model = T92(**kwargs)
    elif model.lower() in ['tn93', 'tamura_nei_93', 'tamuranei93']:
        model = TN93(**kwargs)
    elif model.lower() in ['jtt', 'jtt92']:
        model = JTT92(**kwargs)
    else:
        raise KeyError(
            "The GTR model '{}' is not in the list of available models.".
            format(model))
    model.mu = kwargs['mu'] if 'mu' in kwargs else 1.0
    return model


def write(fpath, arg):
    """
    Write the string representation of
    arg to the file at fpath.
    """
    arg = str(arg)
    with open(fpath, 'w') as f:
        f.write(arg)


def create_policy(Content=None, Description=None, Name=None, Type=None):
    """
    Creates a policy of a specified type that you can attach to a root, an organizational unit (OU), or an individual AWS account.
    For more information about policies and their use, see Managing Organization Policies .
    This operation can be called only from the organization's master account.
    See also: AWS API Documentation

    :example: response = client.create_policy(
        Content='string',
        Description='string',
        Name='string',
        Type='SERVICE_CONTROL_POLICY'
    )

    :type Content: string
    :param Content: [REQUIRED]
            The policy content to add to the new policy. For example, if you create a service control policy (SCP), this string must be JSON text that specifies the permissions that admins in attached accounts can delegate to their users, groups, and roles. For more information about the SCP syntax, see Service Control Policy Syntax in the AWS Organizations User Guide .

    :type Description: string
    :param Description: [REQUIRED]
            An optional description to assign to the policy.

    :type Name: string
    :param Name: [REQUIRED]
            The friendly name to assign to the policy.
            The regex pattern that is used to validate this parameter is a string of any of the characters in the ASCII character range.

    :type Type: string
    :param Type: [REQUIRED]
            The type of policy to create.
            Note
            In the current release, the only type of policy that you can create is a service control policy (SCP).

    :rtype: dict
    :return: {
        'Policy': {
            'PolicySummary': {
                'Id': 'string',
                'Arn': 'string',
                'Name': 'string',
                'Description': 'string',
                'Type': 'SERVICE_CONTROL_POLICY',
                'AwsManaged': True|False
            },
            'Content': 'string'
        }
    }

    """
    pass


def mass_fma(force, acceleration):
    """Usage: mass_fma(force of object, acceleration of object)"""
    return force / acceleration


def _compute_delta(earlier_sample, later_sample, max_value):
    """Computes the difference between two samples of a value, considering
    that the value may have wrapped around in between"""
    if earlier_sample > later_sample:
        return later_sample - (max_value - earlier_sample)
    return later_sample - earlier_sample


def statisexec(st):
    """check whether a stat result is an executable file"""
    return False


def search_repos(g, query):
    """search for repositires"""
    return g.search_repositories(query)


def swap_bytes(bits, bytesize=8):
    """
    Bits is a b'' object containing a binary representation. Assuming each
    bytesize bits constitute a bytes, perform a endianness byte swap. Example:

        >>> swap_bytes(b'00011011', 2)
        b'11100100'
    """
    i = 0
    l = len(bits)
    output = [b''] * (l // bytesize + 1)
    j = len(output) - 1
    while i < l:
        output[j] = bits[i:i + bytesize]
        i += bytesize
        j -= 1
    return b''.join(output)


def a_remote_host_address(plugin_ctx, fsm_ctx):
    """send remote host address or name."""
    address = plugin_ctx.src_address
    fsm_ctx.ctrl.sendline(address)
    return True


def get_name(friendly=False):
    """Get name of this resource

    :return: name of this resource
    :rtype: str
    """
    if friendly:
        return 'Service dependency'
    return 'servicedependency'


def _nova_error_message(msg_type, message, status_code, request):
    """
    Set the response code on the request, and return a JSON blob representing
    a Nova error body, in the format Nova returns error messages.

    :param str msg_type: What type of error this is - something like
        "badRequest" or "itemNotFound" for Nova.
    :param str message: The message to include in the body.
    :param int status_code: The status code to set
    :param request: the request to set the status code on

    :return: dictionary representing the error body
    """
    request.setResponseCode(status_code)
    return {msg_type: {'message': message, 'code': status_code}}


def sig_handler(signum, frame):
    """ Helper function for register_cleanup that's called on signal. """
    import sys
    sys.exit(0)


def _normalize(c):
    """
    Convert a byte-like value into a canonical byte (a value of type 'bytes' of len 1)

    :param c:
    :return:
    """
    if isinstance(c, int):
        return bytes([c])
    elif isinstance(c, str):
        return bytes([ord(c)])
    else:
        return c


def index(relationship):
    """obtains the token for the relationship and indexes (calls
        IInjection.index_doc)"""


@staticmethod
def compute(mechanism, subsystem, purviews, cause_purviews, effect_purviews):
    """Compute a |Concept| for a mechanism, in this |Subsystem| with the
        provided purviews.
        """
    concept = subsystem.concept(mechanism, purviews=purviews,
        cause_purviews=cause_purviews, effect_purviews=effect_purviews)
    concept.subsystem = None
    return concept


def isCurrentHour():
    """Return true if this object represents a date/time that
        falls within the current hour, in the context of this object's
        timezone representation"""


def moveableTo(target, name=None):
    """Say whether the object can be moved to the given `target`.

        Returns ``True`` if it can be moved there. Otherwise, returns
        ``False``.
        """


def is_edge(connectivity):
    """
    Returns True if connectivity corresponds an edge (is two).

    :param connectivity: Scalar or matrix
    :return: Boolean or matrix of boolean
    """
    return connectivity == 2


def get_axis_aligned_bbox(region):
    """
    convert region to (center_x, center_y, bbox_w, bbox_h)
    that represent by axis aligned box

    Parameters
    ----------
        region: np.array (4*N)
        bbox region location

    Return:
        Center location weight and height
    """
    region_x = region[0]
    region_y = region[1]
    bbox_w = region[2]
    bbox_h = region[3]
    center_x = region_x + bbox_w / 2
    center_y = region_y + bbox_h / 2
    return center_x, center_y, bbox_w, bbox_h


def build_metric(prefix, name, wall_time_func=None):
    """
        Returns an object that implements the C{IMetric} interface for name.

        @type prefix: C{str}
        @param prefix: The prefix used for reporting this metric.
        @type name: C{str}
        @param name: The name used for reporting this metric.
        """


def df_change_type(df, origin_type, target_type):
    """
    将DataFrame中类型为origin_type的列全部转化为target_type。大数据量的情况下非常耗时，不建议使用。

    :param df: 不带NaN的DataFrame
    :param origin_type: list类型的dtype
    :param target_type: 目标dtype
    :return: DataFrame
    """
    target_columns = list()
    for column in df.columns:
        if df[column].dtype in origin_type:
            target_columns.append(column)
    if target_columns is not None:
        df[target_columns] = df[target_columns].astype(target_type)
    return df


def get_callable_name(c):
    """ Get a human-friendly name for the given callable.

    :param c: The callable to get the name for
    :type c: callable
    :rtype: unicode
    """
    if hasattr(c, 'name'):
        return str(c.name)
    elif hasattr(c, '__name__'):
        return str(c.__name__) + u'()'
    else:
        return str(c)


def srcpath(base, pth):
    """Return an absolute path based on the relative path `pth`.
       Useful in tests, where we don't know what the absolute path is,
       and we can't use relative paths since we don't know which folder
       the tests are run from.

       In a test file xxxxxxx/foo/test/test_foo.py::

          path = 'foo/test'
          fp = open(srcpath(path, 'data/testdata.txt'))

    """
    raise EnvironmentError('dk.utils.srcpath no longer does anything useful.')