@classmethod
def add(cls, name, value=0, textvalue='', datevalue=None, comment=''):
    """add a new var of given name with given values"""
    v = cls.new()
    v.name = name
    v.value = value
    v.textvalue = textvalue
    v.datevalue = datevalue
    v.comment = comment
    v.flush()


def set_dig1(lucid, srcval):
    """Call lucid8824.set_dig1"""
    lucid.set_dig1(srcval)


def isalpha(text):
    """
    Checks if all characters in ``text`` are alphabetic and there is at least one character.

    Alphabetic characters are those characters defined in the Unicode character database
    as a "Letter". Note that this is different from the "Alphabetic" property defined in
    the Unicode Standard.

    :param text: The string to check
    :type text:  ``str``

    :return: True if all characters in ``text`` are alphabetic and there is at least one character, False otherwise.
    :rtype:  ``bool``
    """
    assert isinstance(text, str), '%s is not a string' % text
    return text.isalpha()


@staticmethod
def make_show_page_link(page_id, sub_page, text):
    """
        Prepares a link to call the JavaScript method "showSubPage"

        :param page_id: ID of the page to show
        :param sub_page: Sub-URL of the page to show
        :param text: Link text
        :return: The link string
        """
    return (
        '{2}'
        .format(page_id, sub_page, text))


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


def get_listOfReactants(reaction):
    """Get list of reactants of a reaction

    Args:
        reaction (xml.etree.ElementTree.Element): reaction

    Returns:
        xml.etree.ElementTree.Element: list of reactants
    """
    listOfReactants = None
    for e in reaction:
        if e.tag[0] == '{':
            uri, tag = e.tag[1:].split('}')
        else:
            tag = e.tag
        if tag == 'listOfReactants':
            listOfReactants = e
            break
    return listOfReactants


def sampling_freq_to_minimum_duration(ts, desired_length_in_ms=20):
    """Computes the minimum window length that corresponds with the desired length in ms"""
    sr = float(ts['samplerate'])
    window_length = int(float(desired_length_in_ms) / 1000 / (1 / sr))
    return window_length


def fib(n):
    """Fibonacci example function

    Args:
      n (int): integer

    Returns:
      int: n-th Fibonacci number
    """
    assert n > 0
    a, b = 1, 1
    for i in range(n - 1):
        a, b = b, a + b
    return a


def get_dbadmin_commands():
    """Returns a list of available commands for dbadmin

        :returns: a C{list} of available commands
        """
    pass


@conf
def find_msgfmt(conf):
    """
	Detects msgfmt and sets the ``MSGFMT`` variable
	"""
    conf.find_program('msgfmt', var='MSGFMT')


@classmethod
def _loadUserModule(cls, userModule):
    """
        Imports and returns the module object represented by the given module descriptor.

        :type userModule: ModuleDescriptor
        """
    return userModule.load()


def simple(y, x, N, beta, gamma, mu):
    """
    Defines the SIRS simple model.

    :param array y: Individuals at time step x
    :param array x: Time step
    :param int N: Population
    :param float beta: The parameter controlling how often a susceptible-infected contact results in a new infection.
    :param float gamma: The rate an infected recovers and moves into the resistant phase.
    :param float mu: The parameter represents the average death rate

    :returns: S, I, R at time step n
    :rtype: tuple(int/float, int/float, int/float)
    """
    S = -beta * y[0] * y[1] / N + mu * y[2]
    I = beta * y[0] * y[1] / N - gamma * y[1]
    R = gamma * y[1] - mu * y[2]
    return S, I, R


def Creator():
    """ Return the first DCMI Creator element, or an empty string.

        o Permission:  View
        """


@classmethod
def read_chunk(cls, opc_sync: bool, context: str) ->'IoTransferEventArgs':
    """Creates new IoTransferEventArgs of read string

		:param opc_sync: defines if the command is OPC-synchronised
		:param context: SCPI query. It is truncated to maximum of 100 characters.
		:return: IoTransferEventArgs object of a read string operation."""
    return cls(True, opc_sync, None, context)


def form_initialized(obj, event):
    """Due to some events in PloneFormGen, we need to use this event to end the signupsheet configuration"""
    action_adapters = []
    for id in ('registrants', 'manager_notification_mailer'):
        action_adapters.append(id)
    obj.actionAdapter = action_adapters


def datetime_format(value):
    """Validate the correct format of a datetime string and deserialize."""
    from msrest.serialization import Deserializer
    from msrest.exceptions import DeserializationError
    try:
        datetime_obj = Deserializer.deserialize_iso(value)
    except DeserializationError:
        message = 'Argument {} is not a valid ISO-8601 datetime format'
        raise ValueError(message.format(value))
    return datetime_obj


def div(a, b):
    """ Divide two values, ignoring None """
    if a is None:
        if b is None:
            return None
        else:
            return 1 / b
    elif b is None:
        return a
    return a / b


def fabclass_2_umax(fab_class=None):
    """
    Max dimple displacement.

    Returns the maximum displacement for a dimple imperfection on a cylindrical shell. The values are taken from table
    8.4 of EN1993-1-6[1] for a given fabrication quality class, A, B or C.

    Parameters
    ----------
    fab_class : {'fcA', 'fcB', 'fcC'}
        The fabrication quality class.

    Returns
    -------
    float
        u_max / l, where u_max is the maximum deviation and l the dimple's size (circumferencial or meridional)

    References
    ----------
    .. [1] Eurocode 3: Design of steel structures - Part 1-6: Strength and stability of shell structures.
        Brussels: CEN, 2006.

    """
    if fab_class is None:
        fab_class = 'fcA'
    if fab_class is 'fcA':
        u_max = 0.006
    elif fab_class is 'fcB':
        u_max = 0.01
    else:
        u_max = 0.016
    return u_max


@classmethod
def HomogeneousOcean(cls, wind_speed, wind_azimuth, salinity,
    pigment_concentration):
    """Parameterisation for a surface BRDF based on the Ocean BRDF model.

        The parameters are:

        - wind speed (in m/s)
        - azimuth of the wind (in degrees)
        - salinity (in ppt) (set to 34.3ppt if < 0)
        - pigment concentration (in mg/m3)

        """
    return (
        '0 Homogeneous surface\n1 (directional effects)\n6 (Ocean BRDF)\n%f %f %f %f\n'
         % (wind_speed, wind_azimuth, salinity, pigment_concentration))


def list_gen(query, item):
    """查询结果列表生成（每一个列表项为一个相关键值的字符串）

    :param query: 查询语句
    :param item: 包括相关查询查询键值的字典字符串（需要eval进行转换，转换后则包括了obj）
    :return: 查询结果列表
    """
    list = []
    for obj in query:
        dict = eval(item)
        list.append(dict)
    return list


@classmethod
def lat_lng_to_precise_location(cls, latitude, longitude, precision):
    """
        Get location with computed octant and levels.

        Given latitude / longitude and a precision (in a number of bits), return
        a location with computed octant and levels

        Parameters
        ----------
        latitude : float
            Latitude
        longitude : float
            Longitude
        precision : int

        Returns
        -------
        Location
            location with the computed octant and levels
        """
    location = cls(latitude=latitude, longitude=longitude)
    for current_precision in range(3, precision, 2):
        location.compute_level()
    return location


def restexpose(func):
    """
    Decorate a function to clearly mark it as an exposed REST method
    """
    setattr(func, 'restexposed', True)
    setattr(func, 'exposed', False)
    return func


def readline(length=None):
    """Read one entire line from the file.
        """


def _calc_mean_confining_stress(sigma_v0, K0):
    """
    Calculate mean (of three directions) confining stress.

    Parameters
    ----------
    sigma_v0 : numpy.ndarray
        (Effective) vertical stress of each layer. Unit: Pa.
    K0 : numpy.ndarray
        Lateral stress coefficient of each layer. Unit: 1.

    Returns
    -------
    sigma_m0 : numpy.ndarray
        Mean effective confining stress (of three directions). Unit: Pa.
    """
    sigma_m0 = (2 * K0 + 1) / 3.0 * sigma_v0
    return sigma_m0


@staticmethod
def user_parse(data):
    """Parse information from provider."""
    resp = data.get('response', [{}])[0]
    yield 'id', resp.get('id')
    yield 'first_name', resp.get('first_name')
    yield 'last_name', resp.get('last_name')
    yield 'username', resp.get('nickname')
    yield 'city', resp.get('city')
    yield 'country', resp.get('country')
    yield 'picture', resp.get('photo_big')


