def string2python_telegram_bot_dict(string: str):
    """
    Convert a proxy string for `request_kwargs` of python-telegram-bot.

    :param str string: Proxy string
    :return: dict
    """
    return {'proxy_url': string}


@classmethod
def getProtocols(cls):
    """ Return all Protocol subclasses from all plugins for this domain."""
    return cls.__getSubclasses('protocols', cls._protocolClass)


def get_user_by_id(user_id):
    """Get the user associated with the given id.

        :param user_id: The user id.
        :type user_id: `uuid.UUID`
        :return: The user found or None.
        :rtype: `IUser`.
        """


@staticmethod
def _define_module_argument_spec():
    """
        Define the argument spec for the ansible module
        :return: argument spec dictionary
        """
    argument_spec = dict(jobId=dict(required=True), executionId=dict(
        required=True), referenceId=dict(required=True), name=dict(required
        =True), description=dict(required=True), data=dict(required=True),
        state=dict(choices=['present', 'absent']))
    return {'argument_spec': argument_spec}


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


def should_cache(request_args):
    """Check the request args for cache-control specifications.

    :param request_args: flask request args
    """
    if 'cache-control' in request_args and request_args['cache-control'] in [
        'no-cache', 'no-store']:
        return False
    return True


def size():
    """Return the data length in bytes.
        """


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


def two_opt_swap(r: list, i: int, k: int) ->list:
    """Reverses items `i`:`k` in the list `r`
    https://en.wikipedia.org/wiki/2-opt."""
    out = r.copy()
    out[i:k + 1] = out[k:i - 1:-1]
    return out


def delete():
    """Delete selected nodes

    """
    pass


def median(data_list):
    """
    Accepts a list of numbers and returns the median value.

    The median is the number in the middle of a sequence,
    with 50 percent of the values above, and 50 percent below.

    In cases where the sequence contains an even number of values -- and
    therefore no exact middle -- the two values nearest the middle
    are averaged and the mean returned.

    h3. Example usage

        >> import calculate
        >> seq1 = [1,2,3]
        >> calculate.median(seq1)
        2.0
        >> seq2 = (1,4,3,2)
        >> calculate.median(seq2)
        2.5

    h3. Documentation

        * "median":http://en.wikipedia.org/wiki/Median

    """
    try:
        data_list = list(map(float, data_list))
    except TypeError:
        raise TypeError('Input values should be a number')
    n = len(data_list)
    data_list.sort()
    if n & 1:
        index = n / 2
        median = data_list[int(index)]
    else:
        low_index = n / 2 - 1
        high_index = n / 2
        median = (data_list[int(low_index)] + data_list[int(high_index)]) / 2.0
    return median


def swait_setup_incrementer(swait, scan=None, limit=100000):
    """setup swait record as an incrementer"""
    scan = scan or '.1 second'
    swait.reset()
    swait.scan.put('Passive')
    pvname = swait.val.pvname.split('.')[0]
    swait.channels.A.input_pv.put(pvname)
    swait.channels.B.value.put(limit)
    swait.calc.put('(A+1) % B')
    swait.scan.put(scan)
    swait.desc.put('incrementer')
    swait.hints = {'fields': ['val']}
    swait.read_attrs = ['val']


def _noprint(*args, **kwargs):
    """Do nothing with the arguments. Used for suppressing print output."""


def check_textbound_overlap(anns):
    """
    Checks for overlap between the given TextBoundAnnotations.
    Returns a list of pairs of overlapping annotations.
    """
    overlapping = []
    for a1 in anns:
        for a2 in anns:
            if a1 is a2:
                continue
            if a2.first_start() < a1.last_end() and a2.last_end(
                ) > a1.first_start():
                overlapping.append((a1, a2))
    return overlapping


def p_not_test(p):
    """not_test : comparison
                 | NOT not_test"""
    if len(p) == 2:
        p[0] = p[1]
    else:
        p[0] = ['UNARY', 'not', p[2]]


def reduce_max(input):
    """Returns the max of all elements in the input tensor.

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

    Returns
    -------
    Tensor
        A framework-specific tensor with shape (1,)
    """
    pass


def ygginstall():
    """Call installation script."""
    from yggdrasil.languages import install_languages
    parser = install_languages.update_argparser()
    args = parser.parse_args()
    if len(args.language) == 0 or 'all' in args.language:
        install_languages.install_all_languages(args=args)
    else:
        for x in args.language:
            install_languages.install_language(x, args=args)


@staticmethod
def finalize_registration(cls):
    """Final operations to perform after a class has been fully initialized.
        These actions will not be performed if the environment variable
        YGG_RUNNING_YGGSCHEMA is set."""
    pass


def get_labeled_points_from_rdd(rdd):
    """
    returns a labeledpoint from the RDD provided
    """
    from pyspark.mllib.regression import LabeledPoint
    return rdd.map(lambda x: LabeledPoint(float(x[0]), x[1:]))


def get_least_severe_state(states):
    """ Get the state that has the least severity > 0 """
    least_severe_state = None
    for state in states:
        if state.severity == 0:
            continue
        if least_severe_state is None:
            least_severe_state = state
        elif state.get_severity() < least_severe_state.get_severity():
            least_severe_state = state
    if least_severe_state is None:
        least_severe_state = states[0]
    return least_severe_state


def delete_queue(QueueUrl=None):
    """
    Deletes the queue specified by the QueueUrl , even if the queue is empty. If the specified queue doesn't exist, Amazon SQS returns a successful response.
    When you delete a queue, the deletion process takes up to 60 seconds. Requests you send involving that queue during the 60 seconds might succeed. For example, a ``  SendMessage `` request might succeed, but after 60 seconds the queue and the message you sent no longer exist.
    When you delete a queue, you must wait at least 60 seconds before creating a queue with the same name.
    See also: AWS API Documentation

    :example: response = client.delete_queue(
        QueueUrl='string'
    )

    :type QueueUrl: string
    :param QueueUrl: [REQUIRED]
            The URL of the Amazon SQS queue to delete.
            Queue URLs are case-sensitive.

    """
    pass


def init_model(N, y0):
    """
    Initialize the SIR model.

    :param int y0: Infected rate at initial time step.
    :param int N: Population

    :returns: Model at initial time step
    :rtype: tuple(int, int, int)
    """
    return N - y0, y0, 0


def register_callback(callback):
    """
        Register 'callback' function to be invoked whenever a solution
        cal has been found or a 'partial' argument has been defined
        and reached

        See also -- prepare for details
        """
    raise NotImplementedError


@classmethod
def splits(cls, datasets, batch_sizes=None, **kwargs):
    """Create Iterator objects for multiple splits of a dataset.

        Arguments:
            datasets: Tuple of Dataset objects corresponding to the splits. The
                first such object should be the train set.
            batch_sizes: Tuple of batch sizes to use for the different splits,
                or None to use the same batch_size for all splits.
            Remaining keyword arguments: Passed to the constructor of the
                iterator class being used.
        """
    if batch_sizes is None:
        batch_sizes = [kwargs.pop('batch_size')] * len(datasets)
    ret = []
    for i in range(len(datasets)):
        train = i == 0
        ret.append(cls(datasets[i], batch_size=batch_sizes[i], train=train,
            **kwargs))
    return tuple(ret)


def validate_fasta(path):
    """
    Validate FASTA file

    Parameters
    ----------
    path : str
        File to check
    """
    raise NotImplementedError()


def check(name, type, country, geometry, **args):
    """Should return True if this area is NEW, False if we should match"""
    return False


def df_fill_empty(data, fill_with):
    """Finds and replaces any value in dataframe that only consist of
    whitespace. A common scenario is where you first fill empties
    with np.nan and then handle nans as you would otherwise do it.

    NOTE: this results in all columns to be converted into strings. You can use
    wrangle.df_to_numeric() to convert all back to numeric.

    data : Pandas Dataframe
        The dataframe to be processed
    fill_with: str
        Fill the values with a string.
    """
    return data.astype(str).apply(lambda x: x.str.strip().replace('',
        fill_with))


@classmethod
def _Vapor_Entropy(cls, T):
    """Auxiliary equation for the specific entropy for saturated vapor

        Parameters
        ----------
        T : float
            Temperature, [K]

        Returns
        -------
        s : float
            Saturated liquid entropy, [kJ/kgK]

        References
        ----------
        IAPWS, Revised Supplementary Release on Saturation Properties of
        Ordinary Water Substance September 1992,
        http://www.iapws.org/relguide/Supp-sat.html, Eq.9
        """
    phi = cls._phi_sat(T)
    rho = cls._Vapor_Density(T)
    dpdT = cls._dPdT_sat(T)
    s = phi + dpdT / rho * 1000
    return s


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

        :param FileGetCopyReferenceType val:
        :rtype: EventType
        """
    return cls('file_get_copy_reference', val)


def userdefined_roles():
    """Return list of user-defined roles.
        """


@staticmethod
def _sql_literal(o):
    """
        Tries to convert a python literal to its SQL equivalent

        :param o: The literal object to ve converted
        :returns: A string containing the object as a SQL literal
        """
    if isinstance(o, str):
        return '"{}"'.format(o)
    else:
        return str(o)


@staticmethod
def p_kp_blob(p):
    """kp_blob : KP_BLOB"""
    p[0] = p[1]


def is_(var):
    """intuitive handling of variable truth value also for `numpy` arrays.

    Return `True` for any non-empty container, otherwise the truth value of the
    scalar `var`.

    Caveat of the most unintuitive case: [0] evaluates to True, like [0, 0].

    >>> import numpy as np
    >>> from cma.utilities.utils import is_
    >>> is_({}) or is_(()) or is_(0) or is_(None) or is_(np.array(0))
    False
    >>> is_({0:0}) and is_((0,)) and is_(np.array([0]))
    True

    """
    try:
        return True if len(var) else False
    except TypeError:
        return True if var else False


def cross_product(x1, y1, z1, x2, y2, z2):
    """
    Cross product of two vectors, v1 x v2

    Parameters
    ----------
    x1 : float or array-like
        X component of vector 1
    y1 : float or array-like
        Y component of vector 1
    z1 : float or array-like
        Z component of vector 1
    x2 : float or array-like
        X component of vector 2
    y2 : float or array-like
        Y component of vector 2
    z2 : float or array-like
        Z component of vector 2

    Returns
    -------
    x, y, z
        Unit vector x,y,z components

    """
    x = y1 * z2 - y2 * z1
    y = z1 * x2 - x1 * z2
    z = x1 * y2 - y1 * x2
    return x, y, z


@staticmethod
def get_link_page_text(link_page):
    """
        Construct the dialog box to display a list of links to the user.
        """
    text = ''
    for i, link in enumerate(link_page):
        capped_link_text = link['text'] if len(link['text']) <= 20 else link[
            'text'][:19] + '…'
        text += '[{}] [{}]({})\n'.format(i, capped_link_text, link['href'])
    return text


def is_struct_seq(obj):
    """Returns whether obj is a structured sequence subclass: sys.float_info"""
    return isinstance(obj, tuple) and hasattr(obj, 'n_fields')


@classmethod
def load_image(cls, filename, height=1, array=False, bounds=None, bare=
    False, **kwargs):
    """
        Returns an raster element or raw numpy array from a PNG image
        file, using matplotlib.

        The specified height determines the bounds of the raster
        object in sheet coordinates: by default the height is 1 unit
        with the width scaled appropriately by the image aspect ratio.

        Note that as PNG images are encoded as RGBA, the red component
        maps to the first channel, the green component maps to the
        second component etc. For RGB elements, this mapping is
        trivial but may be important for subclasses e.g. for HSV
        elements.

        Setting bare=True will apply options disabling axis labels
        displaying just the bare image. Any additional keyword
        arguments will be passed to the Image object.
        """
    try:
        from matplotlib import pyplot as plt
    except:
        raise ImportError('RGB.load_image requires matplotlib.')
    data = plt.imread(filename)
    if array:
        return data
    h, w, _ = data.shape
    if bounds is None:
        f = float(height) / h
        xoffset, yoffset = w * f / 2, h * f / 2
        bounds = -xoffset, -yoffset, xoffset, yoffset
    rgb = cls(data, bounds=bounds, **kwargs)
    if bare:
        rgb = rgb(plot=dict(xaxis=None, yaxis=None))
    return rgb


@staticmethod
def _s2d(css):
    """Parse list of colon-separated address and port to dictionary.

        :param css: list of colon-separated address and port
        :returns: dictionary
        """
    result = []
    for key_val in css:
        key, val = key_val.split(':')
        result.append({'address': key, 'port': int(val)})
    return result


def emphasis(text):
    """Wrap text with asterisks."""
    return '*{}*'.format(text)


def writeScores(scoresO, strainNamesT, scoresFN, genesO=None, geneInfoFN=None):
    """Write a scores object to file. If scoresFN has the .bout extension, write
