def reverse_contiguous_sequence(chars, line_start, line_end, highest_level,
    lowest_odd_level):
    """L2. From the highest level found in the text to the lowest odd
    level on each line, including intermediate levels not actually
    present in the text, reverse any contiguous sequence of characters
    that are at that level or higher.

    """
    for level in range(highest_level, lowest_odd_level - 1, -1):
        _start = _end = None
        for run_idx in range(line_start, line_end + 1):
            run_ch = chars[run_idx]
            if run_ch['level'] >= level:
                if _start is None:
                    _start = _end = run_idx
                else:
                    _end = run_idx
            elif _end is not None:
                chars[_start:+_end + 1] = reversed(chars[_start:+_end + 1])
                _start = _end = None
        if _start is not None:
            chars[_start:+_end + 1] = reversed(chars[_start:+_end + 1])


def temp_separation_tac(T_c, T_s, fc, T_air, r_ah, r_s, r_x):
    """Compute air temperature at the canopy interface

    Parameters
    ----------
    T_c : ee.Image
        Canopy temperature (Kelvin).
    T_s : ee.Image
        Soil temperature (Kelvin).
    fc
    T_air : ee.Image
    r_ah : ee.Image
    r_s : ee.Image
    r_x : ee.Image

    Returns
    -------
    T_ac : ee.Image
        Air temperature at the canopy interface (Kelvin).

    """
    T_ac = fc.expression(
        '((T_air / r_ah) + (T_s / r_s) + (T_c / r_x)) / ((1 / r_ah) + (1 / r_s) + (1 / r_x))'
        , {'r_ah': r_ah, 'r_s': r_s, 'r_x': r_x, 'T_c': T_c, 'T_s': T_s,
        'T_air': T_air})
    return T_ac


def setlsb(component: int, bit: str) ->int:
    """Set Least Significant Bit of a colour component.
    """
    return component & ~1 | int(bit)


def updatecaches(tr=None, full=False):
    """Warm repo caches."""


def ishex(s):
    """True iff given string is a valid hexadecimal number.
    >>> ishex('deadbeef')
    True
    >>> ishex('01bn78')
    False
    """
    try:
        int(s, 16)
    except ValueError:
        return False
    return True


def primitive_nurbs_surface_surface_add(radius: float=1.0, view_align: bool
    =False, enter_editmode: bool=False, location: float=(0.0, 0.0, 0.0),
    rotation: float=(0.0, 0.0, 0.0), layers: bool=(False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False, False, False, False, False, False)):
    """Construct a Nurbs surface Patch

    :param radius: Radius
    :type radius: float
    :param view_align: Align to View, Align the new object to the view
    :type view_align: bool
    :param enter_editmode: Enter Editmode, Enter editmode when adding this object
    :type enter_editmode: bool
    :param location: Location, Location for the newly added object
    :type location: float
    :param rotation: Rotation, Rotation for the newly added object
    :type rotation: float
    :param layers: Layer
    :type layers: bool
    """
    pass


@staticmethod
def method():
    """method returns an associated ID for the Juju API call.
        """
    return 'createOffer'


def blur_pool():
    """
  https://richzhang.github.io/antialiased-cnns/
  Returns:

  """
    raise NotImplementedError()


@staticmethod
def cached_surrogate(cache, name_string, replacement_generator):
    """Generate a new surrogate for the given name or use an existing one if it already exist.

        Parameters
        ----------
        cache : dict(str: str)
            Lookup table of already replaced names. Keys are original names and values are
            surrogates.
        name_string : str
            The name to generate a replacement for
        replacement_generator : callable accepting `name_string`
            A callable that generates a new surrogate for `name_string`, in case no previous
            replacement exists.

        Returns
        -------
        str
            The surrogate name.

        """
    replacement = cache.get(name_string.lower(), None)
    if not replacement:
        replacement = replacement_generator(name_string)
        cache[name_string.lower()] = replacement
    return replacement


def is_valid_port(port):
    """Check if given port is valid"""
    return 0 <= int(port) <= 65535


def reduce_nums(val_1, val_2, val_op):
    """
	Apply arithmetic rules to compute a result

	:param val1: input parameter
	:type val1: int or string
	:param val2: input parameter
	:type val2: int or string
	:param val_op: C operator in *+*, */*, *-*, etc
	:type val_op: string
	:rtype: int
	"""
    try:
        a = 0 + val_1
    except TypeError:
        a = int(val_1)
    try:
        b = 0 + val_2
    except TypeError:
        b = int(val_2)
    d = val_op
    if d == '%':
        c = a % b
    elif d == '+':
        c = a + b
    elif d == '-':
        c = a - b
    elif d == '*':
        c = a * b
    elif d == '/':
        c = a / b
    elif d == '^':
        c = a ^ b
    elif d == '==':
        c = int(a == b)
    elif d == '|' or d == 'bitor':
        c = a | b
    elif d == '||' or d == 'or':
        c = int(a or b)
    elif d == '&' or d == 'bitand':
        c = a & b
    elif d == '&&' or d == 'and':
        c = int(a and b)
    elif d == '!=' or d == 'not_eq':
        c = int(a != b)
    elif d == '^' or d == 'xor':
        c = int(a ^ b)
    elif d == '<=':
        c = int(a <= b)
    elif d == '<':
        c = int(a < b)
    elif d == '>':
        c = int(a > b)
    elif d == '>=':
        c = int(a >= b)
    elif d == '<<':
        c = a << b
    elif d == '>>':
        c = a >> b
    else:
        c = 0
    return c


def _tr_paren(line_info):
    """Translate lines escaped with: /"""
    return '%s%s(%s)' % (line_info.pre, line_info.ifun, ', '.join(line_info
        .the_rest.split()))


def psi_Na_Cl_HCO3_PP82(T, P):
    """c-a-a': sodium chloride bicarbonate [PP82]."""
    psi = -0.0143
    valid = T == 298.15
    return psi, valid


def write_html(fname, html):
    """Write `html` to `fname`, properly encoded."""
    with open(fname, 'wb') as fout:
        fout.write(html.encode('ascii', 'xmlcharrefreplace'))


def _normalize_site_motif(motif):
    """Normalize the PSP site motif to all caps with no underscores and return
    the preprocessed motif sequence and the position of the target residue
    in the motif (zero-indexed)."""
    no_underscores = motif.replace('_', '')
    offset = motif.find(no_underscores)
    respos = 7 - offset
    return no_underscores.upper(), respos


def time_to_text(t):
    """Convert time to text."""
    if t <= 0:
        return '--:--'
    elif t < 3600:
        minutes = t // 60
        seconds = t % 60
        return '{:02d}:{:02d}'.format(minutes, seconds)
    else:
        hours = t // 3600
        minutes = t % 3600 // 60
        seconds = t % 60
        return '{:d}:{:02d}:{:02d}'.format(hours, minutes, seconds)


def default_skip(builder, layer, input_names, output_names, keras_layer):
    """ Layers that can be skipped (because they are train time only. """
    return


@classmethod
def from_bytes(cls, data, timestamp, instance_id, offset=0):
    """ Deserializes and creates an instance of this object.

         - data: the data to deserialize
         - timestamp: the timestamp to put on the object instance
         - offset: an optional index into data where to begin deserialization
        """
    unpack_field_values = cls._packstruct.unpack_from(data, offset)
    field_values = []
    field_values.append(cls._name)
    if timestamp is not None:
        field_values.append(timestamp / 1000.0)
    field_values.append(cls._id)
    if instance_id is not None:
        field_values.append(instance_id)
    if not cls._flat:
        pos = 0
        for n in cls._num_subelems:
            if n == 1:
                field_values.append(unpack_field_values[pos])
            else:
                field_values.append(tuple(unpack_field_values[pos:pos + n]))
            pos += n
        field_values = tuple(field_values)
    else:
        field_values = tuple(field_values) + tuple(unpack_field_values)
    return cls._make(field_values)


def validate(adr, servicelevel=1):
    """Validates an address and returns a possibly corrected address.

    'adr' should be a object conforming to the address protocol
        - see http://cybernetics.hudora.biz/projects/wiki/AddressProtocol
    'servicelevel' can be an integer with the following values:
    1 - generic validation, no money/effort should be spend on correction and suggestions
    2 - TBD.

    returns (status, message, [corrected addresses and variants])

    status can be:
    '10invalid' - address is for sure non deliverable in this form
    '20troubled' - bounced before or is unlikely to be correct - possible alternatives are returned
    '30ok' - likely to work
    '31ok' - likely to work but was corrected
    '40verified' - we are sure it works
    """
    adr['land'] = adr['land'].strip()
    adr['plz'] = adr['plz'].strip()
    if adr['land'] != 'IE' and not adr['plz']:
        return '10invalid', 'Postleitzahl fehlt', [adr]
    if adr['land'] == 'DE' and len(adr.get('plz', '')) != 5:
        return '10invalid', 'Postleitzahl fehlerhaft', [adr]
    return '30ok', '', [adr]


def asunicodetype(m, input_encoding=None, errors='strict'):
    """Create type unicode from type string"""


def diff_values(l1, l2):
    """
        from elist.elist import *
        l1 = [1,2,3,5]
        l2 = [0,2,3,4]
        diff_values(l1,l2)
    """
    rslt = []
    for i in range(0, l1.__len__()):
        if l1[i] != l2[i]:
            rslt.append(l1[i])
    return rslt


@staticmethod
def getJavaPackage():
    """ Returns package name String. """
    return 'com.microsoft.ml.spark.image.ImageFeaturizer'


@classmethod
def from_file(cls, filepath: str, **kwargs) ->'Config':
    """Reading a configuration from a file"""
    with open(filepath, 'r') as fp:
        cfg = cls._load(fp, **kwargs)
    setattr(cfg, 'filepath', filepath)
    return cfg


def context_set_int(data_path: str='', value: int=0, relative: bool=False):
    """Set a context value

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    :param value: Value, Assign value
    :type value: int
    :param relative: Relative, Apply relative to the current value (delta)
    :type relative: bool
    """
    pass


def modifier_remove(modifier: str=''):
    """Remove a modifier from the active object

    :param modifier: Modifier, Name of the modifier to edit
    :type modifier: str
    """
    pass


@classmethod
def all(cls, **kwargs):
    """
        Override this to retrieve all instances of the model

        Initially this is being implemented for result sets, with the intention
        to also implement it for query sets, for which Model.objects.all() will
        return a generator which will not trigger any API requests until we
        attempt to index it or convert it to a list etc.
        """


def zerocopy_to_dlpack(input):
    """Create a dlpack tensor that shares the input memory.

    Parameters
    ----------
    input : Tensor
        The input tensor

    Returns
    -------
    dlpack capsule
        A dlpack capsule that can be used by other framework.
    """
    pass


def robustness(ds, name='PCM_POST', classdimname='pcm_class', outname=
    'PCM_ROBUSTNESS'):
    """ Compute classification robustness

        Parameters
        ----------
        name: str, default is 'PCM_POST'
            Name of the :class:`xarray.DataArray` with prediction probability (posteriors)

        classdimname: str, default is 'pcm_class'
            Name of the dimension holding classes

        outname: 'PCM_ROBUSTNESS' or str
            Name of the :class:`xarray.DataArray` with robustness

        inplace: boolean, False by default
            If False, return a :class:`xarray.DataArray` with robustness
            If True, return the input :class:`xarray.Dataset` with robustness added as a new :class:`xarray.DataArray`

        Returns
        -------
        :class:`xarray.Dataset` if inplace=True
        or
        :class:`xarray.DataArray` if inplace=False

    """
    maxpost = ds[name].max(dim=classdimname)
    K = len(ds[classdimname])
    robust = (maxpost - 1.0 / K) * K / (K - 1.0)
    id = dict()
    id[classdimname] = 0
    da = ds[name][id].rename(outname)
    da.values = robust
    da.attrs['long_name'] = 'PCM classification robustness'
    da.attrs['units'] = ''
    da.attrs['valid_min'] = 0
    da.attrs['valid_max'] = 1
    da.attrs['llh'] = ds[name].attrs['llh']
    return da


