def edit(text=None, editor=None, env=None, require_save=True, extension=
    '.txt', filename=None):
    """Edits the given text in the defined editor.  If an editor is given
    (should be the full path to the executable but the regular operating
    system search path is used for finding the executable) it overrides
    the detected editor.  Optionally, some environment variables can be
    used.  If the editor is closed without changes, `None` is returned.  In
    case a file is edited directly the return value is always `None` and
    `require_save` and `extension` are ignored.

    If the editor cannot be opened a :exc:`UsageError` is raised.

    Note for Windows: to simplify cross-platform usage, the newlines are
    automatically converted from POSIX to Windows and vice versa.  As such,
    the message here will have ``\\n`` as newline markers.

    :param text: the text to edit.
    :param editor: optionally the editor to use.  Defaults to automatic
                   detection.
    :param env: environment variables to forward to the editor.
    :param require_save: if this is true, then not saving in the editor
                         will make the return value become `None`.
    :param extension: the extension to tell the editor about.  This defaults
                      to `.txt` but changing this might change syntax
                      highlighting.
    :param filename: if provided it will edit this file instead of the
                     provided text contents.  It will not use a temporary
                     file as an indirection in that case.
    """
    from ._termui_impl import Editor
    editor = Editor(editor=editor, env=env, require_save=require_save,
        extension=extension)
    if filename is None:
        return editor.edit(text)
    editor.edit_file(filename)


def checkpars(lines, regex):
    """Checks that parameters are unique"""
    import re
    result = []
    for l in lines:
        match = re.match(regex, l)
        if match:
            result += [l]
    return result


def receive_group_specific_query(group_state: 'GroupState',
    max_response_time: int):
    """
    Received IGMP Group Specific Query packet regarding group GroupState
    """
    group_state.group_state_logger.debug(
        'NonQuerier NoMembersPresent: receive_group_specific_query')
    return


def cumsum(a, output_dtype=None, queue=None, wait_for=None, return_event=False
    ):
    """
    .. versionadded:: 2013.1
    """
    if output_dtype is None:
        output_dtype = a.dtype
    if wait_for is None:
        wait_for = []
    result = a._new_like_me(output_dtype)
    from pyopencl.scan import get_cumsum_kernel
    krnl = get_cumsum_kernel(a.context, a.dtype, output_dtype)
    evt = krnl(a, result, queue=queue, wait_for=wait_for + a.events)
    result.add_event(evt)
    if return_event:
        return evt, result
    else:
        return result


@classmethod
def downloadManager(cls):
    """
        Class method to get a reference to the download manager.

        @return reference to the download manager (DownloadManager)
        """
    if cls._downloadManager is None:
        from .Download.DownloadManager import DownloadManager
        cls._downloadManager = DownloadManager()
    return cls._downloadManager


def dict_to_sequence(d):
    """Returns an internal sequence dictionary update."""
    if hasattr(d, 'items'):
        d = d.items()
    return d


def stats_table_region_label_column_name():
    """
    Returns the name of the column that contains the region names for the table in stats files. The name is identical for all standard Freesurfer parcellation and segmentation stats files (aseg.stats, ?h.aparc.stats, ?h.aparc.a2009s.stats, and ?h.aparc.DKTatlas.stats), so the current version returns a fixed string.
    """
    return 'StructName'


def escape(x, lb=False):
    """
    Ensure a string does not contain HTML-reserved characters (including
    double quotes)
    Optionally also insert a linebreak if the string is too long
    """
    if lb:
        l = len(x)
        if l >= 10:
            l >>= 1
            s1 = x.find(' ', l)
            s2 = x.rfind(' ', 0, l)
            if s2 > 0:
                s = s2 if s1 < 0 or l - s1 > s2 - l else s1
                x = x[:s] + '\\n' + x[s + 1:]
            elif s1 > 0:
                x = x[:s1] + '\\n' + x[s1 + 1:]
    return x.replace('&', '&').replace('<', '<').replace('>', '>'
        ).replace('"', '"')


@classmethod
def match(cls, segments, parse_context):
    """This will never be called. If it is then we're using it wrong."""
    raise NotImplementedError(
        '{0} has no match method, it should only be used in a Sequence!'.
        format(cls.__name__))


def single_key(seq):
    """ Pick out the only element of this list, a list of keys """
    return seq[0]


def fg_validator(passed_kwargs, merged_kwargs):
    """ fg is not valid with basically every other option """
    invalid = []
    msg = """_fg is invalid with nearly every other option, see warning and workaround here:

    https://amoffat.github.io/sh/sections/special_arguments.html#fg"""
    whitelist = set(('env', 'fg', 'cwd'))
    offending = set(passed_kwargs.keys()) - whitelist
    if 'fg' in passed_kwargs and passed_kwargs['fg'] and offending:
        invalid.append(('fg', msg))
    return invalid


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

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


@classmethod
def edit_form_entry_help_text_extra(cls):
    """Edit FormEntry help_text extra.

        For adding the edit link to edit form entry view.

        :return str:
        """
    return (
        """

          {edit_option_html}

             {delete_text}

        <input type="hidden" value="{form_element_position}"
               name="form-{counter}-position"
               id="id_form-{counter}-position"
               class="form-element-position">
        <input type="hidden" value="{form_element_pk}"
               name="form-{counter}-id" id="id_form-{counter}-id">
        """
        .format(container_class=cls.form_list_container_class,
        edit_option_html='{edit_option_html}', delete_url='{delete_url}',
        delete_option_class=cls.form_delete_form_entry_option_class,
        delete_text='{delete_text}', form_element_position=
        '{form_element_position}', counter='{counter}', form_element_pk=
        '{form_element_pk}'))


def test_7z(archive, compression, cmd, verbosity, interactive):
    """Test a 7z archive."""
    cmdlist = [cmd, 't']
    if not interactive:
        cmdlist.append('-y')
    cmdlist.extend(['--', archive])
    return cmdlist


@staticmethod
def p_function_list_optional_list_optional(p):
    """function_list_optional_list_optional : empty
                                                | function_list_optional_list"""
    p[0] = tuple() if p[1] is None else p[1]


def plot_registration(anat_nii, div_id, plot_params=None, order=('z', 'x',
    'y'), cuts=None, estimate_brightness=False, label=None, contour=None,
    compress='auto', overlay=None, overlay_params=None):
    """
    Plot the foreground and background views.

    Default order is: axial, coronal, sagittal
    """
    from uuid import uuid4
    from lxml import etree
    import matplotlib.pyplot as plt
    from nilearn.plotting import plot_anat
    from svgutils.transform import SVGFigure
    from niworkflows.viz.utils import robust_set_limits, extract_svg, SVGNS
    plot_params = plot_params or {}
    if cuts is None:
        raise NotImplementedError
    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(anat_nii.get_fdata(dtype='float32')
            .reshape(-1), plot_params)
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            plot_params['title'] = label
        else:
            plot_params['title'] = None
        display = plot_anat(anat_nii, **plot_params)
        if overlay is not None:
            _overlay_params = {'vmin': overlay.get_fdata(dtype='float32').
                min(), 'vmax': overlay.get_fdata(dtype='float32').max(),
                'cmap': plt.cm.gray, 'interpolation': 'nearest'}
            _overlay_params.update(overlay_params)
            display.add_overlay(overlay, **_overlay_params)
        if contour is not None:
            display.add_contours(contour, colors='g', levels=[0.5],
                linewidths=0.5)
        svg = extract_svg(display, compress=compress)
        display.close()
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))
        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)
    return out_files


def make_date(year, month, day):
    """
    Make from three parametres year, month, day, date_string in format: "Year-Month_Day". Also, if day or month < 10, added 0 before it.
    """
    new_year = str(year)
    if day < 10:
        new_day = '0' + str(day)
    else:
        new_day = str(day)
    if month < 10:
        new_month = '0' + str(month)
    else:
        new_month = str(month)
    string = new_year + '-' + new_month + '-' + new_day
    return string


def top5(df):
    """Given dataframe, generate top 5 unique values for non-numeric data"""
    columns = df.select_dtypes(include=['object', 'category']).columns
    for col in columns:
        print('Top 5 unique values of ' + col)
        print(df[col].value_counts().reset_index().rename(columns={'index':
            col, col: 'Count'})[:min(5, len(df[col].value_counts()))])
        print(' ')


@staticmethod
def supportsWorkAddition():
    """
            Block start policy supports continuous addition of work
        """
    return True


def update(im, *args, **kw):
    """Update an immutable object.

    This is a helper method for ``IImmutable.__im_update__(*args, **kw)``.
    """
    return im.__im_update__(*args, **kw)


def vocab(table, text):
    """
    Return a new table containing only the vocabulary in the source text.

    Create a new translation table containing only the rules that are
    relevant for the given text. This is created by checking all source
    terms against a copy of the text.

    """
    text_rules = []
    text_copy = str(text)
    for rec in table:
        if rec[0] in text_copy:
            text_copy = text_copy.replace(rec[0], '\x1f')
            text_rules.append(rec)
    return text_rules


def RemoveProperty(cls, attr: str):
    """Removes a dynamically defined property.

    :param cls: The class containing the property (must be a positional argument).
    :param attr: Property name (must be passed as a keyword).
    :type attr: str
    """
    pass


@staticmethod
def is_comment_string(data_string):
    """ Checks if supplied string after stripping corresponds to comment and shall thus be ignored in data processing

        :param data_string: a string to check if it is a pure comment string
        :type data_string: ``str``
        :return: a flag indicating if supplied string is a pure comment string
        :rtype: ``Boolean``
        """
    return data_string.strip().startswith('#')


def get_proper_str(str_option, end=False, size=43):
    """
    Method to shorten a string into the proper size for display

    :param str_option: string to shorten
    :param end: keep the end of the string visible (default beginning)
    :return: shortened string
    """
    if len(str_option) > size:
        if end:
            return '...%s' % str_option[-(size - 3):]
        else:
            return '%s...' % str_option[:size - 3]
    else:
        return str_option


@staticmethod
def state_default(value):
    """Any unparsed state."""
    yield ''


def view_zoom_border(gesture_mode: int=0, xmin: int=0, xmax: int=0, ymin:
    int=0, ymax: int=0):
    """Zoom in the view to the nearest item contained in the border

    :param gesture_mode: Gesture Mode
    :type gesture_mode: int
    :param xmin: X Min
    :type xmin: int
    :param xmax: X Max
    :type xmax: int
    :param ymin: Y Min
    :type ymin: int
    :param ymax: Y Max
    :type ymax: int
    """
    pass


@classmethod
def disable(cls):
    """Disables page domain notifications.
        """
    return cls.build_send_payload('disable', {}), None


def announce(event):
    """ announce text on all channels in fleet. """
    event.announce(event._parsed.rest)


def density(values, value):
    """ Return density of value among values

    :param values:
    :param value:
    :return: density (between 0 and 1)
    """
    return values[values == value].size / values.size


def theta_B3O3OH4_Cl_FW86(T, P):
    """a-a': triborate chloride [FW86]."""
    theta = 0.12
    valid = T == 298.15
    return theta, valid