binary version, otherwise write in text output format."""
    scoreTypeL = ['rawSc', 'synSc', 'coreSynSc']
    if scoresFN.split('.')[-1] == 'bout':
        scoresO.writeScoresBinary(strainNamesT, scoreTypeL, scoresFN)
    else:
        scoresO.writeScoresText(strainNamesT, scoreTypeL, scoresFN, genesO,
            geneInfoFN)


@classmethod
def from_both(cls, tags_file: str, tags_folder: str, folder: str
    ) ->'TrainData':
    """Load data from both a database and a structured folder"""
    return cls.from_tags(tags_file, tags_folder) + cls.from_folder(folder)


def c_divide(x, y):
    """ C-style division operation (different treatment of negative numbers) """
    return x // y if x >= 0 else -(-x // y)


def rememberRootURL():
    """
        Remember the currently-processed part of the URL for later
        recalling.
        """


@staticmethod
def _get_body(response):
    """Access the response body from an HTTP response.

        Args:
            response (object): The HTTP response object.

        Raises:
            NotImplementedError: Always, since virtual.
        """
    raise NotImplementedError(u'This implementation is virtual.')


@classmethod
def validate_faces(cls, faces):
    """Raises an exception if not all faces in ``faces`` are defining either all triangles, lines
        or points.

        Parameters
        ----------
        faces : list

        Returns
        -------

        """
    if not faces:
        return
    if len(faces[0]) > 3:
        raise Exception(
            'Invalid mesh. Expected mesh composed of points, lines xor triangles.'
            )
    for face in faces:
        if len(face) != len(faces[0]):
            raise NotImplementedError(
                'Invalid mesh. Expected mesh composed of points, lines xor triangles.'
                )


def _target_from_queries(queries):
    """Get a target from some queries.

    If the queries contain differing targets (other than some containing None),
    raises an exception.

    Returns None if none of the queries have a target set.

    """
    target = None
    for query in queries:
        if query._target is not None:
            if target is not None and target is not query._target:
                raise ValueError('Queries have inconsistent targets.')
            target = query._target
    return target


def __init__(source):
    """Initialize the renderer.

        The source argument is the source code that needs to be converted.
        """


def classdot2class(path):
    """ Convert a path such as 'android.support.v4.app.ActivityCompat'
        into a string 'Landroid/support/v4/app/ActivityCompat'
        so we can change name of a class by d.CLASS_Landroid_support_v4_app_ActivityCompat.set_name(new_name)
    """
    if path[0] == 'L' and path[-1] == ';':
        print('WARNING: %s already a Lclass; name' % path)
        return path
    new_name = 'L' + path.replace('.', '/') + ';'
    return new_name


def from_long(v: int, prefix: int, base: int, charset):
    """The inverse of to_long. Convert an integer to an arbitrary base.
    v: the integer value to convert
    prefix: the number of prefixed 0s to include
    base: the new base
    charset: an array indicating a printable character to use for each value.
    """
    ba = bytearray()
    while v > 0:
        try:
            v, mod = divmod(v, base)
            ba.append(charset(mod))
        except Exception:
            raise ValueError(
                "can't convert to character corresponding to %d" % mod)
    ba.extend([charset(0)] * prefix)
    ba.reverse()
    return bytes(ba)


@staticmethod
def _from_db_object(quota, db_quota):
    """Converts a database entity to a formal object"""
    for field in quota.fields:
        if field == 'uuid':
            continue
        setattr(quota, field, db_quota[field])
    quota.obj_reset_changes()
    return quota


def find_null_idx(df, column=None):
    """returns the indices of null values found in the series/column.
    if df is a dataframe and column is none, it returns a dictionary
    with the column names as a value and  null_idx for each column as the values.
    Example Usage:
    1)
    >> null_idx = get_null_idx(series)
    >> series_null_removed = series[null_idx]
    2)
    >> null_dict = get_null_idx()
    """
    import pandas as pd
    import numpy as np
    idx_null = []
    if isinstance(df, pd.Series) and column is not None:
        raise Exception('If passing a series, column must be None')
    elif isinstance(df, pd.Series):
        series = df
        idx_null = series.loc[series.isna() == True].index
    elif isinstance(df, pd.DataFrame) and isinstance(column, str):
        series = df[column]
        idx_null = series.loc[series.isna() == True].index
    elif isinstance(df, pd.DataFrame):
        idx_null = {}
        if column is None:
            col_list = df.columns
        else:
            col_list = column
        for col in col_list:
            series = df[col]
            idx_null[col] = series.loc[series.isna() == True].index
    else:
        raise Exception('Input df must be a pandas DataFrame or Series.')
    return idx_null


def _minus(lhs=None, rhs=None, name=None, attr=None, out=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 : Symbol
        first input
    rhs : Symbol
        second input

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

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


def provider_parser(subparser):
    """Configure provider parser for Namecheap"""
    subparser.add_argument('--auth-token', help=
        'specify api token for authentication')
    subparser.add_argument('--auth-username', help=
        'specify username for authentication')
    subparser.add_argument('--auth-client-ip', help=
        'Client IP address to send to Namecheap API calls', default='127.0.0.1'
        )
    subparser.add_argument('--auth-sandbox', help=
        'Whether to use the sandbox server', action='store_true')


def remove_node_keeping_tail(node):
    """Remove the node from the tree but keeping tail by appending to the
    previous or parent node.
    """
    parent = node.getparent()
    if node.tail:
        previous = node.getprevious()
        if previous is not None:
            if not previous.tail:
                previous.tail = node.tail
            else:
                previous.tail += node.tail
        elif not parent.text:
            parent.text = node.tail
        else:
            parent.text += node.tail
    parent.remove(node)


@staticmethod
def with_attrs(attributes):
    """Confuse pylint so it doesn't complain about fluent-endpoints."""


@classmethod
def __dir__(cls):
    """returns the list of available methods associated with the parameterized intent"""
    rtn_list = []
    for m in dir(cls):
        if not m.startswith('_'):
            rtn_list.append(m)
    return rtn_list


def keyconfig_import(filepath: str='keymap.py', filter_folder: bool=True,
    filter_text: bool=True, filter_python: bool=True, keep_original: bool=True
    ):
    """Import key configuration from a python script

    :param filepath: filepath
    :type filepath: str
    :param filter_folder: Filter folders
    :type filter_folder: bool
    :param filter_text: Filter text
    :type filter_text: bool
    :param filter_python: Filter python
    :type filter_python: bool
    :param keep_original: Keep original, Keep original file after copying to configuration folder
    :type keep_original: bool
    """
    pass


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

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

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


def get_action(argv, default=None):
    """ Get the tool action part of the argument list """
    if len(argv) < 2:
        return default
    else:
        return argv[1]


def expandTokensInOptions(options, opt_names, **kwargs):
    """
    Given an options instance, the list of option names, and the list of
    keywords to replace, replace the options with the correct expanded stings.

    >>> from optparse import Values
    >>> options = Values()
    >>> options.name = '{token}'
    >>> expandTokensInOptions(options, ['name'], token='Hello')
    >>> options.name
    'Hello'
    """
    for opt_name in opt_names:
        try:
            val = getattr(options, opt_name)
            if val:
                setattr(options, opt_name, val.format(**kwargs))
        except AttributeError:
            pass


def unduplicate_field_names(field_names):
    """Append a number to duplicate field names to make them unique. """
    res = []
    for k in field_names:
        if k in res:
            i = 1
            while k + '_' + str(i) in res:
                i += 1
            k += '_' + str(i)
        res.append(k)
    return res


def utf8_cut(bytestr, maxlen):
    """Cuts an utf8 bytestring in two parts where the left is at most maxlen
    long, and both are valid utf8 strings.
    """
    left = bytestr[:maxlen].decode('utf-8', 'ignore').encode('utf-8')
    return left, bytestr[len(left):]


@classmethod
def from_records(cls, data, *, columns=None):
    """
        Convert structured or record ndarray to DataFrame.

        Parameters
        ----------
        data : ndarray (structured dtype), list of tuples, dict, or DataFrame
        columns : sequence, default None, keyword-only
            Column names to use. If the passed data do not have names
            associated with them, this argument provides names for the
            columns. Otherwise this argument indicates the order of the columns
            in the result (any names not found in the data will become all-NA
            columns)

        Returns
        -------
        DataFrame
        """
    return cls(data=data, columns=columns)


def question(message, default='', required=False):
    """
    Ask a question to the user

    Args:
        message (str): message to display
        default (str): the default value
        required (bool): if True, loop to get an answer

    Returns:
        str: user's value
    """
    while True:
        if default != '':
            message += f' [{default}] '
        elif not message.endswith(' '):
            message += ' '
        answer = input(message)
        if answer == '':
            answer = default
        if answer != '':
            break
        elif required is False:
            break
    return answer


def get_matched_rule_ids(matches, query_run):
    """
    Yield the subset of matched rule ids from a `matches` LicenseMatch
    sequence that are within the `query_run` query run.
    """
    qstart = query_run.start
    qend = query_run.end
    for match in matches:
        if qstart <= match.qstart and match.qend <= qend:
            yield match.rule.rid


@staticmethod
def get_normalized_title(title):
    """Function that removes bad symbols from title"""
    title = title.replace('$', '')
    title = title.replace('{', '')
    title = title.replace('}', '')
    title = title.replace('\\mathcal', '')
    title = title.replace('\\mathbf', '')
    title = title.replace('\\mathbb', '')
    title = title.replace('\\ensuremath', '')
    title = title.replace('&', 'e')
    title = title.replace('\\', '')
    title = title.replace('/', '_')
    title = title.replace('>', 'gt')
    title = title.replace('<', 'lt')
    title = title.replace(':', ' ')
    title = title.replace('.', ' ')
    title = title.replace(',', ' ')
    title = title.replace(';', ' ')
    return title


def name_highway_key(tags):
    """ Convert way tags to name, highway keys.

        Used by ParserOSM.parse().
    """
    if 'name' not in tags:
        return None
    if 'highway' not in tags:
        return None
    if not tags['name'] or not tags['highway']:
        return None
    return tags['name'], tags['highway']