@classmethod
def _reset_copyleft(cls):
    """Deprecated after change to LGPLv3 and has no effect."""
    pass


def check_aggregator(aggregator, source, expression_type, group_by):
    """Check aggregator fields."""
    if aggregator['source'] != source:
        raise ValueError(
            'All expressions must be annotated by the same genome database (NCBI, UCSC, ENSEMBLE,...).'
            )
    if aggregator['expression_type'] != expression_type:
        raise ValueError('All expressions must be of the same type.')
    if aggregator['group_by'] != group_by:
        raise ValueError('Group by field must be the same.')


def set_default_log_level(log_level: int):
    """Set the default log level for logging."""
    global _DEFAULT_LOG_LEVEL
    _DEFAULT_LOG_LEVEL = log_level


def open(filename, compression=None, mode='rb', *args, **kwargs):
    """ Override default open() function """
    open_statement = 'builtins.open(filename, mode=mode, *args, **kwargs)'
    if compression:
        open_statement = open_statement.replace('builtins', compression)
    return eval(open_statement)


def get_trans(comment, overlaptrans):
    """
    Find transition part of overlap system, if existing.
    """
    for k in range(len(comment)):
        headline = comment[k, 0].split()
        if 'overlap' in headline and headline[2] == overlaptrans:
            break
    return headline[0]


def is_hdf5_file(fp):
    """Guess if file is HDF5.

    Parameters
    ----------
    fn : str
        File name

    Returns
    -------
    bool
        Whether the file is an HDF5 file
    """
    with open(fp, 'rb') as f:
        return f.read(8) == b'\x89HDF\r\n\x1a\n'


@staticmethod
def truncate(coord):
    """
        Formats a coordinate to an acceptable degree of accuracy (7 decimal
        places for Geodetic).
        """
    return '%.7f' % (int(coord * 10000000) / float(10000000))


@classmethod
def _validate_token_class(cls, token_class):
    """Validate token_class.

        Ensures that the token_class supplied has `blacklist_jti` and `get_blacklisted`
        methods

        :param token_class: ORM database model.
        :return: token_class
        :raises RuntimeError if token_class is missing required methods.
        """
    if getattr(token_class, 'blacklist_jti') is None:
        raise RuntimeError(
            'token_class must have a blacklist_jti method that persists data to database'
            )
    if getattr(token_class, 'get_blacklisted') is None:
        raise RuntimeError(
            'token_class must have a get_blacklisted method that returns a list of blacklisted tokens with attr `jti`'
            )
    return token_class


def changechr(chr):
    """change between two chr versions
  """
    if chr.isdigit() or chr in ('X', 'Y', 'M'):
        return 'chr' + chr
    elif chr == 'MT':
        return 'chrM'
    elif chr == 'chrM':
        return 'MT'
    elif chr[0:3] == 'chr':
        return chr[3:]
    else:
        return chr


def commit_all(repo, message):
    """Creating a commit from repo with given message"""
    repo.index.commit(message)


@staticmethod
def _from_db_object(image, db_image):
    """Converts a database entity to a formal object."""
    for field in image.fields:
        setattr(image, field, db_image[field])
    image.obj_reset_changes()
    return image


@staticmethod
def rootPath():
    """Returns the root path's string representation"""
    return '.'


def __convert_char_hex(message_char):
    """
        Input: message_char - string (one character)

        Output: hex_str - string (hexadecimal value of that character)
    """
    hex_str = hex(message_char)[2:]
    if len(hex_str) % 2 == 1:
        hex_str = '0' + hex_str
    return hex_str


def require_minimum_pyarrow_version():
    """ Raise ImportError if minimum version of pyarrow is not installed
    """
    minimum_pyarrow_version = '0.8.0'
    from distutils.version import LooseVersion
    try:
        import pyarrow
        have_arrow = True
    except ImportError:
        have_arrow = False
    if not have_arrow:
        raise ImportError(
            'PyArrow >= %s must be installed; however, it was not found.' %
            minimum_pyarrow_version)
    if LooseVersion(pyarrow.__version__) < LooseVersion(minimum_pyarrow_version
        ):
        raise ImportError(
            'PyArrow >= %s must be installed; however, your version was %s.' %
            (minimum_pyarrow_version, pyarrow.__version__))


def _idnaText(octets):
    """
    Convert some IDNA-encoded octets into some human-readable text.

    Currently only used by the tests.

    @param octets: Some bytes representing a hostname.
    @type octets: L{bytes}

    @return: A human-readable domain name.
    @rtype: L{unicode}
    """
    try:
        import idna
    except ImportError:
        return octets.decode('idna')
    else:
        return idna.decode(octets)


def back_to_previous():
    """Revert back to the original screen layout, before fullscreen area overlay

    """
    pass


def superset(alldicts):
    """ Returns dict containing all keys from the dicts contained in `alldicts`

    :param dict alldicts: a dictionary containing dictionaries"""
    superdict = {}
    for dict_ in alldicts.values():
        superdict.update(dict_)
    return superdict


@classmethod
def userFromResponse(cls, userData: dict):
    """
        create a user object from an OG operation response
        :param userData: the user data received from the OG operation
        :type userData: dict
        :return: The created user object
        :rtype: User
        """
    user = cls()
    user.businessPhones = userData.get('businessPhones')
    user.displayName = userData.get('displayName')
    user.givenName = userData.get('givenName')
    user.jobTitle = userData.get('jobTitle')
    user.mail = userData.get('mail')
    user.mobilePhone = userData.get('mobilePhone')
    user.officeLocation = userData.get('officeLocation')
    user.preferredLanguage = userData.get('preferredLanguage')
    user.surname = userData.get('surname')
    user.userPrincipalName = userData.get('userPrincipalName')
    user.uid = userData.get('id')
    return user


def convert_frequency(frequecy, unit='GHz', output='Hz'):
    """
    Convert frequencies in other units.

    Parameters
    ----------
    frequency : int, float or array_like
        Frequency.
    unit : {'Hz', 'MHz', 'GHz', 'THz'}
        Unit of entered frequency.
    output : {'Hz', 'MHz', 'GHz', 'THz'}
        Unit of desired frequency.

    Returns
    -------
    frequency: float or array_like
    """
    if unit is 'Hz':
        pass
    elif unit is 'MHz':
        f = frequecy * 1000000.0
    elif unit is 'GHz':
        f = frequecy * 1000000000.0
    elif unit is 'THz':
        f = frequecy * 1000000000000.0
    else:
        raise ValueError('unit must be MHz, GHz or THz.')
    if output is 'Hz':
        return f
    elif output is 'MHz':
        return f / 1000000.0
    elif output is 'GHz':
        return f / 1000000000.0
    elif output is 'THz':
        return f / 1000000000000.0


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


def _png_scanline(line_bytes, fu=4, prev=None):
    """ Scanline unfiltering, taken from png.py
    """
    filter = ord(line_bytes[0:1])
    line1 = bytearray(line_bytes[1:])
    line2 = bytearray(line_bytes[1:])
    if filter == 0:
        pass
    elif filter == 1:
        ai = 0
        for i in range(fu, len(line2)):
            x = line1[i]
            a = line2[ai]
            line2[i] = x + a & 255
            ai += 1
    elif filter == 2:
        for i in range(len(line2)):
            x = line1[i]
            b = prev[i]
            line2[i] = x + b & 255
    elif filter == 3:
        ai = -fu
        for i in range(len(line2)):
            x = line1[i]
            if ai < 0:
                a = 0
            else:
                a = line2[ai]
            b = prev[i]
            line2[i] = x + (a + b >> 1) & 255
            ai += 1
    elif filter == 4:
        ai = -fu
        for i in range(len(line2)):
            x = line1[i]
            if ai < 0:
                a = c = 0
            else:
                a = line2[ai]
                c = prev[ai]
            b = prev[i]
            p = a + b - c
            pa = abs(p - a)
            pb = abs(p - b)
            pc = abs(p - c)
            if pa <= pb and pa <= pc:
                pr = a
            elif pb <= pc:
                pr = b
            else:
                pr = c
            line2[i] = x + pr & 255
            ai += 1
    else:
        raise RuntimeError('Invalid filter %r' % filter)
    return line2


def average(v):
    """
    This function can calculate the average of a list of vectors.

    Parameter:

    v:
        A list of (3x1) np.array. It contains several vectors

    Return:
        (3x1) tuple. The averaged vector.
    """
    n = len(v)
    if n == 0:
        return 0
    else:
        tot = [0, 0, 0]
        for i in v:
            if i[2] < 0:
                i = i * -1
            tot = tot + i
        return [tot[0] / n, tot[1] / n, tot[2] / n]


def bisect_find_sha(start, end, sha, unpack_name):
    """Find a SHA in a data blob with sorted SHAs.

    :param start: Start index of range to search
    :param end: End index of range to search
    :param sha: Sha to find
    :param unpack_name: Callback to retrieve SHA by index
    :return: Index of the SHA, or None if it wasn't found
    """
    assert start <= end
    while start <= end:
        i = (start + end) // 2
        file_sha = unpack_name(i)
        if file_sha < sha:
            start = i + 1
        elif file_sha > sha:
            end = i - 1
        else:
            return i
    return None


@classmethod
def bind(cls, ns, location=None):
    """
        Bind a namespace to a schema location (URI).
        This is used for imports that don't specify a schemaLocation.
        @param ns: A namespace-uri.
        @type ns: str
        @param location: The (optional) schema location for the
            namespace.  (default=ns).
        @type location: str
        """
    if location is None:
        location = ns
    cls.locations[ns] = location


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

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


@classmethod
def empty_platform(cls, arch):
    """
        Create a platform without an ELF loaded.

        :param str arch: The architecture of the new platform
        :rtype: Linux
        """
    platform = cls(None)
    platform._init_cpu(arch)
    platform._init_std_fds()
    return platform


def _get_type(obj):
    """Return the type of an instance (old and new-style)"""
    return getattr(obj, '__class__', None) or type(obj)


def _consolidate_elemental_array_(elemental_array):
    """
    Accounts for non-empirical chemical formulas by taking in the compositional array generated by _create_compositional_array_() and returning a consolidated array of dictionaries with no repeating elements

    :param elemental_array: an elemental array generated from _create_compositional_array_()
    :return: an array of element dictionaries
    """
    condensed_array = []
    for e in elemental_array:
        exists = False
        for k in condensed_array:
            if k['symbol'] == e['symbol']:
                exists = True
                k['occurances'] += e['occurances']
                break
        if not exists:
            condensed_array.append(e)
    return condensed_array


@classmethod
def __is_bool__(cls, name: str) ->bool:
    """Tell if the type of the prop defined by `name` is ``bool``.

        Parameters
        ----------
        name : str
            The name of the prop we ask for.

        Returns
        -------
        bool
            ``True`` if the type of the prop is ``bool``. False otherwise.

        """
    return cls.__type__(name) is bool


def get_bool_arg(r, name):
    """
    Retrieve argument from :attr:`flask:flask.request` and convert to boolean

    :param r: :attr:`flask:flask.request`
    :param name: argument name
    :type: str
    :return: `True` if lowercase value equals 'true', `False` otherwise
    """
    return r.args.get(name, 'false').lower() == 'true'


