def get_input2(prompt, conditions_any=[], conditions_all=[], debug=False):
    """Return user input, after validating it against arbitrary criteria.

    The user input must satisfy all conditions in conditions_all, and one or
    more of the conditions in conditions_any.  Conditions_any is a list, with
    the first item the error string to display if none of the conditions are
    met.  Conditions_all is a list of tuples, with each tuple having one
    condition + the associated error string to display to the user if the
    condition is not met.

    The conditions will be inserted in 'if' statements, and must be written
    so that the 'if' statement will be true if the data is valid.  E.g.

    if a 'Q' is needed:
    'X == "Q"'

    Note 1: all data input by the user is seen as a string, even if numbers are
    entered.  If the test is looking for an integer, write it as:
    'int(X)'

    Note 2: All tests are run inside 'try' statements, so exceptions will not
    cause problems.  Any test that raises an exception is treated as a failed
    test.

    Note 3: One idiosyncrasy of 'if' statements is that any statement that
    returns a '0' is treated as a False.  Tests must be crafted so a pass
    does not return a '0'.  E.g., if the test is intended to check that the
    data is a float, and a zero would be valid data, do not write the test as:
    'float(X)', as 'if float("O"):' will not pass.

    """
    input_validated = False
    while not input_validated:
        X = eval(input(prompt))
        validated_any = False
        validated_all = True
        if len(conditions_any) > 0:
            error_string = conditions_any[0]
            for condition in conditions_any[1:]:
                if debug:
                    print(('Testing condition', condition))
                try:
                    if eval(condition):
                        validated_any = True
                        if debug:
                            print(('Test of ', condition, 'passed'))
                    elif debug:
                        print(('Test of ', condition, 'failed'))
                except:
                    if debug:
                        print('Exception during test')
                    pass
        if len(conditions_all) > 0:
            for condition in conditions_all:
                if debug:
                    print(('Testing condition', condition[0]))
                try:
                    if eval(condition[0]):
                        if debug:
                            print(('Test of ', condition[0], 'passed'))
                        pass
                    else:
                        if debug:
                            print(('Test of ', condition[0], 'failed'))
                        validated_all = False
                        print(condition[1])
                except:
                    if debug:
                        print('Exception during test')
                    validated_all = False
                    print(condition[1])
        if not validated_any:
            print((error_string, '\n'))
        elif validated_all:
            input_validated = True
    return X


@classmethod
def toStr(cls, value, blacklist=None):
    """Convert numeric type to human-readable string if possible"""
    ret = cls.toRepr(value, blacklist)
    if ret is not None:
        return ret
    else:
        return '{0}'.format(value)


@classmethod
def is_valid_chip_key(cls, key):
    """
        Valid chip keys must be strings formatted as:
        ``'<io_chain>-<chip_id>'``

        """
    if not super(cls, cls).is_valid_chip_key(key):
        return False
    if not isinstance(key, str):
        return False
    parsed_key = key.split('-')
    if not len(parsed_key) == 2:
        return False
    try:
        _ = int(parsed_key[0])
        _ = int(parsed_key[1])
    except ValueError:
        return False
    return True


def slurm_handle(piped_input):
    """piped_input: list, this is the output from the command function
    intended for squeue but maybe will be used for other commands
    keep in mind that this modifies the input inplace
    """
    for idx, line in enumerate(piped_input):
        piped_input[idx] = line.split()
    if not piped_input[-1]:
        del piped_input[-1]


def generate_func_dict(plot_toggles, module_name, function_prefix,
    keyword_args={}):
    """
    Generates a dictionary where the keys are the function name and the value is a list
    containing the function itself (0th element) and keyword arguments as a dictionary
    (1st element). All functions in the returned dictionary are expected to have the same
    call signature for non-keyword arguments. Functions are only added when the
    ``plot_toggles`` value is non-zero.

    Functions are required to be named ``<module_name><function_prefix><plot_toggle_key>``
    For example, the default calculation function are kept in the ``model.py`` module and
    are named ``calc_<toggle>``.  E.g., ``sage_analysis.model.calc_SMF()``,
    ``sage_analysis.model.calc_BTF()``, ``sage_analysis.model.calc_sSFR()`` etc.

    Parameters
    ----------

    plot_toggles: dict, [string, int]
        Dictionary specifying the name of each property/plot and whether the values
        will be generated + plotted. A value of 1 denotes plotting, whilst a value of
        0 denotes not plotting.  Entries with a value of 1 will be added to the function
        dictionary.

    module_name: string
        Name of the module where the functions are located. If the functions are located
        in this module, pass an empty string "".

    function_prefix: string
        Prefix that is added to the start of each function.

    keyword_args: dict [string, dict[string, variable]], optional
        Allows the adding of keyword aguments to the functions associated with the
        specified plot toggle. The name of each keyword argument and associated value is
        specified in the inner dictionary.

    Returns
    -------

    func_dict: dict [string, list(function, dict[string, variable])]
        The key of this dictionary is the name of the function.  The value is a list with
        the 0th element being the function and the 1st element being a dictionary of
        additional keyword arguments to be passed to the function. The inner dictionary is
        keyed by the keyword argument names with the value specifying the keyword argument
        value.

    Examples
    --------
    >>> import sage_analysis.example_calcs
    >>> import sage_analysis.example_plots
    >>> plot_toggles = {"SMF": 1}
    >>> module_name = "sage_analysis.example_calcs"
    >>> function_prefix = "calc_"
    >>> generate_func_dict(plot_toggles, module_name, function_prefix) #doctest: +ELLIPSIS
    {'calc_SMF': [<function calc_SMF at 0x...>, {}]}
    >>> module_name = "sage_analysis.example_plots"
    >>> function_prefix = "plot_"
    >>> generate_func_dict(plot_toggles, module_name, function_prefix) #doctest: +ELLIPSIS
    {'plot_SMF': [<function plot_SMF at 0x...>, {}]}

    >>> import sage_analysis.example_plots
    >>> plot_toggles = {"SMF": 1}
    >>> module_name = "sage_analysis.example_plots"
    >>> function_prefix = "plot_"
    >>> keyword_args = {"SMF": {"plot_sub_populations": True}}
    >>> generate_func_dict(plot_toggles, module_name, function_prefix, keyword_args) #doctest: +ELLIPSIS
    {'plot_SMF': [<function plot_SMF at 0x...>, {'plot_sub_populations': True}]}

    >>> import sage_analysis.example_plots
    >>> plot_toggles = {"SMF": 1, "quiescent": 1}
    >>> module_name = "sage_analysis.example_plots"
    >>> function_prefix = "plot_"
    >>> keyword_args = {"SMF": {"plot_sub_populations": True},
    ...                 "quiescent": {"plot_output_format": "pdf", "plot_sub_populations": True}}
    >>> generate_func_dict(plot_toggles, module_name, function_prefix, keyword_args) #doctest: +ELLIPSIS
    {'plot_SMF': [<function plot_SMF at 0x...>, {'plot_sub_populations': True}], 'plot_quiescent': [<function plot_quiescent at 0x...>, {'plot_output_format': 'pdf', 'plot_sub_populations': True}]}
    """
    import sys
    if module_name == '':
        module = sys.modules[__name__]
    else:
        try:
            module = sys.modules[module_name]
        except KeyError:
            msg = (
                """Module {0} has not been imported.
Perhaps you need to create an empty `__init__.py` file to ensure your package can be imported."""
                .format(module_name))
            raise KeyError(msg)
    func_dict = {}
    for toggle in plot_toggles.keys():
        if plot_toggles[toggle]:
            func_name = '{0}{1}'.format(function_prefix, toggle)
            try:
                func = getattr(module, func_name)
            except AttributeError:
                msg = (
                    "Tried to get the func named '{0}' corresponding to 'plot_toggle' value '{1}'.  However, no func named '{0}' could be found in '{2}' module."
                    .format(func_name, toggle, module_name))
                raise AttributeError(msg)
            try:
                key_args = keyword_args[toggle]
            except KeyError:
                key_args = {}
            func_dict[func_name] = [func, key_args]
    return func_dict


def enable(true_false):
    """Enable/Disable ANSII Color formatting"""
    global __ISON
    __ISON = true_false


@classmethod
def clear_cache(cls):
    """Remove all items from the cache."""
    with cls.ca_lock:
        cls.cache = {}
        cls.timeouts = {}


def get_db_url_sqlserver(config):
    """
    Helper function for creating the "pyodbc" connection string.

    @see http://docs.sqlalchemy.org/en/latest/dialects/mssql.html
    @see https://code.google.com/p/pyodbc/wiki/ConnectionStrings
    """
    from urllib import parse
    params = parse.quote(
        'Driver={{FreeTDS}};Server={};Port={};Database={};UID={};PWD={};'.
        format(config['DB_HOST'], config['DB_PORT'], config['DB_NAME'],
        config['DB_USER'], config['DB_PASS']))
    return 'mssql+pyodbc:///?odbc_connect={}'.format(params)


def project_process(index, start, end):
    """Compute the metrics for the project process section of the enriched
    git index.

    Returns a dictionary containing "bmi_metrics", "time_to_close_metrics",
    "time_to_close_review_metrics" and patchsets_metrics as the keys and
    the related Metrics as the values.

    :param index: index object
    :param start: start date to get the data from
    :param end: end date to get the data upto
    :return: dictionary with the value of the metrics
    """
    results = {'bmi_metrics': [], 'time_to_close_metrics': [],
        'time_to_close_review_metrics': [], 'patchsets_metrics': []}
    return results


def identifyKeyValue(string):
    """
    identify key-end and value-start position
    from data start immediately with the key.

    the data should not have leading whitespace
    since whitespace will be read as seperator,
    then the key will be empty.

    @example
    identifyKeyValue('key=value') -> 3, 4
    identifyKeyValue('key = value') -> 3, 6
    """
    limit = len(string)
    keyEnd = 0
    valueStart = limit
    hasSep = False
    precedingBackslash = False
    while keyEnd < limit:
        c = string[keyEnd]
        if (c == '=' or c == ':') and not precedingBackslash:
            valueStart = keyEnd + 1
            hasSep = True
            break
        elif (c == ' ' or c == '\t' or c == '\x0c') and not precedingBackslash:
            valueStart = keyEnd + 1
            break
        if c == '\\':
            precedingBackslash = not precedingBackslash
        else:
            precedingBackslash = False
        keyEnd += 1
    while valueStart < limit:
        c = string[valueStart]
        if c != ' ' and c != '\t' and c != '\x0c':
            if not hasSep and (c == '=' or c == ':'):
                hasSep = True
            else:
                break
        valueStart += 1
    return keyEnd, valueStart


def LoWord(value):
    """Return the low word from a long"""
    return value & 65535


def _repeatlast(numfields, listin):
    """repeat last item in listin, until len(listin) = numfields"""
    if len(listin) < numfields:
        last = listin[-1]
        for n in range(len(listin), numfields):
            listin.append(last)
    return listin


def edit_mesh_extrude_move_normal():
    """Extrude region together along the average normal

    """
    pass