def _get_list_from_slice(s):
    """Get a list from a slice object.

    :param s: slice object representing list of columns
    :type s: slice
    :return: list of elements that were in the slice object
    :rtype: list[int]
    """
    args = [s.start, s.stop]
    if s.step is not None:
        args.append(s.step)
    return list(range(*args))


def greater(arr, comp):
    """ Compares all the elements of the an array to the number comp and generates a list which is greater than the number comp.

	- **parameters**, **types**, **return** and **return types**::
		:param arr: Array on which the operation is to be done.
		:param comp: The number to which the array elements is to be compared.
		:type arr: floats[]
		:type arr: float
		:return: float[]
	"""
    result = []
    for idx in range(len(arr)):
        if arr[idx] > comp:
            result[idx] = arr[idx]
    return result


def extract_ini_from_doc(doc):
    """Extracts INI from doc strings."""
    return doc.rsplit('INI')[-1]


@classmethod
def min(cls, item='uid', like={}, isin={}, orderby='', where='', limit='',
    **criteria):
    """return min of item (column) filtered by these criteria
    """
    what = 'min(%s)' % item
    return cls.list(asObjects=False, sql='', like=like, isin=isin, orderby=
        orderby, where=where, limit=limit, what=what, **criteria)[0][what]


@classmethod
def set_logging_level(cls, level, prefix=None):
    """
        Set the logging level of a logger associated with this SDK, one
        of it's Traces or one of it's Spans, Helpers or Decorators.

        :param int level: New logging level to set.
        :param prefix: All loggers with this prefix will have their levels set.
        :type prefix: Union[None, None, str]
        """
    for logger_name, logger in cls._context.loggers.items():
        if prefix and logger_name.split('.')[0] != prefix:
            continue
        logger.setLevel(level)


def dms2dd(direction, degrees, minutes, seconds):
    """Converts a latitude or longitude from DMS to decimal degrees notation

    Consider the following coordinate:

        N038.57.38.000
        W009.11.04.000

    >>> from geo_tools import dms2dd
    >>> (dms2dd('N', 38.0, 57.0, 38.0), dms2dd('W', 9.0, 11.0, 4.0))
    (38.96055555555556, -9.184444444444445)

    Args:
        direction   (string): The coordinate hemisphere; 'N', 'E', 'S', or 'W'
        degrees     (float): Degrees deviation
        minutes     (float): Minutes deviation
        seconds     (float): Seconds deviation

    Returns:
        float: the DMS coordinate latitude or longitude in decimal degrees
        notation
    """
    decimal_degrees = float(degrees) + float(minutes) / 60 + float(seconds) / (
        60 * 60)
    direction = direction.upper()
    if direction == 'S' or direction == 'W':
        decimal_degrees *= -1
    return decimal_degrees


def round_float(x):
    """ Rounds a float to it's first significant digit
    """
    a = list(str(x))
    for i, e in enumerate(a):
        if e != '.':
            if e != '0':
                pos = i
                a[i] = '1'
                break
    return float(''.join(a[:pos + 1]))


def read_output(filename):
    """Reads in a Tarquin txt results file and returns a dict of the information

    Parameters
    ----------
    filename : txt file
        The filename to read from

    Returns
    -------
    result : dict

    """
    with open(filename) as fin:
        data = fin.read()
        metabolite_fits = {}
        fit_quality = {}
        sections = data.split('\n\n')
        metabolite_lines = sections[0].splitlines()[2:]
        for line in metabolite_lines:
            name, concentration, pc_sd, sd = line.split()
            metabolite_fits[name] = {'concentration': concentration, 'sd':
                pc_sd}
        lines = sections[1].splitlines()[2:]
        for line in lines:
            key, value = line.split(':')
            fit_quality[key.strip()] = float(value.strip())
        return {'metabolite_fits': metabolite_fits, 'quality': fit_quality}


@classmethod
def from_refresh_token(Cls, refresh_token):
    """
        Given a refresh token, return an instance of ShortLivedTokenMixin
        configured using information from ``refresh_token``.

        :param refresh_token: A refresh token instance.
        :returns: A new ShortLivedToken instance.

        .. warning::

            You must implement this method

        """
    raise NotImplementedError(
        'You must implement from_refresh_token. Invoke {}() and instantiate it using information from the refresh token'
        .format(Cls.__name__))


def partition(elts, predicate):
    """Splits elts depending on their result.

    Partitions set of elts. Result of the predicate must be hashable.

        >>> partition("qweryuop ", lambda x: "How are you ?".count(x))
        {0: ['q', 'p'], 1: ['w', 'e', 'r', 'y', 'u'], 2: ['o'], 3: [' ']}

    """
    heaps = {}
    for elt in elts:
        key = predicate(elt)
        heaps[key] = heaps.get(key, []) + [elt]
    return heaps


def map_nic_name_to_dict(instance, value):
    """Convert a name of interface into a dictionary.

    `parents` and `children` just hold a list of interface names. This is need
    so instead they can return a `ObjectSet`.

    '__incomplete__' is set so the object knows that the data passed is
    incomplete data.
    """
    return {'system_id': instance._data['system_id'], 'name': value,
        '__incomplete__': True}


def run():
    """Run app in the development environment.

    Don't call this in production.
    """
    from .app import create_app
    app = create_app()
    app.config.from_envvar('CORRAL_SETTINGS')
    return app.run()


def create_user(email=None, display_name=None):
    """Create and return an `IUser`.

        :param email: The text email address for the user being created.
        :type email: str
        :param display_name: The display name of the user.
        :type display_name: str
        :return: The newly created user, with the given email address and real
            name, if given.
        :rtype: `IUser`
        :raises ExistingAddressError: when the email address is already
            registered.
        """


def move_detach_links_release(NODE_OT_links_detach=None,
    NODE_OT_translate_attach=None):
    """Move a node to detach links

    :param NODE_OT_links_detach: Detach Links, Remove all links to selected nodes, and try to connect neighbor nodes together
    :param NODE_OT_translate_attach: Move and Attach, Move nodes and attach to frame
    """
    pass


def convex_hull(delete_unused: bool=True, use_existing_faces: bool=True,
    make_holes: bool=False, join_triangles: bool=True, face_threshold:
    float=0.698132, shape_threshold: float=0.698132, uvs: bool=False, vcols:
    bool=False, seam: bool=False, sharp: bool=False, materials: bool=False):
    """Enclose selected vertices in a convex polyhedron

    :param delete_unused: Delete Unused, Delete selected elements that are not used by the hull
    :type delete_unused: bool
    :param use_existing_faces: Use Existing Faces, Skip hull triangles that are covered by a pre-existing face
    :type use_existing_faces: bool
    :param make_holes: Make Holes, Delete selected faces that are used by the hull
    :type make_holes: bool
    :param join_triangles: Join Triangles, Merge adjacent triangles into quads
    :type join_triangles: bool
    :param face_threshold: Max Face Angle, Face angle limit
    :type face_threshold: float
    :param shape_threshold: Max Shape Angle, Shape angle limit
    :type shape_threshold: float
    :param uvs: Compare UVs
    :type uvs: bool
    :param vcols: Compare VCols
    :type vcols: bool
    :param seam: Compare Seam
    :type seam: bool
    :param sharp: Compare Sharp
    :type sharp: bool
    :param materials: Compare Materials
    :type materials: bool
    """
    pass


def _glsl_mix(controls=None):
    """Generate a GLSL template function from a given interpolation patterns
    and control points."""
    assert (controls[0], controls[-1]) == (0.0, 1.0)
    ncolors = len(controls)
    assert ncolors >= 2
    if ncolors == 2:
        s = '    return mix($color_0, $color_1, t);\n'
    else:
        s = ''
        for i in range(ncolors - 1):
            if i == 0:
                ifs = 'if (t < %.6f)' % controls[i + 1]
            elif i == ncolors - 2:
                ifs = 'else'
            else:
                ifs = 'else if (t < %.6f)' % controls[i + 1]
            adj_t = '(t - %s) / %s' % (controls[i], controls[i + 1] -
                controls[i])
            s += '%s {\n    return mix($color_%d, $color_%d, %s);\n} ' % (ifs,
                i, i + 1, adj_t)
    return 'vec4 colormap(float t) {\n%s\n}' % s


@staticmethod
def uild_index(index):
    """ Create an index """
    if index is not None:
        return super().build_index(index)
    return None


@classmethod
def has_archiving(cls):
    """Returns whether it supports archiving items on the fetch process.

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


def __get_common_properties(item1, item2):
    """Return the common keys that two maps have"""
    return set(item1.keys()) & set(item2.keys())


def _subject(subject):
    """
    Returns a query item matching "subject".

    Args:
        subject: The subject of the message.

    Returns:
        The query string.

    """
    return f'subject:{subject}'


def extrude_move(CURVE_OT_extrude=None, TRANSFORM_OT_translate=None):
    """Extrude curve and move result

    :param CURVE_OT_extrude: Extrude, Extrude selected control point(s)
    :param TRANSFORM_OT_translate: Move, Move selected items
    """
    pass


def get(isamAppliance, check_mode=False, force=False):
    """
    Get advanced tuning parameters
    """
    return isamAppliance.invoke_get('Get advanced tuning parameters',
        '/core/adv_params')


def get_current_word(code, cursorPos):
    """Returns the word before the `cursorPos`"""
    import re
    last_word = []
    wordChar = re.compile('[a-zA-Z]')
    for i in range(cursorPos - 1, -1, -1):
        if wordChar.match(code[i]):
            last_word.append(code[i])
        else:
            break
    return ''.join(reversed(last_word))


@classmethod
def disable(cls):
    """Disables network tracking, prevents network events from being sent to the client.
        """
    return cls.build_send_payload('disable', {}), None


def write_table(table, header, handle):
    """General function for saving tables.

    :arg list table: Table content.
    :arg str header: Table header.
    :arg stream handle: Open writable handle to the output file.
    """
    if header:
        handle.write(header)
    if table:
        for i in table:
            handle.write('{}\n'.format('\t'.join(map(str, i))))


def append_method(form, method):
    """ Return a new form with ``method`` added to methods_stack """
    stack = form[4]
    return form[:4] + (stack + (method,),)


def _check_is_max_context(doc_spans, cur_span_index, position):
    """Check if this is the 'max context' doc span for the token."""
    best_score = None
    best_span_index = None
    for span_index, doc_span in enumerate(doc_spans):
        end = doc_span.start + doc_span.length - 1
        if position < doc_span.start:
            continue
        if position > end:
            continue
        num_left_context = position - doc_span.start
        num_right_context = end - position
        score = min(num_left_context, num_right_context
            ) + 0.01 * doc_span.length
        if best_score is None or score > best_score:
            best_score = score
            best_span_index = span_index
    return cur_span_index == best_span_index


def crack_secret_exponent_from_k(generator, signed_value, sig, k):
    """
    Given a signature of a signed_value and a known k, return the secret exponent.
    """
    r, s = sig
    return (s * k - signed_value) * generator.inverse(r) % generator.order()


@classmethod
def modify_url_for_impersonation(cls, url, impersonate_user, username):
    """
        Modify the SQL Alchemy URL object with the user to impersonate if applicable.
        :param url: SQLAlchemy URL object
        :param impersonate_user: Bool indicating if impersonation is enabled
        :param username: Effective username
        """
    if impersonate_user is not None and username is not None:
        url.username = username


def enable_lazy_search():
    """
        Enables lazy search for this view,
        it only makes sense when the items are displayed in
        an ObjectList
        """


@classmethod
def from_wfs_element(cls, feature, namespace):
    """Build `GrondwaterFilter` instance from a WFS feature element.

        Parameters
        ----------
        feature : etree.Element
            XML element representing a single record of the WFS layer.
        namespace : str
            Namespace associated with this WFS featuretype.

        Returns
        -------
        filter : GrondwaterFilter
            An instance of this class populated with the data from the WFS
            element.

        """
    gwfilter = cls(feature.findtext('./{{{}}}filterfiche'.format(namespace)))
    for field in cls.get_fields(source=('wfs',)).values():
        gwfilter.data[field['name']] = cls._parse(func=feature.findtext,
            xpath=field['sourcefield'], namespace=namespace, returntype=
            field.get('type', None))
    return gwfilter


def pil_available():
    """Test if PIL/Pillow is available"""
    out = False
    try:
        from PIL import Image
        out = True
    except:
        pass
    return out


def fromqpixmap(im):
    """Creates an image instance from a QPixmap image"""
    from . import ImageQt
    if not ImageQt.qt_is_installed:
        raise ImportError('Qt bindings are not installed')
    return ImageQt.fromqpixmap(im)


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

        :param LegalHoldsExportCancelledDetails val:
        :rtype: EventDetails
        """
    return cls('legal_holds_export_cancelled_details', val)