def _transform_positioning(ha, va):
    """Converts matplotlib positioning to pgf node positioning.
    Not quite accurate but the results are equivalent more or less."""
    if ha == 'center' and va == 'center':
        return None
    ha_mpl_to_tikz = {'right': 'east', 'left': 'west', 'center': ''}
    va_mpl_to_tikz = {'top': 'north', 'bottom': 'south', 'center': '',
        'baseline': 'base'}
    return 'anchor={} {}'.format(va_mpl_to_tikz[va], ha_mpl_to_tikz[ha]).strip(
        )


@classmethod
def fromstring(cls, value):
    """Return the state object attribute that matches the string
        :param str value: the string to look up
        :return: the state object attribute that matches the string
        :rtype: str
        """
    return getattr(cls, value.upper(), None)


def mySettings():
    """ Define your trading system settings here """
    settings = {}
    settings['markets'] = ['CASH', 'F_AD', 'F_AE', 'F_AH', 'F_AX', 'F_BC',
        'F_BG', 'F_BO', 'F_BP', 'F_C', 'F_CA', 'F_CC', 'F_CD', 'F_CF',
        'F_CL', 'F_CT', 'F_DL', 'F_DM', 'F_DT', 'F_DX', 'F_DZ', 'F_EB',
        'F_EC', 'F_ED', 'F_ES', 'F_F', 'F_FB', 'F_FC', 'F_FL', 'F_FM',
        'F_FP', 'F_FV', 'F_FY', 'F_GC', 'F_GD', 'F_GS', 'F_GX', 'F_HG',
        'F_HO', 'F_HP', 'F_JY', 'F_KC', 'F_LB', 'F_LC', 'F_LN', 'F_LQ',
        'F_LR', 'F_LU', 'F_LX', 'F_MD', 'F_MP', 'F_ND', 'F_NG', 'F_NQ',
        'F_NR', 'F_NY', 'F_O', 'F_OJ', 'F_PA', 'F_PL', 'F_PQ', 'F_RB',
        'F_RF', 'F_RP', 'F_RR', 'F_RU', 'F_RY', 'F_S', 'F_SB', 'F_SF',
        'F_SH', 'F_SI', 'F_SM', 'F_SS', 'F_SX', 'F_TR', 'F_TU', 'F_TY',
        'F_UB', 'F_US', 'F_UZ', 'F_VF', 'F_VT', 'F_VW', 'F_VX', 'F_W',
        'F_XX', 'F_YM', 'F_ZQ']
    settings['lookback'] = 252
    settings['budget'] = 10 ** 6
    settings['slippage'] = 0.05
    settings['gap'] = 20
    settings['dimension'] = 5
    return settings


def getDiscussionFor(content):
    """ Return an IDiscussionItemContainer for 'content'.

        o Create the IDC if necessary.

        o Raise ValueError if discussion is not allowed on 'content'.

        o Permission:  Public
        """


def __setitem__(path, node):
    """Define the node value for a path in the manifest.

        If the path is already in the manifest, its flags will be copied to
        the new entry.
        """


def prompt_for_role(roles):
    """Ask user which role to assume."""
    if len(roles) == 1:
        return roles[0]
    print('Please select a role:')
    count = 1
    for role in roles:
        print('  {count}) {role}'.format(count=count, role=role[0]))
        count = count + 1
    choice = 0
    while choice < 1 or choice > len(roles) + 1:
        try:
            choice = int(input('Choice: '))
        except ValueError:
            choice = 0
    return roles[choice - 1]


def g_to_oz(g):
    """
    Convert grams to ounces
    """
    return g / 28.34952


def psi_Na_Cl_HCO3_HMW84(T, P):
    """c-a-a': sodium chloride bicarbonate [HMW84]."""
    psi = -0.15
    valid = T == 298.15
    return psi, valid


@classmethod
def get(cls, id: str, **kwargs):
    """Get unique Client instance."""
    return cls._get(id, cls, **kwargs)


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


def ref(series, n):
    """
    简单移动: 求series序列位移n个周期的结果

        注意: 当n为0, 函数返回原序列; 当n为有效值但当前的series序列元素个数不足 n + 1 个, 函数返回 NaN 序列

    Args:
        series (pandas.Series): 数据序列

        n (int): 位移周期

    Returns:
        pandas.Series: 位移后的序列

    Example::

        from tqsdk import TqApi, TqSim, tafunc

        api = TqApi(TqSim())
        klines = api.get_kline_serial("CFFEX.IF1908", 24 * 60 * 60)
        pre_close = tafunc.ref(klines.close, 1)  # 将收盘价序列右移一位, 得到昨收盘序列
        change = klines.close - pre_close        # 收盘价序列 - 昨收盘序列, 得到涨跌序列
        print(list(change))
    """
    m = series.shift(n)
    return m


def get_wins(point_margin):
    """Determine a win based on the point margin.

    Parameters
    ----------
    point_margin : int
        The point margin can be positive, zero, or negative.

    Returns
    -------
    won : int
        If the point margin is greater than 0, return 1, else 0.

    """
    won = 1 if point_margin > 0 else 0
    return won


def merge_code(left_code, right_code):
    """
    { relative_line:
      ((left_abs_line, ((offset, op, args), ...)),
       (right_abs_line, ((offset, op, args), ...))),
      ... }
    """
    data = dict()
    code_lines = left_code and left_code.iter_code_by_lines() or tuple()
    for abs_line, rel_line, dis in code_lines:
        assert rel_line is not None
        data[rel_line] = [(abs_line, dis), None]
    code_lines = right_code and right_code.iter_code_by_lines() or tuple()
    for abs_line, rel_line, dis in code_lines:
        assert rel_line is not None
        found = data.get(rel_line, None)
        if found is None:
            found = [None, (abs_line, dis)]
            data[rel_line] = found
        else:
            found[1] = abs_line, dis
    return data


@staticmethod
def _df_mods(df):
    """
        _df_mods applies modifications to the dataframe before it is cached.

        :param df: `pd.DataFrame`.
        :return: `pd.DataFrame`.
        """
    df.fillna('', inplace=True)
    df.iloc[:, (2)] = df.iloc[:, (2)].astype(int)
    return df


def __new__(cls, source=None, root=None, *args, **kwargs):
    """Create new Mutable object

        Begin by creating a new object of type cls using super().__new__. If
        super().__new__ takes arguments, I assume the first argument is a
        source object (the new methods of many literals work this way).
        Otherwise, begin by creating an empty new object.

        Then set the root, python type, and empty tracked attribute names
        registry. The root is used to register changes with the root Mutable
        object. The python type is used to check for valid attribute setting
        (see __setattr__). The tracked attribute registry is used for
        assigning new root mutable objects.
        """
    try:
        new = super().__new__(cls, source)
    except:
        new = super().__new__(cls)
    new._python_type = type(source) if source is not None else None
    new._tracked_attr_names = set()
    new.root = root
    return new


@staticmethod
def _filepath_assign_edits(block, path, filepath, binary_edits):
    """
        Record the write to a separate entry (binary file-like object),
        this lets us replay the edits later.
        (so we can replay them onto the clients local cache without a file transfer).
        """
    import struct
    assert type(filepath) is bytes
    assert type(path) is bytes
    ofs, size = block.get_file_offset(path)
    filepath = filepath[:size - 1]
    binary_edits.append((ofs, filepath + b'\x00'))


def replace(text, replacements):
    """
  Replaces multiple slices of text with new values. This is a convenience method for making code
  modifications of ranges e.g. as identified by ``ASTTokens.get_text_range(node)``. Replacements is
  an iterable of ``(start, end, new_text)`` tuples.

  For example, ``replace("this is a test", [(0, 4, "X"), (8, 1, "THE")])`` produces
  ``"X is THE test"``.
  """
    p = 0
    parts = []
    for start, end, new_text in sorted(replacements):
        parts.append(text[p:start])
        parts.append(new_text)
        p = end
    parts.append(text[p:])
    return ''.join(parts)


def _infer_coreml_output_shape(tf_shape):
    """Infer CoreML output shape from TensorFlow shape.
  """
    shape = []
    if len(tf_shape) == 1:
        shape = [tf_shape[0], 1, 1]
    elif len(tf_shape) == 2:
        if tf_shape[0] == 1:
            shape = [tf_shape[1]]
        else:
            shape = None
    elif len(tf_shape) == 3:
        shape = None
    elif len(tf_shape) == 4:
        shape = [tf_shape[3], tf_shape[1], tf_shape[2]]
    elif len(tf_shape) == 0:
        shape = [1]
    else:
        raise ValueError('Unrecognized TensorFlow output shape ' + str(
            tf_shape))
    return shape