def hp_is_nest(hp_header):
    """Return True if the healpix header is in nested

    Parameters
    ----------
    hp_header : :class:`~astropy.io.fits.header.Header`
        the header

    Returns
    -------
    boolean :
        True if the header is nested
    """
    ordering = hp_header.get('ORDERING', None)
    if not ordering:
        raise ValueError('Np ordering in healpix header')
    if ordering.lower() in ['nested', 'nest']:
        return True
    elif ordering.lower() == 'ring':
        return False
    else:
        raise ValueError('Unknown ordering in healpix header')


@classmethod
def add_smart_proxy(cls, options=None):
    """Associate a smart proxy"""
    cls.command_sub = 'add-smart-proxy'
    return cls.execute(cls._construct_command(options))


def vector_add(vector1, vector2):
    """
    Adds one vector to another
    :param vector1: list(float, float, float)
    :param vector2: list(float, float, float)
    :return: list(float, float, float)
    """
    return [vector1[0] + vector2[0], vector1[1] + vector2[1], vector1[2] +
        vector2[2]]


def __getitem__(name):
    """Return the form field with the given name

        If the desired firld has a prefix, then the given name should
        be the prefix, a dot, and the unprefixed name.  Otherwise, the
        given name is just the field name.

        Raise a KeyError if a field can't be found for the given name.
        """


def set_subscription_attributes(SubscriptionArn=None, AttributeName=None,
    AttributeValue=None):
    """
    Allows a subscription owner to set an attribute of the topic to a new value.
    See also: AWS API Documentation

    :example: response = client.set_subscription_attributes(
        SubscriptionArn='string',
        AttributeName='string',
        AttributeValue='string'
    )

    :type SubscriptionArn: string
    :param SubscriptionArn: [REQUIRED]
            The ARN of the subscription to modify.

    :type AttributeName: string
    :param AttributeName: [REQUIRED]
            The name of the attribute you want to set. Only a subset of the subscriptions attributes are mutable.
            Valid values: DeliveryPolicy | RawMessageDelivery

    :type AttributeValue: string
    :param AttributeValue: The new value for the attribute in JSON format.

    """
    pass


def compute_meandiff_bias_correction(bootstraps, effsize):
    """
    Computes the bias correction required for the BCa method
    of confidence interval construction.

    Keywords
    --------
    bootstraps: array-like
        An numerical iterable, comprising bootstrap resamples
        of the effect size.

    effsize: numeric
        The effect size for the original sample.

    Returns
    -------
    bias: numeric
        The bias correction value for the given bootstraps
        and effect size.

    """
    from scipy.stats import norm
    from numpy import array
    B = array(bootstraps)
    prop_less_than_es = sum(B < effsize) / len(B)
    return norm.ppf(prop_less_than_es)


def archive_message(mlist, msg):
    """Send the message to the archiver.

        :param mlist: The IMailingList object.
        :param msg: The message object.
        :returns: The url string or None if the message's archive url cannot
            be calculated.
        """


def calculatePVMismatch(stdpl, cellsx, cellsy, Gpoat):
    """ calls PVMismatch with all the pre-generated values on bifacial_radiance

    Example:
    PowerAveraged, PowerDetailed = def calculatePVMismatch(stdpl, cellsx, cellsy, Gpoat)

    """
    import pvmismatch
    import numpy as np
    if np.mean(Gpoat) < 0.001:
        PowerAveraged = 0
        PowerDetailed = 0
    else:
        if cellsx * cellsy == 72:
            cell_pos = pvmismatch.pvmismatch_lib.pvmodule.STD72
        elif cellsx * cellsy == 96:
            cell_pos = pvmismatch.pvmismatch_lib.pvmodule.STD96
        else:
            print(
                'Error. Only 72 and 96 cells modules supported at the moment. Change numcells to either of this options!'
                )
            return
        pvmod = pvmismatch.pvmismatch_lib.pvmodule.PVmodule(cell_pos=cell_pos)
        pvsys = pvmismatch.pvsystem.PVsystem(numberStrs=1, numberMods=1,
            pvmods=pvmod)
        G = np.array([Gpoat]).transpose()
        H = np.ones([1, cellsx])
        array_det = np.dot(G, H)
        array_avg = np.ones([cellsy, cellsx]) * np.mean(Gpoat)
        pvsys.setSuns({(0): {(0): [array_avg, stdpl]}})
        PowerAveraged = pvsys.Pmp
        pvsys.setSuns({(0): {(0): [array_det, stdpl]}})
        PowerDetailed = pvsys.Pmp
    return PowerAveraged, PowerDetailed


@classmethod
def get_index_name(cls):
    """Return class name for a current config."""
    prefix = cls.ELASTIC_INDEX_PREFIX
    if cls.INDEX_PREFIX:
        prefix += cls.INDEX_PREFIX
    if cls.ENV == 'test':
        prefix += 'test_'
    return prefix + cls.__index_name__


@staticmethod
def get_opt(opt_name, args):
    """Return option name and value.

        :param opt_name: name of the option, e.g., "username"
        :param args: parsed arguments
        """
    return opt_name, getattr(args, 'os_%s' % opt_name, None)


@classmethod
def get_backend(cls):
    """
        Return name of currently active backend.
        if no backend has been loaded, loads and returns name of default backend.

        :raises passlib.exc.MissingBackendError:
            if no backends are available.

        :returns:
            name of active backend
        """
    if not cls.__backend:
        cls.set_backend()
        assert cls.__backend, 'set_backend() failed to load a default backend'
    return cls.__backend


def window_none(x):
    """
    No window function; simply return x.

    See Also
    --------
    window_hanning : Another window algorithm.
    """
    return x


def calc_multifactor(returns, factors):
    """Computes multiple ordinary least squares linear fits, and returns
    fit parameters.

    Parameters
    ----------
    returns : pd.Series
        Daily returns of the strategy, noncumulative.
         - See full explanation in tears.create_full_tear_sheet.
    factors : pd.Series
        Secondary sets to fit.

    Returns
    -------
    pd.DataFrame
        Fit parameters.

    """
    import statsmodels.api as sm
    factors = factors.loc[returns.index]
    factors = sm.add_constant(factors)
    factors = factors.dropna(axis=0)
    results = sm.OLS(returns[factors.index], factors).fit()
    return results.params


def parse_content_type(value: str) ->str:
    """
    Parse out the content type from a content type header.

    >>> parse_content_type('application/json; charset=utf8')
    'application/json'

    """
    if not value:
        return ''
    return value.split(';')[0].strip()


def inverse_mod(a, m):
    """Inverse of a mod m."""
    if a < 0 or m <= a:
        a = a % m
    c, d = a, m
    uc, vc, ud, vd = 1, 0, 0, 1
    while c != 0:
        q, c, d = divmod(d, c) + (c,)
        uc, vc, ud, vd = ud - q * uc, vd - q * vc, uc, vc
    assert d == 1
    if ud > 0:
        return ud
    else:
        return ud + m


def get(seq, ind, defVal=None):
    """Return seq[ind] if available, else defVal"""
    try:
        return seq[ind]
    except LookupError:
        return defVal


@classmethod
def join_segments(cls, segments, absolute=True):
    """Create a :class:`URLPath` from an iterable of segments."""
    if absolute:
        path = cls('/')
    else:
        path = cls('')
    for segment in segments:
        path = path.add_segment(segment)
    return path


def freestyle_lineset_remove():
    """Remove the active line set from the list of line sets

    """
    pass


def _process_docstring(app, what, name, obj, options, lines):
    """Process the docstring for a given python object.
  Called when autodoc has read and processed a docstring. `lines` is a list
  of docstring lines that `_process_docstring` modifies in place to change
  what Sphinx outputs.
  The following settings in conf.py control what styles of docstrings will
  be parsed:
  * ``napoleon_google_docstring`` -- parse Google style docstrings
  * ``napoleon_numpy_docstring`` -- parse NumPy style docstrings
  Parameters
  ----------
  app : sphinx.application.Sphinx
      Application object representing the Sphinx process.
  what : str
      A string specifying the type of the object to which the docstring
      belongs. Valid values: "module", "class", "exception", "function",
      "method", "attribute".
  name : str
      The fully qualified name of the object.
  obj : module, class, exception, function, method, or attribute
      The object to which the docstring belongs.
  options : sphinx.ext.autodoc.Options
      The options given to the directive: an object with attributes
      inherited_members, undoc_members, show_inheritance and noindex that
      are True if the flag option of same name was given to the auto
      directive.
  lines : list of str
      The lines of the docstring, see above.
      .. note:: `lines` is modified *in place*
  """
    if hasattr(obj, 'rationale') and obj.rationale:
        lines.append('**Rationale:**')
        for line in obj.rationale.split('\n'):
            lines.append(line)


def _make_divisible(v, divisor, min_value=None):
    """
    This function is taken from the original tf repo.
    It ensures that all layers have a channel number that is divisible by 8
    It can be seen here:
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    :param v:
    :param divisor:
    :param min_value:
    :return:
    """
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


def mad_quote(value):
    """Add quotes to a string value."""
    if '"' not in value:
        return '"' + value + '"'
    if "'" not in value:
        return "'" + value + "'"
    raise ValueError('MAD-X unable to parse string with escaped quotes: {!r}'
        .format(value))


def digit_str(item):
    """
        从第一个字符开始删除，直到所有字符都是数字为止，或者item长度 < 2
        eg:
            input:  ABuStrUtil.digit_str('sh000001')
            output: 000001

            input:  ABuStrUtil.digit_str('shszsh000001')
            output: 000001
    :param item: 字符串对象
    :return: 过滤head字母的字符串对象
    """
    while True:
        if item.isdigit():
            break
        if len(item) < 2:
            break
        item = item[1:]
    return item


def pipe_collapse_unity(p_e, p_c, gamma_m, gamma_SCLB, p_min=0
    ) ->'pipe_collapse_uty':
    """Calculate pipe collapse unity value.
    Local buckling – system collapse (external over pressure only).
    Reference:
    DNVGL-ST-F101 (2017-12)
        sec:5.4.4.1 eq:5.10 page:95 $p_{lt}$
    """
    pipe_collapse_uty = (p_e - p_min) * gamma_m * gamma_SCLB / p_c
    return pipe_collapse_uty


def change_node_properties(nodelist, kv_map, is_delete=False):
    """修改/增加 /删除 节点的属性及属性值
       nodelist: 节点列表
       kv_map:属性及属性值map"""
    for node in nodelist:
        for key in kv_map:
            if is_delete:
                if key in node.attrib:
                    del node.attrib[key]
            else:
                node.set(key, kv_map.get(key))


def is_lalinference_file(path):
    """Determine if the results file is a LALInference results file

    Parameters
    ----------
    path: str
        path to the results file
    """
    import h5py
    f = h5py.File(path, 'r')
    keys = list(f.keys())
    f.close()
    if 'lalinference' in keys:
        return True
    return False