def as_mutable_matrix(matrix):
    """
    sympy sometimes converts matrices to immutable objects
    this can be reverted by a call to    .as_mutable()
    this function provides access to that call as a function
    (just for cleaner syntax)
    """
    return matrix.as_mutable()


def __call__(cls, value, names=None, module=None, type=None):
    """Either returns an existing member, or creates a new enum class.

        This method is used both when an enum class is given a value to match
        to an enumeration member (i.e. Color(3)) and for the functional API
        (i.e. Color = Enum('Color', names='red green blue')).

        When used for the functional API: `module`, if set, will be stored in
        the new class' __module__ attribute; `type`, if set, will be mixed in
        as the first base class.

        Note: if `module` is not set this routine will attempt to discover the
        calling module by walking the frame stack; if this is unsuccessful
        the resulting class will not be pickleable.

        """
    if names is None:
        return cls.__new__(cls, value)
    return cls._create_(value, names, module=module, type=type)


def get_forum_image_upload_to(instance, filename):
    """ Returns a valid upload path for an image file associated with a forum instance. """
    return instance.get_image_upload_to(filename)


def _ihexline(address, buffer, end=False, record_type=0):
    """internal use: generate a line with intel hex encoded data"""
    out = []
    if end:
        record_type = 1
    out.append(b':%02X%04X%02X' % (len(buffer), address & 65535, record_type))
    sum = len(buffer) + (address >> 8 & 255) + (address & 255) + (record_type &
        255)
    for b in bytearray(buffer):
        out.append(b'%02X' % (b & 255))
        sum += b & 255
    out.append(b'%02X\r\n' % (-sum & 255))
    return b''.join(out)


def intify(obj, str_fun=str, use_ord=True, use_hash=True, use_len=True):
    """FIXME: this is unpythonic and does things you don't expect!

    FIXME: rename to "integer_from_category"

    Returns an integer representative of a categorical object (string, dict, etc)

    >>> intify('1.2345e10')
    12345000000
    >>> intify([12]), intify('[99]'), intify('(12,)')
    (91, 91, 40)
    >>> intify('A'), intify('a'), intify('AAA'), intify('B'), intify('BB')
    (97, 97, 97, 98, 98)
    >>> intify(272)
    272
    >>> intify(float('nan'), use_ord=False, use_hash=False, str_fun=None)
    >>> intify(float('nan'), use_ord=False, use_hash=False, use_len=False)
    >>> intify(float('nan')), intify('n'), intify(None)
    (110, 110, 110)
    >>> intify(None, use_ord=False, use_hash=False, use_len=False)
    >>> intify(None, use_ord=False, use_hash=False, str_fun=False)
    >>> intify(None, use_hash=False, str_fun=False)
    """
    try:
        return int(obj)
    except (IndexError, ValueError, AttributeError, TypeError):
        pass
    try:
        float_obj = float(obj)
        if float('-inf') < float_obj < float('inf'):
            return int(float_obj)
    except (IndexError, ValueError, AttributeError, TypeError):
        pass
    if not str_fun:

        def str_fun(x):
            return x
    if use_ord:
        try:
            return ord(str_fun(obj)[0].lower())
        except (IndexError, ValueError, AttributeError, TypeError):
            pass
    if use_hash:
        try:
            return hash(str_fun(obj))
        except (IndexError, ValueError, AttributeError, TypeError):
            pass
    if use_len:
        try:
            return len(obj)
        except (IndexError, ValueError, AttributeError, TypeError):
            pass
        try:
            return len(str_fun(obj))
        except (IndexError, ValueError, AttributeError, TypeError):
            pass
    return None


def visstd(a, s=0.1):
    """Normalize the image range for visualization"""
    return (a - a.mean()) / max(a.std(), 0.0001) * s + 0.5


def _getindex(s, search=['ADT', 'CHD', 'INF']):
    """
        Finds the smallest index of all the elements in search (list)
            present in the s (string).
        inputs:
            s: Parent string to search in (string)
            search: list of sub-strings to search for (list)
        returns:
            index: list of all indices (list)
    """
    index = []
    for value in search:
        index.append(int(s.find(value)))
    return index


def split_attenuation(att):
    """
    Split the attenuation value into two parts, one that can be realized by
    setting the hardware attenuator (the RZ6 attenuator can be set to 0, 20, 40
    or 60 dB) and the second that must be realized by scaling the waveform.

    Returns (hw_attenuation, sw_attenuation)
    ----------------------------------------
    hw_attenuation : float
        hardware attenuation setting
    sw_attenuation : float
        remaining attenuation that must be realized by scaling the waveform
    """
    hw_step = min(int(att / 20.0), 3)
    hw_att = hw_step * 20.0
    sw_att = att - hw_att
    return hw_att, sw_att


def get_func_from_callback(method, callback):
    """
    Get function from callback
    :param callback: endpoint's callback (urlpattern's callback)
    :param method: get, post, ...
    :return: function
    """
    cls = getattr(callback, 'cls', None)
    actions = getattr(callback, 'actions', None)
    if cls is None:
        return None
    if actions is None:
        if callable(cls):
            return getattr(cls(), method.lower(), None)
    view_name = actions.get(method.lower(), None)
    if view_name is None:
        return None
    return getattr(cls, view_name, None)


def write_binary(data, filename):
    """
        Write binary data to a file on disk
    """
    import struct
    f = open(filename, 'wb+')
    f.write(struct.pack('%dB' % len(data), *data))
    f.close()


def minmax(n, min_val, max_val):
    """Limit n to be between min_val and max_val"""
    assert min_val <= max_val
    return max(min(n, max_val), min_val)


def longest_common_substring(string1, string2):
    """  Function to find the longest common substring of two strings

        :param string1: string1
        :type string1: str
        :param string2: string2
        :type string2: str
        :returns: longest common substring
        :rtype: str

        :Example:

        >>> import chana.lemmatizer
        >>> chana.lemmatizer.longest_common_substring('limanko','limanra')
        'liman'

    """
    m = [([0] * (1 + len(string2))) for i in range(1 + len(string1))]
    longest, x_longest = 0, 0
    for x in range(1, 1 + len(string1)):
        for y in range(1, 1 + len(string2)):
            if string1[x - 1] == string2[y - 1]:
                m[x][y] = m[x - 1][y - 1] + 1
                if m[x][y] > longest:
                    longest = m[x][y]
                    x_longest = x
            else:
                m[x][y] = 0
    return string1[x_longest - longest:x_longest]


@classmethod
def itstat_fields(cls):
    """Construct tuple of field names used to initialise
        IterationStats named tuple.
        """
    return (('Iter',) + cls.itstat_fields_objfn + cls.itstat_fields_alg +
        cls.itstat_fields_extra + ('Time',))


@classmethod
def from_coco(cls, coco, dataset=None):
    """
        Creates an :class:`Image` from a dict in COCO formatted image

        :param coco: COCO formatted image
        :type coco: dict
        :rtype: :class:`Image`
        """
    metadata = coco.get('metadata', {})
    metadata.update({'license': coco.get('license'), 'flickr_url': coco.get
        ('flickr_url'), 'coco_url': coco.get('coco_url'), 'date_captured':
        coco.get('date_captured')})
    data = {'id': coco.get('id', 0), 'width': coco.get('width', 0),
        'height': coco.get('height', 0), 'path': coco.get('path', coco.get(
        'file_name', '')), 'metadata': metadata, 'dataset': dataset}
    return cls(**data)


def is_prefix(uri1, uri2):
    """ returns 1 of uri1 is a prefix of uri2 """
    if uri2[:len(uri1)] == uri1:
        return 1
    else:
        return None


@staticmethod
def get_data(**kwargs):
    """
        Override this static method to provide data for the report.
        It gets called with the form's data as arguments.
        Make sure it's a static method.
        """
    return []


def w2Midi(name, BytesIo):
    """
    Writes the output of `get_music` inside a '.midi' file on disk.

    Parameters
    ----------
    name : str
        name of file
    BytesIo : get_music output variable
        varible of music generated with `get_music`
    """
    muz_file = open(str(name) + '.midi', 'w')
    muz_file.write(BytesIo.getvalue())
    muz_file.close()


@classmethod
def create_dialog(cls, title, body):
    """
        Creates a dialog from given title and body.
        Adds it to the dialogs track list.
        Appends dismiss action.
        """
    dialog = cls.create_dialog_helper(title, body)
    dialog.add_action_button('Dismiss', action=lambda *x: dialog.dismiss())
    return dialog


def yesno(texte):
    """Interprète un texte comme un booléen"""
    return texte.lower() in ['y', 'yes', '1', 'o', 'oui']


def eta_ratio(M2, M4, M6):
    """Compute the ratio eta using the method of moments

    Ulbrich and Atlas (JAM 1998), Eqn 8

    Parameters
    ----------
    M2: float
        Second moment of the DSD [m^-1]
    M4: float
        Fourth moment of the DSD [m]
    M6: float
        Sixth moment of the DSD [m^3]

    Returns
    -------
    Eta: float
        Ratio of M4^2/(M2*M6) [unitless]

    Notes
    -----
    This particular methodology uses the 2nd, 4th, and 6th moments.
    """
    Eta = M4 ** 2 / (M2 * M6)
    return Eta


def pop(key, default=None):
    """remove specified key and return the corresponding value
        *args may contain a single default value, or may not be supplied.
        If key is not found, default is returned if given, otherwise
        KeyError is raised"""


def sizeof_fmt(num):
    """
    Handy formatting for human readable filesize.

    From http://stackoverflow.com/a/1094933/1657047
    """
    for x in ['bytes', 'KB', 'MB', 'GB']:
        if num < 1024.0 and num > -1024.0:
            return '%3.1f %s' % (num, x)
        num /= 1024.0
    return '%3.1f %s' % (num, 'TB')