def data_chunk(data, chunk, with_overlap=False):
    """Get a data chunk."""
    assert isinstance(chunk, tuple)
    if len(chunk) == 2:
        i, j = chunk
    elif len(chunk) == 4:
        if with_overlap:
            i, j = chunk[:2]
        else:
            i, j = chunk[2:]
    else:
        raise ValueError("'chunk' should have 2 or 4 elements, not {0:d}".
            format(len(chunk)))
    return data[i:j, (...)]


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

    :return: name of this resource
    :rtype: str
    """
    if friendly:
        return 'Acknowledges'
    return 'actionacknowledge'


@staticmethod
def complement_doc(name, docstr):
    """ complement the process docstring
        """
    docstring = docstr.split('\n')
    indent = -1
    for line in docstring[1:]:
        lstrip = line.strip()
        if not lstrip:
            continue
        lindent = line.index(line.strip())
        if indent == -1 or lindent < indent:
            indent = lindent
    if indent < 0:
        indent = 0
    docstring += [(' ' * indent + line) for line in ['', '.. note::', '',
        "    * Type '{0}.help()' for a full description of this process parameters."
        .format(name),
        "    * Type '<{0}>.get_input_spec()' for a full description of this process input trait types."
        .format(name),
        "    * Type '<{0}>.get_output_spec()' for a full description of this process output trait types."
        .format(name), '']]
    return '\n'.join(docstring)


def copy_expr_remove_action(expr):
    """ Use this instead of copy() """
    e2 = expr.copy()
    e2.parseAction = []
    return e2


def _seq_of_Ns_from_db(dotbracket):
    """
    Get a sequence containing only 'N'-characters with the same length and
    the same position of cutpoints as the dotbracketstring.

    :param dotbracket: A string, optionally containing '&' to indicate
                       seperate cofolded structures.
    """
    seq = []
    for substr in dotbracket.split('&'):
        seq.append('N' * len(substr))
    return '&'.join(seq)


def camstop_com():
    """Stop the cam scan.

    Return a list with parts for the cam command.
    """
    return [('cmd', 'stopcamscan')]


def addon_refresh():
    """Scan add-on directories for new modules

    """
    pass


def delete():
    """Remove all selected keyframes

    """
    pass


def add_snmp(data, interfaces):
    """
    Format data for adding SNMP to an engine.

    :param list data: list of interfaces as provided by kw
    :param list interfaces: interfaces to enable SNMP by id
    """
    snmp_interface = []
    if interfaces:
        interfaces = map(str, interfaces)
        for interface in data:
            interface_id = str(interface.get('interface_id'))
            for if_def in interface.get('interfaces', []):
                _interface_id = None
                if 'vlan_id' in if_def:
                    _interface_id = '{}.{}'.format(interface_id, if_def[
                        'vlan_id'])
                else:
                    _interface_id = interface_id
                if _interface_id in interfaces and 'type' not in interface:
                    for node in if_def.get('nodes', []):
                        snmp_interface.append({'address': node.get(
                            'address'), 'nicid': _interface_id})
    return snmp_interface


def post_install(context):
    """Post install script"""


def set_validation_data(nn, task, reader):
    """Sets the neural network validation data."""
    if task == 'pos' or task == 'srl_predicates':
        nn.set_validation_data(reader.sentences, reader.tags)
    elif task.startswith('srl') and task != 'srl_predicates':
        arg_limits = None if task != 'srl_classify' else reader.arg_limits
        nn.set_validation_data(reader.sentences, reader.predicates, reader.
            tags, arg_limits)
    elif task.endswith('dependency'):
        if task.startswith('unlabeled'):
            nn.set_validation_data(reader.sentences, reader.heads)
        else:
            nn.set_validation_data(reader.sentences, reader.heads, reader.
                labels)
    else:
        raise ValueError('Unknown task: %s' % task)


def context_menu():
    """Display properties editor context_menu

    """
    pass


def f_measure(precision, recall, beta=1.0):
    """Compute f-measure

    f-measure is defined as follows:
        F(P, R, b) = (1+b²).P.R / (b².P + R)

    where P is `precision`, R is `recall` and b is `beta`
    """
    if precision + recall == 0.0:
        return 0
    return (1 + beta * beta) * precision * recall / (beta * beta *
        precision + recall)


@classmethod
def get_by_id(cls, context, id):
    """Find a DB AttachHandle by ID and return an Obj AttachHandle."""
    db_ah = cls.dbapi.attach_handle_get_by_id(context, id)
    obj_ah = cls._from_db_object(cls(context), db_ah)
    return obj_ah


@staticmethod
def AdditionalArgs(parser):
    """
		Asks for additional command-line arguments to be added by the generator.

		:param parser: A parser for these arguments to be added to
		:type parser: argparse.argument_parser
		"""
    pass


def search(_data=None, **kwargs):
    """Searches available data offers at the data custodian.

    Args:
        _data (dict): filter options for retrieving offers. Follows the model
            `OfferFilter`.

    Returns:
        list: of `dict` that match the model `OfferCollection`.
    """
    pass


def image_to_image_filter(*args, **kwargs):
    """Procedural interface for ImageToImageFilter"""
    import itk
    instance = itk.ImageToImageFilter.New(*args, **kwargs)
    return instance.__internal_call__()


def update_progress(progress, task='Progress of task'):
    """Edits 1 line in terminal to display progress. Progress is in [0,1]"""
    print('\rProgress of task: [{0:50s}] {1:.1f}%'.format('#' * int(
        progress * 50), progress * 100), end='', flush=True)


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 p_case_statement(t):
    """case_statement : CASE value COLON"""
    t[0] = [t[2]]


def _set_cadence(lkwargs):
    """ Select the cadence of the data to download

    Determines the extension to use later in the lookup of cached fits files,
    to be passed to LightKurve for online lookup.

    If no cadence argument is passed it will default to long cadence.

    Parameters
    ----------
    lkwargs : dict
        Dictionary to be passed to LightKurve.

    Returns
    -------
    ext : str
        Fits file short/long cadence extension.

    """
    if not lkwargs['cadence']:
        lkwargs['cadence'] = 'long'
    if lkwargs['cadence'] == 'short':
        ext = '*_slc.fits'
    elif lkwargs['cadence'] == 'long':
        ext = '*_lc.fits'
    else:
        raise TypeError('Unrecognized cadence input for %s' % id)
    return ext


def _is_1d_varray(arr):
    """
    Check whether the array has single dimension like (x, ) or (x, 1)
    """
    return len(arr.shape) < 2 or arr.shape[1] == 1


def _verify_wave_tokens(wave_lane):
    """Validate tokens in a WaveLane string.

    Parameters
    ----------
    wave_lane : str
        A string consisting of the WaveLane tokens.

    Returns
    -------
    Boolean
        True if all the tokens in the WaveLane are valid.

    """
    valid_tokens = {'l', 'h', '.'}
    wave_lane_tokens = list(wave_lane)
    for token in wave_lane_tokens:
        if token not in valid_tokens:
            raise ValueError('Valid tokens are: {}'.format(valid_tokens))


def atom_degree(atom):
    """Get the degree of an atom.

    Note that the result will be different depending on whether the Hs are
    explicitly modeled in the graph.

    Parameters
    ----------
    atom : rdkit.Chem.rdchem.Atom
        RDKit atom instance.

    Returns
    -------
    list
        List containing one int only.

    See Also
    --------
    atom_total_degree
    """
    return [atom.GetDegree()]


def _create_transcript_index(subexon_table):
    """Return a pandas' DataFrame with the gene and transcript ids."""
    transcript_id_columns = ['GeneID', 'TranscriptID']
    unique_transcripts = subexon_table.drop_duplicates(subset=
        transcript_id_columns)
    unique_transcripts = unique_transcripts.loc[:, (transcript_id_columns)]
    unique_transcripts = unique_transcripts.assign(TranscriptIndex=list(
        range(0, unique_transcripts.shape[0])))
    output = subexon_table.merge(unique_transcripts)
    return output


def predict(model, module, sess=None, compute_pars=None, data_pars=None,
    out_pars=None, **kwarg):
    """
       predict  using a pre-trained model and some data
    :param model:
    :param module:
    :param sess:
    :param data_pars:
    :param out_pars:
    :param kwarg:
    :return:
    """
    return module.predict(model, sess, data_pars, **kwarg)


def add_auth_args(parser, config):
    """Return a parser for configuring authentication parameters"""
    parser.add_argument('-p', '--provider', default=config.DEFAULT_PROVIDER)
    parser.add_argument('-u', '--userid', default=config.DEFAULT_USERID)
    parser.add_argument('-k', '--secret_key', default=config.DEFAULT_SECRET_KEY
        )
    return parser