def with_metaclass(meta, base=object):
    """Create a base class with a metaclass."""
    return meta('NewBase', (base,), {})


@classmethod
def is_request(cls, payload):
    """Returns True if the payload (which has a method) is a request.
        False means it is a notification."""
    return 'id' in payload


def add_histogram_args(parser):
    """Add arguments for specifying the histogram of wire lengths (i.e.
	cabinets/frames) available for a given system."""
    histogram_group = parser.add_argument_group('wire length histogram options'
        )
    histogram_mut_group = histogram_group.add_mutually_exclusive_group()
    histogram_mut_group.add_argument('--histogram-bins', '-H', type=int,
        metavar='N', default=5, help=
        'number of bins to pack wire lengths into in the histogram of wire lengths (default: %(default)s)'
        )


@classmethod
def serialize(cls, value):
    """Return a string representing the formatted value"""
    raise NotImplementedError


@classmethod
def set_spotify(cls):
    """A factory method that creates a :class:`CacheLevel` with Spotify caching level."""
    return cls(3)


@classmethod
def converted(cls, image):
    """given an Image-compatible object,
        returns a new M4A_ILST_COVR_Data_Atom object"""
    return cls(0, 0, image.data)


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

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

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


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

    :return: name of this resource
    :rtype: str
    """
    if friendly:
        return 'Alignak notifications'
    return 'alignak_notifications'


@classmethod
def delete_parameter(cls, options=None):
    """
        Deletes parameter from record.
        """
    cls.command_sub = 'delete-parameter'
    result = cls.execute(cls._construct_command(options))
    return result


def _hamming_distance(str1: str, str2: str) ->int:
    """
    Count the # of differences between strings str1 and str2,
    padding the shorter one with whitespace
    """
    diffs = 0
    if len(str1) < len(str2):
        str1, str2 = str2, str1
    len_dist = len(str1) - len(str2)
    str2 += ' ' * len_dist
    for ch1, ch2 in zip(str1, str2):
        if ch1 != ch2:
            diffs += 1
    return diffs


def group_add():
    """Add a new bone group

    """
    pass


def write_executor_id(num):
    """Write executor_id into a local file in the executor's current working directory"""
    with open('executor_id', 'w') as f:
        f.write(str(num))


def location_3d_to_region_2d(region, rv3d, coord, default=None):
    """
    Return the *region* relative 2d location of a 3d position.

    :arg region: region of the 3D viewport, typically bpy.context.region.
    :type region: :class:`bpy.types.Region`
    :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
    :type rv3d: :class:`bpy.types.RegionView3D`
    :arg coord: 3d worldspace location.
    :type coord: 3d vector
    :arg default: Return this value if ``coord``
       is behind the origin of a perspective view.
    :return: 2d location
    :rtype: :class:`mathutils.Vector` or ``default`` argument.
    """
    from mathutils import Vector
    prj = rv3d.perspective_matrix * Vector((coord[0], coord[1], coord[2], 1.0))
    if prj.w > 0.0:
        width_half = region.width / 2.0
        height_half = region.height / 2.0
        return Vector((width_half + width_half * (prj.x / prj.w),
            height_half + height_half * (prj.y / prj.w)))
    else:
        return default


def set_solution_scale(distance: float=0.0):
    """Set object solution scale using distance between two selected tracks

    :param distance: Distance, Distance between selected tracks
    :type distance: float
    """
    pass


def find_in_array(array, item):
    """
    Finds item in array or returns None
    """
    if array.ndim > 1:
        raise TypeError('array must be 1D')
    try:
        return list(array).index(item)
    except ValueError:
        return None


def list_cab(archive, compression, cmd, verbosity, interactive):
    """List a CAB archive."""
    cmdlist = [cmd, '-l']
    if verbosity > 0:
        cmdlist.append('-v')
    cmdlist.append(archive)
    return cmdlist


@classmethod
def from_int(cls, n, size=None, byteorder='little', signed=False):
    """
        buf.from_int(n[, size[, byteorder='little'[, signed=False]]])

        Convert an integer to a byte array.
        The optional size arguemnt determines the size of the resulting array
        (By default the size is the minimum possible).
        This function is made to be behaviorally compatible with Python 3's int.to_bytes.

        >>> buf.from_int(0x1234)
        buf(hex='3412')
        >>> buf.from_int(1, 4, 'big')
        buf(hex='00000001')
        """
    if size is None:
        bl = max(n.bit_length(), 1) + bool(signed)
        size = (bl + 7) // 8
    return cls._from_int(n, size, byteorder, signed)


def vectorize(e, tolerance=0.1):
    """
    vectorizes the pdf object's bounding box
    min_width is the width under which we consider it a line
    instead of a big rectangle
    """
    tolerance = max(tolerance, e.linewidth)
    is_high = e.height > tolerance
    is_wide = e.width > tolerance
    if is_wide and not is_high:
        return e.width, 0.0
    if is_high and not is_wide:
        return 0.0, e.height


@classmethod
def awake(cls, config, display):
    """
        Proceed every db which is available and random query a table to keep connection.
        對每個資料庫，做一次亂數取表單，透過請求表單第一個物件，保持db連線狀態。

        :params config: flask config
        :type config: <class 'config.Config'>

        :params display: to display activities of every poke
        :type display: bool
        """
    now = cls._get_now()
    db_binds = cls._get_db_binds(config)
    models_path_list = getattr(config, 'MODELS_PATH_LIST', None)
    if not models_path_list:
        raise Exception(f'[ * = DBPacemaker = "MODELS_PATH_LIST" is empty!]')
    models_list = cls._get_models_list(models_path_list)
    if not models_list:
        raise Exception(f'[ * = DBPacemaker = No available models!]')
    random_tables = cls._get_random_tables(db_binds, models_list)
    if not random_tables:
        raise Exception(f'[ * = DBPacemaker = cannot source any tables!]')
    for db, table in random_tables.items():
        cls._poke(db=db, table=table, display=display)


def display_current_scene(name):
    """display function for showing the current scene"""
    print('Current scene: %s' % name)


def resolve_mutation_tracker(mutation_tracker):
    """
    From a dictionary with comma separated keys (e.g. {'a.b.c.d': 'e'}), creates a new dictionary with nested
    dictionaries, each of which containing a key taken from comma separated keys. (e.g. {'a': {'b' {'c': {'d': 'e'}}}})

    :param mutation_tracker: the dictionary with comma separated keys
    :return: a new dictionary containing nested dictionaries with old comma separated keys
    """
    body = {}
    for key in mutation_tracker:
        update_dictionary = body
        splitted = key.split('.')
        for attr in splitted:
            if attr == splitted[-1]:
                update_dictionary[attr] = mutation_tracker[key]
            else:
                if attr not in update_dictionary:
                    update_dictionary[attr] = {}
                update_dictionary = update_dictionary[attr]
    return body


def ParseBool(text):
    """Parse a boolean value.

  Args:
    text: Text to parse.

  Returns:
    Boolean values parsed

  Raises:
    ValueError: If text is not a valid boolean.
  """
    if text in ('true', 't', '1', 'True'):
        return True
    elif text in ('false', 'f', '0', 'False'):
        return False
    else:
        raise ValueError('Expected "true" or "false".')


def factorial(n):
    """
    This function calculates the factorial of a given number n.

    parameters
    ----------
    n: an integer you want to calculate the factorial af

    returns
    -------
    The factorial of the number you just provided

    examples
    --------
    >>> factorial(4)
    24
    >>> factorial(5)
    120
    >>> factorial(6)
    720
    """
    n = int(n)
    fact = 1
    while n != 0:
        fact *= n
        n -= 1
    return fact


def SQRT(number):
    """
    Calculates the square root of a positive number and returns the result as a double.
    See https://docs.mongodb.com/manual/reference/operator/aggregation/sqrt/
    for more details
    :param number: The number or field of number
    :return: Aggregation operator
    """
    return {'$sqrt': number}


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

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

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


def is_string_like(obj: object) ->bool:
    """
    Check if the object is a string.

    Parameters
    ----------
    obj : The object to check.

    Returns
    -------
    bool
        Whether `obj` is a string or not.
    """
    return isinstance(obj, str)


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


@classmethod
def from_script(cls, script):
    """Creates and address object from a Script object"""
    return cls(script=script)


@classmethod
def arraySize(cls, value, typeCode=None):
    """Given a data-value, calculate dimensions for the array"""
    dims = 1
    for base in cls.types(value):
        length = getattr(base, '_length_', None)
        if length is not None:
            dims *= length
    return dims


def p_step_5(p):
    """Step : NodeTest PredicateList"""
    p[0] = 'step', 'child', p[1], p[2]


def assert_results_contain(check_results, expected_status, expected_msgcode
    =None):
    """
  This helper function is useful when we want to make sure that
  a certain log message is emited by a check but it can be in any
  order among other log messages.
  """
    found = False
    for status, message in list(check_results):
        if status == expected_status and message.code == expected_msgcode:
            found = True
            break
    assert found


def unbind(event=None, subscriber=None):
    """Unbind subscribers.

        :param event: Event name. If not given, all events are affected.
        :param subscriber: Subscriber callable. If not given, all subscribers
            are affected.
        """


@classmethod
def decode(cls, value):
    """
        read bytes from redis and turn it back into an integer.

        :param value: bytes
        :return: int
        """
    return None if value is None else int(float(value))


def command(cmd, params=None):
    """
        Execute command on connected process

        Args:
            cmd: command to execute
            params: command params (optional, free format dict)
        """
    return None


def ER(radius, thickness):
    """
        Equivalent radius
        @param radius: core radius
        @param thickness: shell thickness
    """
    return radius + thickness


@staticmethod
def _get_recursion_available_value_from_flags(flags: int) ->bool:
    """
        Retrieve the recursion_available value from flags.

        :param flags: an integer representing the flags of a dns message
        :return: value of the recursion_available field as bool
        """
    return (flags & int.from_bytes(b'\x00\x00\x00\x80', 'big')) >> 7 == 1


def __contains__(key):
    """Is the key in the cache?"""


def get_ids(session, lastid, ids, detach=False):
    """
    Get or create lastid rows.

    Parameters
    ----------
    session : sqlalchemy.orm.session instance, bound
    lastid : sqlalchemy orm mapped lastid table
    ids : list
        Desired lastid keyname strings.
    detach : bool, optional
        If True, expunge results from session before returning.
        Useful if you don't have permission on lastid, and don't want
        session commits to throw a permission error.

    Returns
    -------
    list
        Corresponding existing or new rows from lastid table.

    Notes
    -----
    Keyvalue is 0 if id name not present in lastid table.

    """
    out = []
    for idname in ids:
        iid = session.query(lastid).filter(lastid.keyname == idname).first()
        if not iid:
            iid = lastid(keyname=idname, keyvalue=0)
        out.append(iid.keyvalue)
    if detach:
        session.expunge_all(out)
    return out