def add_resource_permissions(ResourceId=None, Principals=None):
    """
    Creates a set of permissions for the specified folder or document. The resource permissions are overwritten if the principals already have different permissions.
    See also: AWS API Documentation

    :example: response = client.add_resource_permissions(
        ResourceId='string',
        Principals=[
            {
                'Id': 'string',
                'Type': 'USER'|'GROUP'|'INVITE'|'ANONYMOUS'|'ORGANIZATION',
                'Role': 'VIEWER'|'CONTRIBUTOR'|'OWNER'|'COOWNER'
            },
        ]
    )

    :type ResourceId: string
    :param ResourceId: [REQUIRED]
            The ID of the resource.

    :type Principals: list
    :param Principals: [REQUIRED]
            The users, groups, or organization being granted permission.
            (dict) --Describes the recipient type and ID, if available.
            Id (string) -- [REQUIRED]The ID of the recipient.
            Type (string) -- [REQUIRED]The type of the recipient.
            Role (string) -- [REQUIRED]The role of the recipient.

    :rtype: dict
    :return: {
        'ShareResults': [
            {
                'PrincipalId': 'string',
                'Role': 'VIEWER'|'CONTRIBUTOR'|'OWNER'|'COOWNER',
                'Status': 'SUCCESS'|'FAILURE',
                'ShareId': 'string',
                'StatusMessage': 'string'
            },
        ]
    }

    """
    pass


@classmethod
def getUrl(class_, url, tool):
    """Gets an absolute URL based on p_url, that can already be absolute or
           not."""
    if url.startswith('http'):
        return url
    return tool.buildUrl(url)


@classmethod
def get_instance(cls):
    """Get the manager singleton instance"""
    if cls._instance is None:
        cls._instance = cls()
        cls._try_register_messages()
    return cls._instance


def make_url(imdb_id):
    """Return IMDb URL of the given ID"""
    return u'https://www.imdb.com/title/%s/' % imdb_id


@staticmethod
def remove(d, k):
    """ Remove a key from dict d """
    if k in d:
        d.pop(k)


def econfigstr_hole(econfigstr, corelevel, highesunoccp, htype='valence'):
    """
    # '1s2 | 2s2' , '1s2' , '2p0' -> '1s1 | 2s2 2p1'

    :param: string
    :param: string
    :param: string

    :return: string
    """
    corestates = econfigstr.split()
    hoc = int(highesunoccp[2:])
    if htype == 'valence':
        new_highocc = str(hoc + 1)
    elif hoc == 0:
        highesunoccp = ''
        new_highocc = ''
    else:
        new_highocc = str(hoc)
    new_econfig = ''
    added = False
    for state in corestates:
        if state == corelevel:
            occ = int(state[2:])
            new_occ = occ - 1
            state = state[:2] + str(new_occ)
        if state == highesunoccp:
            added = True
            state = highesunoccp[:2] + str(new_highocc)
        new_econfig = new_econfig + state + ' '
    if not added:
        new_econfig = new_econfig + highesunoccp[:2] + str(new_highocc)
    return new_econfig.rstrip(' ')


def to_underscore(name):
    """
    >>> to_underscore("FooBar")
    'foo_bar'
    >>> to_underscore("HTTPServer")
    'http_server'
    """
    if not name:
        return name
    iterator = iter(name)
    out = [next(iterator).lower()]
    last_is_upper = True
    parse_abbreviation = False
    for char in iterator:
        if char.isupper():
            if last_is_upper:
                parse_abbreviation = True
                out.append(char.lower())
            else:
                out.append('_' + char.lower())
            last_is_upper = True
        else:
            if parse_abbreviation:
                out.insert(-1, '_')
                parse_abbreviation = False
            out.append(char)
            last_is_upper = False
    return ''.join(out)


@staticmethod
def _map_by_target_id(device_mapping_table, platform_name, target_ids):
    """
        Map available devices to required devices by target id
        :param device_mapping_table: available devices
        :param platform_name: platform
        :param target_ids: list of target ids
        :return: list of targets which matched the requirements
        """
    aux_device_mapping_table = []
    for tid in target_ids:
        for item in device_mapping_table:
            if platform_name:
                if item['platform_name'] != platform_name:
                    continue
            if item['target_id'] == tid:
                aux_device_mapping_table.append(item)
    return aux_device_mapping_table


def _steps_to_run(current_step, steps_per_epoch, steps_per_loop):
    """Calculates steps to run on device."""
    if steps_per_loop <= 0:
        raise ValueError('steps_per_loop should be positive integer.')
    if steps_per_loop == 1:
        return steps_per_loop
    remainder_in_epoch = current_step % steps_per_epoch
    if remainder_in_epoch != 0:
        return min(steps_per_epoch - remainder_in_epoch, steps_per_loop)
    else:
        return steps_per_loop


def query(mdx_stmt):
    """Return a IMDXResult resulting from executing the mdx statement."""


def t_REAL(t):
    """(([0-9]+[.][0-9]*)|([.][0-9]+))([Ee][+-]?[0-9]+)?"""
    try:
        value = float(t.value)
    except ValueError:
        print('Error converting %s to real' % t.value)
    return t


def get_content_length(environ):
    """Returns the content length from the WSGI environment as
    integer. If it's not available or chunked transfer encoding is used,
    ``None`` is returned.

    .. versionadded:: 0.9

    :param environ: the WSGI environ to fetch the content length from.
    """
    if environ.get('HTTP_TRANSFER_ENCODING', '') == 'chunked':
        return None
    content_length = environ.get('CONTENT_LENGTH')
    if content_length is not None:
        try:
            return max(0, int(content_length))
        except (ValueError, TypeError):
            pass


@classmethod
def from_dict(cls, task_dict):
    """
        Create a new task description object from the given dictionary.
        The dictionary takes the form of:
            {
                "id": <task-template-id>,
                "name": <registered-task-name>,
                "config": <config-dict>,
                "topics": {[<>]|null}
            }

        The parameters 'topics' and 'config' are both optional.
        See below the behavior of a task at runtime according to the value of
        'topics':
            {"topics": None}
            the task will receive ALL data disptached by the broker
            ** default behavior **

            {"topics": []}
            the task will receive NO data from the broker

            {"topics": ["blob", "foo"]}
            the task will receive data dispatched by the broker in topics
            "blob" and "foo" only
        """
    uid = task_dict.get('id')
    name = task_dict['name']
    config = task_dict.get('config', {})
    topics = task_dict.get('topics', [])
    timeout = task_dict.get('timeout')
    return cls(name, uid=uid, config=config, timeout=timeout, topics=topics)


def autogenPermission(autogenCmd, outputLines, autogenDict, entryDict):
    """
    Set permissions for files or directories as requested by the user.
    """
    if not autogenDict.has_key('perms'):
        return
    for containerDst, permsDict in autogenDict['perms'].iteritems():
        with autogenCmd.getRoleIfContext(permsDict.get('onroles', None),
            outputLines) as ric:
            rwx = permsDict['rwx']
            uid = permsDict['uid'] if permsDict.has_key('uid') else None
            gid = permsDict['gid'] if permsDict.has_key('gid') else None
            if rwx:
                outputLines.append('%schmod -v %s %s\n' % (ric.spaces, rwx,
                    containerDst))
            if uid and not gid:
                outputLines.append('%schown -v %s %s\n' % (ric.spaces, uid,
                    containerDst))
            if uid and gid:
                outputLines.append('%schown -v %s:%s %s\n' % (ric.spaces,
                    uid, gid, containerDst))
        outputLines.append('\n')
    return


def drop_all():
    """Drop all tables and sequences."""


def interpolate(y_2, n, a, b, c):
    """See Eqn 3.3, p.25 Astro. Alg."""
    y = y_2 + n / 2 * (a + b + n * c)
    return y


def __init__(context):
    """Adapts any object with ``ILabelSupport``.
        """


@classmethod
def accepts_default_mpiprocs_per_machine(cls):
    """
        Return True if this JobResource accepts a 'default_mpiprocs_per_machine'
        key, False otherwise.
        """
    return False


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


def runserver():
    """
    Runs Django's runserver command.
    """
    from miniserver.manage import main
    main(['miniserver', 'runserver'])


@classmethod
def from_spec1d(cls, spec1d):
    """ Input Spectrum1D

        Avoids error array for now
        """
    slf = cls.from_tuple((spec1d.dispersion, spec1d.flux))
    return slf


def __ne__(A, other):
    """Returns true if both objects are not equal"""
    return not A == other


def is_pubkey(p: str) ->bool:
    """
    determines if a string can be interpreted as btc hex formatted pubkey
    """
    prefix = p[0:2]
    try:
        bytes.fromhex(p)
    except ValueError:
        return False
    if len(p) == 66:
        return prefix in ['02', '03']
    if len(p) == 130:
        return prefix == '04'
    return False


def is_stream_binary_plist(stream):
    """
    Module function to check, if the stream is a binary plist.

    @param stream plist stream (file object)
    @return flag indicating a binary plist (boolean)
    """
    stream.seek(0)
    header = stream.read(7)
    if header == b'bplist0':
        return True
    else:
        return False


def force_readable_domain_name(s):
    """
    Converts punycode hostname to human-readable name.
    """
    if s is None:
        return s
    s = s.lower().strip()
    if s.startswith('xn--') or '.xn--' in s:
        try:
            s = s.encode()
            return s.decode('idna')
        except UnicodeError:
            return s
    else:
        return s