def rewrite_elife_title_prefix_json(json_content, doi):
    """ this does the work of rewriting elife title prefix json values"""
    if not json_content:
        return json_content
    title_prefix_values = {}
    title_prefix_values['10.7554/eLife.00452'] = 'Point of View'
    title_prefix_values['10.7554/eLife.00615'] = 'Point of View'
    title_prefix_values['10.7554/eLife.00639'] = 'Point of View'
    title_prefix_values['10.7554/eLife.00642'] = 'Point of View'
    title_prefix_values['10.7554/eLife.00856'] = 'Point of View'
    title_prefix_values['10.7554/eLife.01061'] = 'Point of View'
    title_prefix_values['10.7554/eLife.01138'] = 'Point of View'
    title_prefix_values['10.7554/eLife.01139'] = 'Point of View'
    title_prefix_values['10.7554/eLife.01820'] = 'Animal Models of Disease'
    title_prefix_values['10.7554/eLife.02576'] = 'Point of View'
    title_prefix_values['10.7554/eLife.04902'] = 'Point of View'
    title_prefix_values['10.7554/eLife.05614'] = 'Point of View'
    title_prefix_values['10.7554/eLife.05635'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.05826'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.05835'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.05849'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.05861'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.05959'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.06024'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.06100'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.06793'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.06813'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.06956'
        ] = 'The Natural History of Model Organisms'
    title_prefix_values['10.7554/eLife.09305'] = 'Point of View'
    title_prefix_values['10.7554/eLife.10825'] = 'Point of View'
    title_prefix_values['10.7554/eLife.11628'] = 'Living Science'
    title_prefix_values['10.7554/eLife.12708'] = 'Point of View'
    title_prefix_values['10.7554/eLife.12844'] = 'Point of View'
    title_prefix_values['10.7554/eLife.13035'] = 'Point of View'
    title_prefix_values['10.7554/eLife.14258'] = 'Cutting Edge'
    title_prefix_values['10.7554/eLife.14424'] = 'Point of View'
    title_prefix_values['10.7554/eLife.14511'] = 'Cell Proliferation'
    title_prefix_values['10.7554/eLife.14721'] = 'Intracellular Bacteria'
    title_prefix_values['10.7554/eLife.14790'] = 'Decision Making'
    title_prefix_values['10.7554/eLife.14830'] = 'Progenitor Cells'
    title_prefix_values['10.7554/eLife.14953'] = 'Gene Expression'
    title_prefix_values['10.7554/eLife.14973'] = 'Breast Cancer'
    title_prefix_values['10.7554/eLife.15352'] = 'Autoimmune Disorders'
    title_prefix_values['10.7554/eLife.15438'] = 'Motor Circuits'
    title_prefix_values['10.7554/eLife.15591'] = 'Protein Tagging'
    title_prefix_values['10.7554/eLife.15928'] = 'Point of View'
    title_prefix_values['10.7554/eLife.15938'] = 'Cancer Metabolism'
    title_prefix_values['10.7554/eLife.15957'] = 'Stem Cells'
    title_prefix_values['10.7554/eLife.15963'] = 'Prediction Error'
    title_prefix_values['10.7554/eLife.16019'] = 'Social Networks'
    title_prefix_values['10.7554/eLife.16076'] = 'mRNA Decay'
    title_prefix_values['10.7554/eLife.16207'] = 'Cardiac Development'
    title_prefix_values['10.7554/eLife.16209'] = 'Neural Coding'
    title_prefix_values['10.7554/eLife.16393'] = 'Neural Circuits'
    title_prefix_values['10.7554/eLife.16598'] = 'RNA Localization'
    title_prefix_values['10.7554/eLife.16758'] = 'Adaptive Evolution'
    title_prefix_values['10.7554/eLife.16800'] = 'Point of View'
    title_prefix_values['10.7554/eLife.16846'] = 'Living Science'
    title_prefix_values['10.7554/eLife.16931'] = 'Point of View'
    title_prefix_values['10.7554/eLife.16964'] = 'Ion Channels'
    title_prefix_values['10.7554/eLife.17224'] = 'Host-virus Interactions'
    title_prefix_values['10.7554/eLife.17293'] = 'Ion Channels'
    title_prefix_values['10.7554/eLife.17393'] = 'Point of View'
    title_prefix_values['10.7554/eLife.17394'] = 'p53 Family Proteins'
    title_prefix_values['10.7554/eLife.18203'] = 'Antibody Engineering'
    title_prefix_values['10.7554/eLife.18243'] = 'Host-virus Interactions'
    title_prefix_values['10.7554/eLife.18365'] = 'DNA Repair'
    title_prefix_values['10.7554/eLife.18431'] = 'Unfolded Protein Response'
    title_prefix_values['10.7554/eLife.18435'] = 'Long Distance Transport'
    title_prefix_values['10.7554/eLife.18721'] = 'Decision Making'
    title_prefix_values['10.7554/eLife.18753'] = 'Resource Competition'
    title_prefix_values['10.7554/eLife.18871'] = 'Mathematical Modeling'
    title_prefix_values['10.7554/eLife.18887'] = 'Sensorimotor Transformation'
    title_prefix_values['10.7554/eLife.19285'] = 'Genetic Screen'
    title_prefix_values['10.7554/eLife.19351'] = 'Motor Control'
    title_prefix_values['10.7554/eLife.19405'] = 'Membrane Structures'
    title_prefix_values['10.7554/eLife.19733'] = 'Focal Adhesions'
    title_prefix_values['10.7554/eLife.20043'] = 'Amyloid-beta Peptides'
    title_prefix_values['10.7554/eLife.20314'] = 'Plant Reproduction'
    title_prefix_values['10.7554/eLife.20468'] = 'Endoplasmic Reticulum'
    title_prefix_values['10.7554/eLife.20516'] = 'Innate Like Lymphocytes'
    title_prefix_values['10.7554/eLife.21070'] = 'Scientific Publishing'
    title_prefix_values['10.7554/eLife.21236'] = 'Developmental Neuroscience'
    title_prefix_values['10.7554/eLife.21522'] = 'Developmental Neuroscience'
    title_prefix_values['10.7554/eLife.21723'] = 'Living Science'
    title_prefix_values['10.7554/eLife.21863'] = 'Genetic Screening'
    title_prefix_values['10.7554/eLife.21864'] = 'Evolutionary Biology'
    title_prefix_values['10.7554/eLife.22073'] = 'Unfolded Protein Response'
    title_prefix_values['10.7554/eLife.22186'] = 'Point of View'
    title_prefix_values['10.7554/eLife.22215'] = 'Neural Wiring'
    title_prefix_values['10.7554/eLife.22256'] = 'Molecular Communication'
    title_prefix_values['10.7554/eLife.22471'] = 'Point of View'
    title_prefix_values['10.7554/eLife.22661'
        ] = 'Reproducibility in Cancer Biology'
    title_prefix_values['10.7554/eLife.22662'
        ] = 'Reproducibility in Cancer Biology'
    title_prefix_values['10.7554/eLife.22735'] = 'Motor Networks'
    title_prefix_values['10.7554/eLife.22850'] = 'Heat Shock Response'
    title_prefix_values['10.7554/eLife.22915'
        ] = 'Reproducibility in Cancer Biology'
    title_prefix_values['10.7554/eLife.22926'] = 'Skeletal Stem Cells'
    title_prefix_values['10.7554/eLife.23375'] = 'Social Evolution'
    title_prefix_values['10.7554/eLife.23383'
        ] = 'Reproducibility in Cancer Biology'
    title_prefix_values['10.7554/eLife.23447'] = 'Genetic Rearrangement'
    title_prefix_values['10.7554/eLife.23693'
        ] = 'Reproducibility in Cancer Biology'
    title_prefix_values['10.7554/eLife.23804'] = 'Point of View'
    title_prefix_values['10.7554/eLife.24038'] = 'Cell Division'
    title_prefix_values['10.7554/eLife.24052'] = 'DNA Replication'
    title_prefix_values['10.7554/eLife.24106'] = 'Germ Granules'
    title_prefix_values['10.7554/eLife.24238'] = 'Tumor Angiogenesis'
    title_prefix_values['10.7554/eLife.24276'] = 'Stem Cells'
    title_prefix_values['10.7554/eLife.24611'] = 'Point of View'
    title_prefix_values['10.7554/eLife.24896'] = 'Visual Behavior'
    title_prefix_values['10.7554/eLife.25000'] = 'Chromatin Mapping'
    title_prefix_values['10.7554/eLife.25001'] = 'Cell Cycle'
    title_prefix_values['10.7554/eLife.25159'] = 'Ion Channels'
    title_prefix_values['10.7554/eLife.25358'] = 'Cell Division'
    title_prefix_values['10.7554/eLife.25375'] = 'Membrane Phase Separation'
    title_prefix_values['10.7554/eLife.25408'
        ] = 'Plain-language Summaries of Research'
    title_prefix_values['10.7554/eLife.25410'
        ] = 'Plain-language Summaries of Research'
    title_prefix_values['10.7554/eLife.25411'
        ] = 'Plain-language Summaries of Research'
    title_prefix_values['10.7554/eLife.25412'
        ] = 'Plain-language Summaries of Research'
    title_prefix_values['10.7554/eLife.25431'] = 'Genetic Diversity'
    title_prefix_values['10.7554/eLife.25654'] = 'Systems Biology'
    title_prefix_values['10.7554/eLife.25669'] = 'Paternal Effects'
    title_prefix_values['10.7554/eLife.25700'] = 'TOR Signaling'
    title_prefix_values['10.7554/eLife.25835'] = 'Cutting Edge'
    title_prefix_values['10.7554/eLife.25858'] = 'Developmental Biology'
    title_prefix_values['10.7554/eLife.25956'] = 'Point of View'
    title_prefix_values['10.7554/eLife.25996'] = 'Cancer Therapeutics'
    title_prefix_values['10.7554/eLife.26295'] = 'Point of View'
    title_prefix_values['10.7554/eLife.26401'] = 'Object Recognition'
    title_prefix_values['10.7554/eLife.26775'] = 'Human Evolution'
    title_prefix_values['10.7554/eLife.26787'] = 'Cutting Edge'
    title_prefix_values['10.7554/eLife.26942'] = 'Alzheimer’s Disease'
    title_prefix_values['10.7554/eLife.27085'] = 'Translational Control'
    title_prefix_values['10.7554/eLife.27198'] = 'Cell Signaling'
    title_prefix_values['10.7554/eLife.27438'] = 'Point of View'
    title_prefix_values['10.7554/eLife.27467'
        ] = 'Evolutionary Developmental Biology'
    title_prefix_values['10.7554/eLife.27605'] = 'Population Genetics'
    title_prefix_values['10.7554/eLife.27933'] = 'Ion Channels'
    title_prefix_values['10.7554/eLife.27982'] = 'Living Science'
    title_prefix_values['10.7554/eLife.28339'] = 'Oncogene Regulation'
    title_prefix_values['10.7554/eLife.28514'] = 'Maternal Behavior'
    title_prefix_values['10.7554/eLife.28699'] = 'Point of View'
    title_prefix_values['10.7554/eLife.28757'] = 'Mitochondrial Homeostasis'
    title_prefix_values['10.7554/eLife.29056'] = 'Gene Variation'
    title_prefix_values['10.7554/eLife.29104'] = 'Cardiac Hypertrophy'
    title_prefix_values['10.7554/eLife.29502'] = 'Meiotic Recombination'
    title_prefix_values['10.7554/eLife.29586'] = 'Virus Evolution'
    title_prefix_values['10.7554/eLife.29942'
        ] = 'Post-translational Modifications'
    title_prefix_values['10.7554/eLife.30076'] = 'Scientific Publishing'
    title_prefix_values['10.7554/eLife.30183'] = 'Point of View'
    title_prefix_values['10.7554/eLife.30194'] = 'Organ Development'
    title_prefix_values['10.7554/eLife.30249'] = 'Tissue Regeneration'
    title_prefix_values['10.7554/eLife.30280'] = 'Adverse Drug Reactions'
    title_prefix_values['10.7554/eLife.30599'] = 'Living Science'
    title_prefix_values['10.7554/eLife.30865'] = 'Stone Tool Use'
    title_prefix_values['10.7554/eLife.31106'] = 'Sensory Neurons'
    title_prefix_values['10.7554/eLife.31328'] = 'Drought Stress'
    title_prefix_values['10.7554/eLife.31697'] = 'Scientific Publishing'
    title_prefix_values['10.7554/eLife.31808'] = 'Tissue Engineering'
    title_prefix_values['10.7554/eLife.31816'] = 'Sound Processing'
    title_prefix_values['10.7554/eLife.32011'] = 'Peer Review'
    title_prefix_values['10.7554/eLife.32012'] = 'Peer Review'
    title_prefix_values['10.7554/eLife.32014'] = 'Peer Review'
    title_prefix_values['10.7554/eLife.32015'] = 'Peer Review'
    title_prefix_values['10.7554/eLife.32016'] = 'Peer Review'
    title_prefix_values['10.7554/eLife.32715'] = 'Point of View'
    if doi in title_prefix_values:
        if json_content.lower() == title_prefix_values[doi].lower():
            json_content = title_prefix_values[doi]
    return json_content


def combine(value, new=None):
    """ Jinja2 filter which merges dictionaries.
	"""
    new = new or {}
    value = dict(value)
    value.update(new)
    return value


def rand_cmap(nlabels, type='bright', first_color_black=True,
    last_color_black=False, verbose=True):
    """
    Creates a random colormap to be used together with matplotlib. Useful for segmentation tasks
    :param nlabels: Number of labels (size of colormap)
    :param type: 'bright' for strong colors, 'soft' for pastel colors
    :param first_color_black: Option to use first color as black, True or False
    :param last_color_black: Option to use last color as black, True or False
    :param verbose: Prints the number of labels and shows the colormap. True or False
    :return: colormap for matplotlib
    """
    from matplotlib.colors import LinearSegmentedColormap
    import colorsys
    import numpy as np
    if type not in ('bright', 'soft'):
        print('Please choose "bright" or "soft" for type')
        return
    if verbose:
        print('Number of labels: ' + str(nlabels))
    if type == 'bright':
        randHSVcolors = [(np.random.uniform(low=0.0, high=1), np.random.
            uniform(low=0.2, high=1), np.random.uniform(low=0.9, high=1)) for
            i in range(nlabels)]
        randRGBcolors = []
        for HSVcolor in randHSVcolors:
            randRGBcolors.append(colorsys.hsv_to_rgb(HSVcolor[0], HSVcolor[
                1], HSVcolor[2]))
        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]
        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]
        random_colormap = LinearSegmentedColormap.from_list('new_map',
            randRGBcolors, N=nlabels)
    if type == 'soft':
        low = 0.6
        high = 0.95
        randRGBcolors = [(np.random.uniform(low=low, high=high), np.random.
            uniform(low=low, high=high), np.random.uniform(low=low, high=
            high)) for i in range(nlabels)]
        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]
        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]
        random_colormap = LinearSegmentedColormap.from_list('new_map',
            randRGBcolors, N=nlabels)
    if verbose:
        from matplotlib import colors, colorbar
        from matplotlib import pyplot as plt
        fig, ax = plt.subplots(1, 1, figsize=(15, 0.5))
        bounds = np.linspace(0, nlabels, nlabels + 1)
        norm = colors.BoundaryNorm(bounds, nlabels)
        cb = colorbar.ColorbarBase(ax, cmap=random_colormap, norm=norm,
            spacing='proportional', ticks=None, boundaries=bounds, format=
            '%1i', orientation=u'horizontal')
    return random_colormap


def _areareduceA(area, area0, crossings, reverse, sign):
    """Reduce accumulator area to allowed range."""
    area.Remainder(area0)
    if crossings & 1:
        area.Add((1 if area.Sum() < 0 else -1) * area0 / 2)
    if not reverse:
        area.Negate()
    if sign:
        if area.Sum() > area0 / 2:
            area.Add(-area0)
        elif area.Sum() <= -area0 / 2:
            area.Add(area0)
    elif area.Sum() >= area0:
        area.Add(-area0)
    elif area.Sum() < 0:
        area.Add(area0)
    return 0.0 + area.Sum()


def encode(token):
    """Escape special characters in a token for path representation.

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


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

        :param DurationLogInfo val:
        :rtype: WebSessionsFixedLengthPolicy
        """
    return cls('defined', val)


@classmethod
def load_fasttext_format(cls, model_file, encoding='utf8'):
    """
        Load the input-hidden weight matrix from the fast text output files.

        Note that due to limitations in the FastText API, you cannot continue training
        with a model loaded this way, though you can query for word similarity etc.

        `model_file` is the path to the FastText output files.
        FastText outputs two model files - `/path/to/model.vec` and `/path/to/model.bin`

        Expected value for this example: `/path/to/model` or `/path/to/model.bin`,
        as gensim requires only `.bin` file to load entire fastText model.

        """
    model = cls()
    if not model_file.endswith('.bin'):
        model_file += '.bin'
    model.file_name = model_file
    model.load_binary_data(encoding=encoding)
    return model