@staticmethod
def get_dns_length(bts):
    """
        return -- length of DNS name including terminating 0 (if present)
        """
    off = 0
    while off < len(bts):
        if bts[off] == 192:
            return off + 2
        elif bts[off] == 0:
            return off + 1
        off += bts[off] + 1
    return 0


def includeme(config):
    """ Pyramid includeme hook.

    :param config: app config
    :type config: :class:`pyramid.config.Configurator`
    """
    config.scan('.default_views')


def permute(a):
    """
    Creates all unique combinations of a list a that is passed in.
    Function is based off of a function written by John Lettman:
    TCHS Computer Information Systems.  My thanks to him.
    """
    a.sort()
    yield list(a)
    i = 0
    first = 0
    alen = len(a)
    while True:
        i = alen - 1
        while True:
            i -= 1
            if a[i] < a[i + 1]:
                j = alen - 1
                while not a[i] < a[j]:
                    j -= 1
                a[i], a[j] = a[j], a[i]
                t = a[i + 1:alen]
                t.reverse()
                a[i + 1:alen] = t
                yield list(a)
                break
            if i == first:
                a.reverse()
                return


def _native_type(s):
    """
    Convert value in the string to its native (i.e. either int, float or str) type.
    :param s: string
    :return: value in native type
    """
    try:
        return int(s)
    except ValueError:
        try:
            return float(s)
        except ValueError:
            return s


def lookupProtocol(protocolNames, request):
    """
        Build a protocol instance for the given protocol options and request.
        The returned protocol is plugged to the HTTP transport, and the
        returned protocol name, if specified, is used as
        I{Sec-WebSocket-Protocol} value. If the protocol provides
        L{IWebSocketsProtocol}, it will be connected directly, otherwise it
        will be wrapped by L{WebSocketsProtocolWrapper}.

        @param protocolNames: The asked protocols from the client.
        @type protocolNames: C{list} of C{str}

        @param request: The connecting client request.
        @type request: L{IRequest<twisted.web.iweb.IRequest>}

        @return: A tuple of (protocol, matched protocol name or C{None}).
        @rtype: C{tuple}
        """


def handle_stats(name, obj):
    """
    Stats object handler.
    :param name: Unused String
    :param obj: GitPython Stats
    :return: Dictionary of attributes.
    """
    return {'total_deletions': obj.total['deletions'], 'total_insertions':
        obj.total['insertions'], 'total_lines': obj.total['lines'],
        'total_files': obj.total['files'], 'changes': obj.files}


@staticmethod
def from_h5(filename):
    """
        Read the reflections table from a HDF5 file.

        :param filename: The hdf5 filename
        :return: The reflection table

        """
    from dials.util.nexus_old import NexusFile
    handle = NexusFile(filename, 'r')
    self = handle.get_reflections()
    handle.close()
    return self


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

        :param PaperDocViewDetails val:
        :rtype: EventDetails
        """
    return cls('paper_doc_view_details', val)


@classmethod
def splitCaptcha(cls, filepath, extension, captcha_name='captcha'):
    """ 分割验证码, 需要人工筛选放入将结果放入captcha_set目录 """
    binary_object, letters, extension = cls.captchaRecognize(filepath,
        extension, captcha_name=captcha_name)
    cls.cropImage(binary_object, letters, extension, cls.CAPTCHA_SET_PATH,
        captcha_name=captcha_name)
    if len(letters) < 4:
        raise ValueError('分割后的字符数小于4！')


@classmethod
def check_uri(cls, uri):
    """Check URI for validity

        Raises ValueError appropriately
        """
    if len(uri) > cls.MAX_URI_LENGTH:
        raise ValueError('URI exceeds maximum length')
    for char in uri:
        if char not in cls.ALLOWED_URI_CHARS:
            raise ValueError('URI contains invalid character %r' % bytes([
                char]))


@staticmethod
def cigar_prefix_length(cigar, reference_bases):
    """
		Given a prefix of length reference_bases relative to the reference, how
		long is the prefix of the read? In other words: If reference_bases on
		the reference are consumed, how many bases on the query does that
		correspond to?

		If the position is within or at the end of an insertion (which do not
		consume bases on the reference), then the number of bases up to the
		beginning of the insertion is reported.

		Return a pair (reference_bases, query_bases) where the value for
		reference_bases may be smaller than the requested one if the CIGAR does
		not cover enough reference bases.

		Reference skips (N operators) are treated as the end of the read. That
		is, no positions beyond a reference skip are reported.
		"""
    ref_pos = 0
    query_pos = 0
    for op, length in cigar:
        if op in (0, 7, 8):
            ref_pos += length
            query_pos += length
            if ref_pos >= reference_bases:
                return reference_bases, query_pos + reference_bases - ref_pos
        elif op == 2:
            ref_pos += length
            if ref_pos >= reference_bases:
                return reference_bases, query_pos
        elif op == 1:
            query_pos += length
        elif op == 4 or op == 5:
            pass
        elif op == 3:
            return reference_bases, query_pos
        else:
            assert False, 'unknown CIGAR operator'
    assert ref_pos < reference_bases
    return ref_pos, query_pos


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

        :param SsoChangeLoginUrlDetails val:
        :rtype: EventDetails
        """
    return cls('sso_change_login_url_details', val)


@staticmethod
def metadata_id(item):
    """Extracts the identifier from an Askbot question item."""
    return str(item['id'])


def order_case_queryset(cases, field, asc=False):
    """
    Annotate the TestCase queryset
    by calling order_by on it.
    """
    orderable_fields = ('id', 'summary', 'author__username',
        'default_tester__username', 'priority', 'is_automated',
        'category__name', 'case_status', 'create_date')
    if field in orderable_fields:
        order_by = field
        if not asc:
            order_by = '-%s' % order_by
        cases = cases.order_by(order_by)
    return cases


def _centers(edges):
    """
    This takes histogram edges and calculates the centers of each bin.

    All this does is take the average of each pair of edges.

    :param edges: List of edges of the bins of the histogram.
    :type edges: list
    :return: list of bin centers
    :rtype: list of float
    """
    centers = []
    for left_edge_idx in range(len(edges) - 1):
        centers.append((edges[left_edge_idx] + edges[left_edge_idx + 1]) / 2.0)
    return centers


def _string_to_bool(value: str) ->bool:
    """In accordance to configparser.ConfigParser.getboolean"""
    value_lower = value.lower()
    if value_lower in ['1', 'yes', 'true', 'on']:
        return True
    if value_lower in ['0', 'no', 'false', 'off']:
        return False
    raise TypeError(f'Cannot convert string "{value}" to bool.')


def get_resultset_status(matched, nextrecord):
    """ Helper function to assess status of a result set """
    status = 'subset'
    if nextrecord == 0:
        status = 'complete'
    elif matched == 0:
        status = 'none'
    return status


def _rebuild_reduction(cls, *args):
    """
    Global hook to rebuild a given class from its __reduce__ arguments.
    """
    return cls._rebuild(*args)


def decode_channel_parameters(channel):
    """Decode a channel object's parameters into human-readable format."""
    channel_types = {(1): 'device', (5): 'static', (6): 'user input', (7):
        'system'}
    io_options = {(0): 'readonly', (1): 'readwrite'}
    datatype_options = {(1): 'float', (2): 'string', (3): 'integer', (4):
        'boolean', (5): 'datetime', (6): 'timespan', (7): 'file', (8): 'latlng'
        }
    channel['channelType'] = channel_types[channel['channelType']]
    channel['io'] = io_options[channel['io']]
    channel['dataType'] = datatype_options[channel['dataType']]
    return channel


def is_authenticated(user):
    """Is a user instance authenticated?"""
    if callable(user.is_authenticated):
        return user.is_authenticated()
    else:
        return user.is_authenticated


def pull(src, target, toolkit=None):
    """
    adb pull <src> <target>

    :param src:
    :param target:
    :param toolkit:
    :return:
    """
    return toolkit.adb.run(['pull', src, target])


def IBA_calc(TPR, TNR, alpha=1):
    """
    Calculate IBA (Index of balanced accuracy).

    :param TNR: specificity or true negative rate
    :type TNR : float
    :param TPR: sensitivity, recall, hit rate, or true positive rate
    :type TPR : float
    :param alpha : alpha coefficient
    :type alpha : float
    :return: IBA as float
    """
    try:
        IBA = (1 + alpha * (TPR - TNR)) * TPR * TNR
        return IBA
    except TypeError:
        return 'None'


def discreteTruncate(number, discreteSet):
    """ Truncates the number to the closest element in the positive discrete set.
    Returns False if the number is larger than the maximum value or negative.
    """
    if number < 0:
        return False
    discreteSet.sort()
    for item in discreteSet:
        if number <= item:
            return item
    return False


def copy_all_lines_from_to(inputFile, outputFile):
    """Copy all lines from an input file object to an output file object."""
    currentLine = inputFile.readline()
    while currentLine:
        outputFile.write(currentLine)
        currentLine = inputFile.readline()


def expander(callable_, collection):
    """
    Takes a callable object and calls it repeatedly with arguments generated
    by performing expansion on elements from the iterable collection.  This is
    similar to the starmap function, although expander supports both
    positional and keyword argument expansion.

    :param callable_: The callable object which should receive arguments from
        items in the collection.

    :param collection: an iterable providing iterables of positional or keyword
        arguments.
    """
    for item in collection:
        if isinstance(item, dict):
            yield callable_(**item)
        else:
            yield callable_(*item)


def cmp_mount_order(this, other):
    """Sort comparision function for mount-point sorting

    See if ``this`` comes before ``other`` in mount-order list.  In
    words: if the other mount-point has us as it's parent, we come
    before it (are less than it). e.g. ``/var < /var/log <
    /var/log/foo``

    :param this: tuple of mount_point, node name
    :param other: tuple of mount_point, node name
    :returns int: cmp value

    """
    this, _ = this
    other, _ = other
    if this == other:
        return 0
    if other.startswith(this):
        return -1
    else:
        return 1


@classmethod
def fromObject(cls, obj, decode=None):
    """
        Construct a `Documentation` from any object with a docstring

        With `decode=True`, decode docstrings as utf-8, then run them through ftfy, and return unicode.
        This is for compatibility with Python 2, where docstrings are usually byte strings.
        """
    if obj.__doc__ is None:
        return cls(u'' if decode else '')
    r = cls.fromString(obj.__doc__, decode=decode)
    return r


@classmethod
def can_handle(cls, location):
    """
        Indicates whether or not this Extender is capable of retrieving the
        specified location.

        :param location:
            a URI indicating where to retrieve the TidyPy configuration from
        :type location: str
        :rtype: bool
        """
    raise NotImplementedError()


def _close_ssh_proc(proc, sock):
    """Carefully close stdin/stdout and reap the SSH process.

    If the pipes are already closed and/or the process has already been
    wait()ed on, that's ok, and no error is raised.  The goal is to do our best
    to clean up (whether or not a clean up was already tried).
    """
    funcs = []
    for closeable in (proc.stdin, proc.stdout, sock):
        if closeable is not None:
            funcs.append(closeable.close)
    funcs.append(proc.wait)
    for func in funcs:
        try:
            func()
        except OSError:
            continue