def match_type(obj, matchers):
    """Matches a given object using the given matchers list/iterable.

    NOTE(harlowja): each element of the provided list/iterable must be
    tuple of (valid types, result).

    Returns the result (the second element of the provided tuple) if a type
    match occurs, otherwise none if no matches are found.
    """
    for match_types, match_result in matchers:
        if isinstance(obj, match_types):
            return match_result
    else:
        return None


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

        :param FileTransfersPolicyChangedType val:
        :rtype: EventType
        """
    return cls('file_transfers_policy_changed', val)


@classmethod
def from_dict(cls, tree):
    """Make an SeparatedCoords from a dictionary, previously created by `to_dict()`.

		Parameters
		----------
		tree : dictionary
			The dictionary from which to make a new SeparatedCoords object.

		Returns
		-------
		SeparatedCoords
			The created object.

		Raises
		------
		ValueError
			If the dictionary is not formatted correctly.
		"""
    if tree['type'] != 'separated':
        raise ValueError('The type of coordinates should be "separated".')
    return cls(tree['separated_coords'])


def _categorical_stats(idadf, stat, columns):
    """
    Computes various stats from one or several categorical columns of the IdaDataFrame.
    This is not implemented.

    Parameters
    ----------
    idadf : IdaDataFrame
    stat : str
        Name of the statistic function to be computed.
    columns : str or list of str
        Name of columns belonging to the IdaDataFrame.

    Returns
    -------
        Tuple.
    """
    raise NotImplementedError('TODO')


def format_pi(rs):
    """Predicate Information (identified by operation id):"""
    c_i_v = rs['ID']
    c_fp_v = rs['FILTER_PREDICATES']
    c_ap_v = rs['ACCESS_PREDICATES']
    t_pi = []
    for i, [fp, ap] in list(enumerate(zip(c_fp_v, c_ap_v))):
        if fp is not None:
            t_pi.append([c_i_v[i], 'filter', fp])
        if ap is not None:
            t_pi.append([c_i_v[i], 'access', ap])
    tit = 'Predicate Information (identified by operation id):'
    tit_ = ''.rjust(len(tit), '-')
    pi = []
    for i, x, fa in t_pi:
        pi.append('   %d - %s(%s)' % (i, x, fa))
    return [tit, tit_, ''] + pi if len(pi) >= 1 else []


def __contains__(path):
    """Whether a path exists in the manifest."""


def get_caller_identity():
    """
    Returns details about the IAM identity whose credentials are used to call the API.
    See also: AWS API Documentation

    Examples
    This example shows a request and response made with the credentials for a user named Alice in the AWS account 123456789012.
    Expected Output:
    This example shows a request and response made with temporary credentials created by AssumeRole. The name of the assumed role is my-role-name, and the RoleSessionName is set to my-role-session-name.
    Expected Output:
    This example shows a request and response made with temporary credentials created by using GetFederationToken. The Name parameter is set to my-federated-user-name.
    Expected Output:

    :example: response = client.get_caller_identity()

    :rtype: dict
    :return: {
        'UserId': 'string',
        'Account': 'string',
        'Arn': 'string'
    }

    """
    pass


@classmethod
def _create(cls, name, node_type, nodeid=1, loopback_ndi=None):
    """
        Create the node/s for the engine. This isn't called directly,
        instead it is used when engine.create() is called

        :param str name: name of node
        :param str node_type: based on engine type specified
        :param int nodeid: used to identify which node
        :param list LoopbackInterface loopback_ndi: optional loopback
            interface for node.
        """
    loopback = loopback_ndi if loopback_ndi else []
    node = {node_type: {'activate_test': True, 'disabled': False,
        'loopback_node_dedicated_interface': loopback, 'name': name +
        ' node ' + str(nodeid), 'nodeid': nodeid}}
    return node


def tio_is_attribute(tree_item):
    """
    Returns 'True' if the tree item object is an attribute of the parent
    opposed to e.g. a list element.
    """
    if tree_item.is_attribute is None:
        return ''
    else:
        return str(tree_item.is_attribute)


def add_properties(props, mol):
    """apply properties to the molecule object

    Returns:
        None (alter molecule object directly)
    """
    if not props:
        return
    for _, atom in mol.atoms_iter():
        atom.charge = 0
        atom.multi = 1
        atom.mass = None
    for prop in props.get('CHG', []):
        mol.atom(prop[0]).charge = prop[1]
    for prop in props.get('RAD', []):
        mol.atom(prop[0]).multi = prop[1]
    for prop in props.get('ISO', []):
        mol.atom(prop[0]).mass = prop[1]


def has_digest_subscribers():
    """
        Returns True or False based on whether or not there is one or
        more digest subscribers for the context list.
        """


@classmethod
def from_ra_dec_dms(cls, ra, dec, name='Custom Body'):
    """Return sky positions from angles in degrees.

        Parameters
        ----------
        ra : string
            Right Ascension of the body
        dec : string
            Declination of the body
        name : string (optional)
        """
    return cls(name, ra, dec)


def log1p(data=None, name=None, attr=None, out=None, **kwargs):
    """Returns element-wise ``log(1 + x)`` value of the input.

    This function is more accurate than ``log(1 + x)``  for small ``x`` so that
    :math:`1+x\\approx 1`

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

       - log1p(default) = default
       - log1p(row_sparse) = row_sparse
       - log1p(csr) = csr

    Defined in src/operator/tensor/elemwise_unary_op_logexp.cc:L206

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

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

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


def merge_result(command, res):
    """
    Merge all items in `res` into a list.

    This command is used when sending a command to multiple nodes
    and they result from each node should be merged into a single list.
    """
    if not isinstance(res, dict):
        raise ValueError('Value should be of dict type')
    result = set([])
    for _, v in res.items():
        for value in v:
            result.add(value)
    return list(result)


def get_list(node, tag):
    """
    Get sub-nodes of this node by their tag, and make sure to return a list.

    The problem here is that xmltodict returns a nested dictionary structure,
    whose substructures have different *types* if there's repeated nodes
    with the same tag. So a list of one thing ends up being a totally different
    thing than a list of two things.

    So, here, we look up a sub-node by its tag, and return a list regardless of
    whether it matched 0, 1, or more things.
    """
    subnode = node.get(tag, [])
    if isinstance(subnode, list):
        return subnode
    else:
        return [subnode]


def dashed(requestContext, seriesList, dashLength=5):
    """
    Takes one metric or a wildcard seriesList, followed by a float F.

    Draw the selected metrics with a dotted line with segments of length F
    If omitted, the default length of the segments is 5.0

    Example::

        &target=dashed(server01.instance01.memory.free,2.5)

    """
    for series in seriesList:
        series.name = 'dashed(%s, %g)' % (series.name, dashLength)
        series.options['dashed'] = dashLength
    return seriesList


@classmethod
def get_tablenames(cls):
    """Get a list of table names.

        Returns list of table names the datasource has
        """
    return set(cls.get_schema().keys())


@classmethod
def get_db_url(cls):
    """We can use the dict passed from settings.DATABASE_CONFIG_DICT to construct a db url.

        :return: Database url. See: http://docs.sqlalchemy.org/en/latest/core/engines.html
        :rtype: str
        """
    raise NotImplementedError('Please implement this function.')


def track_event(track_events_to, event, sequence):
    """Writes all details necessary to generate event to a file.

    Called each time an event occurs if the track_events_to variable of the CircuitEditor is not None.

    Example contents of the file:
    '<Motion>', serial = 329, state = 8, x = 643, y = 10
    '<Control-MouseWheel>', serial = 335, state = 12, x = 292, y = 239, delta = -120

    Parameters
    ----------
    track_events_to:    string
                        name (or path) of the folder to write to
    event:              Tkinter event
    sequence:           string
                        For example '<ButtonRelease-1>' or 'c'
    """
    to_exclude = ['<Enter>', '<Leave>']
    if sequence not in to_exclude:
        event_string = "'" + sequence + "'"
        for key, value in event.__dict__.items():
            if key in ['when', 'above', 'borderwidth', 'button', 'count',
                'data', 'detail', 'focus', 'height', 'keycode', 'keysym',
                'mode', 'override', 'place', 'root', 'rootx', 'rooty',
                'sendevent', 'serial', 'state', 'subwindow', 'warp',
                'width', 'window', 'x', 'y'
                ] or key == 'delta' and 'MouseWheel' in sequence:
                if value != '??':
                    event_string += ', ' + key + ' = ' + repr(value)
        with open(track_events_to, 'a+') as event_tracking_file:
            event_tracking_file.write(event_string + '\n')


@staticmethod
def _parse_tide_obs(in_str):
    """
        TODO: Add docstring

        """
    error_code_dict = {'M': 1, 'N': 2, 'T': 3}
    try:
        int(in_str[-1])
        error_code = 0
        meas = float(in_str)
    except:
        error_code_str = in_str[-1]
        meas = float(in_str[0:-1])
        try:
            error_code = error_code_dict[error_code_str]
        except:
            print('Unrecognised error code')
            return
    return meas, error_code


def count_static_vars(static_vars_table):
    """ Count the number of variables defined in the STATIC_VARS_TABLE
    """
    return len(static_vars_table.nodes[0].value)


def reset_cities(cursor):
    """
    reset all cities to 1 (unknown)
    """
    sql = 'UPDATE trackpoints SET citydef_uid = 1'
    cursor.execute(sql)


def setup(app):
    """Entry point for Sphinx customizations."""
    app.add_stylesheet('customizations.css')


def equals(arr1, arr2):
    """计算两个数组中的每一个元素是否相等"""
    return arr1 == arr2


def extract_psf(psf, psf_patch):
    """Extract the central region of a PSF.

    This function is 2D: the polarization axis must have already been removed.
    """
    y0 = (psf.shape[0] - psf_patch[0]) // 2
    y1 = y0 + psf_patch[0]
    x0 = (psf.shape[1] - psf_patch[1]) // 2
    x1 = x0 + psf_patch[1]
    return psf[(...), y0:y1, x0:x1]


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

        :param TfaRemoveBackupPhoneType val:
        :rtype: EventType
        """
    return cls('tfa_remove_backup_phone', val)


@classmethod
def _parse_value(cls, stream_rdr, offset, value_count, value_offset):
    """
        Return the long int value contained in the *value_offset* field of
        this entry. Only supports single values at present.
        """
    if value_count == 1:
        return stream_rdr.read_long(offset, 8)
    else:
        return 'Multi-value long integer NOT IMPLEMENTED'


def dupliob_remove():
    """Remove the selected dupliobject

    """
    pass


def err_response(reqid, code, msg, data=None):
    """
    Formats a JSON-RPC error as a dict with keys: 'jsonrpc', 'id', 'error'
    """
    err = {'code': code, 'message': msg}
    if data:
        err['data'] = data
    return {'jsonrpc': '2.0', 'id': reqid, 'error': err}


@staticmethod
def _index_to_doctag(i_index, offset2doctag, max_rawint):
    """Get string key for given `i_index`, if available. Otherwise return raw int doctag (same int)."""
    candidate_offset = i_index - max_rawint - 1
    if 0 <= candidate_offset < len(offset2doctag):
        return offset2doctag[candidate_offset]
    else:
        return i_index


def getFinal(endstr):
    """ returns the final consonant or empty string """
    if not endstr:
        return ''
    if endstr.endswith('ng'):
        return 'ng'
    lastchar = endstr[-1]
    if lastchar in ['m', 'b', 'n', 'x', 'r', 'l', 't', 'x']:
        return lastchar
    return ''


@classmethod
def has_archiving(cls):
    """Returns whether it supports archiving items on the fetch process.

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


def p_expr_big_op_du(p):
    """p_expr_big_op_du : p_expr_big_op_d UP LBRACE expression RBRACE"""
    operator, index, down = p[1]
    p[0] = operator, index, down, p[4]


def get_nearest_option(spot, n=1, opt='C', step=100):
    """
    Given a spot price, calculate the nearest options
    spot
        spot price of the instrument
    n
        number of nearest option prices
    opt
        call or put option. 'C' for call and 'P' for put
    step
        step size of the option price
    returns a list of options
    >>> get_nearest_option(23457, 2)
    >>> [23400, 23500]
    >>> get_nearest_option(23457, 2, 'P')
    >>> [23400, 23300]
    All calculations are based on in the money option. So,
    get_nearest_option(24499) would return 24400
    """
    in_money = int(spot / step) * step
    option_prices = []
    for i in range(n):
        if opt == 'C':
            strike = in_money + step * i
            option_prices.append(strike)
        elif opt == 'P':
            strike = in_money - step * i
            option_prices.append(strike)
        else:
            print('Option type not recognized; Check the opt argument')
    return option_prices


def trim_list_by_inds(list_to_trim: list, indices: list):
    """Trim a list given an unordered list of indices.

    :param list_to_trim: list to remove elements from
    :type list_to_trim: list
    :param indices: indices of list items to remove
    :type indices: list
    :return: new list, trimmed items
    :rtype: list, list
    """
    new_list = list_to_trim.copy()
    trimmed = []
    for index in sorted(indices, reverse=True):
        trimmed.append(new_list[index])
        del new_list[index]
    return new_list, trimmed


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 pick_first_not_none(*values):
    """Returns first of values that is *not* None (or None if all are/were)."""
    for val in values:
        if val is not None:
            return val
    return None


def pytest_benchmark_generate_commit_info(config):
    """
    To completely replace the generated commit_info do something like this:

    .. sourcecode:: python

        def pytest_benchmark_generate_commit_info(config):
            return {'id': subprocess.check_output(['svnversion']).strip()}
    """
    pass