def extract_header(msg_or_header):
    """Given a message or header, return the header."""
    if not msg_or_header:
        return {}
    try:
        h = msg_or_header['header']
    except KeyError:
        try:
            h = msg_or_header['msg_id']
        except KeyError:
            raise
        else:
            h = msg_or_header
    if not isinstance(h, dict):
        h = dict(h)
    return h


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

        :param PaperDocSlackShareDetails val:
        :rtype: EventDetails
        """
    return cls('paper_doc_slack_share_details', val)


def psi_K_HSO4_OH_HMW84(T, P):
    """c-a-a': potassium bisulfate hydroxide [HMW84]."""
    psi = 0.0
    valid = T == 298.15
    return psi, valid


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

        :param FolderOverviewItemUnpinnedDetails val:
        :rtype: EventDetails
        """
    return cls('folder_overview_item_unpinned_details', val)


@classmethod
def cross(cls, u, v):
    """
        Calculate the cross product of two given vectors
        """
    return [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[
        1] - u[1] * v[0]]


def geo_cellsize(raster_geo, x_only=False):
    """Return pixel width & pixel height of geo-transform

    Parameters
    ----------
    raster_geo : tuple :class:`gdal.Geotransform` object
    x_only : bool, optional
        If True, only return cell width (the default is False).

    Returns
    -------
        tuple: tuple containing the x or x and y cell size
    """
    if x_only:
        return raster_geo[1]
    else:
        return raster_geo[1], raster_geo[5]


def _check_valid(key, val, valid):
    """Helper to check valid options"""
    if val not in valid:
        raise ValueError('%s must be one of %s, not "%s"' % (key, valid, val))


@staticmethod
def combine_adjacent_lines(line_numbers):
    """
        Given a sorted collection of line numbers this will
        turn them to strings and combine adjacent values

        [1, 2, 5, 6, 100] -> ["1-2", "5-6", "100"]
        """
    combine_template = '{0}-{1}'
    combined_list = []
    line_numbers.append(None)
    start = line_numbers[0]
    end = None
    for line_number in line_numbers[1:]:
        if (end if end else start) + 1 == line_number:
            end = line_number
        else:
            if end:
                combined_list.append(combine_template.format(start, end))
            else:
                combined_list.append(str(start))
            start = line_number
            end = None
    return combined_list


def get(oid, default=None):
    """ -> the persistent object for OID.

        o Return 'default' if not found.
        """


def clean_address_data(column_one, column_two):
    """Return tuple of cleaned landmark and street address."""
    landmark = column_one.split('\n')[0].strip()
    street_address = column_two.replace('\n(', ' ').rstrip(')').strip()
    street_address = street_address.replace('South', 'S').replace('North', 'N'
        ).replace('East', 'E').replace('West', 'W')
    return landmark, street_address


def set_analog_src(lucid, srcval):
    """Call lucid8824.set_analog_src"""
    lucid.set_analog_src(srcval)


def stamp_iter_range(h5object, start_iter, stop_iter):
    """Mark that the HDF5 object ``h5object`` (dataset or group) contains data from iterations
    start_iter <= n_iter < stop_iter."""
    h5object.attrs['iter_start'] = start_iter
    h5object.attrs['iter_stop'] = stop_iter


def primer_clean(primer):
    """Handle non-IUPAC entries in primers, maps I for inosine to N.

    >>> primer_clean("I")
    'N'

    Inosine is found naturally at the wobble position of tRNA, and can match
    any base. Structurally similar to guanine (G), it preferentially binds
    cytosine (C). It sometimes used in primer design (Ben-Dov et al, 2006),
    where degeneracy N would give similar results.
    """
    return primer.upper().replace('I', 'N')


def unindex(relationship):
    """obtains the token for the relationship and unindexes (calls
        IInjection.unindex_doc)"""


def add_path(G, nodes, t, **attr):
    """Add a path at time t.

            Parameters
            ----------
            G : graph
                A DyNetx graph

            nodes : iterable container
                A container of nodes.

            t : snapshot id (default=None)
                snapshot id

            See Also
            --------
            add_path, add_cycle

            Examples
            --------
            >>> G = dn.DynGraph()
            >>> dn.add_path(G, [0,1,2,3], t=0)
            """
    nlist = list(nodes)
    edges = zip(nlist[:-1], nlist[1:])
    G.add_interactions_from(edges, t, **attr)


def setup_logging(default_level='WARNING'):
    """ Setup logging configuration

    The logging configuration can be overridden with one environment variable:

    ADLFS_LOG_LEVEL (defines logging level)
    """
    import logging
    import os
    import sys
    log_level = os.environ.get('ADLFS_LOG_LEVEL', default_level)
    levels = dict(CRITICAL=logging.CRITICAL, ERROR=logging.ERROR, WARNING=
        logging.WARNING, INFO=logging.INFO, DEBUG=logging.DEBUG)
    if log_level in levels:
        log_level = levels[log_level]
    else:
        sys.exit("invalid ADLFS_LOG_LEVEL '{0}'".format(log_level))
    logging.basicConfig(level=log_level)


def view_toggle():
    """Toggle between sequencer views (sequence, preview, both)

    """
    pass


@staticmethod
def set_time_field():
    """
        sets number mapping values
        :return dictionary:
        """
    return {'type': 'date', 'format': 'dateOptionalTime'}


def convert_time_diff_to_total_milliseconds(sample):
    """ Convert between a time diff and total milliseconds.

    :return: total milliseconds
    :rtype: float
    """
    return sample.total_seconds() * 1000.0 + sample.microseconds / 1000.0


def get_breakpoints(text, min_width, max_width):
    """
    Find where newlines could be added to a string
    but don't bother if the result would be longer than max width
    or shorter than min width
    """
    breakpoints = []
    text = text.replace('\n', ' ')
    words = text.split(' ')
    growing_string = ''
    for word in words:
        growing_string += word + ' '
        if len(growing_string.rstrip()) >= min_width and len(growing_string
            .rstrip()) <= max_width:
            breakpoints.append(len(growing_string.rstrip()))
    return breakpoints


def sorted_activity(activity_pair):
    """Interator over activity pairs sorted by isotope then daughter product."""
    return sorted(activity_pair, key=lambda x: (x[0].isotope, x[0].daughter))


def smoothscroll():
    """Smooth scroll to make editable file visible

    """
    pass


def KK_RC2(w, Rs, R_values, t_values):
    """
    Kramers-Kronig Function: -RC-

    Kristian B. Knudsen (kknu@berkeley.edu / kristianbknudsen@gmail.com)
    """
    return Rs + R_values[0] / (1 + w * 1.0j * t_values[0]) + R_values[1] / (
        1 + w * 1.0j * t_values[1])


def check_sanic_motor_installed():
    """Check sanic_motor installed, if absent - raises error.
    """
    try:
        import sanic_motor
    except ImportError:
        msg = (
            'Please install Mongo dependencies: pip install sanic_session[mongo]'
            )
        raise RuntimeError(msg)


def _idealized_arc_curve(n, x):
    """
    Returns the value at x for the parabola of width n and height n / 2.
    Formula taken from https://www.desmos.com/calculator/awtnrxh6rk.

    Parameters
    ----------
    n: Length of the time series to calculate the parabola for.
    x: location to compute the parabola value at.
    """
    height = n / 2
    width = n
    c = width / 2
    b = height
    a = height / (width / 2) ** 2
    y = -(a * (x - c) ** 2) + b
    return y


def dgl_subgraph(*data, **kwargs):
    """This operator constructs an induced subgraph for
    a given set of vertices from a graph. The operator accepts multiple
    sets of vertices as input. For each set of vertices, it returns a pair
    of CSR matrices if return_mapping is True: the first matrix contains edges
    with new edge Ids, the second matrix contains edges with the original
    edge Ids.

    Example:

       .. code:: python

         x=[[1, 0, 0, 2],
           [3, 0, 4, 0],
           [0, 5, 0, 0],
           [0, 6, 7, 0]]
         v = [0, 1, 2]
         dgl_subgraph(x, v, return_mapping=True) =
           [[1, 0, 0],
            [2, 0, 3],
            [0, 4, 0]],
           [[1, 0, 0],
            [3, 0, 4],
            [0, 5, 0]]

    Defined in src/operator/contrib/dgl_graph.cc:L1140

    Parameters
    ----------
    graph : NDArray
        Input graph where we sample vertices.
    data : NDArray[]
        The input arrays that include data arrays and states.
    return_mapping : boolean, required
        Return mapping of vid and eid between the subgraph and the parent graph.

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

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


def correct_byteorder(ptype, byteorder):
    """Fix the byteorder depending on the PyTables types."""
    if ptype in ['string', 'bool', 'int8', 'uint8', 'object']:
        return 'irrelevant'
    else:
        return byteorder


def last(seq):
    """Returns the last item in the sequence or iterator.
       Returns None if the sequence is empty."""
    try:
        return seq[-1]
    except IndexError:
        return None
    except TypeError:
        item = None
        for item in seq:
            pass
        return item


@classmethod
def read(cls, source, *args, **kwargs):
    """Read data into a `TimeSeries`

        Arguments and keywords depend on the output format, see the
        online documentation for full details for each format, the parameters
        below are common to most formats.

        Parameters
        ----------
        source : `str`, `list`
            Source of data, any of the following:

            - `str` path of single data file,
            - `str` path of LAL-format cache file,
            - `list` of paths.

        name : `str`, `~gwpy.detector.Channel`
            the name of the channel to read, or a `Channel` object.

        start : `~gwpy.time.LIGOTimeGPS`, `float`, `str`, optional
            GPS start time of required data, defaults to start of data found;
            any input parseable by `~gwpy.time.to_gps` is fine

        end : `~gwpy.time.LIGOTimeGPS`, `float`, `str`, optional
            GPS end time of required data, defaults to end of data found;
            any input parseable by `~gwpy.time.to_gps` is fine

        format : `str`, optional
            source format identifier. If not given, the format will be
            detected if possible. See below for list of acceptable
            formats.

        nproc : `int`, optional
            number of parallel processes to use, serial process by
            default.

        pad : `float`, optional
            value with which to fill gaps in the source data,
            by default gaps will result in a `ValueError`.

        Raises
        ------
        IndexError
            if ``source`` is an empty list

        Notes
        -----"""
    from .io.core import read as timeseries_reader
    return timeseries_reader(cls, source, *args, **kwargs)


def new(name: str=''):
    """Create new mask

    :param name: Name, Name of new mask
    :type name: str
    """
    pass


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

    The ".dev0" means dirty.

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


@classmethod
def configurable_base(cls):
    """Returns the base class of a configurable hierarchy.

        This will normally return the class in which it is defined.
        (which is *not* necessarily the same as the cls classmethod parameter).
        """
    raise NotImplementedError()


@classmethod
def setLibrarySearchPath(cls, searchPath):
    """Set the path to a directory that should be used to search for the native library
        before trying to load it from the default (OS specific) lookup path.
        """
    cls._sharedLibrarySearchPath = searchPath


def print_qm_kind(int_list, element_name, fname, mode='w'):
    """
    Writes the list to the given file, formatted for CP2K to read as qm atom indices.

    @param int_list: The list to write.
    @param element_name: element type to designate
    @param fname: The location of the file to write.
    @param mode: default is to write to a new file. Use option to designate to append to existing file.
    """
    with open(fname, mode) as m_file:
        m_file.write('    &QM_KIND {}\n'.format(element_name))
        m_file.write('        MM_INDEX {}\n'.format(' '.join(map(str,
            int_list))))
        m_file.write('    &END QM_KIND\n')
    if mode == 'w':
        print('Wrote file: {}'.format(fname))


def proven():
    """Generate a method precedence level for proven methods. Proven methods
    should be such that any applicable one gives the same result, and in case
    of ambiguity no particular proven method is preferred.

    Returns:
        int: Precedence level.
    """
    global _proven_level
    _proven_level += 1
    return _proven_level


def ensure_list(value, attr):
    """raise an error if `value` is not a list"""
    from distutils.errors import DistutilsSetupError
    if not isinstance(value, list):
        raise DistutilsSetupError('{} must be a list, got {}'.format(attr,
            value.__class__))


def _build_key(host, port):
    """Build a key based upon the hostname or address supplied."""
    return '%s:%s' % (host, port)


def bin2int(buf):
    """the reverse of int2bin, convert a binary buffer to an integer"""
    x = 0
    for b in bytearray(buf):
        x <<= 8
        x |= b
    return x


@staticmethod
def join_i3_name(number, plain_name):
    """Return an i3_name given a number and a plain_name"""
    return '{}:{}'.format(number, plain_name)