def convert_missing_indexer(indexer):
    """
    Reverse convert a missing indexer, which is a dict
    return the scalar indexer and a boolean indicating if we converted
    """
    if isinstance(indexer, dict):
        indexer = indexer['key']
        if isinstance(indexer, bool):
            raise KeyError('cannot use a single bool to index into setitem')
        return indexer, True
    return indexer, False


def set_dry_run(value: bool) ->None:
    """Set the value for DRY_RUN outside this module."""
    global DRY_RUN
    DRY_RUN = value


def iteritems(dictionary):
    """
  Function to use the generator-based items iterator over built-in
  dictionaries in both Python 2 and 3.
  """
    try:
        return getattr(dictionary, 'iteritems')()
    except AttributeError:
        return iter(getattr(dictionary, 'items')())


def parent(node):
    """
        | Get parent-node

        :param  lxml.etree._Element node:
            lxml-etree-element
        :return lxml.etree._Element:
            parent-node
    """
    return node.getparent()


def multivalue(reverse_commands, value):
    """
    Given an string value, look for the key in commands, if value
    has upper or lower case, consider that.
    """
    result = False
    final_value = value
    key = None
    if value in reverse_commands:
        key = reverse_commands.get(value)
        result = True
    elif value.lower() in reverse_commands:
        final_value = value.lower()
        key = reverse_commands.get(final_value)
        result = True
    elif value.upper() in reverse_commands:
        final_value = value.upper()
        key = reverse_commands.get(final_value)
        result = True
    return result, key


@classmethod
def parse_data_block(cls, data_block_bytes):
    """Parse a data block"""
    raise NotImplementedError


def put_attributes(DomainName=None, ItemName=None, Attributes=None,
    Expected=None):
    """
    The PutAttributes operation creates or replaces attributes in an item. The client may specify new attributes using a combination of the Attribute.X.Name and Attribute.X.Value parameters. The client specifies the first attribute by the parameters Attribute.0.Name and Attribute.0.Value , the second attribute by the parameters Attribute.1.Name and Attribute.1.Value , and so on.
    Attributes are uniquely identified in an item by their name/value combination. For example, a single item can have the attributes { "first_name", "first_value" } and { "first_name", second_value" } . However, it cannot have two attribute instances where both the Attribute.X.Name and Attribute.X.Value are the same.
    Optionally, the requestor can supply the Replace parameter for each individual attribute. Setting this value to true causes the new attribute value to replace the existing attribute value(s). For example, if an item has the attributes { 'a', '1' } , { 'b', '2'} and { 'b', '3' } and the requestor calls PutAttributes using the attributes { 'b', '4' } with the Replace parameter set to true, the final attributes of the item are changed to { 'a', '1' } and { 'b', '4' } , which replaces the previous values of the 'b' attribute with the new value.
    You cannot specify an empty string as an attribute name.
    Because Amazon SimpleDB makes multiple copies of client data and uses an eventual consistency update model, an immediate  GetAttributes or  Select operation (read) immediately after a  PutAttributes or  DeleteAttributes operation (write) might not return the updated data.
    The following limitations are enforced for this operation:
    See also: AWS API Documentation

    :example: response = client.put_attributes(
        DomainName='string',
        ItemName='string',
        Attributes=[
            {
                'Name': 'string',
                'Value': 'string',
                'Replace': True|False
            },
        ],
        Expected={
            'Name': 'string',
            'Value': 'string',
            'Exists': True|False
        }
    )

    :type DomainName: string
    :param DomainName: [REQUIRED] The name of the domain in which to perform the operation.

    :type ItemName: string
    :param ItemName: [REQUIRED] The name of the item.

    :type Attributes: list
    :param Attributes: [REQUIRED] The list of attributes.
            (dict) --
            Name (string) -- [REQUIRED] The name of the replaceable attribute.
            Value (string) -- [REQUIRED] The value of the replaceable attribute.
            Replace (boolean) -- A flag specifying whether or not to replace the attribute/value pair or to add a new attribute/value pair. The default setting is false .

    :type Expected: dict
    :param Expected: The update condition which, if specified, determines whether the specified attributes will be updated or not. The update condition must be satisfied in order for this request to be processed and the attributes to be updated.
            Name (string) --The name of the attribute involved in the condition.
            Value (string) --The value of an attribute. This value can only be specified when the Exists parameter is equal to true .
            Exists (boolean) --A value specifying whether or not the specified attribute must exist with the specified value in order for the update condition to be satisfied. Specify true if the attribute must exist for the update condition to be satisfied. Specify false if the attribute should not exist in order for the update condition to be satisfied.

    :returns:
    DomainName (string) -- [REQUIRED] The name of the domain in which to perform the operation.
    ItemName (string) -- [REQUIRED] The name of the item.
    Attributes (list) -- [REQUIRED] The list of attributes.

    (dict) --
    Name (string) -- [REQUIRED] The name of the replaceable attribute.
    Value (string) -- [REQUIRED] The value of the replaceable attribute.
    Replace (boolean) -- A flag specifying whether or not to replace the attribute/value pair or to add a new attribute/value pair. The default setting is false .

    Expected (dict) -- The update condition which, if specified, determines whether the specified attributes will be updated or not. The update condition must be satisfied in order for this request to be processed and the attributes to be updated.

    Name (string) --The name of the attribute involved in the condition.

    Value (string) --The value of an attribute. This value can only be specified when the Exists parameter is equal to true .

    Exists (boolean) --A value specifying whether or not the specified attribute must exist with the specified value in order for the update condition to be satisfied. Specify true if the attribute must exist for the update condition to be satisfied. Specify false if the attribute should not exist in order for the update condition to be satisfied.

    """
    pass


def get_verifier():
    """
        Wait for key verification to occur, then return the verifier string.
        When this fires, we have seen at least one validly-encrypted message
        from our peer, indicating that we have established a shared secret
        key with some party who knows (or correctly guessed) the wormhole
        code.

        The verifier string (bytes) can be displayed to the user (perhaps as
        hex), who can manually compare it with the peer's verifier, to obtain
        more confidence in the secrecy of the established key.

        If we receive an invalid encrypted message (such as what would happen
        if an attacker tried and failed to guess the wormhole code), this
        will instead errback with a ``WrongPasswordError``.

        :return: the verifier string, after a valid encrypted message has
                 arrived
        :rtype: ``Deferred[bytes]``
        """


def p_nonempty_lists(t):
    """case_spec_list      : case_spec case_spec_list
                           | case_spec
       case_statement_list : case_statement case_statement_list
                           | case_statement"""
    if len(t) == 2:
        t[0] = t[1]
    else:
        t[0] = t[1] + t[2]


def convert_iobes_to_bracket(tag):
    """
    Convert tags from the IOBES scheme to the CoNLL bracketing.

    Example:
    B-A0 -> (A0*
    I-A0 -> *
    E-A0 -> *)
    S-A1 -> (A1*)
    O    -> *
    """
    if tag.startswith('I') or tag.startswith('O'):
        return '*'
    if tag.startswith('B'):
        return '(%s*' % tag[2:]
    if tag.startswith('E'):
        return '*)'
    if tag.startswith('S'):
        return '(%s*)' % tag[2:]
    else:
        raise ValueError('Unknown tag: %s' % tag)


def ready():
    """Returns flag indicating whether we are ready to handle requests.

    :rtype: bool
    """
    return False


def dispatch_hook(key, hooks, hook_data, **kwargs):
    """Dispatches a hook dictionary on a given piece of data."""
    hooks = hooks or dict()
    if key in hooks:
        hooks = hooks.get(key)
        if hasattr(hooks, '__call__'):
            hooks = [hooks]
        for hook in hooks:
            _hook_data = hook(hook_data, **kwargs)
            if _hook_data is not None:
                hook_data = _hook_data
    return hook_data


def bool2check(val, true='✓', false=''):
    """Filter value as boolean and show check mark (✓) or nothing."""
    return true if val else false


def atse_getSchemaById(schema_id):
    """ return a schema by its schema_id """


def make_squash_key(d):
    """Dict squashing key function"""
    d = d.copy()
    d.pop('datetime')
    return d


def _bool_value(element):
    """
    Given an xml element, returns the tag text converted to a bool.

    :param element: The element to fetch the value from.

    :return: A boolean.
    """
    return element.text.lower() == 'true'


@classmethod
def from_dict(cls, data):
    """Construct an instance a from python built-in containers.

        Parameters
        ----------
            data : Sequence[Container]
                list of objects as ``item_class.from_dict`` input.
        """
    return cls(map(cls._item_from_dict, data))


def authGSSServerClean(context):
    """
    Destroys the context for GSSAPI server-side authentication. This function is provided for API
    compatibility with original pykerberos but does nothing. The context object destroys itself
    when it is reclaimed.

    @param context: the context object returned from authGSSServerInit.
    @return: a result code (see above).
    """


def isoformat(dt):
    """Return iso-formatted timestamp

    Like .isoformat(), but uses Z for UTC instead of +00:00
    """
    return dt.isoformat().replace('+00:00', 'Z')


def add():
    """Add a new time marker

    """
    pass


@staticmethod
def _return_list_brackets(brackets: str) ->list:
    """
        If, after trimming the spaces, an empty line remains, then we will
        return the list [' ', ''] that will allow you to indent from the left
        edge of the console window for the progress bar, but will not make an
        unnecessary space from the right of the progress bar.
        Otherwise, we return the list of the two specified brackets.
        """
    return [' ', ''] if brackets == '' else list(brackets)


@classmethod
def from_string(cls, game_type):
    """
        Retrieves the game type enum value from a string.

        :param str game_type: Type of the game, as returned by gbx_remote.GetVersion()['Name']
        """
    return {'TmForever': cls.FOREVER}[game_type]


def setRules(rules):
    """
        Установить новые правила анализа.

        @param rules: правила анализа
        @type rules: C{str}
        """


def get_method_function(cls, method_name):
    """Get definition function given in its `method_name`.

    There is a difference between the result of this function and
    ``getattr(cls, method_name)`` because the last one return the unbound
    method and this a python function.

    """
    if not isinstance(cls, type):
        cls = cls.__class__
    mro = cls.mro()
    i, res = 0, None
    while not res and i < len(mro):
        sc = mro[i]
        method = sc.__dict__.get(method_name)
        if callable(method):
            res = method
        else:
            i += 1
    return res


def should_build_with_cython(package, release=None):
    """Returns the previously used Cython version (or 'unknown' if not
    previously built) if Cython should be used to build extension modules from
    pyx files.  If the ``release`` parameter is not specified an attempt is
    made to determine the release flag from `astropy.version`.
    """
    try:
        version_module = __import__(package + '.cython_version', fromlist=[
            'release', 'cython_version'])
    except ImportError:
        version_module = None
    if release is None and version_module is not None:
        try:
            release = version_module.release
        except AttributeError:
            pass
    try:
        cython_version = version_module.cython_version
    except AttributeError:
        cython_version = 'unknown'
    have_cython = False
    try:
        import Cython
        have_cython = True
    except ImportError:
        pass
    if have_cython and (not release or cython_version == 'unknown'):
        return cython_version
    else:
        return False


def convert_qe_time_to_sec(timestr):
    """Given the walltime string of Quantum Espresso, converts it in a number of seconds (float)."""
    rest = timestr.strip()
    if 'd' in rest:
        days, rest = rest.split('d')
    else:
        days = '0'
    if 'h' in rest:
        hours, rest = rest.split('h')
    else:
        hours = '0'
    if 'm' in rest:
        minutes, rest = rest.split('m')
    else:
        minutes = '0'
    if 's' in rest:
        seconds, rest = rest.split('s')
    else:
        seconds = '0.'
    if rest.strip():
        raise ValueError(
            "Something remained at the end of the string '{}': '{}'".format
            (timestr, rest))
    num_seconds = float(seconds) + float(minutes) * 60.0 + float(hours
        ) * 3600.0 + float(days) * 86400.0
    return num_seconds