def mean_std_polishing(A, nb_iterations=5):
    """
    Iterative z-score on rows and columns.

    Args:
        A (pandas.DataFrame or numpy.array): matrix
        nb_iterations (int): number of polishing iterations

    Returns:
        pandas.DataFrame or numpy.array: Polished matrix

    Examples:
        >>> import pandas as pd
        >>> import numpy as np
        >>> np.random.seed(0)
        >>> data = pd.DataFrame(np.random.randn(5, 5),
                            index=["c1", "c2", "c3", "c4", "c5"],
                            columns=["gene1", "gene2", "gene3", "gene4", "gene5"])
        >>> norm_data = mean_std_polishing(data)
        >>> norm_data
               gene1     gene2     gene3     gene4     gene5
        c1  0.336095 -1.618781  0.187436  1.109617 -0.014367
        c2 -0.321684  0.586608 -1.606905  0.484159  0.857821
        c3  0.139260  0.860934  0.976541 -1.395814 -0.580921
        c4  1.243263  0.421752 -0.585940  0.282319 -1.361394
        c5 -1.363323 -0.161066  0.826375 -0.421998  1.120013

    """
    epsilon = 1e-10
    for i in range(nb_iterations):
        A = A - A.mean(axis=0)
        A = A / (A.std(axis=0) + epsilon)
        A = (A.T - A.T.mean(axis=0)).T
        A = (A.T / (A.T.std(axis=0) + epsilon)).T
    return A


def nessus_smbscan_loopy(var1, reporthost, smb_obs, var2):
    """ Specific Nessus loop to find all SMB issues """
    for reportitem in reporthost.findall('ReportItem'):
        if int(reportitem.get('pluginID')) in smb_obs.keys():
            if var1 == 'addr':
                var2.append(reporthost.get('name') + ':' + reportitem.get(
                    'port'))
            elif var1 == 'obs':
                var2.append(smb_obs.get(int(reportitem.get('pluginID'))))


def bit2byte(in_bits):
    """
    Function for converting a bit stream into the corresponding byte stream.
    Original Author: Filippo Valmori
    """
    in_len = len(in_bits)
    out_len = in_len >> 3
    out_bytes = [0] * out_len
    for j in range(in_len):
        if in_bits[j]:
            byte_idx = j >> 3
            bit_idx = 7 - j % 8
            out_bytes[byte_idx] += 1 << bit_idx
    return out_bytes


def ad(df, high, low, close, volume, col):
    """
    Accumulation/distribution is a cumulative indicator that uses volume and price to assess whether a stock is being accumulated or distributed.
    The accumulation/distribution measure seeks to identify divergences between the stock price and volume flow.
    This provides insight into how strong a trend is. If the price is rising but the indicator is falling this
    indicates that buying or accumulation volume may not be enough to support the price rise and a price decline could be forthcoming.
    The CLV is based on the movement of the issue within a single bar and can be +1, -1 or zero.

    A/D=Previous A/D+Current Money Flow Value
    CMFV = ((Close - Low) - (high - close)//(high - Low)) * Volume

    Parameters:
        df (pd.DataFrame): DataFrame which contain the asset information.
        high (string): the column name for the period highest price  of the asset.
        low (string): the column name for the period lowest price of the asset.
        close (string): the column name for the closing price of the asset.
        volume (string): the column name for the volume of the asset.
        col (string): the column name for the ad values.

    Returns:
        df (pd.DataFrame): Dataframe with ad of the asset calculated.

    Sample Strategy:

    Bullish:

	AND [Daily SMA(60,Daily Volume) > 100000]
	AND [Daily SMA(60,Daily Close) > 10]

	AND [Daily Close < Daily SMA(65,Daily Close)]
	AND [Daily AccDist > Daily AccDist Signal (65)]
	AND [Daily OBV > Daily OBV Signal(65)]
	AND [Daily Close < Daily SMA(20,Daily Close)]
	AND [Daily AccDist > Daily AccDist Signal (20)]
	AND [Daily OBV > Daily OBV Signal(20)]

	Bearish:
	AND [Daily SMA(60,Daily Volume) > 100000]
	AND [Daily SMA(60,Daily Close) > 10]

	AND [Daily Close > Daily SMA(65,Daily Close)]
	AND [Daily AccDist < Daily AccDist Signal (65)]
	AND [Daily OBV < Daily OBV Signal(65)]
	AND [Daily Close > Daily SMA(20,Daily Close)]
	AND [Daily AccDist < Daily AccDist Signal (20)]
	AND [Daily OBV < Daily OBV Signal(20)]

	Citation: https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
    """
    money_flow_multiplier = (df[close] - df[low] - (df[high] - df[close])) / (
        df[high] - df[low])
    df[col + '_money_flow_volume'] = money_flow_multiplier * df[volume]
    prev_ad = df.loc[0, col + '_money_flow_volume']
    df.loc[0, col] = prev_ad
    ads = [0.0]
    for row in df.loc[1:, ([col + '_money_flow_volume'])].itertuples(index=
        False):
        ads.append(prev_ad + row[0])
        prev_ad = ads[-1]
    df = df.fillna(0)
    df[col] += ads
    df.drop([col + '_money_flow_volume'], axis=1, inplace=True)
    return df


@staticmethod
def _validate_date(date):
    """validate date has format of YYYY-MM-DD"""
    date_list = date.split('-')
    if len(date_list) == 3:
        if len(date_list[0]) == 4:
            if len(date_list[1]) == 2 and len(date_list[2]) == 2:
                return True
    raise Exception("format should be 'YYYY-MM-DD'")


def check_params(**kwargs):
    """check_params: check whether some parameters are missing
    """
    missing_params = []
    check = True
    for param in kwargs:
        if kwargs[param] is None:
            missing_params.append(param)
    if len(missing_params) > 0:
        print('POT - Warning: following necessary parameters are missing')
        for p in missing_params:
            print('\n', p)
        check = False
    return check


@staticmethod
def do_quit(connection, parameters):
    """
        Turn pdem-server off
        no parameters required
        """
    connection.manager.server.app.die()


def p_single_stat(p):
    """single_stat : entity_to_entity
                   | entity_to_outcome
                   | outcome_to_entity"""
    p[0] = p[1]


@staticmethod
def _e_ref_lafferty(model, e_min, e_max):
    """Helper for `to_sed_type`.

        Compute e_ref that the value at e_ref corresponds
        to the mean value between e_min and e_max.
        """
    flux = model.integral(e_min, e_max)
    dnde_mean = flux / (e_max - e_min)
    return model.inverse(dnde_mean)


def _merge_subexon_columns(subexons_df):
    """Create the SubexonID/SubexonIDCluster of the merged subexons."""
    merged_id = ''
    merged_protein = ''
    merged_dna = ''
    for index in range(1, subexons_df.shape[0]):
        rowi = subexons_df.iloc[(index - 1), :]
        rowj = subexons_df.iloc[(index), :]
        if not merged_id:
            merged_id = rowi['SubexonIDCluster'] + '_' + rowj[
                'SubexonIDCluster'].split('_')[-1]
        else:
            merged_id = merged_id + '_' + rowj['SubexonIDCluster'].split('_')[
                -1]
        if not merged_protein:
            merged_protein = rowi['SubexonProteinSequence'] + rowj[
                'SubexonProteinSequence']
        else:
            merged_protein = merged_protein + rowj['SubexonProteinSequence']
        if not merged_dna:
            merged_dna = rowi['SubexonSequence'] + rowj['SubexonSequence']
        else:
            merged_dna = merged_dna + rowj['SubexonSequence']
    return merged_id, merged_dna, merged_protein


def getInputDF(spark, inputPath, inputFormat):
    """
    Returns DataFrame from input configurations
    :param spark:
    :param inputPath:
    :param inputFormat:
    :return: DataFrame
    """
    df = spark.read.format(inputFormat).load(inputPath)
    return df


def bytes2human(num):
    """
    Convert a size into a human readable format.
    """
    symbols = 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
    prefix = {}
    nume = ''
    if num < 0:
        num = num * -1
        nume = '-'
    for pos, sym in enumerate(symbols):
        prefix[sym] = 1 << (pos + 1) * 10
    for sym in reversed(symbols):
        if num >= prefix[sym]:
            value = '%.2f' % float(float(num) / float(prefix[sym]))
            return '%s%s%s' % (nume, value, sym)
    return '%s%.2fB' % (nume, num)


@classmethod
def getImage(cls, node, frame=-1, growing=0, refresh=True):
    """parses the field and add it into the description list

        :param node: nexus field node
        :type node: :class:`pni.io.nx.h5.nxfield` or                     :class:`pni.io.nx.h5.nxgroup` or                     :class:`pni.io.nx.h5.nxlink` or                     :class:`pni.io.nx.h5.nxattribute` or                     :class:`pni.io.nx.h5.nxroot`
        :param frame: frame to take, the last one is -1
        :type frame: :obj:`int`
        :param growing: growing dimension
        :type growing: :obj:`int`
        :param refresh: refresh image node
        :type refresh: :obj:`bool`
        :returns: get the image
        :rtype: :class:`numpy.ndarray`
        """
    if refresh:
        node.refresh()
    if node:
        shape = node.shape
    if shape:
        if len(shape) == 2:
            return node[...]
        elif len(shape) == 3:
            if growing == 0:
                if frame < 0 or shape[0] > frame:
                    return node[(frame), :, :]
            elif growing == 1:
                if frame < 0 or shape[1] > frame:
                    return node[:, (frame), :]
            elif frame < 0 or shape[2] > frame:
                return node[:, :, (frame)]
        elif len(shape) == 4:
            if growing == 0:
                if frame < 0 or shape[0] > frame:
                    return node[(frame), :, :, :]
            elif growing == 1:
                if frame < 0 or shape[1] > frame:
                    return node[:, (frame), :, :]
            elif growing == 2:
                if frame < 0 or shape[2] > frame:
                    return node[:, :, (frame), :]
            elif frame < 0 or shape[3] > frame:
                return node[:, :, :, (frame)]


def device_types(*types):
    """Create a device type specifier.

    >>> device_types('ios', 'wns')
    ['ios', 'wns']
    >>> device_types('ios', 'symbian')
    Traceback (most recent call last):
        ...
    ValueError: Invalid device type 'symbian'

    """
    if len(types) == 1 and types[0] == 'all':
        return 'all'
    for t in types:
        if t not in ('ios', 'android', 'blackberry', 'wns', 'mpns'):
            raise ValueError("Invalid device type '%s'" % t)
    return [t for t in types]