def to_dict(I):
    """ Write the activity indicators inside `I` to a dictionary """
    d = {'vrad': I.RV, 'svrad': I.RVerror, 'fwhm': I.FWHM, 'contrast': I.
        contrast, 'bis_span': I.BIS, 'wspan': I.Wspan, 'vspan': I.Vspan}
    try:
        d['DATE-OBS'] = I.HDU[0].header['DATE-OBS']
    except AttributeError:
        pass
    try:
        d['MJD-OBS'] = I.HDU[0].header['MJD-OBS']
    except AttributeError:
        pass
    return d


@classmethod
def batch(cls, args=(), **kwargs):
    """Create instance with default settings to run in batch mode.

		Parameters
		----------
		args : tuple
			Extra arguments to pass the ``emacs`` command.

		Returns
		-------
		.Emacs
		"""
    cmd = ['emacs', '--batch', *args]
    return cls(cmd, client=False, **kwargs)


def get_server_count(ip_config):
    """Get total server count from ip_config file
    """
    with open(ip_config) as f:
        _, _, server_count = f.readline().strip().split(' ')
        server_count = int(server_count)
    return server_count


def utcoffset():
    """Return the timezone offset in minutes east of UTC (negative west of
        UTC)."""


def get_member():
    """Get a specific member by ID.

        GET /entity/id -> 200 OK, member

        """


@classmethod
def ModifiedGammaDistribution(cls, rmin, rmax):
    """Set 6S to use a Modified Gamma distribution.

        Arguments:

        * ``rmin`` -- The minimum aerosol radius
        * ``rmax`` -- The maximum aerosol radius

        This returns an :class:`.AerosolDistribution` object. Components can then be added to this distribution using the :meth:`.add_component`
        method of the returned class.

        Example usage::

          s.aeroprofile = AeroProfile.ModifiedGammaDistribution(0.3, 0.1)
          s.aeroprofile.add_component(...)

        """
    return cls.AerosolDistribution(rmin, rmax, 9)


def tournament_selection(random, population, args):
    """Return a tournament sampling of individuals from the population.

    This function selects ``num_selected`` individuals from the population.
    It selects each one by using random sampling without replacement
    to pull ``tournament_size`` individuals and adds the best of the
    tournament as its selection. If ``tournament_size`` is greater than
    the population size, the population size is used instead as the size
    of the tournament.

    .. Arguments:
       random -- the random number generator object
       population -- the population of individuals
       args -- a dictionary of keyword arguments

    Optional keyword arguments in args:

    - *num_selected* -- the number of individuals to be selected (default 1)
    - *tournament_size* -- the tournament size (default 2)

    """
    num_selected = args.setdefault('num_selected', 1)
    tournament_size = args.setdefault('tournament_size', 2)
    if tournament_size > len(population):
        tournament_size = len(population)
    selected = []
    for _ in range(num_selected):
        tourn = random.sample(population, tournament_size)
        selected.append(max(tourn))
    return selected


def delete_s3acc(module, blade):
    """Delete Object Store Account"""
    changed = False
    count = len(blade.object_store_users.list_object_store_users(filter=
        "name='" + module.params['name'] + "/*'").items)
    if count != 0:
        module.fail_json(msg=
            'Remove all Users from Object Store Account {0} before deletion'
            .format(module.params['name']))
    else:
        try:
            blade.object_store_accounts.delete_object_store_accounts(names=
                [module.params['name']])
            changed = True
        except Exception:
            module.fail_json(msg=
                'Object Store Account {0}: Deletion failed'.format(module.
                params['name']))
    module.exit_json(changed=changed)


def activation_text(activation):
    """Return single activation text"""
    extra = '(still running)'
    if activation.finish:
        extra = 'to {a.finish} ({d} microseconds)'.format(d=activation.
            duration, a=activation)
    result = ['', 'Activation #{a.id} from {a.start} {extra}'.format(extra=
        extra, a=activation)]
    activation.show(print_=lambda x, offset=0: result.append(offset *
        ' ' + x))
    return result


@staticmethod
def get_elastic_mappings(es_major):
    """Get Elasticsearch mapping.

        geopoints type is not created in dynamic mapping

        :param es_major: major version of Elasticsearch, as string
        :returns:        dictionary with a key, 'items', with the mapping
        """
    mapping = """
        {
            "properties": {
               "merge_author_geolocation": {
                   "type": "geo_point"
               },
               "assignee_geolocation": {
                   "type": "geo_point"
               },
               "state": {
                   "type": "keyword"
               },
               "user_geolocation": {
                   "type": "geo_point"
               },
               "title_analyzed": {
                 "type": "text",
                 "index": true
               }
            }
        }
        """
    return {'items': mapping}


def default_cxx_release_flags():
    """Default C++ flags for debug=False. Note: FFC always overrides these."""
    safe_fastmath_parts = ('-fno-math-errno', '-fno-trapping-math',
        '-ffinite-math-only')
    return ('-O3',) + safe_fastmath_parts


def _makeVaryingMap(vertVaryings, fragVaryings):
    """Generates texture unit indices for all varying attributes. """
    indices = range(len(vertVaryings))
    varyingMap = dict(zip(vertVaryings, indices))
    return varyingMap


def evaluations(ty, pv):
    """
    evaluations(ty, pv) -> (ACC, MSE, SCC)

    Calculate accuracy, mean squared error and squared correlation coefficient
    using the true values (ty) and predicted values (pv).
    """
    if len(ty) != len(pv):
        raise ValueError('len(ty) must equal to len(pv)')
    total_correct = total_error = 0
    sumv = sumy = sumvv = sumyy = sumvy = 0
    for v, y in zip(pv, ty):
        if y == v:
            total_correct += 1
        total_error += (v - y) * (v - y)
        sumv += v
        sumy += y
        sumvv += v * v
        sumyy += y * y
        sumvy += v * y
    l = len(ty)
    ACC = 100.0 * total_correct / l
    MSE = total_error / l
    try:
        SCC = (l * sumvy - sumv * sumy) * (l * sumvy - sumv * sumy) / ((l *
            sumvv - sumv * sumv) * (l * sumyy - sumy * sumy))
    except:
        SCC = float('nan')
    return ACC, MSE, SCC


@classmethod
def from_isotherm(cls, isotherm, pressure=None, loading=None, isotherm_data
    =None, pressure_key=None, loading_key=None, model=None, param_guess=
    None, optimization_params=None, branch='ads', verbose=False):
    """
        Construct a ModelIsotherm using a parent isotherm as the template for
        all the parameters.

        Parameters
        ----------

        isotherm : Isotherm
            An instance of the Isotherm parent class.
        pressure : list
            Create an isotherm directly from an array. Values for pressure.
            If the ``isotherm_data`` dataframe is specified, these values are ignored.
        loading : list
            Create an isotherm directly from an array. Values for loading.
            If the ``isotherm_data`` dataframe is specified, these values are ignored.
        isotherm_data : DataFrame
            Pure-component adsorption isotherm data.
        pressure_key : str
            Column of the pandas DataFrame where the pressure is stored.
        loading_key : str
            Column of the pandas DataFrame where the loading is stored.
        model : str
            The model to be used to describe the isotherm.
        param_guess : dict
            Starting guess for model parameters in the data fitting routine.
        optimization_params : dict
            Dictionary to be passed to the minimization function to use in fitting model to data.
            See `here
            <https://docs.scipy.org/doc/scipy/reference/optimize.html#module-scipy.optimize>`__.
            Defaults to "Nelder-Mead".
        branch : ['ads', 'des'], optional
            The branch on which the model isotherm is based on. It is assumed to be the
            adsorption branch, as it is the most commonly modelled part, although may
            set to desorption as well.
        verbose : bool
            Prints out extra information about steps taken.
        """
    iso_params = isotherm.to_dict()
    iso_params['pressure'] = pressure
    iso_params['loading'] = loading
    iso_params['isotherm_data'] = isotherm_data
    iso_params['pressure_key'] = pressure_key
    iso_params['loading_key'] = loading_key
    iso_params['model'] = model
    iso_params['param_guess'] = param_guess
    iso_params['optimization_params'] = optimization_params
    iso_params['branch'] = branch
    iso_params['verbose'] = verbose
    return cls(**iso_params)


def write_m3u8_playlist(filename, files):
    """
    Write an M3U8 playlist named filename containing files.
    """
    out = open(filename, 'w', encoding='utf-8')
    for f in files:
        out.write(f)
        out.write('\n')
    out.close()


def app_nocache(app):
    """ Adds various cache-disabling headers to all responses returned by the
        application
    :param Flask app: A flask application
    """

    @app.after_request
    def add_header(r):
        r.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
        r.headers['Pragma'] = 'no-cache'
        r.headers['Expires'] = '0'
        r.headers['Cache-Control'] = 'public, max-age=0'
        return r


def get_figformat(format):
    """Infer preferred figure format from output format."""
    if format == 'pdf':
        figformat = 'pdf'
    elif 'html' in format:
        figformat = 'svg'
    else:
        figformat = 'png'
    return figformat


def __extract_term(expression):
    """
    Extract a term from an expression with parantheses

    :param expression:  The expression starting with a '('
    :return:            The extracted term string
    """
    open_parantheses = 0
    i = 0
    for char in expression:
        if char == '(':
            open_parantheses += 1
        elif char == ')':
            open_parantheses -= 1
        if open_parantheses == 0:
            return expression[1:i]
        i = i + 1
    raise SystemError('This point in the code should not be reachable')


@staticmethod
def wait(response):
    """
        Wait for a response from requests-futures and return the JSON content.

        This is used a lot to make multiple requests at the same time.
        """
    response = response.result()
    response.raise_for_status()
    return response.json()


def add_sample_presence_count(feature_data, table_sdf):
    """Adds a "qurro_spc" column to a DataFrame of feature information.

       The value in this column corresponds to the number of samples a given
       feature is present in, as determined by the count data given in the
       table_sdf argument.

       Parameters
       ----------

       feature_data: pd.DataFrame
            A DataFrame containing some sort of feature information. At the
            point in Qurro this is called, this will likely include both
            feature ranking information and feature metadata information.

       table_sdf: pd.SparseDataFrame
            Representation of a BIOM table containing count data. The index
            contains feature IDs, and the columns contain sample IDs.
            This table should only contain samples that will be used in the
            Qurro visualization (i.e. this table should be the output of all
            the matching, filtering, removing empty, etc. steps), since the
            presence of irrelevant samples will result in inaccurate SPC values
            being computed.

       Returns
       -------

       output_feature_data: pd.DataFrame
            feature_data, with a qurro_spc column added.

       Raises
       ------

       ValueError: if feature_data already contains a column named "qurro_spc".
                   (Assuming you've already called check_column_names() on this
                   data this shouldn't be a problem, but this checks anyway.)
    """
    table_pa = table_sdf.mask(table_sdf > 0, 1)
    spc_series = table_pa.sum(axis='columns')
    spc_series.name = 'qurro_spc'
    return feature_data.merge(spc_series, how='left', left_index=True,
        right_index=True, suffixes=(False, False))