def free_bake_all():
    """Delete all baked caches of all objects in the current scene

    """
    pass


def anomalous_signals(hklin):
    """
    Compute some measures of anomalous signal: df / f and di / sig(di).
    """
    from iotbx import mtz
    m = mtz.object(hklin)
    mas = m.as_miller_arrays()
    data = None
    for ma in mas:
        if not ma.anomalous_flag():
            continue
        if str(ma.observation_type()) != 'xray.intensity':
            continue
        data = ma
    if not data:
        raise RuntimeError('no data found')
    df_f = data.anomalous_signal()
    differences = data.anomalous_differences()
    di_sigdi = sum(abs(differences.data())) / sum(differences.sigmas())
    return df_f, di_sigdi


def listActionsFor(reference):
    """Returns a list of dictionaries according to
        IReferenceActionProvider.listActionsFor."""


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

        :param ShowcaseUntrashedDeprecatedType val:
        :rtype: EventType
        """
    return cls('showcase_untrashed_deprecated', val)


@staticmethod
def should_analyze_file(modname, path, is_argument=False):
    """Returns whether or not a module should be checked.

        This implementation returns True for all python source file, indicating
        that all files should be linted.

        Subclasses may override this method to indicate that modules satisfying
        certain conditions should not be linted.

        :param str modname: The name of the module to be checked.
        :param str path: The full path to the source code of the module.
        :param bool is_argument: Whetter the file is an argument to pylint or not.
                                 Files which respect this property are always
                                 checked, since the user requested it explicitly.
        :returns: True if the module should be checked.
        :rtype: bool
        """
    if is_argument:
        return True
    return path.endswith('.py')


def is_valid_py_file(path):
    """
    Checks whether the file can be read by the coverage module. This is especially
    needed for .pyx files and .py files with syntax errors.
    """
    import os
    is_valid = False
    if os.path.isfile(path) and not os.path.splitext(path)[1] == '.pyx':
        try:
            with open(path, 'rb') as f:
                compile(f.read(), path, 'exec')
                is_valid = True
        except:
            pass
    return is_valid


@staticmethod
def text(pnode):
    """ extracts the value stored in the node """
    rc = []
    for node in pnode.childNodes:
        if node.nodeType == node.TEXT_NODE:
            rc.append(str(node.data).strip())
    return ''.join(rc)


def relpath(path):
    """Convert the given path to a relative path.

    This is the inverse of `abspath`, stripping a leading ``'/'`` from
    the path if it is present.

    Arguments:
        path (str): A path to adjust.

    Returns:
        str: A relative path.

    Example:
        >>> relpath('/a/b')
        'a/b'

    """
    return path.lstrip('/')


def p_track_flag_isrc(t):
    """track_flag : ISRC STRING"""
    from audiotools.toc import TOCFlag_ISRC
    t[0] = TOCFlag_ISRC(t[2])


def extract_lzh(archive, compression, cmd, verbosity, interactive, outdir):
    """Extract a LZH archive."""
    opts = 'x'
    if verbosity > 1:
        opts += 'v'
    opts += 'w=%s' % outdir
    return [cmd, opts, archive]


def uch_psri(x, dp, d_pipe, gs, rhog, rhos, ut):
    """
    Choking velocity from PSRI 2016 notebook. Uses MKS units for input
    parameters but returns Uch in ft/s. Function requires SciPy fsolve to solve
    for Uch.

    Parameters
    ----------
    x : float
        Solve for Uch with SciPy fsolve
    dp : float
        Particle size [m]
    d_pipe : float
        Pipe diameter [m]
    gs : float
        Solids mass flux [kg/(s m^2)]
    rhog : float
        Density of gas [kg/m^3]
    rhos : float
        Density of particle [kg/m^3]
    ut : float
        Terminal velocity [m/s]

    Returns
    -------
    uch : float
        Choking velocity [ft/s]

    References
    ----------
    Notebook from PSRI 2016 workshop, pages J-20 and J-72.
    """
    uch = x
    g = 32.2
    dp = dp * 3.28084
    d_pipe = d_pipe * 3.28084
    gs = gs * 0.204817303
    rhog = rhog * 0.062428
    rhos = rhos * 0.062428
    ut = ut * 3.28084
    f1 = (uch - ut) / (g * dp) ** 0.5 - (gs / (uch * rhog)) ** 0.35 * (d_pipe /
        dp) ** 0.35 * (rhos / rhog) ** 0.1
    return f1


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


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

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


def 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


@classmethod
def patch(cls, func):
    """Create an authenticate object with a PATCH method

        Arguments:
            func: a function to decorate

        """
    return cls(func, method='PATCH')


def post_install(context):
    """Post install script"""


def rISCO_14067295(a):
    """
    Calculate the ISCO radius of a Kerr BH as a function of the Kerr parameter using eqns. 2.5 and 2.8 from Ori and Thorne, Phys Rev D 62, 24022 (2000)

    Parameters
    ----------
    a : Kerr parameter

    Returns
    -------
    ISCO radius
    """
    import numpy as np
    a = np.array(a)
    z1 = 1.0 + (1.0 - a ** 2.0) ** (1.0 / 3) * ((1.0 + a) ** (1.0 / 3) + (
        1.0 - a) ** (1.0 / 3))
    z2 = np.sqrt(3 * a ** 2 + z1 ** 2)
    a_sign = np.sign(a)
    return 3 + z2 - np.sqrt((3.0 - z1) * (3.0 + z1 + 2.0 * z2)) * a_sign


@classmethod
def get_collection_url_prefix(cls):
    """
        Returns a prefix which (by default) applies to all "collection" URLs
        provided by this view class.
        """
    prefix = getattr(cls, 'collection_url_prefix', None)
    if prefix:
        return prefix
    return '/{}'.format(cls.get_route_prefix())


def parse_mime_type(mime_type):
    """Carves up a mime-type and returns a tuple of the
       (type, subtype, params) where 'params' is a dictionary
       of all the parameters for the media range.
       For example, the media range 'application/xhtml;q=0.5' would
       get parsed into:

       ('application', 'xhtml', {'q', '0.5'})
       """
    type = mime_type.split(';')
    type, plist = type[0], type[1:]
    try:
        type, subtype = type.split('/', 1)
    except ValueError:
        type, subtype = type.strip() or '*', '*'
    else:
        type = type.strip() or '*'
        subtype = subtype.strip() or '*'
    params = {}
    for param in plist:
        param = param.split('=', 1)
        if len(param) == 2:
            key, value = param[0].strip(), param[1].strip()
            if key and value:
                params[key] = value
    return type, subtype, params


def skip_redundant(iterable, skipset=None):
    """
    Redundant items are repeated items or items in the original skipset.

    :param iterable:
    :param skipset:
    :return:
    """
    if skipset is None:
        skipset = set()
    for item in iterable:
        if item not in skipset:
            skipset.add(item)
            yield item


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

    The storage type of ``elemwise_sub`` output depends on storage types of inputs

       - elemwise_sub(row_sparse, row_sparse) = row_sparse
       - elemwise_sub(csr, csr) = csr
       - elemwise_sub(default, csr) = default
       - elemwise_sub(csr, default) = default
       - elemwise_sub(default, rsp) = default
       - elemwise_sub(rsp, default) = default
       - otherwise, ``elemwise_sub`` generates output with default storage

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

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

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


def update_error_pointer(error, pointer_or_prefix):
    """
    Helper function to update an Error's pointer attribute with a (potentially prefixed) dictionary key or list index.
    """
    if error.pointer:
        error.pointer = '{}.{}'.format(pointer_or_prefix, error.pointer)
    else:
        error.pointer = '{}'.format(pointer_or_prefix)
    return error


def _strip_elements(jsn, elements):
    """ Remove supplied elements from the dict object

    We use this with a list of binary elements so that we don't store
    empty tags in couchdb when we are already storing the binary data as
    attachments.

    """
    for tagstack, element in elements:
        if len(tagstack) == 0:
            jsn.pop(element.tag)
        else:
            current_node = jsn
            for tag in tagstack:
                current_node = current_node[tag]
            current_node.pop(element.tag)


def ar_5(provider):
    """Stop ARTIM timer."""
    provider.timer.stop()
    return 'Sta1'


def rethrow(exception, additional_message):
    """
    Re-raise the last exception that was active in the current scope
    without losing the stacktrace but adding an additional message.
    This is hacky because it has to be compatible with both python 2/3
    """
    e = exception
    m = additional_message
    if not e.args:
        e.args = m,
    else:
        e.args = (e.args[0] + m,) + e.args[1:]
    raise e


def locfmt(loc):
    """ Return a (lat, lon) location tuple in a standard string format """
    return '({0:.6f},{1:.6f})'.format(loc[0], loc[1])


def discarding_tids_before(tid):
    """
        Remove the tid, and anything older, from the list of cached entries.

        Return the new value to place in the cache. Return None if all values
        were removed and the cached entry should be removed.
        """


def Nu_Ornatsky(Re, Pr_b, Pr_w, rho_w=None, rho_b=None):
    """Calculates internal convection Nusselt number for turbulent vertical
    upward flow in a pipe under supercritical conditions according to [1]_ as
    shown in both [2]_ and [3]_.

    .. math::
        Nu_b = 0.023Re_b^{0.8}(\\min(Pr_b, Pr_w))^{0.8}
        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.3}

    Parameters
    ----------
    Re : float
        Reynolds number with bulk fluid properties, [-]
    Pr_b : float
        Prandtl number with bulk fluid properties, [-]
    Pr_w : float
        Prandtl number with wall fluid properties, [-]
    rho_w : float, optional
        Density at the wall temperature, [kg/m^3]
    rho_b : float, optional
        Density at the bulk temperature, [kg/m^3]

    Returns
    -------
    Nu : float
        Nusselt number with bulk fluid properties, [-]

    Notes
    -----
    [2]_ ranked it thirteenth in the enhanced heat transfer
    category, with a MAD of 19.8% and 11th in the normal heat transfer with a
    MAD of 17.6%. [3]_ ranked it seventh on a combined database.

    If the extra density information is not provided, it will not be used.

    Examples
    --------
    >>> Nu_Ornatsky(1E5, 1.2, 1.5, 330, 290.)
    276.63531150832307

    References
    ----------
    .. [1] Ornatsky A.P., Glushchenko, L.P., Siomin, E.T. (1970). The research
       of temperature conditions of small diameter parallel tubes cooled by
       water under supercritical pressures. In: Proceedings of the 4th
       international heat transfer conference, Paris-Versailles, France.
       Elsevier, Amsterdam, vol VI, Paper no. B, 8 November 1970
    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. "An Assessment of
       Correlations of Forced Convection Heat Transfer to Water at
       Supercritical Pressure." Annals of Nuclear Energy 76 (February 2015):
       451-60. doi:10.1016/j.anucene.2014.10.027.
    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. "Optimization of
       Heat Transfer Coefficient Correlation at Supercritical Pressure Using
       Genetic Algorithms." Heat and Mass Transfer 45, no. 6 (January 8, 2009):
       757-66. doi:10.1007/s00231-008-0475-4.
    """
    Nu = 0.023 * Re ** 0.8 * min(Pr_b, Pr_w) ** 0.8
    if rho_w and rho_b:
        Nu *= (rho_w / rho_b) ** 0.3
    return Nu


def check_consecutive(claimset_list):
    """
    Checks claims are numbered consecutively.

    :param claimset_list: set of (number, text) tuples for claims.
    :type claimset_list: tuples (int, str)
    :return: true for consecutive; false if check fails
    """
    previous_number = 0
    try:
        for number, claim in claimset_list:
            if number == previous_number + 1:
                previous_number = previous_number + 1
            else:
                return False
        return True
    except:
        return False


def define_peers(peer_names, peer_hosts, organisation, domain=None):
    """Define peers as connection objects.

        Args:
            peer_names (Iterable): List of peer names.
            peer_hosts (Iterable): List of peer hosts.
            organisation (str): What organisation the peers belong to
            domain (str): Domain used. Defaults to none.

        Returns:
            tuple: A tuple of dictionaries with Peer Options and Peer Connections.
    """
    peer_options = {}
    peer_connections = {}
    for name, host in zip(peer_names, peer_hosts):
        if domain:
            key = f'{name}.{organisation}.{domain}'
        else:
            key = name
        peer_options[key] = {'chaincodeQuery': True, 'endorsingPeer': True,
            'eventSource': True, 'ledgerQuery': True}
        peer_connections[key] = {'url': 'grpc://' + host + ':7051',
            'eventUrl': 'grpc://' + host + ':7053'}
    return peer_options, peer_connections


def pib(coords, box):
    """
    Pack coordinates into periodic box.

    Args:
        coords: (N,3) numpy array of atom coordinates.
        box: (3,3) numpy array of box parameters.

    Returns:
        coords: (N,3) numpy array of packed coordinates (overwrites input).
    """
    import numpy as np
    import numpy as np
    assert len(coords.shape) == 2
    assert coords.shape[1] == 3
    assert box.shape == (3, 3)
    boxinv = np.zeros(3)
    boxinv[0] = 1.0 / box[0, 0]
    boxinv[1] = 1.0 / box[1, 1]
    boxinv[2] = 1.0 / box[2, 2]
    for xyz in coords:
        s = np.floor(xyz[2] * boxinv[2])
        xyz[2] -= s * box[2, 2]
        xyz[1] -= s * box[2, 1]
        xyz[0] -= s * box[2, 0]
        s = np.floor(xyz[1] * boxinv[1])
        xyz[1] -= s * box[1, 1]
        xyz[0] -= s * box[1, 0]
        s = np.floor(xyz[0] * boxinv[0])
        xyz[0] -= s * box[0, 0]
    return coords


def greatest_common_divisor(a, b):
    """
    Get the greatest common divisor of two numbers

    @param a: First number.
    @type  a: C{int}

    @param b: Second number.
    @type  b: C{int}

    @return: Greatest common divisor.
    @rtype:  C{int}
    """
    while b != 0:
        t = b
        b = a % b
        a = t
    return a


def pgettext_data(msgid: str, msgctxt: str):
    """Try to translate the given msgid (with optional msgctxt), if new data name’s translation is enabled.

    :param msgid: The string to translate.
    :type msgid: str
    :param msgctxt: The translation context (defaults to BLT_I18NCONTEXT_DEFAULT).
    :type msgctxt: str
    :return:  The translated string (or msgid if no translation was found).
    """
    pass


def guess_minimum_encoding(text, charsets=('ascii', 'latin1', 'utf8')):
    """Try to guess the minimum charset that is able to represent.

    Try to guess the minimum charset that is able to represent the given
    text using the provided charsets. text is supposed to be encoded in utf8.
    Returns (encoded_text, charset) where charset is the first charset
    in the sequence being able to encode text.
    Returns (text_in_utf8, 'utf8') in case no charset is able to encode text.

    @note: If the input text is not in strict UTF-8, then replace any
        non-UTF-8 chars inside it.
    """
    text_in_unicode = text.decode('utf8', 'replace')
    for charset in charsets:
        try:
            return text_in_unicode.encode(charset), charset
        except (UnicodeEncodeError, UnicodeDecodeError):
            pass
    return text_in_unicode.encode('utf8'), 'utf8'


def divide_list(a_list, divide_func):
    """Divide a list like object into two parts.

    - a_list: list like object
    - divide_func: the divide function to return True/False

    Return two parts of the list.

    Example:
    divide_list([1, 2, 3], lambda x: x > 1)   ->   [2, 3], [1]
    """
    suit, not_suit = [], []
    for item in a_list:
        result = suit if divide_func(item) else not_suit
        result.append(item)
    return suit, not_suit


def get_records_iex(*args, **kwargs):
    """
    Returns the record value, record date, recent value, and 30-day average for
    market volume, # of symbols traded, # of routed trades and notional value.
    This function accepts no additional parameters.

    Reference: https://www.iextrading.com/developer/docs/#records

    :return: DataFrame
    """
    from pandas_datareader.iex.stats import RecordsReader
    return RecordsReader(*args, **kwargs).read()


@staticmethod
def feed_description(feed: dict) ->str:
    """
        Get feed description.

        :param feed: feed dict
        :return: str
        """
    subtitle = feed.get('subtitle', None)
    if subtitle:
        return subtitle
    return feed.get('description', None)


def loseWriteConnection():
    """
        Half-close the write side of a TCP connection.

        If the protocol instance this is attached to provides
        IHalfCloseableProtocol, it will get notified when the operation is
        done. When closing write connection, as with loseConnection this will
        only happen when buffer has emptied and there is no registered
        producer.
        """


def dot(a, b, dtype=None, queue=None, slice=None):
    """
    .. versionadded:: 2011.1
    """
    from pyopencl.reduction import get_dot_kernel
    krnl = get_dot_kernel(a.context, dtype, a.dtype, b.dtype)
    result, event1 = krnl(a, b, queue=queue, slice=slice, wait_for=a.events +
        b.events, return_event=True)
    result.add_event(event1)
    return result


def _inversion_simple(a3, a0):
    """Solve for degree 5 polynomial with coefficients a5=1, a3=0., a0."""
    return (-a0) ** (1.0 / 5.0)


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

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

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


def DIESIS(n):
    """
	N: Standard core of PyPLaSM
	repetition operator. Returns the sequence with n repetitions of arg
	(n::isintpos)(arg::tt) -> (isseq)
	"""
    return lambda List: [List] * int(n)


@classmethod
def from_dict(cls, dictionary):
    """
        Instantiates a Sortinfo object from dictionary,
        normalising as necessary
        """
    normalised = cls.normalise_dict(dictionary)
    return cls.from_normalised_dict(normalised)


def all_equiv_sat(fsm, winning, agents):
    """
    Return the states s of winning such that all states indistinguishable
    from s by agents are in winning.

    fsm -- a MAS representing the system;
    winning -- a BDD representing a set of states of fsm;
    agents -- a set of agents.

    """
    nwinning = ~winning & fsm.bddEnc.statesInputsMask
    return ~fsm.equivalent_states(nwinning & fsm.reachable_states,
        frozenset(agents)) & winning


def lookupRenderMethod(name):
    """
        Look up and return the render method associated with the given name.

        @type name: L{str}
        @param name: The value of a render directive encountered in the
            document returned by a call to L{IRenderable.render}.

        @return: A two-argument callable which will be invoked with the request
            being responded to and the tag object on which the render directive
            was encountered.
        """


def write_bin_labels(mapper, dest, header='# bin labels:\n', fmt=
    """# bin {index:{max_iwidth}d} -- {label!s}