def echange_position_essai(chemin, a, b, x, inversion, negligeable=1e-05,
    distance=None):
    """
    Echange la place des villes ka et kb pour les placer entre les villes *i* et *i+1*,
    si inversion est True, on inverse également le chemin inséré, si inversion est False,
    on ne l'inverse pas,
    si cela améliore, déplace les villes et retourne True, sinon, retourne False.
    """
    nb = len(chemin)
    xa = (x + 1) % nb
    ka = (a - 1 + nb) % nb
    kb = (b + 1) % nb
    if not inversion:
        if x == ka:
            return False
        if x == kb:
            return False
        if xa == ka:
            return False
        if b < a:
            if a <= x <= b + nb:
                return False
        elif a <= x <= b:
            return False
        if b < a:
            if a <= x + nb <= b + nb:
                return False
        elif a <= x + nb <= b:
            return False
        d_x_xa = distance(chemin[x], chemin[xa])
        d_ka_a = distance(chemin[ka], chemin[a])
        d_b_kb = distance(chemin[b], chemin[kb])
        d_ka_kb = distance(chemin[ka], chemin[kb])
        d_x_a = distance(chemin[x], chemin[a])
        d_b_xa = distance(chemin[b], chemin[xa])
        d = d_ka_kb + d_x_a + d_b_xa - d_x_xa - d_ka_a - d_b_kb
        if d >= -negligeable:
            return False
        ech = []
        bp = b
        if bp < a:
            bp = b + nb
        for i in range(a, bp + 1):
            ech.append(chemin[i % nb])
        diff = bp - a + 1
        xp = x
        if xp < b:
            xp += nb
        for l in range(b + 1, xp + 1):
            ll = l % nb
            bp = (a + l - b - 1) % nb
            chemin[bp] = chemin[ll]
        for l in range(0, len(ech)):
            chemin[(x + l - diff + 1 + nb) % nb] = ech[l]
        return True
    else:
        if x == ka:
            return False
        if x == kb:
            return False
        if xa == ka:
            return False
        if b < a:
            if a <= x <= b + nb:
                return False
        elif a <= x <= b:
            return False
        if b < a:
            if a <= x + nb <= b + nb:
                return False
        elif a <= x + nb <= b:
            return False
        d_x_xa = distance(chemin[x], chemin[xa])
        d_ka_a = distance(chemin[ka], chemin[a])
        d_b_kb = distance(chemin[b], chemin[kb])
        d_ka_kb = distance(chemin[ka], chemin[kb])
        d_x_b = distance(chemin[x], chemin[b])
        d_a_xa = distance(chemin[a], chemin[xa])
        d = d_ka_kb + d_x_b + d_a_xa - d_x_xa - d_ka_a - d_b_kb
        if d >= -negligeable:
            return False
        ech = []
        bp = b
        if bp < a:
            bp = b + nb
        for i in range(a, bp + 1):
            ech.append(chemin[i % nb])
        ech.reverse()
        diff = bp - a + 1
        xp = x
        if xp < b:
            xp += nb
        for l in range(b + 1, xp + 1):
            ll = l % nb
            bp = (a + l - b - 1) % nb
            chemin[bp] = chemin[ll]
        for l in range(0, len(ech)):
            chemin[(x + l - diff + 1 + nb) % nb] = ech[l]
        return True


@classmethod
def get_postmortem_debugger(cls, bits=None):
    """
        Returns the postmortem debugging settings from the Registry.

        @see: L{set_postmortem_debugger}

        @type  bits: int
        @param bits: Set to C{32} for the 32 bits debugger, or C{64} for the
            64 bits debugger. Set to {None} for the default (L{System.bits}.

        @rtype:  tuple( str, bool, int )
        @return: A tuple containing the command line string to the postmortem
            debugger, a boolean specifying if user interaction is allowed
            before attaching, and an integer specifying a user defined hotkey.
            Any member of the tuple may be C{None}.
            See L{set_postmortem_debugger} for more details.

        @raise WindowsError:
            Raises an exception on error.
        """
    if bits is None:
        bits = cls.bits
    elif bits not in (32, 64):
        raise NotImplementedError('Unknown architecture (%r bits)' % bits)
    if bits == 32 and cls.bits == 64:
        keyname = (
            'HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug'
            )
    else:
        keyname = (
            'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug')
    key = cls.registry[keyname]
    debugger = key.get('Debugger')
    auto = key.get('Auto')
    hotkey = key.get('UserDebuggerHotkey')
    if auto is not None:
        auto = bool(auto)
    return debugger, auto, hotkey


@classmethod
def send_error(cls, channel, status, msg, **extra):
    """Send a control packet with an error"""
    error = {'service': 'remote-file', 'type': 'error', 'status': status,
        'msg': msg}
    error.update(extra)
    channel.send_control(error)


def getoriginalfilecontent(file):
    """Get entire file contents in original/list format"""
    with open(file) as f:
        file_in_list_format = f.readlines()
    return file_in_list_format


def binary_column_as_bytes(db_column_data):
    """
        Turn *db_column_data* into a `bytes` object.

        Use this when the specific type must be known,
        for example to prefix or suffix additional byte values
        like that produced by `p64`.
        """


def modify_replication_subnet_group(ReplicationSubnetGroupIdentifier=None,
    ReplicationSubnetGroupDescription=None, SubnetIds=None):
    """
    Modifies the settings for the specified replication subnet group.
    See also: AWS API Documentation

    :example: response = client.modify_replication_subnet_group(
        ReplicationSubnetGroupIdentifier='string',
        ReplicationSubnetGroupDescription='string',
        SubnetIds=[
            'string',
        ]
    )

    :type ReplicationSubnetGroupIdentifier: string
    :param ReplicationSubnetGroupIdentifier: [REQUIRED]
            The name of the replication instance subnet group.

    :type ReplicationSubnetGroupDescription: string
    :param ReplicationSubnetGroupDescription: The description of the replication instance subnet group.

    :type SubnetIds: list
    :param SubnetIds: [REQUIRED]
            A list of subnet IDs.
            (string) --

    :rtype: dict
    :return: {
        'ReplicationSubnetGroup': {
            'ReplicationSubnetGroupIdentifier': 'string',
            'ReplicationSubnetGroupDescription': 'string',
            'VpcId': 'string',
            'SubnetGroupStatus': 'string',
            'Subnets': [
                {
                    'SubnetIdentifier': 'string',
                    'SubnetAvailabilityZone': {
                        'Name': 'string'
                    },
                    'SubnetStatus': 'string'
                },
            ]
        }
    }

    """
    pass


def parachute_opened(info):
    """
        Process 'crew member's parachute opened' event.

        Input:
        `info`  # An object with information about event's time, user's
                # callsign and aircraft, seat number and position on map.
        """


def _getitem_from_frame(f_locals, key, default=None):
    """
    f_locals is not guaranteed to have .get(), but it will always
    support __getitem__. Even if it doesn't, we return ``default``.
    """
    try:
        return f_locals[key]
    except Exception:
        return default


@classmethod
def vol_type(cls):
    """The type of volume supported by this type."""
    return 'fileio'


def mask(input_file, output_file, thresh=0.05):
    """Blackout static pixels in an ultrasound

  Examples

  sonocrop mask in.mp4 out.mp4 --thresh=0.05

  Args:
      input_file: Path to input video (must be mp4, mov, or avi)
      output_file: File path for video output
      thresh (float, optional): Defaults to 0.05
  """
    import numpy as np
    import cv2
    from pathlib import Path
    from sonocrop import vid
    import rich
    from rich.progress import Progress
    v, fps, f, height, width = vid.loadvideo(input_file)
    rich.print(f'Mask video: [underline]{input_file}[/underline]')
    rich.print(f'  Frames: {f}')
    rich.print(f'  FPS: {fps}')
    rich.print(f'  Width x height: {width} x {height}')
    rich.print(f'  Thresh: {thresh}')
    with Progress() as progress:
        task = progress.add_task('[green] Finding static video pixels...',
            total=height)
        u = np.zeros((height, width), np.uint8)
        for i in range(height):
            u[i] = np.apply_along_axis(vid.countUniquePixels, 0, v[:, (i), :])
            progress.update(task, advance=1)
    u_avg = u / f
    mask = u_avg > thresh
    y = vid.applyMask(v, mask)
    rich.print(f' Saving to file: "{output_file}"')
    vid.savevideo(output_file, y, fps)
    return 'Done'


@classmethod
def normalize(cls, name):
    """Return string in all lower case with spaces and question marks removed"""
    name = name.lower()
    for _replace in [' ', '-', '(', ')', '?']:
        name = name.replace(_replace, '')
    return name


def to_float_or_NA(value):
    """Convert to float unless the value is 'N/A', which is left unchanged."""
    if value == 'N/A':
        return 'N/A'
    else:
        return float(value)


def checkavailrawpc(context, am):
    """Returns a list of node objects representing available raw PCs at the
given aggregate."""
    avail = []
    ad = am.listresources(context)
    for node in ad.nodes:
        if node.exclusive and node.available:
            if 'raw-pc' in node.sliver_types:
                avail.append(node)
    return avail


def findValueTokens(name, query=None, maxDepth=None, filter=None,
    targetQuery=None, targetFilter=None, queryFactory=None,
    ignoreSearchIndex=False):
    """find token results for searchTerms.
        - name is the index name wanted for results.
        - if query is None (or evaluates to boolean False), returns the
          underlying btree data structure; which is an iterable result but
          can also be used with BTree operations
        Otherwise, same arguments as findRelationChains.
        """


def boolstr(value: bool) ->str:
    """Return a boolean formatted as string for ADO calls

    :param value: The value to format

    :returns: A string representation of the boolean value
    """
    return str(value).lower()


def PNT2Tidal_Tv10(XA):
    """ TaylorT2 0PN Quadrupolar Tidal Coefficient, v^10 Timing Term.
   XA = mass fraction of object """
    return 288 - 264 * XA


def mes_02pi(liste):
    """Calcule la mesure d'un angle en radians dans l'intervalle [0,2pi]."""
    num = liste[0] % (2 * liste[1])
    return [num, liste[1]]


def yes_or_no():
    """The user must answer with Y or N. Returns a bool"""
    answer = None
    while answer is None:
        answer = input().upper()
        if answer == 'Y':
            answer = True
        elif answer == 'N':
            answer = False
        else:
            answer = None
            print('Invalid input. Your answer must be Y or N')
    return answer


def combine_simulation_input(tree_list, p_dicts, rng_seeds=None):
    """Combine input for multiple simulations."""
    assert len(p_dicts) == len(tree_list
        ), 'Number of trees does not match the number of records with parameter values.'
    if rng_seeds is not None:
        assert len(p_dicts) <= len(rng_seeds), 'There must be at least ' + str(
            len(p_dicts)) + ' seed numbers.'
    assert len(p_dicts) > 0, 'No records to process!'
    rng_seeds = rng_seeds if rng_seeds else [None] * len(p_dicts)
    zipped = zip(tree_list, p_dicts, rng_seeds)
    return zipped


@classmethod
def extract_meta(cls, file_path):
    """
        Extract meta from file.
        """
    raise Exception(NotImplemented)


@staticmethod
def is_volume_manageable(source_vol):
    """Check if a volume with verbose description is valid for management.

        :param source_vol: the verbose volume dict
        :return: bool True/False
        """
    vol_head = source_vol['volumeHeader']
    if vol_head['capMB'] < 1026 or not vol_head['capGB'].is_integer():
        return False
    if vol_head['numSymDevMaskingViews'] > 0 or vol_head['mapped'
        ] is True or source_vol['maskingInfo']['masked'] is True:
        return False
    if vol_head['status'] != 'Ready' or vol_head['serviceState'
        ] != 'Normal' or vol_head['emulationType'] != 'FBA' or vol_head[
        'configuration'] != 'TDEV' or vol_head['system_resource'
        ] is True or vol_head['private'] is True or vol_head['encapsulated'
        ] is True or vol_head['reservationInfo']['reserved'] is True:
        return False
    for key, value in source_vol['rdfInfo'].items():
        if value is True:
            return False
    if source_vol['timeFinderInfo']['snapVXTgt'] is True:
        return False
    if vol_head['nameModifier'][0:3] == 'OS-':
        return False
    return True


@staticmethod
def convert_point_to_pixel(point, focal_length_in_pixels, principal_point):
    """
        This method is used for converting a point in [x, y, z, r, g, b] to a RGBD pixel
        :param point: A point of form [x, y, z, r, g, b]
        :param focal_length_in_pixels: Focal length of the camera measured in pixels
        :param principal_point: Center of the image
        :return: An RGBD pixel in shape [y, x, depth, r, g, b]
        """
    x_dist = point[0] / point[2] * focal_length_in_pixels
    y_dist = point[1] / point[2] * focal_length_in_pixels
    y_coord = principal_point[0] - y_dist
    x_coord = principal_point[1] + x_dist
    return [y_coord, x_coord] + point[2:]