def safe_issubclass(*args):
    """Like issubclass, but will just return False if not a class."""
    try:
        if issubclass(*args):
            return True
    except TypeError:
        pass
    return False


def dump(object, **kwds):
    """dill.dump of object to a NamedTemporaryFile.
Loads with "dill.temp.load".  Returns the filehandle.

    >>> dumpfile = dill.temp.dump([1, 2, 3, 4, 5])
    >>> dill.temp.load(dumpfile)
    [1, 2, 3, 4, 5]

Optional kwds:
    If 'suffix' is specified, the file name will end with that suffix,
    otherwise there will be no suffix.

    If 'prefix' is specified, the file name will begin with that prefix,
    otherwise a default prefix is used.

    If 'dir' is specified, the file will be created in that directory,
    otherwise a default directory is used.

    If 'text' is specified and true, the file is opened in text
    mode.  Else (the default) the file is opened in binary mode.  On
    some operating systems, this makes no difference.

NOTE: Keep the return value for as long as you want your file to exist !
    """
    import dill as pickle
    import tempfile
    file = tempfile.NamedTemporaryFile(**kwds)
    pickle.dump(object, file)
    file.flush()
    return file


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

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

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


def remove_options(args: dict) ->dict:
    """ Strips options part of doc which gets parsed by docopts
        - args: the dictionary of arguments produced by docopts
        - returns: a dictionary with just the useful arguments in it
    """
    options_flag = False
    new_args = dict()
    for arg in args.keys():
        if arg == 'Options:':
            break
        new_args[arg] = args[arg]
    return new_args


def table_drop(name: str) ->str:
    """Return command to drop a table from a PostgreSQL database.

    :param str name: name of table to drop
    :returns: command to remove table from database
    :rtype: str
    """
    return 'DROP TABLE if EXISTS {name} CASCADE;'.format(name=name)


def single_line(txt):
    """Remove multiple spaces and newlines."""
    return u' '.join(txt.split())


def R2_SE2_FFT(f):
    """
    Compute the SE(2) Fourier Transform of f : R^2 -> R as if f is a function on SE(2).
    That is, we view f as a function on SE(2):
    f+(g) = (L_g f)(0) = f(g^{-1} 0)

    If we parameterize g = (r, theta), where r is a translation vector and theta a rotation angle,
    we see that f+ is constant along theta, because a rotation of 0 is 0.
    Therefore,
    """
    pass


def import_file(full_name, path):
    """Import a python module from a path (3.4+ only).

    Does not call sys.modules[full_name] = path

    :param full_name: name of the package
    :param path: path of the package
    :return: the corresponding module

    """
    from importlib import util
    spec = util.spec_from_file_location(full_name, path)
    mod = util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod


@classmethod
def _get_diffs(cls, dict1, dict2, ignore_missing_keys):
    """
        Returns a dict with the differences between dict1 and dict2

        Notes:
            Keys that only exist in dict2 are not included in the diff if
            ignore_missing_keys is True, otherwise they are
            Simple compares are done on lists
        """
    ret_dict = {}
    for p in dict1.keys():
        if p not in dict2:
            ret_dict.update({p: {'new': dict1[p], 'old': cls.NONE_VALUE}})
        elif dict1[p] != dict2[p]:
            if isinstance(dict1[p], dict) and isinstance(dict2[p], dict):
                sub_diff_dict = cls._get_diffs(dict1[p], dict2[p],
                    ignore_missing_keys)
                if sub_diff_dict:
                    ret_dict.update({p: sub_diff_dict})
            else:
                ret_dict.update({p: {'new': dict1[p], 'old': dict2[p]}})
    if not ignore_missing_keys:
        for p in dict2.keys():
            if p not in dict1.keys():
                ret_dict.update({p: {'new': cls.NONE_VALUE, 'old': dict2[p]}})
    return ret_dict


def psi_Ca_HCO3_HSO4_HMW84(T, P):
    """c-a-a': calcium bicarbonate bisulfate [HMW84]."""
    psi = 0.0
    valid = T == 298.15
    return psi, valid


@classmethod
def from_bg_file(cls, bg_file):
    """
        Load a BulgeGraph from a file containing a text-based representation.

        :param bg_file: The filename.
        :return: A bulge Graph.
        """
    with open(bg_file, 'r') as f:
        bg_string = f.read()
    return cls.from_bg_string(bg_string)


def address_type(address):
    """
    Return the types of the address

    This can be 'AF_INET', 'AF_UNIX', or 'AF_PIPE'
    """
    if type(address) == tuple:
        return 'AF_INET'
    elif type(address) is str and address.startswith('\\\\'):
        return 'AF_PIPE'
    elif type(address) is str:
        return 'AF_UNIX'
    else:
        raise ValueError('address type of %r unrecognized' % address)


@classmethod
def fromhexstring(cls, hexstring):
    """
        Construct BitMap from hex string
        """
    bitstring = format(int(hexstring, 16), '0' + str(len(hexstring) / 4) + 'b')
    return cls.fromstring(bitstring)


def rollback_checkpoints(rollback=1):
    """Revert `rollback` number of configuration checkpoints.

        :raises .PluginError: when configuration cannot be fully reverted

        """


def is_owner_of_group(member):
    """
    Check whether a member of a group is an owner with a status of 'ACTIVE'.
    """
    return member['type'] == 'USER' and member['role'] == 'OWNER' and member[
        'status'] == 'ACTIVE'


def vert_select_ungrouped(extend: bool=False):
    """Select vertices without a group

    :param extend: Extend, Extend the selection
    :type extend: bool
    """
    pass


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

    Calculates 1/x.

    Example::

        reciprocal([-2, 1, 3, 1.6, 0.2]) = [-0.5, 1.0, 0.33333334, 0.625, 5.0]

    Defined in src/operator/tensor/elemwise_unary_op_pow.cc:L42

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

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

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


def pipeline_code_wrapper(pipeline_code):
    """Generate code specific to the execution of the sklearn pipeline.

    Parameters
    ----------
    pipeline_code: str
        Code that defines the final sklearn pipeline

    Returns
    -------
    Source code for the sklearn pipeline and calls to fit and predict

    """
    return (
        """exported_pipeline = {}

exported_pipeline.fit(training_features, training_target)
results = exported_pipeline.predict(testing_features)
"""
        .format(pipeline_code))