def printWaitBar(i, total, prefix='', suffix='', decimals=1, length=100,
    fill='█'):
    """
    This function will print a waitbar in the console

    Variables:

    i -- Iteration number
    total -- Total iterations
    fronttext -- Name in front of bar
    prefix -- Name after bar
    suffix -- Decimals of percentage
    length -- width of the waitbar
    fill -- bar fill
    """
    import sys
    import os
    if os.name == 'posix' and total == 0:
        total = 0.0001
    percent = ('{0:.' + str(decimals) + 'f}').format(100 * (i / float(total)))
    filled = int(length * i // total)
    bar = fill * filled + '-' * (length - filled)
    sys.stdout.write('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix))
    sys.stdout.flush()
    if i == total:
        print()


@classmethod
def find(cls, *args, **kwargs):
    """Same as ``collection.find``, return model object instead of simple dict."""
    return cls.from_cursor(cls.collection.find(*args, **kwargs))


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)


@staticmethod
def _sanitise_label(label):
    """Implement label hacks: Hide trailing @, remove label with leading @
        """
    import re
    if re.match('^@.*$', label):
        return None
    else:
        return re.sub('@+$', '', label)


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


def userpref_autoexec_path_remove(index: int=0):
    """Remove path to exclude from autoexecution

    :param index: Index
    :type index: int
    """
    pass


def force_single_line_js(js):
    """Force Javascript to a single line, even if need to add semicolon."""
    return ';'.join(js.splitlines()) if len(js.splitlines()) > 1 else js


@staticmethod
def get_compatable_connection_types():
    """
        This is needed so the build system knows which
        connection types this connection is compatable.
        return::['str'] A list of the compatable socket types.
        """
    return []


def connection_adapter(cls, edges, pageInfo):
    """Adapter for creating Connection instances"""
    return cls(edges=edges, page_info=pageInfo)


def default_parent_inspection(element, parent):
    """
    Check if the element bases has the specified parent
    :param element: the element to check
    :param parent: the expected parent
    :return: the check result
    """
    return parent in element.__bases__


def plot_shapefun(pos, out, mode):
    """
  Creates a simple matplotlib image to show the shapefunctions given it's positions in the unit cell, the atoms's vertices in `ut` and the plotting mode

  :author: Philipp Ruessmann

  :param pos: positions of the centers of the cells
  :param verts: array of vertices of the shapefunction (outlines of shapes)
  :param mode: 'all' or 'single' determines whether or not all shapes are combined in a single figure or plotted as individual figures

  :returns ax: return the axis in which the plot was done (useful to pass to 'change_zoom' and 'zoom_in' functions of this module
  """
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from numpy import array, shape
    if mode == 'all':
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')
    Natm = len(pos)
    for j in range(1, Natm + 1):
        if mode == 'single':
            fig = plt.figure()
            ax = fig.add_subplot(111, projection='3d')
        for i in list(out.keys()):
            if i[0] == j:
                linecolor = 'r'
            if j in [2, 3, 6, 7]:
                linecolor = 'b'
            d = array(out[i])
            if len(shape(pos)) > 1 and len(pos) > 2 and mode == 'all':
                dx, dy, dz = pos[j - 1, 0], pos[j - 1, 1], pos[j - 1, 2]
            else:
                dx, dy, dz = 0, 0, 0
            ax.plot(d[:, (0)] + dx, d[:, (1)] + dy, d[:, (2)] + dz, linecolor)
    if mode == 'all':
        xy_scale = 1
        scale = 1
        ax.set_xlim(-scale * xy_scale, scale * xy_scale)
        ax.set_ylim(-scale * xy_scale, scale * xy_scale)
        ax.set_zlim(-scale, scale)
    return ax


def compact_values(collected_forms):
    """ Takes the input from the first form in a process and compacts it into
    the first set of values for _the state_ that will be used in conditionals
    or jinja templates"""
    context = dict()
    for form in collected_forms:
        form_dict = dict()
        for name, input in form['inputs']['items'].items():
            form_dict[name] = input['value_caption']
        context[form['ref']] = form_dict
    return context


@staticmethod
def get_subtype(object_dictionary):
    """
        Given the hash representation of a subtype of this class,
        use the info in the hash to return the class of the subtype.
        """
    type = object_dictionary['type']
    if type == 'DomainNameServer':
        return 'DhcpDnsOption'
    if type == 'SearchDomain':
        return 'DhcpSearchDomainOption'
    else:
        return 'DhcpOption'


def check_depth(a, deep_level, ifnotraise=True):
    """Check if input list has desired level of nested lists"""
    MAX_ITER = 10
    lev = 0
    while lev < MAX_ITER:
        try:
            a = a[0]
            lev += 1
        except:
            break
    if not lev == deep_level:
        if ifnotraise:
            raise Exception(
                'Wrong input nested level. Excepted %i, got %i\n %s' % (
                deep_level, lev, a))
        else:
            return False
    return True


def merge_label_map(label_map, label_equivalent):
    """
    A function return label_map after merge all label equivalent

    @param:
        - label_map (before merge label)
        - label_equivalent (a collection key label has merged)
    @return:
        - label_map after merge label
    """
    for row in range(len(label_map)):
        for col in range(len(label_map[row])):
            if label_map[row][col].label in label_equivalent.keys():
                label_map[row][col].label = min(list(label_equivalent[
                    label_map[row][col].label]))
    return label_map


def p_expr_group(p):
    """expr : LPAREN expr RPAREN"""
    p[0] = p[2]


def setup_maxbolthist(ax):
    """Builds the simulation velocity histogram
    visualisation pane.

    Parameters
    ----------
    ax: Axes object
        The axes position that the pane should be placed in.
    """
    ax.step([0], [0], color='#34a5daff')
    ax.set_ylabel('PDF', fontsize=16)
    ax.set_xlabel('Velocity/ms$^{-1}$', fontsize=16)


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

        :param SharedLinkMetadata val:
        :rtype: SharedLinkAlreadyExistsMetadata
        """
    return cls('metadata', val)


def get_prefetcher_setup(job):
    """
    Return the proper setup for the Prefetcher.
    Prefetcher is a tool used with the Event Streaming Service.

    :param job: job object.
    :return: setup string for the Prefetcher command.
    """
    return ''


def _as_quantity(a):
    """Convert argument to a Quantity (or raise NotImplementedError)."""
    from astropy.units import Quantity
    try:
        return Quantity(a, copy=False, subok=True)
    except Exception:
        raise NotImplementedError


def _ensure_unix_line_endings(path):
    """Replace windows line endings with Unix.  Return path to modified file."""
    out_path = path + '_unix'
    with open(path) as inputfile:
        with open(out_path, 'w') as outputfile:
            for line in inputfile:
                outputfile.write(line.replace('\r\n', '\n'))
    return out_path


def set_lower_case_keywords(lower_case):
    """
    Set the lower_case_keywords flags which is used to control the case of the
    proposed cobol_keywords

    :param lower_case: True to propose lower case keywords and False to
        propose upper case KEYWORDS
    """
    global lower_case_keywords
    lower_case_keywords = lower_case


def uniq(seq, idfun=lambda x: x):
    """
    Order-preserving unique function.
    """
    seen = {}
    result = []
    for item in seq:
        marker = idfun(item)
        if marker in seen:
            continue
        seen[marker] = 1
        result.append(item)
    return result


def unique(L):
    """Return a list of unhashable elements in s, but without duplicates.
    [[1, 2], [2, 3], [1, 2]] >>> [[1, 2], [2, 3]]"""
    nDupli = 0
    nZcolinear = 0
    L.sort()
    last = L[-1]
    for i in range(len(L) - 2, -1, -1):
        if last[:2] == L[i][:2]:
            if last[2] == L[i][2]:
                nDupli += 1
            else:
                nZcolinear += 1
            del L[i]
        else:
            last = L[i]
    return nDupli, nZcolinear


@staticmethod
def msd_ratio_(msd_ea, n1, n2):
    """
        Ratio of the ensemble averaged mean squared displacements.

        .. math::
            \\langle r^2 \\rangle_{n_1, n_2} = \\frac{\\langle r^2 \\rangle_{n_1 }}
            {\\langle r^2 \\rangle_{n_2 }} - \\frac{n_1}{n_2}

        with

        .. math::
            n_1 < n_2

        :return msd_ratio:
        """
    msd_ratio = msd_ea[n1] / msd_ea[n2] - n1 / n2
    return msd_ratio


def convert_bool(condition):
    """True = 1, False = 0"""
    if condition:
        return 1
    else:
        return 0


def truncate(s, size=80, tail='...'):
    """
    >>> truncate('abc'*20, 10, '...')
    'abcabca...'

    >>> truncate ('abc'*20, 2, '...')
    '..'

    >>> truncate('abc'*20, 0, '...')
    ''

    >>> truncate('abc'*20, 60, '...')
    'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc'

    >>> truncate('abc'*20, 70, '...')
    'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc'

    """
    s_size = len(s)
    if s_size <= size:
        return s
    tail_size = len(tail)
    if tail_size > size:
        return tail[:size]
    pos_max = size - tail_size
    return s[:pos_max] + tail


def make_safe_label(label):
    """Avoid name clashes with GraphViz reserved words such as 'graph'."""
    unsafe_words = 'digraph', 'graph', 'cluster', 'subgraph'
    out = label
    for word in unsafe_words:
        out = out.replace(word, '%sX' % word)
    return out.replace('.', '__').replace('*', '')


@classmethod
def get(cls, pk):
    """
        Select entry by its primary key. It must be define as
        __primary_key__ (string)
        """
    return cls._query(cls).filter(getattr(cls, cls.__primary_key__) == pk
        ).first()


def calc_noise_threshold(imax, noise_dr):
    """
    Calculates the noise threshold
    imax (float): the maximum in the input image
    noise_dr (float): the noise dynamic range to calculate the threshold for
    returns (float): the noise threshold
    """
    noise_threshold = imax / noise_dr
    return noise_threshold


def create(request):
    """called from the script creating all downloads."""


@classmethod
def from_scene_ds(cls, ds_obj):
    """传入 Scene 的 datasource 构造一个 DataSource"""
    return cls(ds_type=ds_obj.data_source_type, ds_dsn=ds_obj.
        data_source_database.dsn, table=ds_obj.data_source_name)


@classmethod
def get_accept(cls):
    """ Load the framework-specific Accept header """
    raise NotImplementedError


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 PMID(val):
    """PubMedUniqueIdentifier"""
    return 'PMID:{}'.format(val[0])


def prettyTime(diffInSecs):
    """Returns a human-readable string from time-difference (in seconds).
    Uses absolute value of time-diff, and thus does not care about before/after.

    diffInSecs - Timedifference in seconds.
    """
    intervals = [('minute', 60), ('hour', 60), ('day', 24), ('week', 7), (
        'month', 4.34811904762), ('year', 12)]
    unit, number = 'second', abs(diffInSecs)
    for new_unit, ratio in intervals:
        new_number = float(number) / ratio
        if new_number < 2:
            break
        unit, number = new_unit, new_number
    shown_num = int(number)
    return '{} {}'.format(shown_num, unit + ('' if shown_num == 1 else 's'))


def load_gffutils_db(f):
    """
    Load database for gffutils.

    Parameters
    ----------
    f : str
        Path to database.

    Returns
    -------
    db : gffutils.FeatureDB
        gffutils feature database.

    """
    import gffutils
    db = gffutils.FeatureDB(f, keep_order=True)
    return db


def tonumber(test, alttext=None):
    """
    Checks if something is a number or matches alttext

    Parameters
    ----------
    test : str
        Text to test.
    alttext : str, optional
        Alternate text to test. The default is None.

    Returns
    -------
    str or int or float
        Returns a lower case verion of alttext, or a number.

    """
    if alttext is not None and test.lower() == alttext.lower():
        return test.lower()
    if not test.replace('.', '', 1).isdigit():
        return -999
    if '.' in test:
        return float(test)
    return int(test)


def get_key(data, search_key):
    """Goes through a template looking for a key.

    :param data: The template to traverse.
    :param search_key: The key to look for.
    :return The key value.
    """
    return_value = None
    found = False
    if isinstance(data, dict):
        bucket = []
        for key, value in data.iteritems():
            if key == search_key:
                return_value = value
                found = True
                break
            else:
                bucket.append(value)
        if bucket and not found:
            for element in bucket:
                if isinstance(element, list):
                    for element in element:
                        bucket.append(element)
                elif isinstance(element, dict):
                    for key, value in element.iteritems():
                        if key == search_key:
                            return_value = value
                            found = True
                            break
                        else:
                            bucket.append(value)
                if found:
                    break
    return return_value


def hide_render_clear():
    """Reveal the render object by setting the hide render flag

    """
    pass


def keyframe_delete():
    """Delete a keyframe from selected tracks at current frame

    """
    pass


def _parse_short_form(comment, globalns, localns):
    """Return the hints from the comment.

    Parses the left-hand side of a type comment into a list of type objects.
    (e.g. everything to the left of "->").

    Returns:
        A list of types evaluated from the type comment in the given global
        name space.
    """
    if '(...)' in comment:
        return ()
    comment = comment.replace('*', '')
    hints = eval(comment, globalns, localns)
    if not isinstance(hints, tuple):
        hints = hints,
    return hints


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 simple_start_decorator_with_settings(cls, **settings):
    """
        Decorator creator with settings.

        Resulting decorator turns function into the simple server start method.
        It initializes logging and ConfigLoader in the soft-mode,
        than initializes the class instance, runs this function and starts the server.

        :param settings:
        Settings used for the server initialization
        :return:
        The decorator to the function to start the server

        Example usage:
        @ApplicationBase.simple_start_decorator_with_settings(port=8123, static_files='static', debug=True)
        def my_func(server_app):
            server_app.logger.debug(f"{self.name}: I am going to be run")

        """
    return lambda func: cls.simple_start_decorator(func, **settings)


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

        :param file_properties.LookUpPropertiesError val:
        :rtype: AlphaGetMetadataError
        """
    return cls('properties_error', val)


@classmethod
def set_login_cookie(cls, handler, user_id=None):
    """Call this on handlers to set the login cookie for success"""
    cookie_options = handler.settings.get('cookie_options', {})
    cookie_options.setdefault('httponly', True)
    if handler.settings.get('secure_cookie', handler.request.protocol ==
        'https'):
        cookie_options.setdefault('secure', True)
    handler.set_secure_cookie(handler.cookie_name, user_id, **cookie_options)
    return user_id


def device_from_request(request):
    """
    Determine's the device name from the request by first looking for an
    overridding cookie, and if not found then matching the user agent.
    Used at both the template level for choosing the template to load and
    also at the cache level as a cache key prefix.
    """
    from shuyucms.conf import settings
    try:
        user_agent = request.META['HTTP_USER_AGENT'].lower()
    except KeyError:
        pass
    else:
        try:
            user_agent = user_agent.decode('utf-8')
        except AttributeError:
            pass
        for device, ua_strings in settings.DEVICE_USER_AGENTS:
            for ua_string in ua_strings:
                if ua_string.lower() in user_agent:
                    return device
    return ''


def load_twisted_conch_ssh_transport(finder, module):
    """the twisted.conch.ssh.transport module uses __import__ builtin to
       dynamically load different ciphers at runtime."""
    finder.IncludePackage('Crypto.Cipher')


def _exit_gracefully(signum, _):
    """
    Called when a signal is caught and marks exiting variable True
    """
    global _up
    _up = False


@classmethod
def from_simple_slug(cls, slug):
    """Return an Target from a slug containing user and project."""
    parts = slug.rsplit('/', 1)
    assert len(parts) == 2
    assert '/' not in parts[1]
    obj = cls(*parts)
    return obj


def _group_arguments(tokens, predicate_positions, boundaries, labels):
    """
    Groups words pertaining to each argument and returns a dictionary for
    each predicate.
    """
    arg_structs = []
    for item in zip(predicate_positions, boundaries, labels):
        predicate_position, pred_boundaries, pred_labels = item
        structure = {}
        for token, boundary_tag in zip(tokens, pred_boundaries):
            if boundary_tag == 'O':
                continue
            elif boundary_tag == 'B':
                argument_tokens = [token]
            elif boundary_tag == 'I':
                argument_tokens.append(token)
            elif boundary_tag == 'E':
                argument_tokens.append(token)
                tag = pred_labels.pop(0)
                structure[tag] = argument_tokens
            else:
                tag = pred_labels.pop(0)
                structure[tag] = [token]
        predicate = tokens[predicate_position]
        arg_structs.append((predicate, structure))
    return arg_structs


def with_request(method):
    """
    Decorator to enable the request to be passed as the first argument.
    """
    method.with_request = True
    return method


def create_block_1_response(request):
    """Generate a block 1 response for a specific request.

    Args:
        request (piccata.message.Message): A request received.

    Returns:
        piccata.message.Message: A generated response.
    """
    raise NotImplemented('Feature is not yet implemented')


@staticmethod
def _get_wwn(controllerport):
    """Return the WWN value of the controller port.

        Usually the WWN key in the controller port is wwn or WWN, but there
        are cases where the backend returns wWW, so we have to check all the
        keys.
        """
    for key, value in controllerport.items():
        if key.lower() == 'wwn':
            return value
    return None


def get_frame_planecount(frame):
    """
    Gets the planecount (color channel count) of a video frame.

    Parameters
    ----------
    - frame : numpy array

        A frame extracted by `cv2.VideoCapture().read()`.

    Returns
    -------
    - {3, 1}

        The planecount of the input frame.
    """
    import numpy as np
    return 3 if len(np.array(frame).shape) == 3 else 1


def reorder_dataframe_columns(dataframe, cols, front=True):
    """Takes a dataframe and a subsequence of its columns,
       returns dataframe with seq as first columns if "front" is True,
       and seq as last columns if "front" is False.
       taken from https://stackoverflow.com/questions/12329853/how-to-rearrange-pandas-column-sequence

    Parameters
    ----------
    df : pd.DataFrame
        original dataframe
    cols : list
        List of cols to put first or last.
    front : bool
        Whether to put the columns at the front or the back.

    Usage
    -----
    df = reorder_dataframe_columns(df, ["TMD_start", "database", "whatever other col I want first"])
    """
    for col in cols:
        if col not in dataframe.columns:
            cols.remove(col)
    cols_to_place_first = cols[:]
    for existing_col in dataframe.columns:
        if existing_col not in cols_to_place_first:
            if front:
                cols_to_place_first.append(existing_col)
            else:
                cols_to_place_first.insert(0, existing_col)
    return dataframe[cols_to_place_first]


def _vcf_is_maf(variant_file):
    """Retrun True if variant_file given is in .maf format
    """
    return '.maf' in variant_file.lower()


def read_zip(apath, fname, encoding='utf-8', errors='ignore', process_line=None
    ):
    """Read lines from a file in zip archive.

    :param fname: a name of the file in the archive
    :param process_line: a function that will be invoked to process each file's
                         line. If its result is a list, then it will be
                         returned by lines
    :type process_line: callable
    """
    from zipfile import ZipFile
    with ZipFile(apath) as a:
        with a.open(fname) as f:
            for line in f:
                line = line.decode(encoding=encoding, errors=errors)
                if process_line:
                    line = process_line(line)
                    if isinstance(line, list):
                        for line_ in line:
                            yield line_
                        continue
                yield line


def parse_kwargs(kwargs, *keys, **keyvalues):
    """Return dict with keys from keys|keyvals and values from kwargs|keyvals.

    Existing keys are deleted from kwargs.

    >>> kwargs = {'one': 1, 'two': 2, 'four': 4}
    >>> kwargs2 = parse_kwargs(kwargs, 'two', 'three', four=None, five=5)
    >>> kwargs == {'one': 1}
    True
    >>> kwargs2 == {'two': 2, 'four': 4, 'five': 5}
    True

    """
    result = {}
    for key in keys:
        if key in kwargs:
            result[key] = kwargs[key]
            del kwargs[key]
    for key, value in keyvalues.items():
        if key in kwargs:
            result[key] = kwargs[key]
            del kwargs[key]
        else:
            result[key] = value
    return result


@classmethod
def from_json(cls, p):
    """Builds a `Predicate` from a json object."""
    verb_modifiers_prefix = p.get('verbModifiersPrefix')
    verb_prefix = p.get('verbPrefix')
    verb = p.get('verb')
    verb_suffix = p.get('verbSuffix')
    verb_modifiers_suffix = p.get('verbModifiersSuffix')
    index = p.get('index')
    negated = p.get('negated')
    tense = p.get('tense')
    conjugation = p.get('conjugation')
    auxiliary_qualifier = p.get('auxiliaryQualifier')
    phrasal_particle = p.get('phrasalParticle')
    return cls(verb_modifiers_prefix, verb_prefix, verb, verb_suffix,
        verb_modifiers_suffix, index, negated, tense, conjugation,
        auxiliary_qualifier, phrasal_particle)


def truncate(data, l=20):
    """truncate a string"""
    info = data[:l] + '..' if len(data) > l else data
    return info


def context_set_enum(data_path: str='', value: str=''):
    """Set a context value

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    :param value: Value, Assignment value (as a string)
    :type value: str
    """
    pass


@classmethod
def invoke_ssh_shell(cls, *args, **kwargs):
    """invoke_ssh(arguments..., pty=False, echo=False)

        Star a new shell on a remote server. It first calls
        :meth:`Flow.connect_ssh` using all positional and keyword
        arguments, then calls :meth:`SSHClient.invoke_shell` with the
        pty / echo options.

        Args:
            arguments...: The options for the SSH connection.
            pty(bool): Request a pseudo-terminal from the server.
            echo(bool): Whether to echo read/written data to stdout by default.

        Returns:
            :class:`Flow`: A Flow instance initialised with the SSH channel.
        """
    pty = kwargs.pop('pty', True)
    echo = kwargs.pop('echo', False)
    client = cls.connect_ssh(*args, **kwargs)
    f = client.invoke_shell(pty=pty, echo=echo)
    f.client = client
    return f


def convert_windows_newlines(file_name):
    """
    Helper function for converting windows newlines in a file as a preprocessing step in case users make samplesheet
    in excel.

    Args:
    file_name (str): name of file to convert to unix newlines.

    """
    with open(file_name) as input:
        file_text = input.read()
    file_text = file_text.replace('\r', '\n')
    with open(file_name, 'w') as output:
        output.write(file_text)


def vertex_color_invert():
    """Invert RGB values

    """
    pass


def delete_site():
    """Remove the local site from the publication. No local
        services must be registered on the site for this to be
        successful.

        It raises ``ValueError`` in case of error.
        """


@classmethod
def version_promote(cls, options, timeout=600):
    """Promotes content-view version to next env."""
    cls.command_sub = 'version promote'
    return cls.execute(cls._construct_command(options), ignore_stderr=True,
        timeout=timeout)


def window(theWhere, theX, theY, theWidth, theHeight, theTitle):
    """
	Display a window (a block with a title and a body).

	Parameters
	----------
	theWhere: np.ndarray
		image/frame where the component should be rendered.
	theX: int
		position X where the component should be placed.
	theY: int
		position Y where the component should be placed.
	theWidth: int
		width of the window.
	theHeight: int
		height of the window.
	theTitle: str
		text displayed as the title of the window.

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


def page(ents, current=1, per=50):
    """
Takes a list of entities and drops all from a list but the current page.
Returns a tuple that has the entities and also a page total so it may be
returned to the client.
"""
    first = (current - 1) * per
    last = current * per
    if not last:
        last = 1
    total = len(ents) / per
    total = total + 1 if len(ents) % per else 0
    return ents[first:last], total


@classmethod
def create(cls, longitude, latitude, member):
    """
        Create a new Point instance

        Args:

            longitude(float): the point's longitude

            latitude(float): the point's latitude

            member(string): member
        """
    cls.redis_store.geoadd(cls.__key__, longitude, latitude, member)
    return cls(longitude, latitude, member)


@classmethod
def reload_from_file(cls, env_path: str='.env', override=False):
    """Re-assign class variables using .env config file"""
    import dotenv
    dotenv.load_dotenv(dotenv_path=env_path, override=override)
    cls.reload()


def is_rewrite_name(dirname):
    """ template directory? (default: +package+)"""


def p_annotation(parser):
    """
    annotation  : textbound
                | event
                | modifier
                | equiv
                | relation
                | comment
    """
    parser[0] = parser[1]
    return parser


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

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

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


@classmethod
def enable_all_colors(cls):
    """Enable all colors. Strips any color tags or codes."""
    cls.DISABLE_COLORS = False


def endNumber():
    """Give the end **number** of the batch, which is 1 more than the
        final index."""


def truncate_string_from_end(string: str, max_len: int) ->str:
    """If the string len is below the max_len, the function returns the same string.
	If the string is above the max len, the function returns only the last max_len characters plus '...' at the beginning."""
    if len(string) <= max_len:
        return string
    return f'Last {max_len} chars: "...{string[-max_len:]}"'


@staticmethod
def parse_number(value):
    """Parse and return number (string, float or int) as int or float"""
    value_float = float(value)
    if value_float.is_integer():
        return int(value_float)
    else:
        return value_float


def is_ndarray(array):
    """Check if array is a ndarray."""
    import numpy as np
    return isinstance(array, np.ndarray) or hasattr(array, '__array__')


def plot_fleur_scf_wc(nodes, labels=None):
    """
    This methods takes an AiiDA output parameter node or a list from a scf workchain and
    plots number of iteration over distance and total energy
    """
    from masci_tools.vis.plot_methods import plot_convergence_results_m
    if labels is None:
        labels = []
    if isinstance(nodes, list):
        if len(nodes) >= 2:
            pass
        else:
            nodes = [nodes[0]]
    else:
        nodes = [nodes]
    iterations = []
    distance_all_n = []
    total_energy_n = []
    modes = []
    for node in nodes:
        iteration = []
        output_d = node.get_dict()
        total_energy = output_d.get('total_energy_all')
        distance_all = output_d.get('distance_charge_all')
        iteration_total = output_d.get('iterations_total')
        mode = output_d.get('conv_mode')
        for i in range(1, len(total_energy) + 1):
            iteration.append(iteration_total - len(total_energy) + i)
        iterations.append(iteration)
        distance_all_n.append(distance_all)
        total_energy_n.append(total_energy)
        modes.append(mode)
    if labels:
        plot_convergence_results_m(distance_all_n, total_energy_n,
            iterations, plot_labels=labels, modes=modes)
    else:
        plot_convergence_results_m(distance_all_n, total_energy_n,
            iterations, modes=modes)


def _check_biomart_response(response):
    """
    Return True if the response doesn't look like an query ERROR or 404 page.

    >>> _check_biomart_response('')
    False
    >>> _check_biomart_response('<html>')
    False
    >>> _check_biomart_response('Query ERROR: caught BioMart::Exception')
    False
    >>> _check_biomart_response('ENSG00000107643	ENST00000432379	48306655')
    True
    """
    response = response.strip()
    if response.startswith('<html') or response.startswith('Query ERROR:'
        ) or not response:
        return False
    return True


def fixpath(p):
    """This function is required because if we need to pass a path to something like tarfile,
        we cannot overwrite the function to fix the path, so we need to expose it somehow."""
    return p


def maximum_flow(graph, source, sink, caps=None):
    """
    Find a maximum flow and minimum cut of a directed graph by the Edmonds-Karp algorithm.

    @type graph: digraph
    @param graph: Graph

    @type source: node
    @param source: Source of the flow

    @type sink: node
    @param sink: Sink of the flow

    @type caps: dictionary
    @param caps: Dictionary specifying a maximum capacity for each edge. If not given, the weight of the edge
    will be used as its capacity. Otherwise, for each edge (a,b), caps[(a,b)] should be given.

    @rtype: tuple
    @return: A tuple containing two dictionaries
        1. contains the flow through each edge for a maximal flow through the graph
        2. contains to which component of a minimum cut each node belongs
    """
    if caps == None:
        caps = {}
        for edge in graph.edges():
            caps[edge] = graph.edge_weight((edge[0], edge[1]))
    f = {}.fromkeys(graph.edges(), 0)
    label = {}.fromkeys(graph.nodes(), [])
    label[source] = ['-', float('Inf')]
    u = {}.fromkeys(graph.nodes(), False)
    d = {}.fromkeys(graph.nodes(), float('Inf'))
    q = [source]
    finished = False
    while not finished:
        for i in range(len(q)):
            if not u[q[i]]:
                v = q.pop(i)
                break
        for w in graph.neighbors(v):
            if label[w] == [] and f[v, w] < caps[v, w]:
                d[w] = min(caps[v, w] - f[v, w], d[v])
                label[w] = [v, '+', d[w]]
                q.append(w)
        for w in graph.incidents(v):
            if label[w] == [] and f[w, v] > 0:
                d[w] = min(f[w, v], d[v])
                label[w] = [v, '-', d[w]]
                q.append(w)
        u[v] = True
        if label[sink] != []:
            delta = label[sink][-1]
            w = sink
            while w != source:
                v = label[w][0]
                if label[w][1] == '-':
                    f[w, v] = f[w, v] - delta
                else:
                    f[v, w] = f[v, w] + delta
                w = v
            label = {}.fromkeys(graph.nodes(), [])
            label[source] = ['-', float('Inf')]
            q = [source]
            u = {}.fromkeys(graph.nodes(), False)
            d = {}.fromkeys(graph.nodes(), float('Inf'))
        finished = True
        for node in graph.nodes():
            if label[node] != [] and u[node] == False:
                finished = False
    cut = {}
    for node in graph.nodes():
        if label[node] == []:
            cut[node] = 1
        else:
            cut[node] = 0
    return f, cut


def read_n_spec_pts(fn):
    """Read number of spectral points from WF / BAMF output"""
    with open(fn, 'r') as fd:
        while True:
            ln = fd.readline()
            tmp = ln.split('The number of spectral points:')
            if len(tmp) > 1:
                return int(tmp[-1])
    raise ValueError('Number of spectral points not found in {}'.format(fn))


def _luminance(color):
    """
    Returns the luminance of a RGB tuple. Uses ITU-R 601-2 luma transform.
    """
    r, g, b = color
    return r * 299 / 1000 + g * 587 / 1000 + b * 114 / 1000


def earth_model():
    """
    Define the constants from the WGS-84 ellipsoidal Earth model.

    Parameters
    ----------
    None

    Returns
    -------
    a : semi-major axis of the Earth ellipsoid model
    f : flattening

    Notes
    -----
    The World Geodetic System (WGS) is a standard for use in cartography, geodesy, and navigation.
    The latest revision is WGS-84.

    """
    a = 6378137.0
    f = 1.0 / 298.257223563
    return a, f


def write_input_original(inputs, full_name):
    """
    Creates an original Starburst99 input file.
    """
    f = open(full_name, 'w')
    NAME = inputs.model_name
    if inputs.fixed_mass:
        ISF = -1
    else:
        ISF = 1
    TOMA = inputs.total_mass / 1000000.0
    SFR = inputs.SFR
    NINTERV = len(inputs.IMF_exp)
    XPONENT = ''
    for i in inputs.IMF_exp:
        XPONENT = XPONENT + ',{0}'.format(i)
    XPONENT = XPONENT[1:]
    XMASLIM = ''
    for i in inputs.IMF_bound:
        XMASLIM = XMASLIM + ',{0}'.format(i)
    XMASLIM = XMASLIM[1:]
    SNCUT = inputs.SN_lo_mass
    BHCUT = inputs.SN_hi_mass
    tracks = ['PadovaOrig', 'PadovaAGB', 'GenevaStd', 'GenevaHigh',
        'Genevav00', 'Genevav40']
    PZ = [0.0004, 0.004, 0.008, 0.02, 0.05]
    GSH = [0.001, 0.004, 0.008, 0.02, 0.04]
    Gv = [0.002, 0.014]
    track_dict = {tracks[0]: {PZ[0]: 31, PZ[1]: 32, PZ[2]: 33, PZ[3]: 34,
        PZ[4]: 35}, tracks[1]: {PZ[0]: 41, PZ[1]: 42, PZ[2]: 43, PZ[3]: 44,
        PZ[4]: 45}, tracks[2]: {GSH[0]: 11, GSH[1]: 12, GSH[2]: 13, GSH[3]:
        14, GSH[4]: 15}, tracks[3]: {GSH[0]: 21, GSH[1]: 22, GSH[2]: 23,
        GSH[3]: 24, GSH[4]: 25}, tracks[4]: {Gv[0]: 52, Gv[1]: 54}, tracks[
        5]: {Gv[0]: 62, Gv[1]: 64}}
    IZ = track_dict[inputs.evolve_track][inputs.metallicity]
    models = {'Evolution': 0, 'Emperical': 1, 'Theoretical': 2, 'Elson': 3}
    IWIND = models[inputs.wind_model]
    if inputs.start_time == 0:
        inputs.start_time = 10000.0
    TIME1 = inputs.start_time / 1000000.0
    if inputs.log_scale:
        JTIME = 1
    else:
        JTIME = 0
    TBIV = inputs.dt / 1000000.0
    ITBIV = inputs.nsteps
    TMAX = inputs.end_time / 1000000.0
    grids = {'Full_Isochrone': 3, 'Isochrone_Large': 2, 'Large': 1, 'Small': 0}
    JMG = grids[inputs.mass_grid]
    if inputs.mass_track[0] == 0:
        LMIN = 0
    else:
        LMIN = '{0},{1}'.format(inputs.mass_track[0], inputs.mass_track[1])
    TDEL = inputs.spec_dt / 1000000.0
    models = {'Planck': 1, 'Lejeune': 2, 'Lejuene-Schmutz': 3,
        'Lejeune-Hiller': 4, 'Pauldrach-Hiller': 5}
    IATMOS = models[inputs.low_res_spec]
    Zs = {(0.001): 1, (0.008): 2, (0.02): 3, (0.04): 4}
    ILIB = Zs[inputs.high_res_spec_Z]
    if inputs.UV_line_lib == 'Solar':
        ILINE = 1
    else:
        ILINE = 2
    if inputs.RGS_abund:
        moop = 0
    else:
        moop = 1
    IVT = '{0},{1}'.format(inputs.RGS_turb_vel, moop)
    IO1 = 1 if inputs.outputs['QUANTA'] else -1
    IO2 = 1 if inputs.outputs['SNR'] else -1
    IO3 = 1 if inputs.outputs['HRD'] else -1
    IO4 = 1 if inputs.outputs['POWER'] else -1
    IO5 = 1 if inputs.outputs['SP'] else -1
    IO6 = 1 if inputs.outputs['YIELDS'] else -1
    IO7 = 1 if inputs.outputs['SPECTRUM'] else -1
    IO8 = 1 if inputs.outputs['LINE'] else -1
    IO9 = 1 if inputs.outputs['COLOR'] else -1
    IO10 = 1 if inputs.outputs['WIDTH'] else -1
    IO11 = 1 if inputs.outputs['FEATURES'] else -1
    IO12 = 1 if inputs.outputs['OVI'] else -1
    IO13 = 1 if inputs.outputs['HIRES'] else -1
    IO14 = 1 if inputs.outputs['WRLINES'] else -1
    IO15 = 1 if inputs.outputs['IFASPEC'] else -1
    lines = [
        'MODEL DESIGNATION:                                           [NAME]\n'
        , '{0}\n'.format(NAME),
        """CONTINUOUS STAR FORMATION (>0) OR FIXED MASS (<=0):          [ISF]
"""
        , '{0}\n'.format(ISF),
        "TOTAL STELLAR MASS [1E6 M_SOL] IF 'FIXED MASS' IS CHOSEN:    [TOMA]\n"
        , '{0}\n'.format(TOMA),
        """SFR [SOLAR MASSES PER YEAR] IF 'CONT. SF' IS CHOSEN:         [SFR]
"""
        , '{0}\n'.format(SFR),
        """NUMBER OF INTERVALS FOR THE IMF (KROUPA=2):                  [NINTERV]
"""
        , '{0}\n'.format(NINTERV),
        """IMF EXPONENTS (KROUPA=1.3,2.3):                              [XPONENT]
"""
        , '{0}\n'.format(XPONENT),
        """MASS BOUNDARIES FOR IMF (KROUPA=0.1,0.5,100) [SOLAR MASSES]: [XMASLIM]
"""
        , '{0}\n'.format(XMASLIM),
        """SUPERNOVA CUT-OFF MASS [SOLAR MASSES]:                       [SNCUT]
"""
        , '{0}\n'.format(SNCUT),
        """BLACK HOLE CUT-OFF MASS [SOLAR MASSES]:                      [BHCUT]
"""
        , '{0}\n'.format(BHCUT),
        'METALLICITY + TRACKS:                                        [IZ]\n',
        """GENEVA STD: 11=0.001;  12=0.004; 13=0.008; 14=0.020; 15=0.040
""",
        'GENEVA HIGH:21=0.001;  22=0.004; 23=0.008; 24=0.020; 25=0.040\n',
        """PADOVA STD: 31=0.0004; 32=0.004; 33=0.008; 34=0.020; 35=0.050
""",
        'PADOVA AGB: 41=0.0004; 42=0.004; 43=0.008; 44=0.020; 45=0.050\n',
        """GENEVA v00: 51=0.001;  52=0.002; 53=0.008; 54=0.014; 55=0.040
""",
        'GENEVA v40: 61=0.001;  62=0.002; 63=0.008; 64=0.014; 65=0.040\n',
        '{0}\n'.format(IZ),
        """WIND MODEL (0: MAEDER; 1: EMP.; 2: THEOR.; 3: ELSON):        [IWIND]
"""
        , '{0}\n'.format(IWIND),
        """INITIAL TIME [1.E6 YEARS]:                                   [TIME1]
"""
        , '{0}\n'.format(TIME1),
        """TIME SCALE: LINEAR (=0) OR LOGARITHMIC (=1)                  [JTIME]
"""
        , '{0}\n'.format(JTIME),
        'TIME STEP [1.e6 YEARS] (ONLY USED IF JTIME=0):               [TBIV]\n'
        , '{0}\n'.format(TBIV),
        """NUMBER OF STEPS        (ONLY USED IF JTIME=1):               [ITBIV]
"""
        , '{0}\n'.format(ITBIV),
        'LAST GRID POINT [1.e6 YEARS]:                                [TMAX]\n'
        , '{0}\n'.format(TMAX), """SMALL (=0) OR LARGE (=1) MASS GRID;
""",
        'ISOCHRONE ON  LARGE GRID (=2) OR FULL ISOCHRONE (=3):        [JMG]\n',
        '{0}\n'.format(JMG),
        """LMIN, LMAX (ALL=0):                                          [LMIN,LMAX]
"""
        , '{0}\n'.format(LMIN),
        'TIME STEP FOR PRINTING OUT THE SYNTHETIC SPECTRA [1.e6YR]:   [TDEL]\n'
        , '{0}\n'.format(TDEL),
        """ATMOSPHERE: 1=PLA, 2=LEJ, 3=LEJ+SCH, 4=LEJ+SMI, 5=PAU+SMI:   [IATMOS]
"""
        , '{0}\n'.format(IATMOS),
        """METALLICITY OF THE HIGH RESOLUTION MODELS                    [ILIB]
"""
        , '(1=0.001, 2= 0.008, 3=0.020, 4=0.040):\n', '{0}\n'.format(ILIB),
        """LIBRARY FOR THE UV LINE SPECTRUM: (1=SOLAR, 2=LMC/SMC)       [ILINE]
"""
        , '{0}\n'.format(ILINE),
        """RSG FEATURE: MICROTURB. VEL (1-6), SOL/NON-SOL ABUND (0,1)   [IVT,IRSG]
"""
        , '{0}\n'.format(IVT),
        """OUTPUT FILES (NO<0, YES>=0)                                  [IO1,...]
"""
        ,
        '{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14}\n'
        .format(IO1, IO2, IO3, IO4, IO5, IO6, IO7, IO8, IO9, IO10, IO11,
        IO12, IO13, IO14, IO15),
        """******************************************************************
"""
        , '  OUTPUT FILES:         1    SYNTHESIS.QUANTA\n',
        """                        2    SYNTHESIS.SNR
""",
        '                        3    SYNTHESIS.HRD\n',
        """                        4    SYNTHESIS.POWER
""",
        '                        5    SYNTHESIS.SP\n',
        """                        6    SYNTHESIS.YIELDS
""",
        '                        7    SYNTHESIS.SPECTRUM\n',
        """                        8    SYNTHESIS.LINE
""",
        '                        9    SYNTHESIS.COLOR\n',
        """                       10    SYNTHESIS.WIDTH
""",
        '                       11    SYNTHESIS.FEATURES\n',
        """                       12    SYNTHESIS.OVI
""",
        '                       13    SYNTHESIS.HIRES\n',
        """                       14    SYNTHESIS.WRLINES
""",
        '                       15    SYNTHESIS.IFASPEC\n', '\n',
        '  CORRESPONDENCE I VS. MASS:\n',
        """  M   120 115 110 105 100  95  90  85  80  75  70  65
""",
        '  I     1   2   3   4   5   6   7   8   9  10  11  12\n', '\n',
        """  M    60  55  50  45  40  35  30  25  20  15  10   5
""",
        '  I    13  14  15  16  17  18  19  20  21  22  23  24\n', '\n',
        '\n',
        """  M   120 119 118 117 116 115 114 113 112 111 110 109 108 107 106
"""
        ,
        '  I     1   2   3   4   5   6   7   8   9  10  11  12  13  14  15\n',
        '\n',
        """  M   105 104 103 102 101 100  99  98  97  96  95  94  93  92  91
"""
        ,
        '  I    16  17  18  19  20  21  22  23  24  25  26  27  28  29  30\n',
        '\n',
        """  M    90  89  88  87  86  85  84  83  82  81  80  79  78  77  76
"""
        ,
        '  I    31  32  33  34  35  36  37  38  39  40  41  42  43  44  45\n',
        '\n',
        """  M    75  74  73  72  71  70  69  68  67  66  65  64  63  62  61
"""
        ,
        '  I    46  47  48  49  50  51  52  53  54  55  56  57  58  59  60\n',
        '\n',
        """  M    60  59  58  57  56  55  54  53  52  51  50  49  48  47  46
"""
        ,
        '  I    61  62  63  64  65  66  67  68  69  70  71  72  73  74  75\n',
        '\n',
        """  M    45  44  43  42  41  40  39  38  37  36  35  34  33  32  31
"""
        ,
        '  I    76  77  78  79  80  81  82  83  84  85  86  87  88  89  90\n',
        '\n',
        """  M    30  29  28  27  26  25  24  23  22  21  20  19  18  17  16
"""
        ,
        '  I    91  92  93  94  95  96  97  98  99 100 101 102 103 104 105\n',
        '\n',
        """  M    15  14  13  12  11  10   9   8   7   6   5   4   3   2   1
"""
        ,
        '  I   106 107 108 109 110 111 112 113 114 115 116 117 118 119 120\n',
        """********************************************************************
"""
        ]
    f.writelines(lines)
    f.close()


@classmethod
def wordToNumber(cls, s):
    """
        方法numberTranslator的辅助方法，可将[零-九]正确翻译为[0-9]
        :param s: 大写数字
        :return: 对应的整形数，如果不是数字返回-1
        """
    if s == u'零' or s == '0':
        return 0
    elif s == u'一' or s == '1':
        return 1
    elif s == u'二' or s == u'两' or s == '2':
        return 2
    elif s == u'三' or s == '3':
        return 3
    elif s == u'四' or s == '4':
        return 4
    elif s == u'五' or s == '5':
        return 5
    elif s == u'六' or s == '6':
        return 6
    elif s == u'七' or s == u'天' or s == u'日' or s == u'末' or s == '7':
        return 7
    elif s == u'八' or s == '8':
        return 8
    elif s == u'九' or s == '9':
        return 9
    else:
        return -1


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

        :param UploadSessionLookupError val:
        :rtype: UploadSessionFinishError
        """
    return cls('lookup_failed', val)


def walk(match, subrepos, unknown, ignored, full=True):
    """
        Walk recursively through the directory tree, finding all files
        matched by match.

        If full is False, maybe skip some known-clean files.

        Return a dict mapping filename to stat-like object (either
        mercurial.osutil.stat instance or return value of os.stat()).

        """


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

        :param WatermarkingPolicyChangedType val:
        :rtype: EventType
        """
    return cls('watermarking_policy_changed', val)


def parse_stats(stats_file):
    """Parse stats file."""
    stats = {}
    with open(stats_file) as sfile:
        for row_raw in sfile:
            key, value = row_raw.strip().split('\t')
            stats[key] = value
    return stats


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 importer(name, root_package=False, relative_globals=None, level=0):
    """ We only import modules, functions can be looked up on the module.
    Usage:

    from foo.bar import baz
    >>> baz = importer('foo.bar.baz')

    import foo.bar.baz
    >>> foo = importer('foo.bar.baz', root_package=True)
    >>> foo.bar.baz

    from .. import baz (level = number of dots)
    >>> baz = importer('baz', relative_globals=globals(), level=2)
    """
    return __import__(name, locals=None, globals=relative_globals, fromlist
        =[] if root_package else [None], level=level)


@classmethod
def delete_qs(cls, qs):
    """Удаление списка записей.

        По одной что бы удалились связанные записи в родительской таблице

        """
    for item in qs:
        item.delete()
    cls._session.commit()


def getHistorySource():
    """get source for HistoryAwareMixin

        Must return a (raw) string
        """


@classmethod
def grid_columns(cls):
    """
        Return the column names for the model, except for the excluded ones.

        Returns:
            list: A list of column names, with excluded ones removed.
        """
    columns = []
    exclude = getattr(cls, '__exclude_columns__', [])
    for col in cls.__table__.columns:
        if col.name in exclude:
            continue
        columns.append(col.name)
    return columns


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

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

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


def limit(requestContext, seriesList, n):
    """
    Takes one metric or a wildcard seriesList followed by an integer N.

    Only draw the first N metrics. Useful when testing a wildcard in a
    metric.

    Example::

        &target=limit(server*.instance*.memory.free,5)

    Draws only the first 5 instance's memory free.

    """
    return seriesList[0:n]


def assemble_replace_dict(command, use_gpu, additions, queue, time, ngpu):
    """Create dictionary to update BASH submission script for torque.

    Parameters
    ----------
    command : type
        Command to executer through torque.
    use_gpu : type
        GPUs needed?
    additions : type
        Additional commands to add (eg. module loads).
    queue : type
        Queue to place job in.
    time : type
        How many hours to run job for.
    ngpu : type
        Number of GPU to use.

    Returns
    -------
    Dict
        Dictionary used to update Torque Script.

    """
    replace_dict = {'COMMAND': '{} {}'.format(
        'CUDA_VISIBLE_DEVICES="$gpuNum"' if use_gpu else '', command),
        'GPU_SETUP':
        """gpuNum=`cat $PBS_GPUFILE | sed -e 's/.*-gpu//g'`
unset CUDA_VISIBLE_DEVICES
export CUDA_DEVICE=$gpuNum"""
         if use_gpu else '', 'NGPU': '#PBS -l gpus={}'.format(ngpu) if
        use_gpu and ngpu else '', 'USE_GPU': '#PBS -l feature=gpu' if
        use_gpu else '', 'TIME': str(time), 'QUEUE': queue, 'ADDITIONS':
        additions}
    return replace_dict


def clear_env(_, env):
    """Clears the environment of the unpicklable objects that we left behind."""
    env.autoapi_mapper = None


@classmethod
def add_command_line_options(cls, parser):
    """function to inject command line parameters"""
    if 'add_argument' in dir(parser):
        return cls.add_command_line_options_argparse(parser)
    else:
        return cls.add_command_line_options_optparse(parser)


def getShortName(name):
    """
	Returns a shorter kernel name
	"""
    sname = name.split('<')[0].replace('void ', '').replace('at::', ''
        ).replace('cuda::', '').replace('native::', '').replace(
        '(anonymous namespace)::', '')
    sname = sname.split('(')[0]
    return sname


def get_op_w_rxns(db, operator_id):
    """Returns operator with all its associated reactions.

    :param db: DB to search
    :type db: A Mongo Database
    :param operator_id: Mongo _id or operator name (e.g. 1.1.-1.h)
    :type operator_id: str
    :return: Operator JSON document (with reactions)
    :rtype: list
    """
    operator = db.operators.find_one({'$or': [{'_id': operator_id}, {'Name':
        operator_id}]})
    if operator:
        operator['Reaction_ids'] = db.reactions.find({'Operators': operator_id}
            ).distinct('_id')
    else:
        return None
    return operator


def find_name(path, name):
    """docstring for find_name"""
    for filename in path.rglob(name):
        print(filename)


@classmethod
def build_url(cls, config, namespace, name):
    """ Build a url for a repository """
    return config['host'] + '/' + namespace + '/' + name + '.git'


def _const_compare_digest_backport(a, b):
    """
    Compare two digests of equal length in constant time.

    The digests must be of type str/bytes.
    Returns True if the digests match, and False otherwise.
    """
    result = abs(len(a) - len(b))
    for l, r in zip(bytearray(a), bytearray(b)):
        result |= l ^ r
    return result == 0


def get_wishes_count(manager):
    """Return count of filled wishes."""
    all_wishes = filled_wishes = 0
    if '_wishes' in manager.meta:
        meta_wishes = manager.meta['_wishes']
        for i in range(len(manager.students)):
            if meta_wishes[i] is not None:
                all_wishes += 1
                if manager.result_groups[i][0] == meta_wishes[i]:
                    filled_wishes += 1
    if 'friends_table' in manager.config:
        friends_table = manager.meta[manager.config['friends_table'][0]]
        for row in friends_table:
            all_wishes += 1
            student_one = manager.students.get_by_column(0, row[0])
            student_one = manager.students.body.index(student_one)
            student_two = manager.students.get_by_column(0, row[1])
            student_two = manager.students.body.index(student_two)
            if manager.result_groups[student_one] == manager.result_groups[
                student_two]:
                filled_wishes += 1
    return [filled_wishes, all_wishes]


def is_url(path):
    """Try to determine if the path is an URL.
    """
    if isinstance(path, bytes):
        return False
    return path.split('://', 1)[0] in ['http', 'https']


def report_delete():
    """Delete selected reports

    """
    pass


def _preprocess_for_efficient_roulette_selection(discretized_probabilities):
    """Prepares data for performing efficient roulette selection.

    The output is a tuple (alternates, keep_weights). The output is guaranteed
    to satisfy a sampling-equivalence property. Specifically, the following
    sampling process is guaranteed to be equivalent to simply picking index i
    with probability weights[i] / sum(weights):

        1. Pick a number i in [0, len(weights) - 1] uniformly at random.
        2. Return i With probability keep_weights[i]*len(weights)/sum(weights).
        3. Otherwise return alternates[i].

    In other words, the output makes it possible to perform roulette selection
    while generating only two random numbers, doing a single lookup of the
    relevant (keep_chance, alternate) pair, and doing one comparison. This is
    not so useful classically, but in the context of a quantum computation
    where all those things are expensive the second sampling process is far
    superior.

    Args:
        discretized_probabilities: A list of probabilities approximated by
            integer numerators (with an implied common denominator). In order
            to operate without floating point error, it is required that the
            sum of this list is a multiple of the number of items in the list.

    Returns:
        alternates (list[int]): An alternate index for each index from 0 to
            len(weights) - 1
        keep_weight (list[int]): Indicates how often one should stay at index i
            instead of switching to alternates[i]. To get the actual keep
            probability of the i'th element, multiply keep_weight[i] by
            len(discretized_probabilities) then divide by
            sum(discretized_probabilities).
    """
    weights = list(discretized_probabilities)
    if not weights:
        raise ValueError('Empty input.')
    n = len(weights)
    target_weight = sum(weights) // n
    if sum(weights) != n * target_weight:
        raise ValueError('sum(weights) must be a multiple of len(weights).')
    alternates = list(range(n))
    keep_weights = [0] * n
    donor_position = 0
    for _ in range(2):
        for i in range(n):
            if weights[i] >= target_weight:
                continue
            while weights[donor_position] <= target_weight:
                donor_position += 1
            donated = target_weight - weights[i]
            weights[donor_position] -= donated
            alternates[i] = donor_position
            keep_weights[i] = weights[i]
            weights[i] = target_weight
    return alternates, keep_weights


def default_filter(src, dst):
    """The default progress/filter callback; returns True for all files"""
    return dst


def _box(responses, box_min, box_max):
    """Projects responses from box [box_min, box_max] to [0, 1].

    Arguments
    ---------
    responses : numpy array
       An array of values in [box_min, box_max] to be projected.
    box_min : float
       The minimum value of a box containing responses.
    box_max : float
       The maximum value of a box containing responses.

    Returns
    -------
    numpy array
       responses projected onto [0, 1].
    """
    return (responses - box_min) / (box_max - box_min)


def launch_log_parsers():
    """Run all log file parsers that send entries to Sentry"""
    from ..parsers.nginx import Nginx
    for parser in [Nginx]:
        parser().follow_tail()


def round_up_minute(date_time, min_offset):
    """
    Round up to nearest minute that is at least minimum_offset seconds later
    """
    dt = date_time + 60 + min_offset
    dt.second = 0
    dt.microsecond = 0
    return dt


@staticmethod
def generate_accordion(summary, main):
    """
        Returns an HTML native accordion.
        :param str summary: Accordion's summary.
        :param str main: Accordion's main body.
        :return str: Accordion.
        """
    return (
        """

                {}
                {}

        """
        .format(summary, main))


@classmethod
def getLastFrame(cls, node, growing=0, refresh=True):
    """ provides the last frame number

        :param node: nexus field node
        :type node: :class:`pni.io.nx.h5.nxfield` or                     :class:`pni.io.nx.h5.nxgroup` or                     :class:`pni.io.nx.h5.nxlink` or                     :class:`pni.io.nx.h5.nxattribute` or                     :class:`pni.io.nx.h5.nxroot`
        :param growing: growing dimension
        :type growing: :obj:`int`
        :param refresh: refresh image node
        :type refresh: :obj:`bool`
        :returns: a number of frames
        :rtype: :obj:`int`
        """
    if refresh:
        node.refresh()
    if node:
        shape = node.shape
    if shape:
        if len(shape) > growing and growing > -1:
            return shape[growing]
    return 0


def convert_mongo_query(spec):
    """BBB: providing support for mongo style queries"""


def _utf8_str(s):
    """Convert unicode to utf-8."""
    if isinstance(s, str):
        return s.encode('utf-8')
    else:
        return str(s)


def linalg_potrf(A=None, name=None, attr=None, out=None, **kwargs):
    """Performs Cholesky factorization of a symmetric positive-definite matrix.
    Input is a tensor *A* of dimension *n >= 2*.

    If *n=2*, the Cholesky factor *B* of the symmetric, positive definite matrix *A* is
    computed. *B* is triangular (entries of upper or lower triangle are all zero), has
    positive diagonal entries, and:

      *A* = *B* \\* *B*\\ :sup:`T`  if *lower* = *true*
      *A* = *B*\\ :sup:`T` \\* *B*  if *lower* = *false*

    If *n>2*, *potrf* is performed separately on the trailing two dimensions for all inputs
    (batch mode).

    .. note:: The operator supports float32 and float64 data types only.

    Examples::

       Single matrix factorization
       A = [[4.0, 1.0], [1.0, 4.25]]
       potrf(A) = [[2.0, 0], [0.5, 2.0]]

       Batch matrix factorization
       A = [[[4.0, 1.0], [1.0, 4.25]], [[16.0, 4.0], [4.0, 17.0]]]
       potrf(A) = [[[2.0, 0], [0.5, 2.0]], [[4.0, 0], [1.0, 4.0]]]

    Defined in src/operator/tensor/la_op.cc:L214

    Parameters
    ----------
    A : Symbol
        Tensor of input matrices to be decomposed

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

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


def old_lease(mac, ip_address):
    """Called when an old lease is recognized."""
    pass


def classify_list_f(a_list, *filters):
    """Classfy a list like object. Multiple filters in one loop.

    - collection: list like object
    - filters: the filter functions to return True/False

    Return multiple filter results.

    Example:
    data = [1, 2, 3]
    m1 = lambda x: x > 1
    m2 = lambda x: x > 2
    classify(data, m1, m2)   ->   [2, 3], [3]
    """
    results = tuple([] for i in range(len(filters)))
    for item in a_list:
        for filter_func, result in zip(filters, results):
            if filter_func(item):
                result.append(item)
    return results


def _trans(value, index):
    """
    Copyright (c) 2014 Bruno M. Custódio
    Copyright (c) 2016 Frederick Jansen

    https://github.com/hicsail/polyline/commit/ddd12e85c53d394404952754e39c91f63a808656
    """
    byte, result, shift = None, 0, 0
    while byte is None or byte >= 32:
        byte = ord(value[index]) - 63
        index += 1
        result |= (byte & 31) << shift
        shift += 5
        comp = result & 1
    return ~(result >> 1) if comp else result >> 1, index


def children(node):
    """Obtain nodes that are children of a node.

        Returns a list of nodes.
        """


def _get_fname_nio(store):
    """Try to get the file name from the NioDataStore store"""
    try:
        f = store.ds.file
    except AttributeError:
        return None
    try:
        return f.path
    except AttributeError:
        return None


def describe_game_session_placement(PlacementId=None):
    """
    Retrieves properties and current status of a game session placement request. To get game session placement details, specify the placement ID. If successful, a  GameSessionPlacement object is returned.
    See also: AWS API Documentation

    :example: response = client.describe_game_session_placement(
        PlacementId='string'
    )

    :type PlacementId: string
    :param PlacementId: [REQUIRED]
            Unique identifier for a game session placement to retrieve.

    :rtype: dict
    :return: {
        'GameSessionPlacement': {
            'PlacementId': 'string',
            'GameSessionQueueName': 'string',
            'Status': 'PENDING'|'FULFILLED'|'CANCELLED'|'TIMED_OUT',
            'GameProperties': [
                {
                    'Key': 'string',
                    'Value': 'string'
                },
            ],
            'MaximumPlayerSessionCount': 123,
            'GameSessionName': 'string',
            'GameSessionId': 'string',
            'GameSessionArn': 'string',
            'GameSessionRegion': 'string',
            'PlayerLatencies': [
                {
                    'PlayerId': 'string',
                    'RegionIdentifier': 'string',
                    'LatencyInMilliseconds': ...
                },
            ],
            'StartTime': datetime(2015, 1, 1),
            'EndTime': datetime(2015, 1, 1),
            'IpAddress': 'string',
            'Port': 123,
            'PlacedPlayerSessions': [
                {
                    'PlayerId': 'string',
                    'PlayerSessionId': 'string'
                },
            ]
        }
    }

    """
    pass


@staticmethod
def change_upos_copula(node):
    """deprel=cop needs upos=AUX (or PRON)."""
    if node.deprel == 'cop' and node.upos not in ('AUX', 'PRON'):
        node.upos = 'AUX'


def _is_numpy_type(x):
    """Returns true if the value is a numpy type."""
    return 'numpy' in str(type(x))


def getLocation():
    """Get the location info string"""


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 _str_dotted_getattr(obj, name):
    """Expands extends getattr to allow dots in x to indicate nested objects.

    Args:
       obj (object): an object.
       name (str): a name for a field in the object.

    Returns:
       Any: the value of named attribute.

    Raises:
       AttributeError: if the named attribute does not exist.
    """
    for part in name.split('.'):
        obj = getattr(obj, part)
    return str(obj) if obj else None


def branch_scheme(version):
    """
    Local version scheme that adds the branch name for absolute reproducibility.

    If and when this is added to setuptools_scm this function and file can be removed.
    """
    if version.exact or version.node is None:
        return version.format_choice('', '+d{time:{time_format}}',
            time_format='%Y%m%d')
    elif version.branch == 'master':
        return version.format_choice('+{node}', '+{node}.dirty')
    else:
        return version.format_choice('+{node}.{branch}',
            '+{node}.{branch}.dirty')


def pad_rem(pv, size=None):
    """ Removes linear padding from array

    This is a convenience function that does the opposite
    of `pad_add`.

    Parameters
    ----------
    pv : 1D or 2D ndarray
        The array from which the padding will be removed.
    size : tuple of length 1 (1D) or 2 (2D), optional
        The final size of the un-padded array. Defaults to half the size
        of the input array.

    Returns
    -------
    pv : 1D or 2D ndarray
        Padded array `av` with pads appended to right and bottom.
    """
    if size is None:
        size = list()
        for s in pv.shape:
            assert s % 2 == 0, 'Uneven size; specify correct size of output!'
            size.append(int(s / 2))
    elif not hasattr(size, '__len__'):
        size = [size]
    assert len(pv.shape) in [1, 2], 'Only 1D and 2D arrays!'
    assert len(pv.shape) == len(size
        ), '`size` must have same length as `av.shape`!'
    if len(pv.shape) == 2:
        return pv[:size[0], :size[1]]
    else:
        return pv[:size[0]]


def remove_header(headers, name):
    """
    Removes the named header from the list of headers.  Returns the
    value of that header, or None if no header found.  If multiple
    headers are found, only the last one is returned.
    """
    name = name.lower()
    i = 0
    result = None
    while i < len(headers):
        if headers[i][0].lower() == name:
            result = headers[i][1]
            del headers[i]
            continue
        i += 1
    return result


@classmethod
def url_for(cls, path):
    """Given path of a file uploaded on depot returns the url that serves it

        Path is expected to be ``storage_name/fileid``.
        """
    mw = cls.get_middleware()
    return mw.url_for(path)


def create_envs(service_component_name, *envs):
    """Merge all environment variables maps

    Creates a complete environment variables map that is to be used for creating
    the container.

    Args:
    -----
    envs: Arbitrary list of dicts where each dict is of the structure:

        {
            <environment variable name>: <environment variable value>,
            <environment variable name>: <environment variable value>,
            ...
        }

    Returns:
    --------
    Dict of all environment variable name to environment variable value
    """
    master_envs = {'HOSTNAME': service_component_name, 'SERVICE_NAME':
        service_component_name}
    for envs_map in envs:
        master_envs.update(envs_map)
    return master_envs


def valid_replay(info, ping, replay, replay_list):
    """Make sure the replay isn't corrupt, and is worth looking at."""
    if info.HasField('error'):
        print(' Replay has error field '.center(107, '='))
        return False
    if (info.base_build != ping.base_build or info.game_duration_loops <
        1000 or len(info.player_info) != 2):
        return False
    if replay[0:20] in replay_list:
        print(' Replay has been processed '.center(107, '='))
        return False
    return True


@staticmethod
def make_name_short(name: str):
    """Make short name for workers or users.

        Ковалев Антон Викторович -> Ковалев А.В.
        """
    name = name.split(' ')
    sh_name = name[0] + ' ' + name[1][0] + '.' + name[2][0] + '.'
    return sh_name


def setOptimizationServerIP(address_port):
    """Set Optimization Server IP and Port Number """
    global __SERVER_HOST__
    __SERVER_HOST__ = address_port


def select_loose(extend: bool=False):
    """Select loose geometry based on the selection mode

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


def Date():
    """Return the date string for the object."""


def _hue2rgb(v1, v2, vH):
    """Private helper function (Do not call directly)

    :param vH: rotation around the chromatic circle (between 0..1)

    """
    while vH < 0:
        vH += 1
    while vH > 1:
        vH -= 1
    if 6 * vH < 1:
        return v1 + (v2 - v1) * 6 * vH
    if 2 * vH < 1:
        return v2
    if 3 * vH < 2:
        return v1 + (v2 - v1) * (2.0 / 3 - vH) * 6
    return v1


def ReadFile(fileName, show='silent', mode='r'):
    """Reads netCDF4 file fileName and shows available variables.

        INPUTS:
        fileName: full path to file
        show:     how much detail to show; 'silent' for nothing, 'short' for one line, 'full'
                    for full dimensionality and attributes
        mode:     'r' for read only, 'w' for write, 'r+' for read-write
        OUTPUTS:
        file:     netCDF4 Dataset
    """
    import os
    import netCDF4 as nc
    if not os.path.isfile(fileName):
        raise IOError('File ' + fileName + ' does not exist')
    file = nc.Dataset(fileName, mode)
    if show != 'silent':
        print('All variables:', file.variables.keys())
        for g in file.groups.keys():
            print('              ', 'group ' + g + ':')
            print('              ', file.groups[g].variables.keys())
    if show == 'full':
        for v in file.variables.keys():
            if v not in file.dimensions:
                print(file.variables[v])
        for g in file.groups.keys():
            for v in file.groups[g].variables.keys():
                if v not in file.dimensions:
                    print(g + '/' + file.variables[v])
    return file


def get_dataset_representations(items):
    """
    returns dict with x and y datasets
    """
    results = {}
    results['Xname'] = items.get('Xname')
    results['Yname'] = items.get('Yname')
    return results


def key_prefix_replace(d, prefix, new_prefix=''):
    """
    replaces the list of prefix in keys of a flattened dict

    :param d: the flattened dict
    :param prefix: a list of prefixes that are replaced with a new prefix.
                   Typically this will be ""
    :type prefix: list of str
    :param new_prefix: The new prefix. By default it is set to ""
    :return: the dict with the keys replaced as specified
    """
    items = []
    for k, v in d.items():
        new_key = k
        for p in prefix:
            new_key = new_key.replace(p, new_prefix, 1)
        items.append((new_key, v))
    return dict(items)