def idx(*columns, **kwargs):
    """返回让 table 构建普通索引的信息"""
    name = kwargs.get('name', None)
    return {'type': 'index', 'columns': columns, 'name': name}


def dijkstra(start, end, graph):
    """
    this function takes in a weighted directed graph, a start node, an end node and outputs
    the shortest path from the start node to the end node on that graph
    input:  start - start node
            end - end node
            graph - weighted directed graph
    output: shortest path from start to end node
    """
    if start == end:
        return 0, [start]
    else:
        score = {}
        predecessor = {}
        unmarked_nodes = graph._nodes.copy()
        if start not in graph._nodes or end not in graph._nodes:
            raise SyntaxError(
                'either the start or end node is not in the graph!')
        for node in graph._nodes:
            if node != start:
                score[node] = float('inf')
            else:
                score[node] = 0
        current = start
        while current != end:
            if current in graph._edges:
                for neighbor in graph._edges[current]:
                    new_score = score[current] + graph._weights[current,
                        neighbor]
                    if score[neighbor] > new_score:
                        score[neighbor] = new_score
                        predecessor[neighbor] = current
            unmarked_nodes.remove(current)
            min_node = None
            score[min_node] = float('inf')
            for unmarked in unmarked_nodes:
                if score[unmarked] <= score[min_node]:
                    min_node = unmarked
            current = min_node
        shortest_path = [end]
        if score[end] != float('inf'):
            start_of_suffix = end
            while predecessor[start_of_suffix] != start:
                shortest_path.append(predecessor[start_of_suffix])
                start_of_suffix = predecessor[start_of_suffix]
            shortest_path.append(start)
            shortest_path.reverse()
        else:
            shortest_path = []
    return score[end], shortest_path


def fld_getter(fld):
    """Allows setting pd.DataFrame.get_id = fld_getter('id')"""
    return lambda df, val: df[df[fld] == val]


def as_bool(x):
    """Convert value (possibly a string) into a boolean.
    """
    if x is True or x is False:
        return x
    if isinstance(x, int):
        return bool(x)
    retval = None
    if isinstance(x, str):
        retval = {'yes': True, 'no': False, 'on': True, 'off': False, '1':
            True, '0': False, 'true': True, 'false': False}.get(x.lower(), None
            )
    if retval is None:
        raise ValueError('Cannot convert to bool: %s' % x)
    return retval


@staticmethod
def get_device(device_id):
    """! @brief Return the DAPAccess device with the give ID"""
    raise NotImplementedError()


@classmethod
def set_description(cls, what, description):
    """
        Sets a description for a paremeter.

        :param what: parameter to describe
        :param description: description
        :return:
        """
    cls.descriptions[what] = description


def rectCorner(x, y, width, height, anchor='sw', dims=False):
    """given rectangle controlled by x,y width and height return
    the corner corresponding to the anchor"""
    if anchor not in ('nw', 'w', 'sw'):
        if anchor in ('n', 'c', 's'):
            x += width / 2.0
        else:
            x += width
    if anchor not in ('sw', 's', 'se'):
        if anchor in ('w', 'c', 'e'):
            y += height / 2.0
        else:
            y += height
    return (x, y, width, height) if dims else (x, y)


@staticmethod
def shorten_caption(caption):
    """Loops through the caption and trims it at its latest sentence
        ending (., !, ? or ♪).

        Parameters
        ----------
        caption: str
            The caption to shorten/trim.

        Returns
        -------
        caption: str
            The shortened caption, ending at its latest sentence ending."""
    for i in range(len(caption) - 1, 0, -1):
        if caption[i] == '.' or caption[i] == '!' or caption[i] == '?':
            return caption[:i + 1]
        elif caption[i] == '♪':
            return caption[:i]
    return caption


def read_pprog(filename):
    """
    Read a Bruker pulse program (pulseprogram) file.

    Resultsing dictionary contains the following keys :

    ========    ===========================================================
    key         description
    ========    ===========================================================
    var         dictionary of variables assigned in pulseprogram
    incr        list of lists containing increment times
    loop        list of loop multipliers
    phase       list of lists containing phase elements
    ph_extra    list of lists containing comments at the end of phase lines
    ========    ===========================================================

    The incr,phase and ph_extra lists match up with loop list.  For example
    incr[0],phase[0] and ph_extra[0] are all increment and phase commands
    with comments which occur during loop 0 which has loop[0] steps.

    Parameters
    ----------
    filename : str
        Filename of pulseprogram file to read from,

    Returns
    -------
    dic : dict
        A dictionary with keys described above.

    See Also
    --------
    write_pprog : Write a Bruker pulse program to file.

    """
    f = open(filename, 'r')
    var = dict()
    loop = []
    incr = [[]]
    phase = [[]]
    ph_extra = [[]]
    for line in f:
        if ';' in line:
            comment = line[line.index(';'):]
            text = line[:line.index(';')].strip()
        else:
            comment = ''
            text = line.strip()
        if len(text.split()) != 0:
            s = text.split()[0]
            if s.isdigit() or s[-1] == ',':
                text = text[len(s):].strip()
        if text == '' or text[0] == '#':
            continue
        if '"' in text:
            if '=' in line:
                text = text.strip('"')
                t = text.split('=')
                if len(t) >= 2:
                    key, value = t[0], t[1]
                    var[key] = value
                else:
                    pass
                continue
            else:
                continue
        if text[0:2] == 'lo':
            loop.append(text.split()[4])
            incr.append([])
            phase.append([])
            ph_extra.append([])
            continue
        tokens = text.split()
        if len(tokens) >= 2:
            token2 = tokens[1]
            if token2.startswith('id') or token2.startswith('dd'):
                incr[len(loop)].append(int(token2[2:]))
                continue
            if token2.startswith('ipu') or token2.startswith('dpu'):
                incr[len(loop)].append(int(token2[3:]))
                continue
            if token2.startswith('ip') or token2.startswith('dp'):
                phase[len(loop)].append(int(token2[2:]))
                last = text.find(' ', text.index('ip'))
                if last == -1:
                    ph_extra[len(loop)].append('')
                else:
                    ph_extra[len(loop)].append(text[last:].strip())
                continue
    f.close()
    incr.pop()
    phase.pop()
    ph_extra.pop()
    for i, t in enumerate(loop):
        if t.isdigit():
            loop[i] = int(t)
        elif t in var and var[t].isdigit():
            loop[i] = int(var[t])
    dic = {'var': var, 'incr': incr, 'loop': loop, 'phase': phase,
        'ph_extra': ph_extra}
    return dic