def height_from_head_length(segment_length):
    """
    Calculates body height based on the height of the head

    args:
        segment_length (float): vertical length of head

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


def create_f4l4(cc_number):
    """Creates the token_f4l4 value if a CC number is provided.

        Parameters
            cc_number (str): The Helcim response CC number.

        Returns:
            string: the token F4L4 value.
    """
    if cc_number:
        stripped_cc = cc_number.strip()
        return '{}{}'.format(stripped_cc[:4], stripped_cc[-4:])
    return None


def next_pow2(n):
    """ Return first power of 2 >= n.

    >>> next_pow2(3)
    4
    >>> next_pow2(8)
    8
    >>> next_pow2(0)
    1
    >>> next_pow2(1)
    1
    """
    if n <= 0:
        return 1
    n2 = 1 << int(n).bit_length()
    if n2 >> 1 == n:
        return n
    else:
        return n2


@classmethod
def __patheval(cls, nexuspath):
    """ splits nexus path into list

        :param nexuspath: nexus path
        :type nexuspath: :obj:`str`
        :returns: nexus path in lists of (name, NXtype)
        :rtype: :obj:`list` < (:obj:`str`, :obj:`str`) >
        """
    pathlist = []
    spath = nexuspath.split('/')
    if spath:
        for sp in spath[:-1]:
            nlist = sp.split(':')
            if len(nlist) == 2:
                if len(nlist[0]) == 0 and len(nlist[1]) > 2 and nlist[1
                    ].startswith('NX'):
                    pathlist.append((nlist[1][2:], nlist[1]))
                else:
                    pathlist.append((nlist[0], nlist[1]))
            elif len(nlist) == 1 and nlist[0]:
                if len(nlist[0]) > 2 and nlist[0].startswith('NX'):
                    pathlist.append((nlist[0][2:], nlist[0]))
                else:
                    pathlist.append((nlist[0], 'NX' + nlist[0]))
        pathlist.append((spath[-1], None))
    return pathlist


def duplicate_move(MBALL_OT_duplicate_metaelems=None,
    TRANSFORM_OT_translate=None):
    """Make copies of the selected metaelements and move them

    :param MBALL_OT_duplicate_metaelems: Duplicate Metaelements, Duplicate selected metaelement(s)
    :param TRANSFORM_OT_translate: Translate, Translate (move) selected items
    """
    pass


def getsvfs(repo):
    """Return appropriate object to access files under .hg/store
    """
    svfs = getattr(repo, 'svfs', None)
    if svfs:
        return svfs
    else:
        return getattr(repo, 'sopener')


def unquote_header_value(value, is_filename=False):
    """Unquotes a header value.  (Reversal of :func:`quote_header_value`).
    This does not use the real unquoting but what browsers are actually
    using for quoting.

    :param value: the header value to unquote.
    """
    if value and value[0] == value[-1] == '"':
        value = value[1:-1]
        if not is_filename or value[:2] != '\\\\':
            return value.replace('\\\\', '\\').replace('\\"', '"')
    return value


def addEvent(event, fd, action):
    """
        Add a new win32 event to the event loop.

        @param event: a Win32 event object created using win32event.CreateEvent()

        @param fd: an instance of L{twisted.internet.abstract.FileDescriptor}

        @param action: a string that is a method name of the fd instance.
                       This method is called in response to the event.

        @return: None
        """


def dummy():
    """callback dummy func."""
    raise AssertionError('callback function not initialized')


@classmethod
def bgblue(cls, string, auto=False):
    """Color-code entire string.

        :param str string: String to colorize.
        :param bool auto: Enable auto-color (dark/light terminal).

        :return: Class instance for colorized string.
        :rtype: Color
        """
    return cls.colorize('bgblue', string, auto=auto)


def uch_punwani(xy, d_pipe, gs, rhog, rhos, ut):
    """
    Provide functions to solve for voidage and choking velocity based on
    equations from Punwani 1976. Requires SciPy fsolve function.

    Parameters
    ----------
    xy
        Solves for ep and uch using SciPy fsolve where
        ep = voidage [-] and uch = choking velocity [m/s]
    d_pipe : float
        Internal pipe diameter [m]
    gs : float
        Solids flux [kg/(s m^2)]
    rhog : float
        Density of gas, must be in units of lb/ft^3
    rhos : float
        Density of particle [kg/m^3]
    ut : float
        Terminal velocity [m/s]

    Returns
    -------
    f1, f2 : functions
        Functions to solve for ep and uch

    References
    ----------
    Punwani, Modi, Tarman, 1976. A Generalized Correlation for Estimating
    Choking Velocity in Vertical Solids Transport. Institute of Gas Technology,
    Chicago, IL, 1-14.
    """
    ep, uc = xy
    g = 9.81
    f1 = 2 * g * d_pipe * (ep ** -4.7 - 1) - 0.074 * rhog ** 0.77 * (uc /
        ep - ut) ** 2
    f2 = gs / rhos / (1 - ep) - uc / ep + ut
    return f1, f2


@staticmethod
def _filter_remove_same_results(results):
    """Removes alignments that aligned to themselves.

        :param results:
        :type results:
        :return:
        :rtype:
        """
    new_results = []
    for r in results:
        query = r['query']
        subj = r['subject']
        k1 = query['origin_key']
        k2 = subj['origin_key']
        qends = query['start'], query['end']
        sends = subj['start'], subj['end']
        if k1 == k2 and qends == sends:
            continue
        else:
            new_results.append(r)
    return new_results


def hashdict(d):
    """Hash a dictionary
    """
    k = 0
    for key, val in d.items():
        k ^= hash(key) ^ hash(val)
    return k


def difference_series(argument):
    """
    Gets difference series of ``argument``.

    ..  container:: example

        >>> abjad.mathtools.difference_series([1, 1, 2, 3, 5, 5, 6])
        [0, 1, 1, 2, 0, 1]

        >>> abjad.mathtools.difference_series([9, 6, 8, 5, 7, 4, 6])
        [-3, 2, -3, 2, -3, 2]

    Returns new object of ``argument`` type.
    """
    result = []
    for i, n in enumerate(argument[1:]):
        result.append(n - argument[i])
    return type(argument)(result)


@staticmethod
def get_f1(curr_result):
    """
        Simple getter for F1 statistics (N_F1, J_F1 and distance).
        :param curr_result: a result storer
        :type curr_result: ResultStorer

        :return: (J_F1, N_F1, distance)
        :rtype (float, float, int)
        """
    return curr_result.j_f1[0], curr_result.n_f1[0], -curr_result.distance[0
        ], curr_result.ccode[0] not in ('x', 'X')


def deliverBody(protocol):
    """
        Register an L{IProtocol<twisted.internet.interfaces.IProtocol>} provider
        to receive the response body.

        The protocol will be connected to a transport which provides
        L{IPushProducer}.  The protocol's C{connectionLost} method will be
        called with:

            - ResponseDone, which indicates that all bytes from the response
              have been successfully delivered.

            - PotentialDataLoss, which indicates that it cannot be determined
              if the entire response body has been delivered.  This only occurs
              when making requests to HTTP servers which do not set
              I{Content-Length} or a I{Transfer-Encoding} in the response.

            - ResponseFailed, which indicates that some bytes from the response
              were lost.  The C{reasons} attribute of the exception may provide
              more specific indications as to why.
        """


def get_connection(connections, connection_id=None):
    """Return the connection object from list."""
    if connection_id is None:
        connection = connections[0]
    else:
        for connection in connections:
            if connection.connection_id == connection_id:
                break
        else:
            raise ValueError('Unknown connection_id.')
    return connection


def diff_time(start_time, end_time):
    """
    Computes the elapsed time from the start time to the end time specifed by
    the user.

    Parameters
    ----------
    start_time : Datetime
        Specifies the start time of the time range to be computed.
    end_time : Datetime
        Specifies the start time of the time range to be computed.

    Returns
    -------
        time_dif : Integer
            Represents the time elapsed from the start time to the current time (when the function was called).
    """
    time_dif = int((end_time - start_time).total_seconds() * 1000)
    return time_dif


@classmethod
def is_valid_row(cls, row):
    """Indicates whether or not the given row contains valid data."""
    for k in row.keys():
        if row[k] is None:
            return False
    return True


@classmethod
def is_game_valid(cls):
    """Check whether the game engine is still valid."""
    return cls._game_engine is not None and cls._world is not None


def ApplyXYZshifts(parmDict, varyList):
    """
    takes atom x,y,z shift and applies it to corresponding atom x,y,z value

    :param dict parmDict: parameter dictionary
    :param list varyList: list of variables (not used!)
    :returns: newAtomDict - dictionary of new atomic coordinate names & values; key is parameter shift name

    """
    newAtomDict = {}
    for item in parmDict:
        if 'dA' in item:
            parm = ''.join(item.split('d'))
            parmDict[parm] += parmDict[item]
            newAtomDict[item] = [parm, parmDict[parm]]
    return newAtomDict


def skin_root_mark():
    """Mark selected vertices as roots

    """
    pass


def disable_validate_multiframe_implicit():
    """
    Disable the validation that checks that data is not multiframe implicit
    This allows to sometimes convert Philips Multiframe with implicit transfer syntax
    """
    global validate_multiframe_implicit
    validate_multiframe_implicit = False


@classmethod
def add_region(cls, name, expires, redis_expiration=60 * 60 * 24 * 7):
    """Add a cache region to the current configuration

        :param name: The name of the cache region
        :type name: string
        :param expires: The expiration in seconds.
        :type expires: integer
        :param redis_expiration: How long the Redis key expiration is
                                 set for. Defaults to 1 week.
        :type redis_expiration: integer

        """
    cls.regions[name] = dict(expires=expires, redis_expiration=redis_expiration
        )


def _clean_onerror(func, path, excinfo):
    """
    Error handler for cleaner
    """
    print('%s encountered error when processing %s: %s' % (func, path, excinfo)
        )


def get_gene_info_pt(path):
    """Returns a dictionary that maps gene id to gene information.

    Arguments:
        path (str): Path to annotation in .prot_table format.

    Returns:
        dict: Dictionary of gene id to tuple of information:
            - name
            - description
            - start coordinate
            - end coordinate
            - strand

    """
    orf2info = {}
    for line in open(path):
        if line.startswith('#'):
            continue
        tmp = line.strip().split('\t')
        orf = tmp[8]
        name = tmp[7]
        desc = tmp[0]
        start = int(tmp[1])
        end = int(tmp[2])
        strand = tmp[3]
        orf2info[orf] = name, desc, start, end, strand
    return orf2info


def lorentzian(x, amp, freq, HWHM):
    """compute a Lorentzian peak

    Inputs
    ------
    x : ndarray
        the positions at which the signal should be sampled
    amp : float or ndarray with size equal to x.shape
        amplitude
    freq : float or ndarray with size equal to x.shape
        frequency/position of the Gaussian component
    HWHM : float or ndarray with size equal to x.shape
        half-width at half-maximum

    Returns
    -------
    out : ndarray
        the signal

    Remarks
    -------
    Formula is amp/(1+((x-freq)/HWHM)**2)
    """
    return amp / (1 + ((x - freq) / HWHM) ** 2)


def klGauss(x, y, sig2x=1):
    """ Kullback-Leibler divergence for Gaussian distributions of means ``x`` and ``y`` and variances ``sig2x`` and ``sig2y``, :math:`\\nu_1 = \\mathcal{N}(x, \\sigma_x^2)` and :math:`\\nu_2 = \\mathcal{N}(y, \\sigma_x^2)`:

    .. math:: \\mathrm{KL}(\\nu_1, \\nu_2) = \\frac{(x - y)^2}{2 \\sigma_y^2} + \\frac{1}{2}\\left( \\frac{\\sigma_x^2}{\\sigma_y^2} - 1 \\log\\left(\\frac{\\sigma_x^2}{\\sigma_y^2}\\right) \\right).

    See https://en.wikipedia.org/wiki/Normal_distribution#Other_properties
    """
    return (x - y) ** 2 / (2.0 * sig2x)


@classmethod
def sorted_fields(cls):
    """Get the names of all writable metadata fields, sorted in the
        order that they should be written.

        This is a lexicographic order, except for instances of
        :class:`DateItemField`, which are sorted in year-month-day
        order.
        """
    for property in sorted(cls.fields(), key=cls._field_sort_name):
        yield property


def get_defaults(context):
    """
    Get the default values for a slice's members:
    (start for positive step, start for negative step,
     stop for positive step, stop for negative step, step)
    """
    maxint = (1 << context.address_size - 1) - 1
    return 0, maxint, maxint, -maxint - 1, 1


@classmethod
def beautifyTextInHTML(cls, html, indent=2, encoding=None):
    """Beautifying CSS within the ```` tag.  HTML
        comments(s) (i.e. ``<!-- ... -->``) within the `style tag`, if any,
        will be moved to the end of the tag block.

        **Note**: The function assumes tag ````)

        >>> # pretty print css
        >>> from html5print import CSSBeautifier
        >>> html = '''
        ...
        ... '''
        >>> print(CSSBeautifier.beautifyTextInHTML(html))

        >>> #
        ... '''
        >>> print(CSSBeautifier.beautifyTextInHTML(html))

        """
    return cls._findAndReplace(html, cls.reIndentAndStyle, cls.beautify, (
        indent,), indent)


def _adjust_prices(hist_data, price_list=None):
    """
    Return modifed DataFrame with adjusted prices based on
    'Adj Close' price. Adds 'Adj_Ratio' column.
    """
    if price_list is None:
        price_list = 'Open', 'High', 'Low', 'Close'
    adj_ratio = hist_data['Adj Close'] / hist_data['Close']
    data = hist_data.copy()
    for item in price_list:
        data[item] = hist_data[item] * adj_ratio
    data['Adj_Ratio'] = adj_ratio
    del data['Adj Close']
    return data


def _google_drive():
    """
    Returns a query item matching messages that have Google Drive attachments.

    """
    return f'has:drive'


def light_cache_free():
    """Delete cached indirect lighting

    """
    pass


def rethrow(exception, additional_message):
    """
    重新抛出当前作用域中的最后一个异常, 保留堆栈信息, 并且在报错信息中添加其他内容
    """
    e = exception
    m = additional_message
    if not e.args:
        e.args = m,
    else:
        e.args = (e.args[0] + m,) + e.args[1:]
    raise e


def extend_names_to_match_nparam(names, nparam):
    """
    Append names to list using default convention
    until length of names matches number of parameters.

    For example, if `names = ['name_1', 'name_2']` and `nparam = 4`, then
    two additional names will be appended to the `names` list.
    E.g.,::

        names = ['name_1', 'name_2', '$p_{2}$', '$p_{3}$']

    Args:
        * **names** (:py:class:`list`): Names of parameters provided by user
        * **nparam** (:py:class:`int`): Number of parameter names to generate

    Returns:
        * **names** (:py:class:`list`): List of strings - extended         list of parameter names
    """
    if names is None:
        names = []
    n0 = len(names)
    for ii in range(n0, nparam):
        names.append(str('$p_{{{}}}$'.format(ii)))
    return names


@classmethod
def get_dialect_cls(cls, url):
    """Given a URL, return the :class:`.Dialect` that will be used.

        This is a hook that allows an external plugin to provide functionality
        around an existing dialect, by allowing the plugin to be loaded
        from the url based on an entrypoint, and then the plugin returns
        the actual dialect to be used.

        By default this just returns the cls.

        .. versionadded:: 1.0.3

        """
    return cls


def hasdir(dir):
    """Returns a bool indicating if a directory is in this manifest."""


def find_winner(seq, seq_dict):
    """
    Identify each round winner.

    :param seq: round sequence
    :type seq: str
    :param seq_dict: players sequences
    :type seq_dict: dict
    :return: winner name as str
    """
    winner_name = ''
    min_index = len(seq)
    for name in seq_dict.keys():
        name_index = seq.find(seq_dict[name])
        if name_index != -1:
            if name_index < min_index:
                winner_name = name
                min_index = name_index
    if len(winner_name) != 0:
        return winner_name
    return None


@classmethod
def get_platform(cls):
    """ Returns the identified of the platform (i.e. testbed type)
        for the Resource

        """
    return cls._platform


def histogram(f):
    """
    h = histogram(f)

    Find the histogram of the image f.

    Finds the histogram of the image `f`.

    For binary image the vector size is 2. For gray-scale uint8 and
    uint16 images, the vector size is the maximum pixel value plus
    one. h[0] gives the number of pixels with value 0.

    Parameters
    ----------
    f : Input image (of any integer type).

    Returns
    -------
    h : Histogram in a uint16 or an int32 vector.
    """
    import numpy as np
    return np.histogram(f, np.arange(f.max() + 2))[0]


def max_tok_len(new, count, sofar):
    """
    In token batching scheme, the number of sequences is limited
    such that the total number of src/tgt tokens (including padding)
    in a batch <= batch_size
    """
    global max_src_in_batch, max_tgt_in_batch
    if count == 1:
        max_src_in_batch = 0
        max_tgt_in_batch = 0
    max_src_in_batch = max(max_src_in_batch, len(new.src[0]) + 2)
    max_tgt_in_batch = max(max_tgt_in_batch, len(new.tgt[0]) + 1)
    src_elements = count * max_src_in_batch
    tgt_elements = count * max_tgt_in_batch
    return max(src_elements, tgt_elements)


def cos_angle(left_side: float, right_side: float, third_side: float) ->float:
    """
    Calculate cos of angle if give 3 side of triangle
    """
    return (left_side ** 2 + right_side ** 2 - third_side ** 2) / (2 *
        left_side * right_side)


def set_model_internal_data(model, original_data, modified_data, deleted_data):
    """
    Set internal data to model.
    """
    model.__original_data__ = original_data
    list(map(model._prepare_child, model.__original_data__))
    model.__modified_data__ = modified_data
    list(map(model._prepare_child, model.__modified_data__))
    model.__deleted_fields__ = deleted_data
    return model


def groupby_params(dict_w_params, params):
    """ Groups `dict_w_params` according the given set of parameters. This
 can be used to e.g. seperate physical from numerical parameters. """
    grouped_dict = {}
    for key, item in dict_w_params.items():
        item_copy = item.copy()
        index_dict = {}
        for param in params:
            if param in item_copy:
                index_dict[param] = item_copy[param]
                del item_copy[param]
        index_tuple = tuple((key, index_dict[key]) for key in sorted(
            index_dict))
        grouped_dict.setdefault(index_tuple, {}).update({key: item_copy})
    return grouped_dict


@classmethod
def has_resuming(cls):
    """Returns whether it supports to resume the fetch process.

        :returns: this backend supports items resuming
        """
    return True


def _recenter(in_file):
    """Recenter the phase-map distribution to the -pi..pi range."""
    from os import getcwd
    import numpy as np
    import nibabel as nb
    from nipype.utils.filemanip import fname_presuffix
    nii = nb.load(in_file)
    data = nii.get_fdata(dtype='float32')
    msk = data != 0
    msk[data == 0] = False
    data[msk] -= np.median(data[msk])
    out_file = fname_presuffix(in_file, suffix='_recentered', newpath=getcwd())
    nb.Nifti1Image(data, nii.affine, nii.header).to_filename(out_file)
    return out_file


@classmethod
def converted(cls, sheet_track):
    """given a SheetTrack object, returns a CDTOC_Track"""
    index_1 = sheet_track.index(1).offset()
    return cls(sheet_track.number(), int(index_1 * 75) + 150, sheet_track.
        is_audio())


def _sin(attrs, inputs, proto_obj):
    """Elementwise sine of input array."""
    return 'sin', attrs, inputs


def remove():
    """Removes the refrence adapted to.
        """


def rank_tuple_consistency(new_record, existing_records):
    """
    This function returns an integer which indicates how much the relative sizes of contents is preserved.
    It is 0 if relative sizes of contents are perfectly different from previous records,
    and it is 1 if relative sizes of contents are at exact average of previous records.
    """
    rank = 0
    return rank


def plot_err(x, y, dy, fy, view=None, **kw):
    """
    **DEPRECATED**: subclass Curve and override the plot function.

    Plot data *y* and error *dy* against *x*.

    *view* is one of linear, log, logx or loglog.
    """
    import pylab
    pylab.errorbar(x, y, yerr=dy, fmt='.')
    pylab.plot(x, fy, '-')
    if view == 'log':
        pylab.xscale('linear')
        pylab.yscale('log')
    elif view == 'logx':
        pylab.xscale('log')
        pylab.yscale('linear')
    elif view == 'loglog':
        pylab.xscale('log')
        pylab.yscale('log')
    else:
        pylab.xscale('linear')
        pylab.yscale('linear')


@staticmethod
def metadata_id(item):
    """Extracts the identifier from a StackExchange item."""
    return str(item['question_id'])


def refresh(transitions):
    """Refresh workflow completely with new transitions.
        """


def get_options(args, mutators, converters={}):
    """
	Returns a list of 2-tuple in the form (option, value) for all options
	contained in the `mutators` collection if they're also keys of the `args`
	and have a non-None value. If the option (non- prefixed) is also a key of
	the `converters` dictionary then the associated value should be another
	dictionary indicating convertions to be done on the value found in `args`.
	e.g.
	args = {'deadline': 'none'}
	mutators = {'deadline'}
	converters = {'deadline': {'none': None}}
	=> [('deadline', None)]
	"""
    options = []
    for mutator in mutators:
        if mutator in args and args[mutator] is not None:
            val = args[mutator]
            convertions = converters.get(mutator)
            if convertions is not None and val in convertions:
                val = convertions[val]
            options.append((mutator, val))
    return options


@staticmethod
def _set_custom_facility(gelf_dict, facility_value, record):
    """Set the ``gelf_dict``'s ``facility`` field to the specified value

        Also add a additional ``_logger`` field containing the
        ``LogRecord.name``.

        :param gelf_dict: Dictionary representing a GELF log.
        :type gelf_dict: dict

        :param facility_value: Value to set as the ``gelf_dict``'s
            ``facility`` field.
        :type facility_value: str

        :param record: :class:`logging.LogRecord` to extract it's record
            name to insert into the given ``gelf_dict`` as the ``_logger``
            field.
        :type record: logging.LogRecord
        """
    gelf_dict.update({'facility': facility_value, '_logger': record.name})


@staticmethod
def chooseDelta(x):
    """Choose a reasonable axis range given that one limit is x.

        Given that end of the axis range (i.e., minValue or maxValue) is
        x, choose a reasonable distance to the other limit.
        """
    if abs(x) < 1e-09:
        return 1.0
    else:
        return 0.1 * abs(x)


@classmethod
def from_onnx(cls, graph):
    """ Create a OnnxGraph object from ONNX GraphProto """
    graph_ = cls(graph)
    for idx, node in enumerate(graph_.node):
        if not node.name:
            node.name = '{}_{}'.format(node.op_type, idx)
        elif '/' in node.name:
            node.name = node.name.replace('/', '_')
    graph_.connect_nodes()
    for node in graph_.node:
        for input_ in node.input:
            if input_ in graph_.tensor_dict:
                node.tensors[input_] = graph_.tensor_dict[input_]
    return graph_


def getvariable(name):
    """Get the value of a local variable somewhere in the call stack."""
    import inspect
    fr = inspect.currentframe()
    try:
        while fr:
            fr = fr.f_back
            vars = fr.f_locals
            if name in vars:
                return vars[name]
    except:
        pass
    return None


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

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


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


@classmethod
def from_transformation(cls, transformation):
    """Constructs a frame from a ``Transformation``.

        Parameters
        ----------
        transformation : :class:`compas.geometry.Transformation`
            The transformation defines the orientation of the frame through the
            rotation and the origin through the translation.

        Returns
        -------
        :class:`compas.geometry.Frame`
            The constructed frame.

        Examples
        --------
        >>> from compas.geometry import Transformation
        >>> f1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
        >>> T = Transformation.from_frame(f1)
        >>> f2 = Frame.from_transformation(T)
        >>> f1 == f2
        True
        """
    xaxis, yaxis = transformation.basis_vectors
    point = transformation.translation
    return cls(point, xaxis, yaxis)


def get_formula(phenotype, covars, interaction):
    """Creates the linear/logistic regression formula (for statsmodel).

    Args:
        phenotype (str): the phenotype column
        covars (list): the list of co variable columns
        interaction (str): the interaction column

    Returns:
        str: the formula for the statistical analysis

    Note
    ----
        The phenotype column needs to be specified. The list of co variables
        might be empty (if no co variables are necessary). The interaction
        column can be set to ``None`` if there is no interaction.

    """
    formula = '{} ~ _GenoD'.format(phenotype)
    if len(covars) > 0:
        formula += ' + ' + ' + '.join(covars)
    if interaction is not None:
        formula += ' + _GenoD*{}'.format(interaction)
    return formula


def train_test_split_by_last_days(stock_df, periods_per_day=7,
    num_test_days=90, num_train_days=180, verbose=1, plot=True):
    """Takes the last num_test_days of the time index to use as testing data, and take shte num_Trian_days prior to that date
    as the training data."""
    from IPython.display import display
    import matplotlib.pyplot as plt
    if verbose > 1:
        print(f'Data index (freq={stock_df.index.freq}')
        print(f'index[0] = {stock_df.index[0]}, index[-1]={stock_df.index[-1]}'
            )
    day_freq = periods_per_day
    start_train_day = stock_df.index[-1] - (num_train_days + num_test_days
        ) * day_freq
    last_train_day = stock_df.index[-1] - num_test_days * day_freq
    train_data = stock_df.loc[start_train_day:last_train_day]
    test_data = stock_df.loc[last_train_day:]
    if verbose > 0:
        print(f'Data split on index:\t{last_train_day}:')
        print(
            f'training dates:\t{train_data.index[0]} \t {train_data.index[-1]}.'
            )
        print(f'test dates:\t{test_data.index[0]} \t {test_data.index[-1]}.')
    if verbose > 1:
        display(train_data.head(3).style.set_caption('Training Data'))
        display(test_data.head(3).style.set_caption('Test Data'))
    if plot == True:
        if 'price' in stock_df.columns:
            plot_col = 'price'
        elif 'price_labels' in stock_df.columns:
            plot_col = 'price_labels'
        fig = plt.figure(figsize=(8, 4))
        train_data[plot_col].plot(label='Training')
        test_data[plot_col].plot(label='Test')
        plt.title('Training and Test Data for S&P500')
        plt.ylabel('Price')
        plt.xlabel('Trading Date/Hour')
        plt.legend()
        plt.show()
    return train_data, test_data


def region_2d_to_vector_3d(region, rv3d, coord):
    """
    Return a direction vector from the viewport at the specific 2d region
    coordinate.

    :arg region: region of the 3D viewport, typically bpy.context.region.
    :type region: :class:`bpy.types.Region`
    :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d.
    :type rv3d: :class:`bpy.types.RegionView3D`
    :arg coord: 2d coordinates relative to the region:
       (event.mouse_region_x, event.mouse_region_y) for example.
    :type coord: 2d vector
    :return: normalized 3d vector.
    :rtype: :class:`mathutils.Vector`
    """
    from mathutils import Vector
    viewinv = rv3d.view_matrix.inverted()
    if rv3d.is_perspective:
        persinv = rv3d.perspective_matrix.inverted()
        out = Vector((2.0 * coord[0] / region.width - 1.0, 2.0 * coord[1] /
            region.height - 1.0, -0.5))
        w = out.dot(persinv[3].xyz) + persinv[3][3]
        view_vector = persinv * out / w - viewinv.translation
    else:
        view_vector = -viewinv.col[2].xyz
    view_vector.normalize()
    return view_vector


@classmethod
def get_lilypond_minimum_version_string(class_):
    """
        Gets LilyPond minimum version string.

        ..  container:: example

            >>> abjad_configuration = abjad.AbjadConfiguration()
            >>> abjad_configuration.get_lilypond_minimum_version_string() # doctest: +SKIP
            '2.19.0'

        Returns string.
        """
    version = class_.get_lilypond_version_string()
    parts = version.split('.')[0:2]
    parts.append('0')
    return '.'.join(parts)


@staticmethod
def _wrap_bytes(bytestream):
    """Return `bytestream` without changing it."""
    return bytestream


def absolute_date(resolution, start, end):
    """Select an absolute date range for a location selector.

    :keyword resolution: Time resolution specifier, e.g. ``hours`` or ``days``.
    :keyword start: UTC start time in ISO 8601 format.
    :keyword end: UTC end time in ISO 8601 format.

    >>> from pprint import pprint
    >>> d = absolute_date(resolution='months', start='2013-01', end='2013-06')
    >>> pprint(d)
    {'months': {'end': '2013-06', 'start': '2013-01'}}
    >>> d = absolute_date(resolution='minutes', start='2012-01-01 12:00',
    ...         end='2012-01-01 12:45')
    >>> pprint(d, width=76)
    {'minutes': {'end': '2012-01-01 12:45', 'start': '2012-01-01 12:00'}}

    """
    if resolution not in 'minuteshoursdaysweeksmonthsyears':
        raise ValueError('Invalid date resolution: %s' % resolution)
    payload = {resolution: {'start': start, 'end': end}}
    return payload


def print_query(query):
    """ Pretty prints the given query. """
    formatted = format(query.decode('utf-8'), reindent=True)
    formatted = formatted.replace('\n', '\n  ')
    print('> {}'.format(formatted))


def swipe(x1, y1, x2, y2, toolkit=None):
    """
    swipe from (x1, y1) to (x2, y2)

    :param x1:
    :param y1:
    :param x2:
    :param y2:
    :param toolkit:
    :return:
    """
    x1, y1, x2, y2 = map(str, (x1, y1, x2, y2))
    return toolkit.adb.run(['shell', 'input', 'swipe', x1, y1, x2, y2])


def _iv_to_str(chrom, start, end):
    """Converts a genomic interval into a string representation 'chr:start-end'."""
    return '{}:{}-{}'.format(chrom, start, end)


def _get_docstring_var_description(var_doc):
    """
    Get a description of argument or return value from docstring.

    Parameters
    ----------
    var_doc : str
        Docstring's part of argument or return value.

    Returns
    -------
    description : str
        Description of argument or return value.
    """
    var_doc = var_doc.rstrip()
    splitted_list = var_doc.split('\n')
    if len(splitted_list) < 2:
        return ''
    description = '\n'.join(splitted_list[1:])
    description = description.rstrip()
    return description


def check_min_reads(samfile, chrom, tx_st, tx_end, cutoff):
    """
	make sure the gene has minimum reads coverage. if cutoff = 10, each gene must have
	10 *different* reads.
	"""
    tmp = False
    read_count = set()
    try:
        alignedReads = samfile.fetch(chrom, tx_st, tx_end)
        for aligned_read in alignedReads:
            if aligned_read.is_qcfail:
                continue
            if aligned_read.is_unmapped:
                continue
            if aligned_read.is_secondary:
                continue
            read_start = aligned_read.pos
            if read_start < tx_st:
                continue
            if read_start >= tx_end:
                continue
            read_count.add(read_start)
            if len(read_count) > cutoff:
                tmp = True
                break
        return tmp
    except:
        return False


def theta_Mg_Na_PK74(T, P):
    """c-c': magnesium sodium [PK74]."""
    theta = 0.0
    valid = T == 298.15
    return theta, valid


def matrix_to_lines(matrix, x, y, incby=1):
    """    Converts the `matrix` into an iterable of ((x1, y1), (x2, y2)) tuples which
    represent a sequence (horizontal line) of dark modules.

    The path starts at the 1st row of the matrix and moves down to the last
    row.

    :param x: Initial position on the x-axis.
    :param y: Initial position on the y-axis.
    :param incby: Value to move along the y-axis (default: 1).
    :rtype: iterable of (x1, y1), (x2, y2) tuples
    """
    y -= incby
    last_bit = 1
    for row in matrix:
        x1 = x
        x2 = x
        y += incby
        for bit in row:
            if last_bit != bit and not bit:
                yield (x1, y), (x2, y)
                x1 = x2
            x2 += 1
            if not bit:
                x1 += 1
            last_bit = bit
        if last_bit:
            yield (x1, y), (x2, y)
            last_bit = 0


def location_dict_to_geojson(org_location_dict, filename, hashed_usernames=True
    ):
    """
    CURRENTLY BROKEN!
    Outputs a dict of users : locations to a CSV file.

    Requires org_location_dict and filename, optional hashed_usernames parameter.

    Uses hashes of usernames by default for privacy reasons. Think carefully
    about publishing location data about uniquely identifiable users. Hashing
    allows you to check unique users without revealing personal information.
    """
    import hashlib
    with open(filename, 'w') as f:
        header = '\n{ "type": "FeatureCollection",\n    "features": [\n'
        f.write(header)
        for user, location in org_location_dict.items():
            if location is not None:
                if hashed_usernames:
                    user_output = hashlib.sha1(user.encode('utf-8')).hexdigest(
                        )
                else:
                    user_output = user
                line = (
                    """
    {
        "type": "Feature",
        "geometry": {
            "type": "Point",
            "coordinates": [%s, %s]
        },
        "properties": {
            "name": "%s"
        }
    },
"""
                     % (location.longitude, location.latitude, user_output))
                f.write(line)
        f.write(']}')
    f.close()


def hawkesll(lda=None, alpha=None, beta=None, state=None, lags=None, marks=
    None, valid_length=None, max_time=None, name=None, attr=None, out=None,
    **kwargs):
    """Computes the log likelihood of a univariate Hawkes process.

    The log likelihood is calculated on point process observations represented
    as *ragged* matrices for *lags* (interarrival times w.r.t. the previous point),
    and *marks* (identifiers for the process ID). Note that each mark is considered independent,
    i.e., computes the joint likelihood of a set of Hawkes processes determined by the conditional intensity:

    .. math::

      \\lambda_k^*(t) = \\lambda_k + \\alpha_k \\sum_{\\{t_i < t, y_i = k\\}} \\beta_k \\exp(-\\beta_k (t - t_i))

    where :math:`\\lambda_k` specifies the background intensity ``lda``, :math:`\\alpha_k` specifies the *branching ratio* or ``alpha``, and :math:`\\beta_k` the delay density parameter ``beta``.

    ``lags`` and ``marks`` are two NDArrays of shape (N, T) and correspond to the representation of the point process observation, the first dimension corresponds to the batch index, and the second to the sequence. These are "left-aligned" *ragged* matrices (the first index of the second dimension is the beginning of every sequence. The length of each sequence is given by ``valid_length``, of shape (N,) where ``valid_length[i]`` corresponds to the number of valid points in ``lags[i, :]`` and ``marks[i, :]``.

    ``max_time`` is the length of the observation period of the point process. That is, specifying ``max_time[i] = 5`` computes the likelihood of the i-th sample as observed on the time interval :math:`(0, 5]`. Naturally, the sum of all valid ``lags[i, :valid_length[i]]`` must be less than or equal to 5.

    The input ``state`` specifies the *memory* of the Hawkes process. Invoking the memoryless property of exponential decays, we compute the *memory* as

    .. math::

        s_k(t) = \\sum_{t_i < t} \\exp(-\\beta_k (t - t_i)).

    The ``state`` to be provided is :math:`s_k(0)` and carries the added intensity due to past events before the current batch. :math:`s_k(T)` is returned from the function where :math:`T` is ``max_time[T]``.

    Example::

      # define the Hawkes process parameters
      lda = nd.array([1.5, 2.0, 3.0]).tile((N, 1))
      alpha = nd.array([0.2, 0.3, 0.4])  # branching ratios should be < 1
      beta = nd.array([1.0, 2.0, 3.0])

      # the "data", or observations
      ia_times = nd.array([[6, 7, 8, 9], [1, 2, 3, 4], [3, 4, 5, 6], [8, 9, 10, 11]])
      marks = nd.zeros((N, T)).astype(np.int32)

      # starting "state" of the process
      states = nd.zeros((N, K))

      valid_length = nd.array([1, 2, 3, 4])  # number of valid points in each sequence
      max_time = nd.ones((N,)) * 100.0  # length of the observation period

      A = nd.contrib.hawkesll(
          lda, alpha, beta, states, ia_times, marks, valid_length, max_time
      )

    References:

    -  Bacry, E., Mastromatteo, I., & Muzy, J. F. (2015).
       Hawkes processes in finance. Market Microstructure and Liquidity
       , 1(01), 1550005.

    Defined in src/operator/contrib/hawkes_ll.cc:L84

    Parameters
    ----------
    lda : Symbol
        Shape (N, K) The intensity for each of the K processes, for each sample
    alpha : Symbol
        Shape (K,) The infectivity factor (branching ratio) for each process
    beta : Symbol
        Shape (K,) The decay parameter for each process
    state : Symbol
        Shape (N, K) the Hawkes state for each process
    lags : Symbol
        Shape (N, T) the interarrival times
    marks : Symbol
        Shape (N, T) the marks (process ids)
    valid_length : Symbol
        The number of valid points in the process
    max_time : Symbol
        the length of the interval where the processes were sampled

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

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


def _clear():
    """
        Clear depending loads while the replacement lc occure.
        """
    pass