"""):
    """Print labels for all bins in ``mapper`` to the file-like object``dest``.

    If provided, ``header`` is printed prior to any labels. A number of expansions
    are available in ``header``:
      * ``mapper`` -- the mapper itself (from which most of the following can be obtained)
      * ``classname``  -- the class name of the mapper
      * ``nbins`` -- number of bins in the mapper

    The ``fmt`` string specifies how bin labels are to be printed. A number of
    expansions are available in ``fmt``:
      * ``index`` -- the zero-based index of the bin
      * ``label`` -- the label of the bin
      * ``max_iwidth`` -- the maximum width (in characters) of the bin index, for pretty alignment
    """
    if header:
        dest.write(header.format(mapper=mapper, classname=mapper.__class__.
            __name__, nbins=mapper.bins))
    max_iwidth = len(str(mapper.nbins - 1))
    for ibin, label in enumerate(mapper.labels):
        dest.write(fmt.format(index=ibin, label=label, max_iwidth=max_iwidth))


def post_document_content(gismo, i, max_size=None):
    """
    Document indice to document content.

    Assumes that document has a 'content' key.

    Parameters
    ----------
    gismo: Gismo
        Gismo instance
    i : int
        document indice
    max_size: int, optional
        Maximum number of chars to return

    Returns
    -------
    str
        Content of document i from corpus
    """
    return gismo.corpus[i]['content'][:max_size]


def calc_rho_and_rho_bar_squared(final_log_likelihood, null_log_likelihood,
    num_est_parameters):
    """
    Calculates McFadden's rho-squared and rho-bar squared for the given model.

    Parameters
    ----------
    final_log_likelihood : float.
        The final log-likelihood of the model whose rho-squared and rho-bar
        squared are being calculated for.
    null_log_likelihood : float.
        The log-likelihood of the model in question, when all parameters are
        zero or their 'base' values.
    num_est_parameters : int.
        The number of parameters estimated in this model.

    Returns
    -------
    `(rho_squared, rho_bar_squared)` : tuple of floats.
        The rho-squared and rho-bar-squared for the model.
    """
    rho_squared = 1.0 - final_log_likelihood / null_log_likelihood
    rho_bar_squared = 1.0 - (final_log_likelihood - num_est_parameters
        ) / null_log_likelihood
    return rho_squared, rho_bar_squared


@classmethod
def _file_for_file_module(cls, module):
    """Return the file for the module."""
    try:
        return module.__file__ and cls._make_absolute(module.__file__)
    except AttributeError:
        pass


def pov_index(expenditure, poverty_line, *args):
    """
        Poverty gap index: adds up the extent to which individuals on average fall below the poverty line.
        It is expressed as a percentage of the poverty line.

        First argument is a list having numerical values of individual's or country's expenditure
        Second argument refers to the minimum income for not being considered as poor.

        If just two arguments are passed in pov_index it will calculate the pov_index considering the entire list.
        If *args=0 => entire list will be considered
        If *args=1 => Just the poor population will be considered
    """
    index = 0
    count = 0
    for country in expenditure:
        if country < poverty_line:
            index += (poverty_line - country) / poverty_line
            count += 1
    if len(expenditure) != 0 and (len(args) == 0 or args[0] == 0):
        return index / len(expenditure)
    elif len(expenditure) != 0 and args[0] == 1 and count != 0:
        return index / count
    else:
        print('Check Parameters.')
        return


def readable_keyword(s):
    """Return keyword with only the first letter in title case."""
    if s and not s.startswith('*') and not s.startswith('['):
        if s.count('.'):
            library, name = s.rsplit('.', 1)
            return library + '.' + name[0].title() + name[1:].lower()
        else:
            return s[0].title() + s[1:].lower()
    else:
        return s


@classmethod
def settings(cls, manager, required=None, defaults=None):
    """
        attach settings to class

        @param required: required settings
        @param defaults: default settings
        """
    if required is not None:
        manager.settings.required = required
    if defaults is not None:
        manager.settings.defaults = defaults


def removeAt(astring):
    """remove the leading @ from a string"""
    return astring.replace('@', '')


def get_exception_name(node):
    """
    Find the name of an exception

    Args:
        node: Parso node containing the raises statement

    Returns:
        str: The exception name
    """
    name = node.children[1]
    while not name.type == 'name':
        name = name.children[0]
    return name.value