def box_encode(samples=None, matches=None, anchors=None, refs=None, means=
    None, stds=None, name=None, attr=None, out=None, **kwargs):
    """Encode bounding boxes training target with normalized center offsets.
        Input bounding boxes are using corner type: `x_{min}, y_{min}, x_{max}, y_{max}`.) array

    Defined in src/operator/contrib/bounding_box.cc:L210

    Parameters
    ----------
    samples : Symbol
        (B, N) value +1 (positive), -1 (negative), 0 (ignore)
    matches : Symbol
        (B, N) value range [0, M)
    anchors : Symbol
        (B, N, 4) encoded in corner
    refs : Symbol
        (B, M, 4) encoded in corner
    means : Symbol
        (4,) Mean value to be subtracted from encoded values
    stds : Symbol
        (4,) Std value to be divided from encoded values

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

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


def gps_create_topic():
    """
    This creates a Google Pub/Sub topic.

    TODO: finish this

    """


def type_coerce(type_, value, fallback):
    """Return type_(value), on ValueError return fallback."""
    try:
        return type_(value)
    except ValueError:
        return fallback


def cli_reporter(report):
    """Simple output for report dict

    input: {'view-name' [(platform, px_difference)]}

    output: str

    e.g

    >>> reporter(diffbrowsers.report)

    Regression Report:
    Fonts: [fonts]

    View: Glyphs-All
    WARNING: Desktop_Windows_7_chrome_50.0 is different by 100px,
    WARNING: Desktop_OS_X_Yosemite_safari_8.0 is different by 80px

    View: Waterfall
    PASSED: Desktop_Windows_7_chrome_50.0 is different is the same
    PASSED: Desktop_OS_X_Yosemite_safari_8.0 is different is the same

    TODO (M Foley) this needs more work
    """
    doc = []
    doc.append('Regression Report:\n\n')
    doc.append('Fonts: ["{}"]\n'.format('", "'.join(report['fonts'])))
    for view in report['views']:
        doc.append('\nView: {}\n'.format(view))
        for platform, px_diff in report['views'][view]:
            if px_diff != 0:
                doc.append('WARNING: {} is different by {} pixels\n'.format
                    (platform, px_diff))
            else:
                doc.append('PASSED: {} is the same\n'.format(platform))
    return ''.join(doc)


def bool_formatter(bool_value):
    """
    convert Python boolean to json/xml format of boolean

    Parameters
    ----------
    bool_value: bool
        the boolean value that needs to be converted

    Returns
    -------
    str
        either "true" or "false"

    """
    if isinstance(bool_value, bool):
        if bool_value:
            return 'true'
        else:
            return 'false'
    else:
        msg = 'bool_value must be a boolean'
        raise ValueError(msg)


def describe_alias(AliasId=None):
    """
    Retrieves properties for a fleet alias. This operation returns all alias metadata and settings. To get just the fleet ID an alias is currently pointing to, use  ResolveAlias .
    To get alias properties, specify the alias ID. If successful, an  Alias object is returned.
    See also: AWS API Documentation

    :example: response = client.describe_alias(
        AliasId='string'
    )

    :type AliasId: string
    :param AliasId: [REQUIRED]
            Unique identifier for a fleet alias. Specify the alias you want to retrieve.

    :rtype: dict
    :return: {
        'Alias': {
            'AliasId': 'string',
            'Name': 'string',
            'AliasArn': 'string',
            'Description': 'string',
            'RoutingStrategy': {
                'Type': 'SIMPLE'|'TERMINAL',
                'FleetId': 'string',
                'Message': 'string'
            },
            'CreationTime': datetime(2015, 1, 1),
            'LastUpdatedTime': datetime(2015, 1, 1)
        }
    }

    """
    pass


def word(l, h):
    """
	Given a low and high bit, converts the number back into a word.
	"""
    return (h << 8) + l


def sortWiresByBuildOrder(wireList, plane, result=[]):
    """Tries to determine how wires should be combined into faces.

    Assume:
        The wires make up one or more faces, which could have 'holes'
        Outer wires are listed ahead of inner wires
        there are no wires inside wires inside wires
        ( IE, islands -- we can deal with that later on )
        none of the wires are construction wires

    Compute:
        one or more sets of wires, with the outer wire listed first, and inner
        ones

    Returns, list of lists.
    """
    result = []
    remainingWires = list(wireList)
    while remainingWires:
        outerWire = remainingWires.pop(0)
        group = [outerWire]
        otherWires = list(remainingWires)
        for w in otherWires:
            if plane.isWireInside(outerWire, w):
                group.append(w)
                remainingWires.remove(w)
        result.append(group)
    return result


def spin(steps: int=9, dupli: bool=False, angle: float=1.5708,
    use_auto_merge: bool=True, use_normal_flip: bool=False, center: float=(
    0.0, 0.0, 0.0), axis: float=(0.0, 0.0, 0.0)):
    """Extrude selected vertices in a circle around the cursor in indicated viewport

    :param steps: Steps, Steps
    :type steps: int
    :param dupli: Use Duplicates
    :type dupli: bool
    :param angle: Angle, Rotation for each step
    :type angle: float
    :param use_auto_merge: Auto Merge, Merge first/last when the angle is a full revolution
    :type use_auto_merge: bool
    :param use_normal_flip: Flip Normals
    :type use_normal_flip: bool
    :param center: Center, Center in global view space
    :type center: float
    :param axis: Axis, Axis in global view space
    :type axis: float
    """
    pass


def char_decoding(value):
    """ Decode from 'UTF-8' string to unicode.

    :param value:
    :return:
    """
    if isinstance(value, bytes):
        return value.decode('utf-8')
    return value


def dictset(dct, key, val):
    """Provides `setattr` semantics for modifying dictionaries."""
    dct[key] = val


def impersonate_other_page(page, other):
    """Modify the title and tree location data of `page` to resemble `other`"""
    page.path = other.path
    page.depth = other.depth
    page.url_path = other.url_path
    page.title = other.title


def get_following(item_type, user_id=None):
    """List all <item_type> that <user_id> subscribes to"""


def check_absence_of_monotonous_long_motion(counterpoint_continuation:
    'LineElement', current_motion_start_element: 'LineElement',
    max_distance_in_semitones: int=9, **kwargs) ->bool:
    """
    Check that line does not move too far without any changes in direction.

    :param counterpoint_continuation:
        current continuation of counterpoint line
    :param current_motion_start_element:
        element of counterpoint line such that there are no
        changes in direction after it
    :param max_distance_in_semitones:
        maximum allowed distance (in semitones)
    :return:
        indicator whether a continuation is in accordance with the rule
    """
    current = counterpoint_continuation.scale_element.position_in_semitones
    start = current_motion_start_element.scale_element.position_in_semitones
    if abs(current - start) > max_distance_in_semitones:
        return False
    return True


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

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


@classmethod
def METHODS(cls):
    """ Methods of this class. """
    return cls._METHODS[:]


@staticmethod
def from_json(json_response):
    """Return a submission object from the json response."""
    submission = json_response[0]['data']['children'][0]
    submission.comments = json_response[1]['data']['children']
    return submission


def list_contain_string_subset(ls: list, string: str) ->list:
    """列表中的某一个值是属于字符串的子集

    例子： ls=['a','b','c'],string='eat'
          那么ls中的a属于string中的子集

    >>> print(list_contain_string_subset(['a', 'b', 'c'], 'eat'))

    :param string: 字符串
    :param ls: 字符串列表
    :return: 返回字符串的子集
    """
    pass


def determine_convex_hull(formation_en_grid):
    """
    Wraps the scipy.spatial ConvexHull algo for our purposes.
    For now only for 2D phase diagrams
    Adds the points [1.0, 0.0] and [0.0, 1.0], because in material science these
    are always there.

    :params: formation_en_grid: list of points in phase space [[x, formation_energy]]
    :returns: a hul datatype
    """
    import numpy as np
    from scipy.spatial import ConvexHull
    if [1.0, 0.0] not in formation_en_grid:
        formation_en_grid.append([1.0, 0.0])
    if [0.0, 0.0] not in formation_en_grid:
        formation_en_grid.append([0.0, 0.0])
    points = np.array(formation_en_grid)
    hull = ConvexHull(points)
    return hull


@classmethod
def from_data(cls, nodes):
    """Create an instance from a bunch of nodes.

    Parameters
    ----------
    nodes: list
      A sequence of nodes, each item is (node_name, depends).

    Returns
    -------
    instance: TopologicalGraph
      Instance constructed from input argument.

    """
    instance = cls()
    for node_name, depends in nodes:
        instance.add(node_name, depends)
    return instance


def box(text: str, lang: str='') ->str:
    """Get the given text in a code block.

    Parameters
    ----------
    text : str
        The text to be marked up.
    lang : `str`, optional
        The syntax highlighting language for the codeblock.

    Returns
    -------
    str
        The marked up text.

    """
    ret = '```{}\n{}\n```'.format(lang, text)
    return ret


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

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

        By default this just returns the cls.

        .. versionadded:: 1.0.3

        """
    return cls


def __call__(view, info):
    """
        Derive a new view from the supplied view.

        View options, package information and registry are available on
        ``info``, an instance of :class:`pyramid.interfaces.IViewDeriverInfo`.

        The ``view`` is a callable accepting ``(context, request)``.

        """


def convert_assets_items_to_dict(assets, attributes=''):
    """
  Convert an assets list to proper dict
  """
    b = []
    if not assets:
        return b
    for a in assets:
        if a:
            b.append({'url': a, 'attributes': attributes} if not isinstance
                (a, (dict,)) else a)
    return b


def load_h5py(finder, module):
    """h5py module has a number of implicit imports"""
    finder.IncludeModule('h5py.defs')
    finder.IncludeModule('h5py.utils')
    finder.IncludeModule('h5py._proxy')
    finder.IncludeModule('h5py.api_gen')


def meets_after(epsilon=0):
    """Returns a function that computes whether a temporal interval ends at the
    same time as another interval starts (+/- epsilon).
    This is the inverse of the ``meets_before`` predicate; it checks whether
    the first interval starts when the second interval ends.

    The output function expects two temporal intervals (dicts with keys 't1'
    and 't2' for the start and end times, respectively). It returns ``True`` if
    the absolute time difference between the start of the first interval and
    the end of the second interval is less than ``epsilon``.

    Args:
        epsilon: The maximum time difference between the start of the first
            interval and the end of the second interval.

    Returns:
        An output function that takes two temporal intervals and returns
        ``True`` if the first interval starts at the same time as the second
        interval ends.
    """
    return lambda intrvl1, intrvl2: abs(intrvl2['t2'] - intrvl1['t1']
        ) <= epsilon


def text_encode(source):
    """encode ``source`` using the default codepoint"""
    return source.encode(errors='ignore')


def update(object_id, data):
    """
        Update an object and return the updated object data. May return a
        deferred.

        ``object_id`` may not be ``None``.

        Should raise :class:`CollectionObjectNotFound`` if ``object_id`` refers
        to an object that doesn't exist.
        """


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


def julian2num(j):
    """
    Convert a matplotlib date to a Julian days.

    Parameters
    ----------
    j : numpy.ndarray : int32
        Julian days.

    Returns
    -------
    num : numpy.ndarray : int32
        Number of days since 0001-01-01 00:00:00 UTC *plus* *one*.
    """
    return j - 1721424.5


def export_3dpdf(client, file_=None, filename=None, dirname=None, height=
    None, width=None, dpi=None, use_drawing_settings=None):
    """Export a model to a 3D PDF file.

    Args:
        client (obj):
            creopyson Client.
        `file_` (str, optional):
            Model name. Defaults is current active model.
        filename (str, optional):
            Destination file name. May also contain a path to the file.
            Defaults is the model name with the appropriate file extension,
            in Creo's working directory.
        dirname (str, optional):
            Destination directory. Defaults is Creo's current
            working directory.
        height (float, optional):
            PDF image height. Defaults is Creo default export height.
        width (float, optional):
            PDF image width. Defaults is Creo default export width.
        dpi (int, optional):
            PDF Image DPI. Default is Creo default export DPI.
        use_drawing_settings (boolean, optional):
            Whether to use special settings for exporting drawings.
            Defaut is False.

    Returns:
        dict:
            dirname (str): Directory of the output file
            filename (str): Name of the output file

    """
    data = {}
    if file_ is not None:
        data['file'] = file_
    else:
        active_file = client.file_get_active()
        if active_file is not None:
            data['file'] = active_file['file']
    if filename:
        data['filename'] = filename
    if dirname:
        data['dirname'] = dirname
    if height:
        data['height'] = height
    if width:
        data['width'] = width
    if dpi:
        data['dpi'] = dpi
    if use_drawing_settings:
        data['use_drawing_settings'] = use_drawing_settings
    return client._creoson_post('interface', 'export_3dpdf', data)


def focus_window(window):
    """Focus the given window.

    :param window: the window to focus
    :type window: wmctrl.Window

    """
    window.focus()


def is_reduced(obj):
    """A simple predicate to test whether an object has a reduced structure.

     If `obj` does not have a `reducing_end` attribute, this will return :const:`False`

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

    Returns
    -------
    bool
    """
    try:
        return obj.reducing_end is not None
    except AttributeError:
        return False


@staticmethod
def next_colour(pix):
    """Move each colour along."""
    red = pix[0]
    green = pix[1]
    blue = pix[2]
    if red == 255 and green < 255 and blue == 0:
        green += 1
    if green == 255 and red > 0 and blue == 0:
        red -= 1
    if green == 255 and blue < 255 and red == 0:
        blue += 1
    if blue == 255 and green > 0 and red == 0:
        green -= 1
    if blue == 255 and red < 255 and green == 0:
        red += 1
    if red == 255 and blue > 0 and green == 0:
        blue -= 1
    pix[0] = red
    pix[1] = green
    pix[2] = blue


def load_call_dict(call_dict, lib):
    """Loads argument/return types from the call dictionary

    @param call_dict: call dictionary. Keyed by function name;
                      values are [return type, argtype0, argtype 1...]
    @type call_dict: dict
    @param lib: library where functions specified in L{call_dict} live.
    @type lib: ctypes.WinDLL or ctypes.CDLL
    """
    for funcname in call_dict:
        func = getattr(lib, funcname)
        args = call_dict[funcname]
        func.restype = args[0]
        if len(args) <= 1:
            func.argtypes = None
        else:
            func.argtypes = args[1:]


def map_bool(to_bool) ->bool:
    """Maps value to boolean from a string.

    Parameters
    ----------
    to_bool: str
        Value to be converted to boolean.

    Returns
    -------
    mapped_bool: bool
        Boolean value converted from string.

    Example
    -------
    >>> boolean_string = "True" # can also be lower case

    >>> boolean_value = map_bool(boolean_string)
    """
    try:
        boolean_map = {'true': True, 'false': False}
        mapped_bool = boolean_map[to_bool.lower()]
    except KeyError:
        raise KeyError("Boolean Value Expected got '{}'".format(to_bool))
    return mapped_bool


def _convert_axis_scale(axis_scale):
    """Convert the given axis scale (e.g. "log") to one that can be used by Matplotlib.

    References:
        - https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.set_xscale.html
        - https://matplotlib.org/api/_as_gen/matplotlib.axes.Axes.set_yscale.html
        - https://matplotlib.org/gallery/lines_bars_and_markers/categorical_variables.html
    """
    possible_axis_scale = ['lin', 'linear', 'log', 'logarithmic', 'cat',
        'categorical']
    if axis_scale is None:
        returned_axis_scale = 'linear'
    elif axis_scale == 'linear' or axis_scale == 'lin':
        returned_axis_scale = 'linear'
    elif axis_scale == 'logarithmic' or axis_scale == 'log':
        returned_axis_scale = 'log'
    elif axis_scale == 'categorical' or axis_scale == 'cat':
        returned_axis_scale = 'linear'
    else:
        raise ValueError(
            'Invalid value for axis scale: "{}". Possible values: {}'.
            format(axis_scale, possible_axis_scale))
    return returned_axis_scale