@classmethod
def by_id(cls, user=None, id=None, full_dehydrate='no', force_refresh='no'):
    """Retrieve a node record by id and create a BaseNode instance from it.

        Args:
            user (User): the  User that the node belongs to
            id (str): id of the node to retrieve
            full_dehydrate(optional, str): if 'yes', returns transaction data on node
            force_refresh(optional, str): if 'yes', returns synced account data

        Returns:
            BaseNode: a BaseNode instance corresponding to the record
        """
    response = user.client.nodes.get(user.id, id, full_dehydrate=
        full_dehydrate, force_refresh=force_refresh)
    return cls.from_response(user, response)


def translate_attach_remove_on_cancel(TRANSFORM_OT_translate=None,
    NODE_OT_attach=None, NODE_OT_insert_offset=None):
    """Move nodes and attach to frame

    :param TRANSFORM_OT_translate: Translate, Translate (move) selected items
    :param NODE_OT_attach: Attach Nodes, Attach active node to a frame
    :param NODE_OT_insert_offset: Insert Offset, Automatically offset nodes on insertion
    """
    pass


def random_reflect(board, moves=None):
    """Rotate/flip board at random while keeping same player perspective.
    """
    if moves is not None:
        return board, moves
    return board


def humanize_bytes(bytesize, precision=2):
    """
    Humanize byte size figures

    https://gist.github.com/moird/3684595
    """
    abbrevs = (1 << 50, 'PB'), (1 << 40, 'TB'), (1 << 30, 'GB'), (1 << 20, 'MB'
        ), (1 << 10, 'kB'), (1, 'bytes')
    if bytesize == 1:
        return '1 byte'
    for factor, suffix in abbrevs:
        if bytesize >= factor:
            break
    if factor == 1:
        precision = 0
    return '%.*f %s' % (precision, bytesize / float(factor), suffix)


def getCreator():
    """ Returns the Zope user who created the lock.  This is returned
        in a tuple containing the Users ID and the path to the user folder
        they came from."""


@staticmethod
def get_subtype(object_dictionary):
    """
        Given the hash representation of a subtype of this class,
        use the info in the hash to return the class of the subtype.
        """
    type = object_dictionary['type']
    if type == 'volumeBackup':
        return 'InstanceConfigurationVolumeSourceFromVolumeBackupDetails'
    if type == 'volume':
        return 'InstanceConfigurationVolumeSourceFromVolumeDetails'
    else:
        return 'InstanceConfigurationVolumeSourceDetails'


def bC_K_SO4_HMW84(T, P):
    """c-a: potassium sulfate [HMW84]."""
    b0 = 0.04995
    b1 = 0.7793
    b2 = 0.0
    C0 = 0
    C1 = 0
    alph1 = 2
    alph2 = -9
    omega = -9
    valid = T == 298.15
    return b0, b1, b2, C0, C1, alph1, alph2, omega, valid


def lerp(first, second, mu):
    """Linear Interpolation between values of two lists

    Parameters
    ----------
    first : tuple or list
        first list of values
    second : tuple or list
        second list of values
    mu : float
        Interpolation factor [0,1]

    Returns
    -------
    list
        A list of the interpolated values
    """
    final = first[:]
    for i in range(len(first)):
        diff = second[i] - first[i]
        final[i] += diff * mu
    return final


@classmethod
def bernstein(cls, i, n, **kwargs):
    """
        Return the output of :meth:`mvpoly.dict.MVPolyDict.bernstein`
        converted to other polynomial subclasess.
        """
    from mvpoly.dict import MVPolyDict
    return cls(MVPolyDict.bernstein(i, n, **kwargs), **kwargs)


def getAvailableTLDs():
    """
        Return a sequence of country code top level domains.
        """


def get_title_or_id():
    """The title, or the identifier if there is no title of the
        content object.
        """


@classmethod
def get_header(cls, script_text='', executable=None):
    """Create a #! line, getting options (if any) from script_text"""
    cmd = cls.command_spec_class.best().from_param(executable)
    cmd.install_options(script_text)
    return cmd.as_header()


def factorise(number: int):
    """Factorise a number to avoid too large a downsample factor

    Parameters
    ----------
    number : int
        The number to factorise

    Returns
    -------
    List[int]
        The downsampling factors to use

    Notes
    -----
    There's a few pathological cases here that are being ignored. For example, what if the downsample factor is the product of two primes greater than 13.
    """
    import primefac
    factors = list(primefac.primefac(number))
    downsamples = []
    val = 1
    for f in factors:
        test = val * f
        if test > 13:
            downsamples.append(val)
            val = 1
        val = val * f
    downsamples.append(val)
    return downsamples


@classmethod
def from_fields(cls, field_list):
    """Make an event from a list for (name, value) field tuples."""
    field_dict = dict(field_list)
    return cls(**field_dict)


@classmethod
def mint_uri(cls, target, new_graph, created, basename=None, suffix=''):
    """I mint a fresh URI for a resource of that class.

        This method is called by :class:`rdfrest.cores.mixins.GraphPostableMixin`;
        calling it directly is usually not required.

        :param target:    the resource to which `new_graph` has been posted
        :type  target:    :class:`ILocalCore`
        :param new_graph: a description of the resource for which to mint a URI
        :type  new_graph: rdflib.Graph
        :param created:   the non-URIRef node representing the resource in
                          $`new_graph`
        :type  created:   rdflib.Node
        :param basename:  a base on which the last part of the URI will be
                          generated
        :type  basename:  str
        :param suffix:    a string that will be added at the end of the URI
        :type  suffix:    str

        :rtype: rdflib.URIRef
        """
    raise NotImplementedError


def lis_formes(cls):
    """retourne le dictionnaire des formes tortue disponibles"""
    return cls._formes


def hive_step_properties(script, arguments=None, input=None, output=None):
    """
    Create hive step properties

    :param script: the script path of step
    :type script: string

    :param arguments: arguments for the step
    :type arguments: string

    :param input: the input path of step
    :type input: string

    :param output: the output path of step
    :type output: string

    :return:
    :rtype map
    """
    hive_step = {'script': script}
    if arguments is not None:
        hive_step['arguments'] = arguments
    if input is not None:
        hive_step['input'] = input
    if output is not None:
        hive_step['output'] = output
    return hive_step


@classmethod
def _is_content_identity(cls):
    """Test if content identity was defined."""
    return bool(cls.operation_identity is not None)


def _reduce_datetimes(row):
    """Receives a row, converts datetimes to strings."""
    row = list(row)
    for i in range(len(row)):
        if hasattr(row[i], 'isoformat'):
            row[i] = row[i].isoformat()
    return tuple(row)


def _get_sequential_table(seqType):
    """
    Generates the table to fill sequence data in order to create
    a :class:`.SequenceFrame`

    :param seqType: Type of sequence: ``protein``, ``protein_sse``,
        ``dna``, ``rna``.
    :type seqType: :class:`str`

    :return: :class:`dict`

    :raise:
        :ValueError: If ``seqType`` is not known.
    """
    table = {}
    extra = []
    if seqType.lower() == 'protein':
        table = {'C': [], 'D': [], 'S': [], 'Q': [], 'K': [], 'I': [], 'P':
            [], 'T': [], 'F': [], 'N': [], 'G': [], 'H': [], 'L': [], 'R':
            [], 'W': [], 'A': [], 'V': [], 'E': [], 'Y': [], 'M': [], 'X':
            [], '*': [], 'B': [], 'Z': []}
        extra = ['X', '*', 'B', 'Z']
    elif seqType.lower() in ['dna', 'rna']:
        table = {'C': [], 'A': [], 'T': [], 'G': [], 'X': [], '*': [], 'B':
            [], 'D': [], 'H': [], 'K': [], 'M': [], 'N': [], 'R': [], 'S':
            [], 'V': [], 'W': [], 'Y': []}
        if seqType.lower() == 'rna':
            table.setdefault('U', [])
            table.pop('T', None)
        extra = ['X', '*', 'B', 'D', 'H', 'K', 'M', 'N', 'R', 'S', 'V', 'W',
            'Y']
    elif seqType.lower() == 'protein_sse':
        table = {'H': [], 'E': [], 'L': [], '*': [], 'G': []}
        extra = ['*', 'G']
    else:
        raise ValueError('sequence type {0} unknown'.format(seqType))
    return table, extra


def apply(mailing_list):
    """Apply the style to the mailing list.

        :type mailing_list: `IMailingList`.
        :param mailing_list: the mailing list to apply the style to.
        """


@classmethod
def value_from_buffer(cls, bfr, length=None):
    """ Parse a `BytesField` of length `length` from `bfr`.
    """
    if length < 0:
        raise ValueError('length(%d) < 0' % (length,))
    return bfr.take(length)


@classmethod
def find_son_sysorg_count(cls, org_code):
    """
        根据机构编号获取本机构旗下所有机构信息数量
        :param org_code:
        :return:
        """
    return cls.objects(org_code__startswith=org_code, status__in=[0, 1]).count(
        )


def aliased(cls):
    """Class decorator used in combination with @alias method decorator."""
    orig_methods = cls.__dict__.copy()
    seen_aliases = set()
    for name, method in orig_methods.items():
        if hasattr(method, '_aliases'):
            collisions = method._aliases.intersection(orig_methods.keys() |
                seen_aliases)
            if collisions:
                raise ValueError(
                    'aliases collide with existing attributes: %s' % ({', '
                    .join(collisions)},))
            seen_aliases |= method._aliases
            for alias in method._aliases:
                setattr(cls, alias, method)
    return cls


def etv(b, component, dataset, solve_for=None, **kwargs):
    """
    compute the ETV column from the time_ephem and time_ecl columns (used in the
        ETV dataset).

    This is usually passed as an argument to
     <phoebe.frontend.bundle.Bundle.add_constraint>.
    """
    time_ephem = b.get_parameter(qualifier='time_ephems', component=
        component, dataset=dataset, context=['dataset', 'model'])
    time_ecl = b.get_parameter(qualifier='time_ecls', component=component,
        dataset=dataset)
    etv = b.get_parameter(qualifier='etvs', component=component, dataset=
        dataset)
    if solve_for in [None, etv]:
        lhs = etv
        rhs = time_ecl - time_ephem
    else:
        raise NotImplementedError
    return lhs, rhs, [], {'component': component, 'dataset': dataset}