@staticmethod
def close():
    """Close the connection now (rather than whenever .
        __del__() is called). """
    pass


@classmethod
def http(klass, url, interval, timeout=None, deregister=None, header=None):
    """
        Peform a HTTP GET against *url* every *interval* (e.g. "10s") to peform
        health check with an optional *timeout* and optional *deregister* after
        which a failing service will be automatically deregistered. Optional
        parameter *header* specifies headers sent in HTTP request. *header*
        paramater is in form of map of lists of strings,
        e.g. {"x-foo": ["bar", "baz"]}.
        """
    ret = {'http': url, 'interval': interval}
    if timeout:
        ret['timeout'] = timeout
    if deregister:
        ret['DeregisterCriticalServiceAfter'] = deregister
    if header:
        ret['header'] = header
    return ret


def norm_array(Array, Minval=0.001):
    """Normalise array by largest abs value if >Minval (avoids trying to renormalise zero array)"""
    greatest = 0.0
    flatarray = Array.flat
    for i in range(len(flatarray)):
        if abs(flatarray[i]) > abs(greatest):
            greatest = flatarray[i]
    if abs(greatest) > Minval:
        newarray = Array / greatest
    else:
        newarray = Array
    return newarray


def addMail(message_string):
    """
           Parses a mail message into a string and stores it in the archive
           as an IMailMessage.  Returns the resulting mail message object.
        """


def gate_width(axes, gate_str, plot_params):
    """
    Calculate the width of a gate based on its string representation.

    Args:
        axes (matplotlib.axes.Axes): axes object
        gate_str (str): string representation of a gate
        plot_params (dict): plot parameters

    Returns:
        The width of a gate on the figure (in inches)
    """
    if gate_str == 'X':
        return 2 * plot_params['not_radius'] / plot_params['units_per_inch']
    if gate_str == 'Swap':
        return 2 * plot_params['swap_delta'] / plot_params['units_per_inch']
    if gate_str == 'Measure':
        return plot_params['mgate_width']
    obj = axes.text(0, 0, gate_str, visible=True, bbox=dict(edgecolor='k',
        facecolor='w', fill=True, lw=1.0), fontsize=14)
    obj.figure.canvas.draw()
    width = obj.get_window_extent(obj.figure.canvas.get_renderer()
        ).width / axes.figure.dpi
    obj.remove()
    return width + 2 * plot_params['gate_offset']


def mk(obj, config):
    """Not yet implemented."""
    pass


def lambd_NH3_Li_CB89(T, P):
    """n-c: ammonia lithium [CB89]."""
    lambd = -0.038
    valid = T == 298.15
    return lambd, valid


@classmethod
def supported(cls, conn):
    """Return whether host based authentication is supported"""
    return conn.host_based_auth_supported()


def create_coordinate_clusters(coordinates, cluster_labels):
    """
    Create cluster arrays of the input coordinate data from cluster labels.
    """
    clusters = []
    last_label, cluster = None, None
    for idx, label in enumerate(cluster_labels):
        is_new_cluster = label != -1 and last_label != label
        if is_new_cluster:
            if cluster:
                clusters.append(cluster)
            cluster = []
            last_label = label
        if label != -1:
            cluster.append(coordinates[idx])
    return clusters


def chunks(iterable, chunk_size):
    """Generate sequences of `chunk_size` elements from `iterable`."""
    iterable = iter(iterable)
    while True:
        chunk = [None] * chunk_size
        count = 0
        try:
            for _ in range(chunk_size):
                chunk[count] = next(iterable)
                count += 1
            yield chunk[:count]
        except StopIteration:
            if count:
                yield chunk[:count]
            break


def duration_seconds_to_string(seconds):
    """ Converts a total amount of seconds into a
        string representation of duration.

        >>>  duration_seconds_to_string(196)
        '00:03:16'
    """
    m, s = divmod(seconds, 60)
    h, m = divmod(m, 60)
    return f'{h}:{m:02}:{s:02}'


def dotDotRange(dotDotString):
    """
    A method for generating integers.
    For example:

> for i in util.dotDotRange("1..4,100,-1..1"): print i
1
2
3
4
100
-1
0
1

    """
    for intervalString in dotDotString.split(','):
        parts = intervalString.split('..')
        if len(parts) > 2:
            raise Exception("Expect at most one '..' between commas. (see {0})"
                .format(intervalString))
        start = int(parts[0])
        if len(parts) == 1:
            yield start
        else:
            lastInclusive = int(parts[1])
            for i in range(start, lastInclusive + 1):
                yield i


def duration(duration_ms: float) ->str:
    """
    Formats duration into a string logged in stats

    :param duration_ms: Duration in milliseconds
    :return: formatted duration
    """
    return '{:.2f}ms'.format(duration_ms)


def match(encoded_password):
    """Was the given data was encoded with this manager's scheme?

        Return True when the given data was encoded with the scheme
        implemented by this password manager.
        """


def getBest(arr, getterFunc, takeMax):
    """
        Will return a tuple of the
            index and the value of the best
            as extracted by getterFunc
    """
    theBest = None
    theBestOriginalVal = None
    for originalVal in arr:
        val = getterFunc(originalVal)
        if theBest is None:
            theBest = val
            theBestOriginalVal = originalVal
        isBetter = False
        if takeMax:
            if val > theBest:
                isBetter = True
        elif val < theBest:
            isBetter = True
        if isBetter:
            theBestOriginalVal = originalVal
            theBest = val
    return theBestOriginalVal, theBest


def get(isamAppliance, uuid, check_mode=False, force=False):
    """
    Retrieving a single static route
    """
    return isamAppliance.invoke_get('Retrieving a single static route',
        '/net/routes/{0}'.format(uuid))


def print_error(input, err, scanner):
    """This is a really dumb long function to print error messages nicely."""
    p = err.pos
    line = '\n'.count(input[:p])
    print(err.msg + ' on line ' + repr(line + 1) + ':')
    text = input[max(p - 80, 0):p + 80]
    p = p - max(p - 80, 0)
    i = text[:p].rfind('\n')
    j = text[:p].rfind('\r')
    if i < 0 or 0 <= j < i:
        i = j
    if 0 <= i < p:
        p = p - i - 1
        text = text[i + 1:]
    i = text.find('\n', p)
    j = text.find('\r', p)
    if i < 0 or 0 <= j < i:
        i = j
    if i >= 0:
        text = text[:i]
    while len(text) > 70 and p > 60:
        text = '...' + text[10:]
        p = p - 7
    print('> ', text)
    print('> ', ' ' * p + '^')
    print('List of nearby tokens:', scanner)


def flipud(arr):
    """Flip an image-like array vertically.

    **Supported dtypes**:

        * ``uint8``: yes; fully tested
        * ``uint16``: yes; fully tested
        * ``uint32``: yes; fully tested
        * ``uint64``: yes; fully tested
        * ``int8``: yes; fully tested
        * ``int16``: yes; fully tested
        * ``int32``: yes; fully tested
        * ``int64``: yes; fully tested
        * ``float16``: yes; fully tested
        * ``float32``: yes; fully tested
        * ``float64``: yes; fully tested
        * ``float128``: yes; fully tested
        * ``bool``: yes; fully tested

    Parameters
    ----------
    arr : ndarray
        A 2D/3D `(H, W, [C])` image array.

    Returns
    -------
    ndarray
        Vertically flipped array.

    Examples
    --------
    >>> import numpy as np
    >>> import imgaug.augmenters.flip as flip
    >>> arr = np.arange(16).reshape((4, 4))
    >>> arr_flipped = flip.flipud(arr)

    Create a ``4x4`` array and flip it vertically.

    """
    return arr[::-1, (...)]


def delete(name, context):
    """Delete the named template and any cached contents.

        :param name: The template name, including any extension.
        :type name: str
        :param context: The context for this name->URI mapping.  This can be a
            List-ID, domain mail host name, or None (for global context).
        :type context: str
        """


def copy():
    """Obtain a copy of this manifest instance.

        Returns an object conforming to the ``imanifestrevisionwritable``
        interface. The instance will be associated with the same
        ``imanifestlog`` collection as this instance.
        """


@staticmethod
def reg_score_function(X, y, mean, scale, shape, skewness):
    """ GAS Poisson Regression Update term using gradient only - native Python function

        Parameters
        ----------
        X : float
            datapoint for the right hand side variable

        y : float
            datapoint for the time series

        mean : float
            location parameter for the Poisson distribution

        scale : float
            scale parameter for the Poisson distribution

        shape : float
            tail thickness parameter for the Poisson distribution

        skewness : float
            skewness parameter for the Poisson distribution

        Returns
        ----------
        - Score of the Poisson family
        """
    return X * (y - mean)


def tupletodict(top, left, height, width):
    """
    Converts the parameters passed in to dictionary
    :param top: int
    :param left: int
    :param height: int
    :param width: int
    :return: dict
    """
    return {'top': top, 'left': left, 'width': width, 'height': height}


def get_repo_path(template):
    """Given a git SSH path (e.g git@github.com:owner/repo.git), return the repo path

    The repo path is in the form of "owner/repo"
    """
    return template[:-4].split(':')[1]


def insert_benchmark(data, conn):
    """
    Insert benchmark data on database

    :param data: a tuple with the benchmark data with format:

    ID: integer incremental primary key
    Date: Date/hour of benchmark execution
    Dataset: Identify on which dataset the dataset was performed
    Tag: a user defined word that indentify a benchmark set
    Type: forecasting type (point, interval, distribution)
    Model: FTS model
    Transformation: The name of data transformation, if one was used
    Order: the order of the FTS method
    Scheme: UoD partitioning scheme
    Partitions: Number of partitions
    Size: Number of rules of the FTS model
    Steps: prediction horizon, i. e., the number of steps ahead
    Measure: accuracy measure
    Value: the measure value

    :param conn: a sqlite3 database connection
    :return:
    """
    c = conn.cursor()
    c.execute('INSERT INTO benchmarks(Date, Dataset, Tag, Type, Model, ' +
        "Transformation, 'Order', Scheme, Partitions, " +
        'Size, Steps, Method, Measure, Value) ' +
        "VALUES(datetime('now'),?,?,?,?,?,?,?,?,?,?,?,?,?)", data)
    conn.commit()


def get_vpcid(vpc: dict):
    """
    Gets the ID from a VPC dict.

    :param vpc: A dict containing information about a VPC. Usually the output of get_vpc().
    :return: The ID of the vpc
    """
    return vpc.get('VpcId')


def print_weather_details(data):
    """
    print weather details
    """
    print('Location:', data['location'], end='\n\n')
    for row in data['weather']:
        print('Date:', row['date'])
        print('Weather Type:', row['weather_state_name'])
        print('Min Temp.:', row['min_temp'])
        print('Max Temp.:', row['max_temp'])
        print()


def compute_sign(permutation):
    """Compute sign by sorting."""
    sign = 1
    n = len(permutation)
    p = [p for p in permutation]
    for i in range(n - 1):
        for j in range(n - 1):
            if p[j] > p[j + 1]:
                p[j], p[j + 1] = p[j + 1], p[j]
                sign = -sign
            elif p[j] == p[j + 1]:
                return 0
    return sign


def force_fmg(mass, gravitational_field_strength):
    """Usage: Find force of gravity using mass and a gravitational constant """
    return mass * gravitational_field_strength


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


def psi_Li_Na_ClO4_PK74(T, P):
    """c-c'-a: lithium sodium perchlorate [PK74]."""
    psi = -0.008
    valid = T == 298.15
    return psi, valid


def get_parser(subparsers):
    """Configures the subparser for the ``collect`` command.

    :param argparse.ArgumentParser subparser: subparser for commands.

    Returns :class:`argparse.ArgumentParser` confured for the ``collect`` command.
    """
    parser = subparsers.add_parser('collect', help='Collector server')
    parser.add_argument('-d', '--data-dir', dest='data_dir', help=
        'Data store root directory')
    parser.add_argument('-U', '--db-url', dest='db_url', help=
        'Database URL (SQLAlchemy form)', default=None)
    parser.add_argument('--verbose', dest='store_verbose', action=
        'store_true', help='Make the EventStore to log more verbose output.')
    parser.add_argument('--rdbs-store', dest='rdbs_store', action=
        'store_true', help=
        'Use RDBS EventStore instead of NaiveEventStore.' +
        'The RDBS store keeps the events in a relational database.')
    return parser


def _search_error(col, search_string):
    """
    Check for problems with search
    """
    if not search_string:
        return 'No search string provided.'
    if not col:
        return 'No feature selected to search.'
    return ''


@classmethod
def with_json_and_owner(cls, jsonobj, owner):
    """ Instantiates by forwarding to `with_json()`, then remembers the
        "owner" of the instantiated elements. The "owner" is the resource
        containing the receiver and is used to resolve contained resources.

        :raises: TypeError on anything but dict or list of dicts
        :raises: FHIRValidationError if instantiation fails
        :param dict jsonobj: Decoded JSON dictionary (or list thereof)
        :param FHIRElement owner: The owning parent
        :returns: An instance or a list of instances created from JSON data
        """
    instance = cls.with_json(jsonobj)
    if isinstance(instance, list):
        for inst in instance:
            inst._owner = owner
    else:
        instance._owner = owner
    return instance


@classmethod
def add_hook(cls, hook_type, hook_func):
    """Add a new hook of specified type.

        :param cls: class that registers hooks
        :param hook_type: hook type, e.g., '__pre_parse_args__'
        :param hook_func: hook function
        """
    if hook_type not in cls._hooks_map:
        cls._hooks_map[hook_type] = []
    cls._hooks_map[hook_type].append(hook_func)


def Square(x, a, b, c):
    """Second order polynomial

    Inputs:
    -------
        ``x``: independent variable
        ``a``: coefficient of the second-order term
        ``b``: coefficient of the first-order term
        ``c``: additive constant

    Formula:
    --------
        ``a*x^2 + b*x + c``
    """
    return a * x ** 2 + b * x + c


def reverse_order(order_array):
    """
    Returns the effective 'inverse' of the given order array, that is by
    returning the order array that would be needed to re-arrange back to the
    correct order.
    """
    if not hasattr(order_array, '__iter__'):
        raise TypeError('Non-iterable type passed as order_array argument.')
    length = len(order_array)
    new_array = [None] * length
    for index, replace in enumerate(order_array):
        new_array[replace] = index
    return new_array


def parse_root_file(uid, fd, cascreader):
    """Returns an array of format [TYPE, ID, CKEY, EXTRA...],
    Type = one of NAMED_FILE, ID_FILE, ID_INDEXED_FILE
    Id = depends on type. NAMED:"strname", ID:"id", ID_INDEXED:("id","index")
    Ckey = that file's ckey
    Extra = uid specific data
        d3: extra is the "directory" that the file is in
    """
    from PyCASC.rootfiles import parse_d3_root, parse_wow_root, parse_mndx_root, parse_warcraft3_root, parse_hearthstone_root, parse_ow_root
    if uid in ['hsb']:
        return parse_hearthstone_root(fd)
    elif uid in ['w3']:
        return parse_warcraft3_root(fd)
    elif uid in ['d3']:
        return parse_d3_root(fd, cascreader)
    elif uid in ['hero', 's2']:
        return parse_mndx_root(fd)
    elif uid in ['pro']:
        return parse_ow_root(fd)
    elif uid in ['wow']:
        return parse_wow_root(fd)
    else:
        with open(f'{uid}.rootfile', 'wb+') as f:
            f.write(fd)
        raise Exception(
            f"Don't know how to read root file for {uid}. Dumped contents to {uid}.rootfile"
            )


def merge_noun_chunks(doc):
    """Merge noun chunks into a single token.

    doc (Doc): The Doc object.
    RETURNS (Doc): The Doc object with merged noun chunks.

    DOCS: https://spacy.io/api/pipeline-functions#merge_noun_chunks
    """
    if not doc.is_parsed:
        return doc
    with doc.retokenize() as retokenizer:
        for np in doc.noun_chunks:
            attrs = {'tag': np.root.tag, 'dep': np.root.dep}
            retokenizer.merge(np, attrs=attrs)
    return doc


def shift(cube, axis, n=1, cval=0):
    """Returns a cube with the axis shifted.
        Ex.
            cp.shift(nodo_ejemplo,index_para_ejemplo,1)
    """
    return cube.shift(axis, n, cval)


def append_to_list(lst, val):
    """Append and return lists"""
    lst2 = lst[:]
    lst2.append(val)
    return lst2


def sessionFactory():
    """Create a SQLAlchemy session.

        Typically you'd use sqlalchemy.orm.create_session to create
        the session here.
        """


@staticmethod
def parse_shape(shape):
    """Split shape into height, width and frames.

        Args:
            shape(tuple): Shape of dataset

        Returns:
            frames, height, width

        """
    height, width = shape[-2:]
    frames = shape[:-2]
    return frames, height, width


def PIPELINE(path):
    """The **OASIS Pipeline**. Runs all **OASIS** functions in succession.

    :param str path: Path of data file tree (contains the **configs**, **data**, **psf**, **residuals**, **sources**, **templates** directories). Use a comma-separated list for mapping to multiple datasets.
    :returns: All-in-one difference imaging pipeline. Raw science images are placed in the **data** directory, and residual images and source catalogs are outputted into the **residuals** and **sources** directories, respectively.

    """
    import align_astroalign
    from ref_image import ref_image
    import combine_swarp
    import extract
    import check_saturation
    import subtract
    import mask
    import sys
    import psf
    import MR
    import os
    import time
    import initialize
    paths = path.replace(' ', '').split(',')
    del path
    for path in paths:
        startTime = time.time()
        if os.path.exists(path) == True:
            initialize.create(path)
            location = path + '/data'
            ref_image(location)
            align_astroalign.align2(location)
            mask.MASK(path)
            print('-> Combining images using swarp method...')
            psf.PSF(path)
            combine_swarp.swarp(location)
            psf.PSF(path)
            print('\n-> Subtracting images...')
            subtract.SUBTRACT(path)
            print('-> Running SExtractor on residuals...')
            extract.EXTRACT(path, method='indiv')
            MR.MR(path)
            extract.EXTRACT(path, method='MR')
            endTime = time.time()
            print('-> Finished!\n-> Total runtime: %.2f seconds\n' % (
                endTime - startTime))
        else:
            print(
                """
-> Error: Unknown path entered
-> Please enter the path to an existing exposure time directory
-> Exiting...
"""
                )
            sys.exit()


@classmethod
def close(cls):
    """
        关闭Mysql连接,并返回之前所有执行的结果
        :return:
        """
    cls.__conn.close()
    return cls.__result


@staticmethod
def discrete_to_indicators(x, discrete):
    """Change non-zero values of discrete attributes to 1."""
    if discrete.any():
        x = x.copy()
        for col, disc in enumerate(discrete):
            if disc:
                x[:, (col)].clip(0, 1, out=x[:, (col)])
    return x


def noop(*args, **kwargs):
    """
    No Operation Func - Does Nothing!
    :param args:
    :param kwargs:
    :return:
    """
    pass


def merge(dst, src):
    """put key/value pairs that exist in src but not in dst into dst"""
    for key in src.keys():
        if key not in dst:
            dst[key] = src[key]


def str_list_from_io(stream):
    """Turn stream into a str generator."""
    while True:
        line = stream.readline()
        if line == '':
            break
        if isinstance(line, bytes):
            line = line.decode('utf-8')
        yield line


def is_double_float_register(index):
    """! Returns true for registers holding double-precision float values"""
    return -64 >= index > -96


def arcs2d(arcs):
    """Convert arcseconds into degrees."""
    return arcs / 3600.0


def isString(string):
    """ Check if the input argument is a string. """
    if not type(string) == str:
        raise TypeError('The input argument has to be a string')


def scatter_row_inplace(data, row_index, value):
    """Write the value into the data tensor using the row index inplace.

    This is an inplace write so it will break the autograd.

    Parameters
    ----------
    data : Tensor
        The data tensor to be updated.
    row_index : Tensor
        A 1-D integer tensor containing which rows to be updated.
    value : Tensor
        The new value.
    """
    pass


def normalize_mean(array, array_mean, array_stddev, cols=[]):
    """
    Normalizes columns of the array with mean normalization.

    Parameters
    ----------
    array : numpy.array
        The array to normalize.
    array_mean : numpy.array
        Array containing mean values of each column.
    array_stddev : numpy.array
        Array containing standard deviation values of each column.
    cols : list
        The columns to normalize. If the list is empty (default),
        all columns will be normalized.

    Returns
    -------
    numpy.array
        The normalized array.

    Note
    ----
    You can use :py:func:`~get_meanstd` function to get :code:`array_mean`
    and :code:`array_stddev` parameters.
    """
    normalized_array = array.astype(float)
    all_normalized = (array - array_mean) / array_stddev
    if len(cols) == 0:
        normalized_array = all_normalized
    elif array.ndim == 1:
        normalized_array[cols] = all_normalized[cols]
    else:
        normalized_array[:, (cols)] = all_normalized[:, (cols)]
    return normalized_array


@staticmethod
def remove_ansi_escape_codes(text):
    """
        Remove ansi excape codes from the text string!

        :param text: str
        :return:
        """
    text = text.replace('\x1b[1m\x1b[31m', '')
    text = text.replace('\x1b[1m\x1b[32m', '')
    text = text.replace('\x1b[1m\x1b[33m', '')
    text = text.replace('\x1b[1m\x1b[34m', '')
    text = text.replace('\x1b[0m', '')
    return text


def add_edge_and_delete_fifo_load(g, edge):
    """
    Creates edge in network and deletes the ``'load'`` attr from all nodes upstream
    of connection.

    :param g: directed graph of upstream network

    :param edge: edge to add to network

    """
    g.add_edge(*edge)
    nodes = [edge[0]]
    while nodes:
        for node in nodes:
            if 'load' in g.nodes[node]:
                del g.nodes[node]['load']
        nodes = list(set(edge[0] for edge in g.in_edges(nodes)))