def update_product(AcceptLanguage=None, Id=None, Name=None, Owner=None,
    Description=None, Distributor=None, SupportDescription=None,
    SupportEmail=None, SupportUrl=None, AddTags=None, RemoveTags=None):
    """
    Updates an existing product.
    See also: AWS API Documentation

    :example: response = client.update_product(
        AcceptLanguage='string',
        Id='string',
        Name='string',
        Owner='string',
        Description='string',
        Distributor='string',
        SupportDescription='string',
        SupportEmail='string',
        SupportUrl='string',
        AddTags=[
            {
                'Key': 'string',
                'Value': 'string'
            },
        ],
        RemoveTags=[
            'string',
        ]
    )

    :type AcceptLanguage: string
    :param AcceptLanguage: The language code to use for this operation. Supported language codes are as follows:
            'en' (English)
            'jp' (Japanese)
            'zh' (Chinese)
            If no code is specified, 'en' is used as the default.

    :type Id: string
    :param Id: [REQUIRED]
            The identifier of the product for the update request.

    :type Name: string
    :param Name: The updated product name.

    :type Owner: string
    :param Owner: The updated owner of the product.

    :type Description: string
    :param Description: The updated text description of the product.

    :type Distributor: string
    :param Distributor: The updated distributor of the product.

    :type SupportDescription: string
    :param SupportDescription: The updated support description for the product.

    :type SupportEmail: string
    :param SupportEmail: The updated support email for the product.

    :type SupportUrl: string
    :param SupportUrl: The updated support URL for the product.

    :type AddTags: list
    :param AddTags: Tags to add to the existing list of tags associated with the product.
            (dict) --Key/value pairs to associate with this provisioning. These tags are entirely discretionary and are propagated to the resources created in the provisioning.
            Key (string) -- [REQUIRED]The ProvisioningArtifactParameter.TagKey parameter from DescribeProvisioningParameters .
            Value (string) -- [REQUIRED]The esired value for this key.

    :type RemoveTags: list
    :param RemoveTags: Tags to remove from the existing list of tags associated with the product.
            (string) --

    :rtype: dict
    :return: {
        'ProductViewDetail': {
            'ProductViewSummary': {
                'Id': 'string',
                'ProductId': 'string',
                'Name': 'string',
                'Owner': 'string',
                'ShortDescription': 'string',
                'Type': 'CLOUD_FORMATION_TEMPLATE',
                'Distributor': 'string',
                'HasDefaultPath': True|False,
                'SupportEmail': 'string',
                'SupportDescription': 'string',
                'SupportUrl': 'string'
            },
            'Status': 'AVAILABLE'|'CREATING'|'FAILED',
            'ProductARN': 'string',
            'CreatedTime': datetime(2015, 1, 1)
        },
        'Tags': [
            {
                'Key': 'string',
                'Value': 'string'
            },
        ]
    }

    """
    pass


def bitcount(num: int) ->int:
    """
    Count the number of bits in a numeric (integer or long) value. This
    method is adapted from the Hamming Weight algorithm, described (among
    other places) at http://en.wikipedia.org/wiki/Hamming_weight

    Works for up to 64 bits.

    **Parameters**

    - `num` (`int`): The numeric value

    **Returns**:

    The number of 1 bits in the binary representation of `num`
    """
    num = num - (num >> 1 & 6148914691236517205)
    num = (num & 3689348814741910323) + (num >> 2 & 3689348814741910323)
    num = num + (num >> 4) & 1085102592571150095
    return int(num * 72340172838076673 >> 56)


def clean_axis(ax):
    """
    Remove ticks and tick labels

    Parameters
    ----------
    ax : matplotlib.axes
        Axes to modify
    """
    ax.get_xaxis().set_ticks([])
    ax.get_yaxis().set_ticks([])


def ler_POF(path, header=True):
    """
    Realiza a leitura dos microdados da POF 2017/2018 diretamente do arquivo .zip baixado do site do IBGE
    e exporta os dados como um arquivo .csv.
    :param path: caminho para o arquivo .zip
    :param header: boolean, Default True - acrescenta o código da variável como nome de cada coluna.
    https://github.com/otavio-s-s/lerMicrodados
     """
    import pandas as pd
    from zipfile import ZipFile
    pof_2017 = {'ALUGUEL_ESTIMADO': [[2, 4, 1, 9, 2, 1, 2, 7, 2, 10, 2, 2,
        12, 10, 1, 2, 14, 14, 10], ['UF', 'ESTRATO_POF',
        'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM', 'NUM_UC', 'QUADRO',
        'V9001', 'V9002', 'V8000', 'V9010', 'V9011', 'DEFLATOR',
        'V8000_DEFLA', 'COD_IMPUT_VALOR', 'FATOR_ANUALIZACAO', 'PESO',
        'PESO_FINAL', 'RENDA_TOTAL']], 'CADERNETA_COLETIVA': [[2, 4, 1, 9,
        2, 1, 2, 3, 7, 2, 10, 12, 10, 1, 2, 14, 14, 10, 9, 4, 5, 9], ['UF',
        'ESTRATO_POF', 'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM', 'NUM_UC',
        'QUADRO', 'SEQ', 'V9001', 'V9002', 'V8000', 'DEFLATOR',
        'V8000_DEFLA', 'COD_IMPUT_VALOR', 'FATOR_ANUALIZACAO', 'PESO',
        'PESO_FINAL', 'RENDA_TOTAL', 'V9005', 'V9007', 'V9009', 'QTD_FINAL'
        ]], 'DESPESA_COLETIVA': [[2, 4, 1, 9, 2, 1, 2, 2, 7, 2, 4, 10, 2, 2,
        1, 10, 1, 12, 10, 10, 1, 1, 2, 14, 14, 10], ['UF', 'ESTRATO_POF',
        'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM', 'NUM_UC', 'QUADRO',
        'SEQ', 'V9001', 'V9002', 'V9005', 'V8000', 'V9010', 'V9011',
        'V9012', 'V1904', 'V1905', 'DEFLATOR', 'V8000_DEFLA', 'V1904_DEFLA',
        'COD_IMPUT_VALOR', 'COD_IMPUT_QUANTIDADE', 'FATOR_ANUALIZACAO',
        'PESO', 'PESO_FINAL', 'RENDA_TOTAL']], 'DESPESA_INDIVIDUAL': [[2, 4,
        1, 9, 2, 1, 2, 2, 2, 7, 2, 10, 2, 2, 1, 1, 1, 12, 10, 1, 2, 14, 14,
        10], ['UF', 'ESTRATO_POF', 'TIPO_SITUACAO_REG', 'COD_UPA',
        'NUM_DOM', 'NUM_UC', 'COD_INFORMANTE', 'QUADRO', 'SEQ', 'V9001',
        'V9002', 'V8000', 'V9010', 'V9011', 'V9012', 'V4104', 'V4105',
        'DEFLATOR', 'V8000_DEFLA', 'COD_IMPUT_VALOR', 'FATOR_ANUALIZACAO',
        'PESO', 'PESO_FINAL', 'RENDA_TOTAL']], 'DOMICILIO': [[2, 4, 1, 9, 2,
        1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 14, 14], ['UF', 'ESTRATO_POF',
        'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM', 'V0201', 'V0202',
        'V0203', 'V0204', 'V0205', 'V0206', 'V0207', 'V0208', 'V0209',
        'V02101', 'V02102', 'V02103', 'V02104', 'V02105', 'V02111',
        'V02112', 'V02113', 'V0212', 'V0213', 'V02141', 'V02142', 'V0215',
        'V02161', 'V02162', 'V02163', 'V02164', 'V0217', 'V0219', 'V0220',
        'V0221', 'PESO', 'PESO_FINAL']], 'MORADOR': [[2, 4, 1, 9, 2, 1, 2,
        2, 1, 2, 2, 4, 3, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 2, 14, 14, 10],
        ['UF', 'ESTRATO_POF', 'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM',
        'NUM_UC', 'COD_INFORMANTE', 'V0306', 'V0401', 'V04021', 'V04022',
        'V04023', 'V0403', 'V0404', 'V0405', 'V0406', 'V0407', 'V0408',
        'V0409', 'V0410', 'V0411', 'V0412', 'V0413', 'V0414', 'V0415',
        'V0416', 'V041711', 'V041712', 'V041721', 'V041722', 'V041731',
        'V041732', 'V041741', 'V041742', 'V0418', 'V0419', 'V0420', 'V0421',
        'V0422', 'V0423', 'V0424', 'V0425', 'V0426', 'V0427', 'V0428',
        'V0429', 'V0430', 'ANOS_ESTUDO', 'PESO', 'PESO_FINAL',
        'RENDA_TOTAL']], 'OUTROS_RENDIMENTOS': [[2, 4, 1, 9, 2, 1, 2, 2, 2,
        7, 10, 10, 2, 2, 12, 10, 10, 1, 1, 14, 14, 10], ['UF',
        'ESTRATO_POF', 'TIPO_SITUACAO_REG', 'COD_UPA', 'NUM_DOM', 'NUM_UC',
        'COD_INFORMANTE', 'QUADRO', 'SEQ', 'V9001', 'V8500', 'V8501',
        'V9010', 'V9011', 'DEFLATOR', 'V8500_DEFLA', 'V8501_DEFLA',
        'COD_IMPUT_VALOR', 'FATOR_ANUALIZACAO', 'PESO', 'PESO_FINAL',
        'RENDA_TOTAL']], 'RENDIMENTO_TRABALHO': [[2, 4, 1, 9, 2, 1, 2, 2, 1,
        1, 7, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 2, 2, 3, 1, 12, 10, 10, 10, 10,
        1, 1, 14, 14, 10], ['UF', 'ESTRATO_POF', 'TIPO_SITUACAO_REG',
        'COD_UPA', 'NUM_DOM', 'NUM_UC', 'COD_INFORMANTE', 'QUADRO',
        'SUB_QUADRO', 'SEQ', 'V9001', 'V5302', 'V53021', 'V5303', 'V5304',
        'V5305', 'V5307', 'V8500', 'V531112', 'V531122', 'V531132', 'V9010',
        'V9011', 'V5314', 'V5315', 'DEFLATOR', 'V8500_DEFLA',
        'V531112_DEFLA', 'V531122_DEFLA', 'V531132_DEFLA',
        'COD_IMPUT_VALOR', 'FATOR_ANUALIZACAO', 'PESO', 'PESO_FINAL',
        'RENDA_TOTAL']]}
    zip_file = ZipFile(path, mode='r')
    for text_file in zip_file.infolist():
        file = text_file.filename
        name = '{}'.format(text_file.filename.split('.')[0])
        new_file = pd.read_fwf(zip_file.open(file), widths=pof_2017[name][0
            ], index=False, header=None, dtype=str)
        if header:
            new_file.columns = pof_2017[name][1]
        new_file.to_csv('{}.csv'.format(name), index=False)
        print('{}.csv exportado com sucesso.'.format(name))


def _sample_discrete__python(pmf, rand):
    """Returns a sample from a discrete distribution.

    Note: This version has no bells or whistles.

    Parameters
    ----------
    pmf : list of floats
        A list of floats representing the probability mass function. The events
        will be the indices of the list. The floats should represent
        probabilities (and not log probabilities).
    rand : float
        The sample is drawn using the passed number.

    Returns
    -------
    s : int
        The index of the sampled event.

    """
    total = 0
    for i, prob in enumerate(pmf):
        total += prob
        if rand < total:
            return i


def relationRemoved(token, catalog, removals):
    """message: relation token has been removed from catalog.

        removals is a dictionary of {value name : iterable of removed value
        tokens}.
        """


def get_terminal_nodes(dag: dict) ->[str]:
    """Yield terminal nodes of given dag, with doublons.
    Key None must be associated with roots
    """
    roots = list(dag[None])
    while roots:
        root = roots.pop()
        if root in dag and dag[root]:
            for sub in dag[root]:
                roots.append(sub)
        else:
            yield root


def displayRangeToBricon(dataRange, displayRange):
    """Converts the given brightness/contrast values to a display range,
    given the data range.

    :arg dataRange:    The full range of the data being displayed, a
                       (min, max) tuple.

    :arg displayRange: A (min, max) tuple containing the display range.
    """
    dmin, dmax = dataRange
    dlo, dhi = displayRange
    drange = dmax - dmin
    dmid = dmin + 0.5 * drange
    if drange == 0:
        return 0, 0
    offset = dlo + 0.5 * (dhi - dlo) - dmid
    scale = (dhi - dlo) / drange
    brightness = 0.5 * (offset / drange + 1)
    if scale <= 1:
        contrast = scale / 2.0
    else:
        contrast = ((scale + 0.25) / 20.0) ** 0.25
    brightness = 1.0 - brightness
    contrast = 1.0 - contrast
    return brightness, contrast