@staticmethod
def __identity(scope, name, rse, rse_attrs, protocol_attrs):
    """
        Given a LFN, convert it directly to a path using the mapping:

            scope:path -> scope/path

        :param scope: Scope of the LFN.
        :param name: File name of the LFN.
        :param rse: RSE for PFN (ignored)
        :param rse_attrs: RSE attributes for PFN (ignored)
        :param protocol_attrs: RSE protocol attributes for PFN (ignored)
        :returns: Path for use in the PFN generation.
        """
    del rse
    del rse_attrs
    del protocol_attrs
    if scope.startswith('user') or scope.startswith('group'):
        scope = scope.replace('.', '/')
    return '%s/%s' % (scope, name)


def get_related_models(model_instance):
    """
    Returns a list of all model classes this model has a relationship with
    Must be performed on a model instance rather than a model class - model instance fields will detect external model relationships.
    """
    related_models = []
    for field in model_instance._meta.get_fields():
        if field.related_model:
            related_models.append(field.related_model)
    return related_models


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

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


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

    The ".dev0" means dirty.

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


def blank_frame_add(all_layers: bool=False):
    """Insert a blank frame on the current frame (all subsequently existing frames, if any, are shifted right by one frame)

    :param all_layers: All Layers, Create blank frame in all layers, not only active
    :type all_layers: bool
    """
    pass


def get_x_ang_vel(data, arg, single_row=False, multiple_row=False,
    row_section=False):
    """
    Takes in a file and row arguement(s) along with a boolean that specifies the amount of rows to read the x angular velocity for.

    Parameter:

        data: file
            The csv file that is passed in to read.
        arg: int
            The row(s) that are to be read.
        single_row: boolean
            If chosen the x angular velocity for a single row specified by arg will be output.
        multiple_row: boolean
            If chosen the x angular velocity for multiple rows specified by arg will be output.
        row_section: boolean
            If chosen the x angular velocity for a row section by arg will be output.

    Return:

        An array of x angular velocity.
    """
    x_ang_vel = []
    if single_row is True:
        x_ang_vel_segment = list(data.values[(arg), 37:41])
        x_ang_vel_segment.reverse()
        x_ang = int(''.join(map(str, x_ang_vel_segment)))
        x_ang_vel.append(x_ang)
    elif multiple_row is True:
        for index, elem in enumerate(arg):
            x_ang_vel.append('new row')
            x_ang_vel_segment = list(data.values[(elem), 37:41])
            x_ang_vel_segment.reverse()
            x_ang = int(''.join(map(str, x_ang_vel_segment)))
            x_ang_vel.append(x_ang)
    elif row_section is True:
        for row in range(arg[0], arg[1] + 1):
            x_ang_vel.append('new row')
            x_ang_vel_segment = list(data.values[(row), 37:41])
            x_ang_vel_segment.reverse()
            x_ang = int(''.join(map(str, x_ang_vel_segment)))
            x_ang_vel.append(x_ang)
    return x_ang_vel


def update_service_access_policies(DomainName=None, AccessPolicies=None):
    """
    Configures the access rules that control access to the domain's document and search endpoints. For more information, see Configuring Access for an Amazon CloudSearch Domain .
    See also: AWS API Documentation

    :example: response = client.update_service_access_policies(
        DomainName='string',
        AccessPolicies='string'
    )

    :type DomainName: string
    :param DomainName: [REQUIRED]
            A string that represents the name of a domain. Domain names are unique across the domains owned by an account within an AWS region. Domain names start with a letter or number and can contain the following characters: a-z (lowercase), 0-9, and - (hyphen).

    :type AccessPolicies: string
    :param AccessPolicies: [REQUIRED]
            The access rules you want to configure. These rules replace any existing rules.

    :rtype: dict
    :return: {
        'AccessPolicies': {
            'Options': 'string',
            'Status': {
                'CreationDate': datetime(2015, 1, 1),
                'UpdateDate': datetime(2015, 1, 1),
                'UpdateVersion': 123,
                'State': 'RequiresIndexDocuments'|'Processing'|'Active'|'FailedToValidate',
                'PendingDeletion': True|False
            }
        }
    }

    :returns:
    RequiresIndexDocuments : the option's latest value will not be deployed until  IndexDocuments has been called and indexing is complete.
    Processing : the option's latest value is in the process of being activated.
    Active : the option's latest value is completely deployed.
    FailedToValidate : the option value is not compatible with the domain's data and cannot be used to index the data. You must either modify the option value or update or remove the incompatible documents.

    """
    pass


def epicyclic_gearing_info(c):
    """ create the text info related to the epicyclic_gearing
  """
    r_info = ''
    r_info += (
        """
sun_gear_tooth_nb:        	{:d}
planet_gear_tooth_nb:     	{:d}
annulus_gear_tooth_nb:    	{:d}
smallest_gear_tooth_nb:   	{:d}
planet_nb:                	{:d}
planet_number_max:        	{:d}
epicyclic_gearing_ratio:  	{:0.3f}  1/R: {:0.3f}  1/R2: {:0.3f}  1/R3: {:0.3f}  1/R4: {:0.3f}  1/R5: {:0.3f}
"""
        .format(c['sun_gear_tooth_nb'], c['planet_gear_tooth_nb'], c[
        'annulus_gear_tooth_nb'], c['smallest_gear_tooth_nb'], c[
        'planet_nb'], c['planet_number_max'], c['epicyclic_gearing_ratio'],
        1.0 / c['epicyclic_gearing_ratio'], 1.0 / c[
        'epicyclic_gearing_ratio'] ** 2, 1.0 / c['epicyclic_gearing_ratio'] **
        3, 1.0 / c['epicyclic_gearing_ratio'] ** 4, 1.0 / c[
        'epicyclic_gearing_ratio'] ** 5))
    r_info += (
        """
gear_module:              	{:0.3f}
gear_router_bit_radius:   	{:0.3f}
gear_tooth_resolution:    	{:d}
gear_skin_thickness:      	{:0.3f}
gear_addendum_dedendum_parity_slack: {:0.3f}
"""
        .format(c['gear_module'], c['gear_router_bit_radius'], c[
        'gear_tooth_resolution'], c['gear_skin_thickness'], c[
        'gear_addendum_dedendum_parity_slack']))
    r_info += (
        """
carrier_central radius: 	{:0.3f}  diameter: {:0.3f}
carrier_leg radius:     	{:0.3f}  diameter: {:0.3f}
carrier_peripheral_disable: 	{:d}
carrier_hollow_disable:     	{:d}
carrier_peripheral_external radius: 	{:0.3f}  diameter: {:0.3f}
carrier_peripheral_internal radius: 	{:0.3f}  diameter: {:0.3f}
carrier_leg_middle radius:  	{:0.3f}  diameter: {:0.3f}
carrier_smoothing:          	{:0.3f}  diameter: {:0.3f}
carrier_leg_hole:           	{:0.3f}  diameter: {:0.3f}
"""
        .format(c['carrier_central_radius'], 2 * c['carrier_central_radius'
        ], c['carrier_leg_radius'], 2 * c['carrier_leg_radius'], c[
        'carrier_peripheral_disable'], c['carrier_hollow_disable'], c[
        'carrier_peripheral_external_radius'], 2 * c[
        'carrier_peripheral_external_radius'], c[
        'carrier_peripheral_internal_radius'], 2 * c[
        'carrier_peripheral_internal_radius'], c[
        'carrier_leg_middle_radius'], 2 * c['carrier_leg_middle_radius'], c
        ['carrier_sr'], 2 * c['carrier_sr'], c['carrier_leg_hole_radius'],
        2 * c['carrier_leg_hole_radius']))
    r_info += (
        '\nsun_crenel_nb:      {:d}\nsun_crenel_type:    {:s}\nsun_crenel_mark_nb: {:d}\n'
        .format(c['sun_crenel_nb'], c['sun_crenel_type'], c[
        'sun_crenel_mark_nb']))
    r_info += (
        """
planet_crenel_nb:      {:d}
planet_crenel_type:    {:s}
planet_crenel_mark_nb: {:d}
"""
        .format(c['planet_crenel_nb'], c['planet_crenel_type'], c[
        'planet_crenel_mark_nb']))
    r_info += (
        """
holder radius:  {:0.3f}  diameter: {:0.3f}
holder_crenel_number: {:d}
holder_hole_mark_nb:  {:d}
"""
        .format(c['holder_radius'], 2 * c['holder_radius'], c[
        'holder_crenel_number'], c['holder_hole_mark_nb']))
    r_info += (
        """
planet_nb:                      {:d}
planet-carrier angle:           {:0.3f}
planet-axle radius:             {:0.3f}  diameter: {:0.3f}
planet-axle positioning radius: {:0.3f}  diameter: {:0.3f}
output-gearwheel-crenel nb:     {:d}
output-gearwheel-crenel angle:  {:0.3f}
output-gearwheel-crenel radius: {:0.3f}  diameter: {:0.3f}
output-gearwheel-crenel positioning radius: {:0.3f}  diameter: {:0.3f}
"""
        .format(c['planet_nb'], c['first_planet_position_angle'], c[
        'carrier_leg_hole_radius'], 2 * c['carrier_leg_hole_radius'], c[
        'carrier_hole_position_radius'], 2 * c[
        'carrier_hole_position_radius'], c['output_gearwheel_crenel_number'
        ], c['output_gearwheel_crenel_angle'], c[
        'output_gearwheel_crenel_diameter'] / 2.0, c[
        'output_gearwheel_crenel_diameter'], c[
        'output_gearwheel_crenel_position_diameter'] / 2.0, c[
        'output_gearwheel_crenel_position_diameter']))
    r_info += (
        """
top_clearance_radius: {:0.3f}  diameter: {:0.3}
top_axle_hole_radius: {:0.3f}  diameter: {:0.3}
top_central_radius:   {:0.3f}  diameter: {:0.3}
"""
        .format(c['top_clearance_radius'], 2 * c['top_clearance_radius'], c
        ['top_axle_hole_radius'], 2 * c['top_axle_hole_radius'], c[
        'top_central_radius'], 2 * c['top_central_radius']))
    return r_info


@classmethod
def _get_index_type(cls, index):
    """Assigns an integer code to the type of the index.

        The index type determines how differently typed values are sorted. This ordering is based
        on https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-ordered-data
        """
    if index is None:
        return cls._type_none
    if isinstance(index, bool) and not index:
        return cls._type_bool_false
    if isinstance(index, bool) and index:
        return cls._type_bool_true
    if isinstance(index, (int, float)):
        return cls._type_numeric
    if isinstance(index, str):
        return cls._type_string
    return cls._type_object


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

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

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


def _can_dot(inputs, result, idx_removed):
    """
    Checks if we can use BLAS (np.tensordot) call and its beneficial to do so.

    Parameters
    ----------
    inputs : list of str
        Specifies the subscripts for summation.
    result : str
        Resulting summation.
    idx_removed : set
        Indices that are removed in the summation

    Returns
    -------
    type : bool
        Returns true if BLAS should and can be used, else False

    Notes
    -----
    If the operations is BLAS level 1 or 2 and is not already aligned
    we default back to einsum as the memory movement to copy is more
    costly than the operation itself.

    Examples
    --------

    # Standard GEMM operation
    >>> _can_dot(['ij', 'jk'], 'ik', set('j'))
    True

    # Can use the standard BLAS, but requires odd data movement
    >>> _can_dot(['ijj', 'jk'], 'ik', set('j'))
    False

    # DDOT where the memory is not aligned
    >>> _can_dot(['ijk', 'ikj'], '', set('ijk'))
    False

    """
    if len(idx_removed) == 0:
        return False
    if len(inputs) != 2:
        return False
    input_left, input_right = inputs
    for c in set(input_left + input_right):
        nl, nr = input_left.count(c), input_right.count(c)
        if nl > 1 or nr > 1 or nl + nr > 2:
            return False
        if nl + nr - 1 == int(c in result):
            return False
    set_left = set(input_left)
    set_right = set(input_right)
    keep_left = set_left - idx_removed
    keep_right = set_right - idx_removed
    rs = len(idx_removed)
    if input_left == input_right:
        return True
    if set_left == set_right:
        return False
    if input_left[-rs:] == input_right[:rs]:
        return True
    if input_left[:rs] == input_right[-rs:]:
        return True
    if input_left[-rs:] == input_right[-rs:]:
        return True
    if input_left[:rs] == input_right[:rs]:
        return True
    if not keep_left or not keep_right:
        return False
    return True


def theta_none(T, P):
    """i-i': no interaction effect."""
    theta = 0
    valid = T > 0
    return theta, valid


def _convert_opts(opts):
    """
    Convert list with command options to single string value
    with 'space' delimeter
    :param opts: list with space-delimeted values
    :return: string with space-delimeted values
    """
    return ' '.join(opts)


@staticmethod
def actions():
    """Dictionary of actions that can be performed on object

        Returns:
            Dict[str, str]: Dictionary of actions that can be performed on object
        """
    return {'show': 'package_show', 'update': 'package_update', 'create':
        'package_create', 'delete': 'hdx_dataset_purge', 'search':
        'package_search', 'reorder': 'package_resource_reorder', 'list':
        'package_list', 'hxl': 'package_hxl_update', 'create_default_views':
        'package_create_default_resource_views'}


def extract_boto_args_from_env(env_vars):
    """Return boto3 client args dict with environment creds."""
    boto_args = {}
    for i in ['aws_access_key_id', 'aws_secret_access_key', 'aws_session_token'
        ]:
        if env_vars.get(i.upper()):
            boto_args[i] = env_vars[i.upper()]
    return boto_args


def parse_bip32_path(path):
    """Takes bip32 path, "m/0'/2H" or "m/0H/1/2H/2/1000000000.pub", returns list of ints """
    path = path.lstrip('m/').rstrip('.pub')
    if not path:
        return []
    patharr = []
    for v in path.split('/'):
        if not v:
            continue
        elif v[-1] in "'H":
            v = int(v[:-1]) | 2147483648
        else:
            v = int(v) & 2147483647
        patharr.append(v)
    return patharr


def jd2mjd(jd):
    """
    Converts a Julian Date to a Modified Julian Date

    Parameters
    ----------
    jd : float (any numeric type)
        A julian date

    Returns
    -------
    mjd : float
        The Modified Julian Date (MJD) calculated from the input Julian Date

    Examples
    --------
    >>> jd2mjd(2455581.40429)
    55580.90429

    """
    return float(jd - 2400000.5)


def _reorder(xs, indexes):
    """Reorder list xs by indexes"""
    if not len(indexes) == len(xs):
        raise ValueError('xs and indexes must be the same size')
    ys = [None] * len(xs)
    for i, j in enumerate(indexes):
        ys[j] = xs[i]
    return ys


def _start_process(engine_constructor, player_endpoints, view_connection):
    """
        The target function for the background process. Intializes and starts
        the specified engine.

        :param engine_constructor: The engine class to initialize.
        :type engine_constructor: ``stratumgs.game.engine.BaseEngine``
        :param player_endpoints: The endpoints of the players in the game.
        :type player_endpoints: list(player endpoints)
        :param view_connection: The endpoints for the view connection.
    """
    engine = engine_constructor(players=player_endpoints, view_connection=
        view_connection)
    engine.run()


@classmethod
def _sql_column_to_table(cls, name):
    """
        Returns the table in `cls._sql_tables` containing the
        field `name`.

        If `name` corresponds to a primary key column, then
        the primary table (first table) is returned.

        If a table could not be found, a `exceptions.KeyError` is
        raised.
        """
    if name in cls._sql_tables['primary']:
        return cls._sql_primary_table()
    for table_name, fields in cls._sql_tables['tables']:
        if name in fields:
            return table_name
    raise KeyError('Could not find table for %s' % name)


def _filter_groupby_columns(by, cols, meta):
    """
    Checks ?_by=col&_by=col for filter().

    - ``by``: list of column names to group by
    - ``cols``: list of valid column names
    - ``meta``: meta['by'] and meta['ignored'] are updated

    Returns a list of columns to group by
    """
    colset = set(cols)
    for col in by:
        if col in colset:
            meta['by'].append(col)
        else:
            meta['ignored'].append(('_by', col))
    return meta['by']


def inject_widget_variables(layout, structure, variables=None):
    """ Takes the layout, structure and a dict of variables meant for the
    template engine and injects the variables required by the widgets, if
    the widgets are indeed in use.

    """
    if not structure:
        return variables
    variables = variables or {}
    for tag, widget in layout.app.config.homepage_widget_registry.items():
        if '<{}'.format(tag) in structure:
            if hasattr(widget, 'get_variables'):
                for key, value in widget.get_variables(layout).items():
                    assert key not in variables, 'use unique variable names'
                    variables[key] = value
    return variables


def flat_iterator(nml):
    """Iterator that returns the adress of an element as a 2-tuple,
    along with the element """
    for key, value in nml.items():
        for inner_key, inner_value in value.items():
            yield (key, inner_key), inner_value


def format_timeout(timeout):
    """Render server alive interval option."""
    format_str = '-o ServerAliveInterval={}'.format
    return timeout and format_str(timeout) or ''


def filtrar_cortas(texto, chars=0):
    """Filtra líneas en texto de longitud chars o inferior.

    Parameters
    ----------
    texto : str
        Texto que se quiere filtrar.
    chars : int
        Mínimo número de caracteres en una línea de texto.

    Returns
    -------
    str
       Texto filtrado.
    """
    filtrado = ''
    for linea in texto.splitlines():
        if len(linea) > chars:
            filtrado += linea + '\n'
    return filtrado


def wf_action_external_id(node):
    """
    It returns the external Id for an action node, or an empty string if the
    action has not being executed or it has not completed yet.
    """


def human_oracle(evidence, possible_answers):
    """Simple text interface to query a human for fact generation."""
    colored_fact, colored_segment = evidence.colored_fact_and_text()
    print(u'SEGMENT: %s' % colored_segment)
    question = ' FACT: {0}? ({1}) '.format(colored_fact, u'/'.join(
        possible_answers))
    answer = input(question)
    while answer not in possible_answers:
        answer = input(question)
    return answer


def cDiff():
    """
    Return the kernel source of cDiff.
    """
    R = """
        KERNEL void cDiff(  GLOBAL_MEM    const    int            *order2,
                                               GLOBAL_MEM     const   float2     *indata,
                                               GLOBAL_MEM                  float2     *outdata)
        {
        const unsigned int gid =  get_global_id(0);
        const unsigned int ind = order2[gid];
        outdata[gid]=indata[ind]- indata[gid];
        };
        """
    return R


def can_preview(file):
    """Return True if filetype can be previewed."""
    return file.is_local() and file.has_extensions('.zip')


@staticmethod
def get_build_id(filename, env_name):
    """
        Extract build id from the file name
        In downloader.py, we have the following name convenion
             local_fn = u'{}-{}.{}'.format(self._build_name, self._build, extension)
        """
    prefix = '{0}-'.format(env_name)
    if filename.startswith(prefix) and '.' in filename:
        return True, filename[len(prefix):filename.index('.')]
    return False, None


def _calculate_log2_num_bytes(value: int) ->int:
    """
    Determine the number of bytes required to encode the input value.

    Artificially limited to max of 8 bytes to be compliant

    :param value:
    :return: The calculate the number of bytes
    """
    for log2_num_bytes in range(4):
        limit = 1 << (1 << log2_num_bytes) * 8
        if value < limit:
            return log2_num_bytes
    raise RuntimeError(
        'Unable to calculate the number of bytes required for this value')


def _label_unpack(packed):
    """Unpack a label from its binary form."""
    try:
        return packed.split(b'\x00', 2)[0].decode('utf8')
    except UnicodeDecodeError:
        return packed


@staticmethod
def _merge_slices(match_slices):
    """Return a list of slice indices lists derived from `match_slices`
        with no overlaps."""
    match_slices.sort(key=lambda x: (x[0], -x[1]))
    merged_slices = [match_slices.pop(0)]
    for slice_indices in match_slices:
        last_end = merged_slices[-1][1]
        if slice_indices[0] <= last_end:
            if slice_indices[1] > last_end:
                merged_slices[-1][1] = slice_indices[1]
        else:
            merged_slices.append(slice_indices)
    return merged_slices


def down(f, c):
    """Find the negative values in the series.

    Parameters
    ----------
    f : pandas.DataFrame
        Dataframe containing the column ``c``.
    c : str
        Name of the column in the dataframe ``f``.

    Returns
    -------
    new_column : pandas.Series (bool)
        The array containing the new feature.

    """
    new_column = f[c] < 0
    return new_column


def scroll_page(up: bool=False):
    """Scroll page up or down

    :param up: Up, Scroll up one page
    :type up: bool
    """
    pass


def formatargvalues(args, varargs, varkw, localsDict, formatarg=str,
    formatvarargs=lambda name: '*' + name, formatvarkw=lambda name: '**' +
    name, formatvalue=lambda value: '=' + repr(value)):
    """
    Function to format an argument spec from the 4 values returned
    by getargvalues.

    @param args list of argument names
    @type list of str
    @param varargs name of the variable arguments
    @type str
    @param varkw name of the keyword arguments
    @type str
    @param localsDict reference to the local variables dictionary
    @type dict
    @keyparam formatarg argument formatting function
    @type func
    @keyparam formatvarargs variable arguments formatting function
    @type func
    @keyparam formatvarkw keyword arguments formatting function
    @type func
    @keyparam formatvalue value formating functtion
    @type func
    @return formatted call signature
    @rtype str
    """
    specs = []
    for i in range(len(args)):
        name = args[i]
        specs.append(formatarg(name) + formatvalue(localsDict[name]))
    if varargs:
        specs.append(formatvarargs(varargs) + formatvalue(localsDict[varargs]))
    if varkw:
        specs.append(formatvarkw(varkw) + formatvalue(localsDict[varkw]))
    argvalues = '(' + ', '.join(specs) + ')'
    if '__return__' in localsDict:
        argvalues += ' -> ' + formatvalue(localsDict['__return__'])
    return argvalues


def numeric_version(vers):
    """
    convert a string into a tuple with numbers wherever possible

    @param      vers    string
    @return             tuple
    """
    if isinstance(vers, tuple):
        return vers
    if isinstance(vers, list):
        raise Exception('unexpected value:' + str(vers))
    spl = vers.split('.')
    r = []
    for _ in spl:
        try:
            i = int(_)
            r.append(i)
        except ValueError:
            r.append(_)
    return tuple(r)


def concentric_hexagons(radius, start=(0, 0)):
    """A generator which produces coordinates of concentric rings of hexagons.

    Parameters
    ----------
    radius : int
        Number of layers to produce (0 is just one hexagon)
    start : (x, y)
        The coordinate of the central hexagon.
    """
    x, y = start
    yield x, y
    for r in range(1, radius + 1):
        y -= 1
        for dx, dy in [(1, 1), (0, 1), (-1, 0), (-1, -1), (0, -1), (1, 0)]:
            for _ in range(r):
                yield x, y
                x += dx
                y += dy


def ruler_add():
    """Undocumented contribute <https://developer.blender.org/T51061>

    """
    pass


def get_default_options(max_num_machines=1, max_wallclock_seconds=1800,
    with_mpi=False):
    """Return an instance of the options dictionary with the minimally required parameters for a `CalcJob`.

    :param max_num_machines: set the number of nodes, default=1
    :param max_wallclock_seconds: set the maximum number of wallclock seconds, default=1800
    :param with_mpi: whether to run the calculation with MPI enabled
    """
    return {'resources': {'num_machines': int(max_num_machines)},
        'max_wallclock_seconds': int(max_wallclock_seconds), 'withmpi':
        with_mpi}


def glMultMatrix(m: 'Buffer'):
    """Multiply the current matrix with the specified matrix

    :param m: Points to 16 consecutive values that are used as the elements of a 4x4 column major matrix.
    :type m: 'Buffer'
    """
    pass


@classmethod
def indent(cls, s: s) ->s:
    """Correctly indent the given string, which may be a multi-line message."""
    return cls.s + s.replace('\n', f'\n{cls.s}')


def identifies(id, ref):
    """Returns true if string `id` matches TableReference `ref`"""
    return (id == ref.alias or id == ref.name or ref.schema and id == ref.
        schema + '.' + ref.name)


@staticmethod
def has_attr(module_obj, attr_name):
    """
        检查模块或对象是否有指定名称的属性

        @param {Moudle} module_obj - 模块对象
        @param {string} attr_name - 属性名（类名/函数名/属性名)

        @returns {bool} - 是否包含属性，True-包含，False-不包含

        """
    return hasattr(module_obj, attr_name)


def t_UNIT(t):
    """cm|pt|ex|mm|in|em|%(?=x\\d|$)"""
    return t


def _format_name(address):
    """Retrieve the e-mail and optionally the name from an address.

    :arg vCalAddress address: An address object.

    :returns str: The name and optionally the e-mail address.
    """
    if not address:
        return ''
    email = address.title().split(':')[1]
    if 'cn' in address.params:
        return '{} <{}>'.format(address.params['cn'], email)
    return email


def rate_planet(M_s: float):
    """
	Estimates planet occurrence rate for all planet radii and orbital periods under 50 days.
	Args:
		M_s (float): Star mass [Solar masses].
	Returns:
		Planet occurrence rate.
	"""
    if 2.5 - 1.5 * M_s > 0.1:
        return 2.5 - 1.5 * M_s
    else:
        return 0.1


def compat_loop(loop):
    """
    Retrieves the asyncio API compatible version of the provided
    loop in case such version exists in the current object, otherwise
    returns the proper object (assumed to be asyncio API compatible).

    :type loop: EventLoop
    :param loop: The base event loop object from which an asyncio
    API compatible object is meant to be retrieved.
    :rtype: EventLoop
    :return: The asyncio API compatible event loop object.
    """
    return loop._compat if hasattr(loop, '_compat') else loop


def set_decorating(decorating_):
    """Sets whether the module is operating in decorating mode.
    """
    global decorating
    decorating = decorating_


@staticmethod
def __convert_move_coords_to_indexes(row, col):
    """Convert move coordinates (e.g. "A","1") to board x,y indexes."""
    row_to_x = {'A': 0, 'B': 1, 'C': 2}
    col_to_y = {'1': 0, '2': 1, '3': 2}
    return row_to_x.get(row, -1), col_to_y.get(col, -1)


@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 to_code(cells):
    """
    Turns the cells into Python code.

    :param cells: the cells to iterate
    :type cells: list
    :return: the generated code
    :rtype: list
    """
    result = []
    for cell in cells:
        if 'cell_type' in cell:
            if cell['cell_type'] == 'code' and 'source' in cell:
                for line in cell['source']:
                    if 'install.packages(' in line:
                        result.append('# ' + line.rstrip())
                    else:
                        result.append(line.rstrip())
            elif cell['cell_type'] == 'markdown' and 'source' in cell:
                for line in cell['source']:
                    result.append('# ' + line.rstrip())
            result.append('')
    return result


def lookupSenderPolicy(name, timeout=10):
    """
        Perform a SPF record lookup.

        @type name: C{str}
        @param name: DNS name to resolve.

        @type timeout: Sequence of C{int}
        @param timeout: Number of seconds after which to reissue the query.
            When the last timeout expires, the query is considered failed.

        @rtype: L{Deferred}
        @return: A L{Deferred} which fires with a three-tuple of lists of
            L{twisted.names.dns.RRHeader} instances.  The first element of the
            tuple gives answers.  The second element of the tuple gives
            authorities.  The third element of the tuple gives additional
            information.  The L{Deferred} may instead fail with one of the
            exceptions defined in L{twisted.names.error} or with
            C{NotImplementedError}.
        """


def prune_transfer_option(formats, language):
    """derive a unique list of transfer options.
    The unique character is based on identification language"""
    unique_transfer = []
    nil_reasons = ['missing', 'withheld', 'inapplicable', 'unknown', 'template'
        ]
    for k, v in formats.items():
        if language.split(';')[0] in k and language not in nil_reasons:
            unique_transfer.append(v)
        elif language in nil_reasons:
            unique_transfer.append(v)
    return unique_transfer


def addBeforeCommitHook(hook, args=(), kws=None):
    """Register a hook to call before the transaction is
        committed.

        The specified hook function will be called after the
        transaction's commit method has been called, but before the
        commit process has been started.

        :param sequence args:
            Additional positional arguments to be passed to the hook.
            The default is to pass no positional arguments.
        :param dict kws:
            Keyword arguments to pass to the hook. The default
            is to pass no keyword arguments.

        Multiple hooks can be registered and will be called in the
        order they were registered (first registered, first called).
        This method can also be called from a hook: an executing hook
        can register more hooks. Applications should take care to
        avoid creating infinite loops by recursively registering
        hooks.

        Hooks are called only for a top-level commit. A savepoint
        creation does not call any hooks. If the transaction is
        aborted, hooks are not called, and are discarded. Calling a
        hook "consumes" its registration too: hook registrations do
        not persist across transactions. If it's desired to call the
        same hook on every transaction commit, then
        `addBeforeCommitHook` must be called with that hook during
        every transaction; in such a case consider registering a
        synchronizer object via `ITransactionManager.registerSynch`
        instead.
        """


def find_package(name, installed, package=False):
    """Finds a package in the installed list.

    If `package` is true, match package names, otherwise, match import paths.
    """
    if package:
        name = name.lower()
        tests = lambda x: x.user and name == x.name.lower(
            ), lambda x: x.local and name == x.name.lower(
            ), lambda x: name == x.name.lower()
    else:
        tests = (lambda x: x.user and name in x.import_names, lambda x: x.
            local and name in x.import_names, lambda x: name in x.import_names)
    for t in tests:
        try:
            found = list(filter(t, installed))
            if found and not found[0].is_scan:
                return found[0]
        except StopIteration:
            pass
    return None


@classmethod
def from_TN(cls, tn, inplace=False, **kwargs):
    """Construct a specific tensor network subclass (i.e. one with some
        promise about structure/geometry and tags/inds such as an MPS) from
        a generic tensor network which should have that structure already.

        Parameters
        ----------
        cls : class
            The TensorNetwork subclass to convert ``tn`` to.
        tn : TensorNetwork
            The TensorNetwork to convert.
        inplace : bool, optional
            Whether to perform the conversion inplace or not.
        kwargs
            Extra properties of the TN subclass that should be specified.
        """
    new_tn = tn if inplace else tn.copy()
    for prop in cls._EXTRA_PROPS:
        prop_name = prop.lstrip('_')
        if prop_name in kwargs:
            setattr(new_tn, prop, kwargs.pop(prop_name))
        elif hasattr(tn, prop_name):
            setattr(new_tn, prop, getattr(tn, prop_name))
        else:
            raise ValueError(
                f"You need to specify '{prop_name}' for the tensor network class {cls}, and ensure that it correctly corresponds to the structure of the tensor network supplied, since it cannot be found as an attribute on the TN: {tn}."
                )
    if kwargs:
        raise ValueError(f'Options {kwargs} are invalid for the class {cls}.')
    new_tn.__class__ = cls
    return new_tn


def check_availability():
    """
        Return a boolean indicating whether a call to this factory
        will return a driver (True) or will raise an error (False).
        """


@staticmethod
def is_active():
    """
        Verify if the interface state is Active
        """
    return False


def _indent_levels(line: str) ->int:
    """Determine how many levels the line is indented."""
    spaces = len(line) - len(line.lstrip())
    levels, remainder = divmod(spaces, 4)
    if remainder:
        raise ValueError('indent of first line must be a multiple of four')
    return levels


def unquote(s):
    """
    Strips matching single and double quotes from the start and end of the
    given string.
    """
    if len(s) > 1 and (s[0] == '"' and s[-1] == '"' or s[0] == "'" and s[-1
        ] == "'"):
        return s[1:-1]
    else:
        return s


def canWrite():
    """Can the data manager write a value."""


def _atom_to_filename(atom):
    """Translate an atom to a filename.

   :param atom: filename as atom
   :type atom: Term
   :return: filename as string
   :rtype: str
    """
    atomstr = str(atom)
    if atomstr[0] == atomstr[-1] == "'":
        atomstr = atomstr[1:-1]
    return atomstr


def _check(return_val):
    """Checks the return code of the C calls"""
    if isinstance(return_val, int) and return_val == 1:
        return
    if isinstance(return_val, bool) and return_val == True:
        return
    raise Exception('HMAC exception')


def get_perc_of_geo_info(dataframe):
    """
    Calculates the percentage of all tweets in the given dataframe that contain geo-info

    :param pd.Dataframe dataframe: Dataframe containing twitter data

    :return: Either string telling the error or integer telling the percentage

    """
    if 'is_geo' in dataframe:
        df_geo = dataframe[dataframe.is_geo == 1]
        if len(df_geo) > 0:
            return round(len(df_geo) / len(dataframe) * 100, 1)
        else:
            return 'No geographical Information in dataset'
    else:
        return 'No geographical Information in dataset'


def is_event(attribute: str) ->bool:
    """Test if a method is an event."""
    return attribute.startswith('on_')


def sorted_alnum(list_):
    """
    Returns a list sorted in-place alphanumerically.
    Useful for directories, like /proc, that contain pids and other files
    """
    list_.sort()
    list_.sort(key=lambda x: int(x) if x.isdigit() else float('inf'))
    return list_


def validate_policy(policy):
    """
    Simple validation a policy include som necessary elements.
    """
    if 'name' not in policy:
        raise AttributeError('Policy missing attribute name.')
    if 'policyType' not in policy:
        raise AttributeError('Policy {} do not have PolicyType.'.format(
            policy['name']))
    if policy['policyType'] not in [0, 1, 2]:
        raise AttributeError('Policy {} must have PolicyType 0, 1, or 2.'.
            format(policy['name']))
    if 'resources' not in policy:
        raise AttributeError('Policy {} do not have resources.'.format(
            policy['name']))
    if policy['policyType'] == 0 and not ('policyItems' in policy or
        'denyPolicyItems' in policy):
        raise AttributeError(
            'Policy {} do not have policyItems nor denyPolicyItems.'.format
            (policy['name']))


def getprecision(distance, surface='road'):
    """
    get the precision for rendering, based on distance

    precision might be different for time vs. age group adjusted time

    :param distance: distance (miles)
    :param surface: 'road', 'track' or 'trail', default 'road'
    :rtype: (timeprecision,agtimeprecision)
    """
    meterspermile = 1609
    if surface == 'track':
        timeprecision = 1
        agtimeprecision = 1
    else:
        timeprecision = 0
        agtimeprecision = 0
    return timeprecision, agtimeprecision


def loadfile(fname):
    """load a file as a string"""
    f = open(fname, mode='r')
    r = f.read()
    f.close()
    return r


def copy():
    """Copy the material settings and nodes

    """
    pass


def introspect_many_to_many_relations(through):
    """
    helper to introspect a through model and return all usefull data like the many2many fields,
    the fk and the related models.
    return a list of 2 items: one for each «side» of the many2many.
    each items contains a n3 tuple: the through.foreignkey, the related model, and the ManytoMany(Rel].
    """
    fields = []
    for fk in through._meta.get_fields():
        if fk.is_relation and fk.many_to_one:
            for rel_model_f in fk.rel.model._meta.get_fields():
                if (rel_model_f.is_relation and rel_model_f.many_to_many and
                    getattr(rel_model_f, 'rel', rel_model_f).through == through
                    ):
                    fields.append((fk, fk.rel.model, rel_model_f))
                    break
            else:
                raise AssertionError(
                    "we can't find the field used as relation using through %s"
                     % through)
    return fields


def get_parameter(f):
    """
    Reads a procpar parameter from a file object.

    Returns a dictionary with the attributes of the parameter.

    """
    dic = dict()
    line = f.readline().decode().split()
    dic['name'] = line[0]
    dic['subtype'] = line[1]
    dic['basictype'] = line[2]
    dic['maxvalue'] = line[3]
    dic['minvalue'] = line[4]
    dic['stepsize'] = line[5]
    dic['Ggroup'] = line[6]
    dic['Dgroup'] = line[7]
    dic['protection'] = line[8]
    dic['active'] = line[9]
    dic['intptr'] = line[10]
    line = f.readline().decode()
    num = int(line.split()[0])
    values = []
    if dic['basictype'] == '1':
        values = line.split()[1:]
    elif dic['basictype'] == '2':
        values.append(line.split('"')[1])
        for i in range(num - 1):
            values.append(f.readline().decode().split('"')[1])
    dic['values'] = values
    line = f.readline().decode()
    dic['enumerable'] = line.split()[0]
    if dic['enumerable'] != '0':
        if dic['basictype'] == '1':
            dic['enumerables'] = line.split()[1:]
        elif dic['basictype'] == '2':
            dic['enumerables'] = line.split('"')[1::2]
    return dic


def applyFileUpload(fileUpload):
    """Apply FileUpload given from request publisher"""


def plot_ranges_from_cli(opts):
    """Parses the mins and maxs arguments from the `plot_posterior` option
    group.

    Parameters
    ----------
    opts : ArgumentParser
        The parsed arguments from the command line.

    Returns
    -------
    mins : dict
        Dictionary of parameter name -> specified mins. Only parameters that
        were specified in the --mins option will be included; if no parameters
        were provided, will return an empty dictionary.
    maxs : dict
        Dictionary of parameter name -> specified maxs. Only parameters that
        were specified in the --mins option will be included; if no parameters
        were provided, will return an empty dictionary.
    """
    mins = {}
    for x in opts.mins:
        x = x.split(':')
        if len(x) != 2:
            raise ValueError('option --mins not specified correctly; see help')
        mins[x[0]] = float(x[1])
    maxs = {}
    for x in opts.maxs:
        x = x.split(':')
        if len(x) != 2:
            raise ValueError('option --maxs not specified correctly; see help')
        maxs[x[0]] = float(x[1])
    return mins, maxs


def register(prepared_obj):
    """Register the object saving the initial state.

        Prior to a register the object has to prepared. Pass the
        return value of the 'prepare' method to 'prepared_obj'.
        """


@staticmethod
def debug_skillet_structure(skillet: dict) ->list:
    """
        Verifies the structure of a skillet and returns a list of errors or warning if found

        :param skillet: Skillet Definition Dictionary
        :return: list of errors or warnings if found
        """
    errs = list()
    if skillet is None:
        errs.append('Skillet is blank or could not be loaded')
        return errs
    if not isinstance(skillet, dict):
        errs.append('Skillet is malformed')
        return errs
    if 'labels' not in skillet:
        errs.append('No labels attribute present in skillet')
    elif 'collection' not in skillet['labels']:
        errs.append('No collection defined in skillet')
    if 'label' not in skillet:
        errs.append('No label attribute in skillet')
    if 'type' not in skillet:
        errs.append('No type attribute in skillet')
    else:
        valid_types = ['panos', 'panorama', 'panorama-gpcs',
            'pan_validation', 'python3', 'rest', 'terraform', 'template',
            'workflow', 'docker']
        if skillet['type'] not in valid_types:
            errs.append(f"Unknown type {skillet['type']} in skillet")
    return errs


def remove(pcoll: 'ImagePreviewCollection'):
    """Remove the specified previews collection.

    :param pcoll: Preview collection to close.
    :type pcoll: 'ImagePreviewCollection'
    """
    pass


def authorization_adapter(field, ctx, source_dict, target_obj):
    """
    Default adapter works on single field (non iterable)
    """
    name = field._compute_property(ctx)
    source = field.to_python_value(ctx, source_dict[name])
    target = field.to_python_value(ctx, field._get(target_obj))
    return name, source, target


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


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


@staticmethod
def all(tensor):
    """Returns if all array elements in a tensor are True.

        Parameters
        ----------
        tensor : tensor

        Returns
        -------
        bool
        """
    raise NotImplementedError


def validate_string_dict(dct):
    """Validate that the input is a dict with string keys and values.

    Raises ValueError if not."""
    for k, v in dct.items():
        if not isinstance(k, str):
            raise ValueError('key %r in dict must be a string' % k)
        if not isinstance(v, str):
            raise ValueError('value %r in dict must be a string' % v)


def get_users(username):
    """Get user information from TimeSync"""
    if username:
        p_dict = [{'username': username, 'display_name': 'X. Ample User',
            'email': 'example@example.com', 'active': True, 'site_admin':
            True if username == 'admin' else False, 'site_spectator': True if
            username == 'spectator' else False, 'site_manager': True if
            username == 'manager' else False, 'created_at': '2015-02-29',
            'deleted_at': None}]
    else:
        p_dict = [{'username': 'userone', 'display_name':
            'One Is The Loneliest Number', 'email':
            'exampleone@example.com', 'active': True, 'site_admin': False,
            'site_manager': False, 'site_spectator': False, 'created_at':
            '2015-02-29', 'deleted_at': None}, {'username': 'usertwo',
            'display_name': 'Two Can Be As Bad As One', 'email':
            'exampletwo@example.com', 'active': True, 'site_admin': False,
            'site_manager': False, 'site_spectator': False, 'created_at':
            '2015-02-29', 'deleted_at': None}, {'username': 'userthree',
            'display_name': "Yes It's The Saddest Experience", 'email':
            'examplethree@example.com', 'active': True, 'site_admin': False,
            'site_manager': False, 'site_spectator': False, 'created_at':
            '2015-02-29', 'deleted_at': None}, {'username': 'userfour',
            'display_name': "You'll Ever Do", 'email':
            'examplefour@example.com', 'active': True, 'site_admin': False,
            'site_manager': False, 'site_spectator': False, 'created_at':
            '2015-02-29', 'deleted_at': None}]
    return p_dict


@classmethod
def inter(cls, family):
    """intersection of a family of Lebesgue sets"""
    return cls.operate(cls.INTER, family)


def update_field_type(field_types, item):
    """ Update AxFieldType from yaml data if needed """
    for ax_field in field_types:
        if ax_field.tag == item['tag']:
            if 'name' in item and ax_field.name != item['name']:
                ax_field.name = item['name']
            if 'position' in item and ax_field.position != item['position']:
                ax_field.position = item['position'],
            if 'default_name' in item and ax_field.default_name != item[
                'default_name']:
                ax_field.name = item['default_name']
            if 'default_db_name' in item and ax_field.default_db_name != item[
                'default_db_name']:
                ax_field.default_db_name = item['default_db_name']
            if 'value_type' in item and ax_field.value_type != item[
                'value_type']:
                ax_field.value_type = item['value_type']
            if 'parent' in item and ax_field.parent != item['parent']:
                ax_field.parent = item['parent']
            if 'icon' in item and ax_field.icon != item['icon']:
                ax_field.icon = item['icon']
            if 'comparator' in item and ax_field.comparator != item[
                'comparator']:
                ax_field.comparator = item['comparator']
            if 'virtual_source' in item and ax_field.virtual_source != item[
                'virtual_source']:
                ax_field.virtual_source = item['virtual_source']
            if 'is_virtual' in item and ax_field.is_virtual != item[
                'is_virtual']:
                ax_field.is_virtual = item['is_virtual']
            if 'is_readonly' in item and ax_field.is_readonly != item[
                'is_readonly']:
                ax_field.is_readonly = item['is_readonly']
            if ('is_inline_editable' in item and ax_field.
                is_inline_editable != item['is_inline_editable']):
                ax_field.is_inline_editable = item['is_inline_editable']
            if ('is_backend_available' in item and ax_field.
                is_backend_available != item['is_backend_available']):
                ax_field.is_backend_available = item['is_backend_available']
            if ('is_display_backend_avalible' in item and ax_field.
                is_display_backend_avalible != item[
                'is_display_backend_avalible']):
                the_item = item['is_display_backend_avalible']
                ax_field.is_display_backend_avalible = the_item
            if ('is_columnn_avalible' in item and ax_field.
                is_columnn_avalible != item['is_columnn_avalible']):
                ax_field.is_columnn_avalible = item['is_columnn_avalible']
            if ('is_updated_always' in item and ax_field.is_updated_always !=
                item['is_updated_always']):
                ax_field.is_updated_always = item['is_updated_always']
            if 'is_group' in item and ax_field.is_group != item['is_group']:
                ax_field.is_group = item['is_group']
            if ('is_always_whole_row' in item and ax_field.
                is_always_whole_row != item['is_always_whole_row']):
                ax_field.is_always_whole_row = item['is_always_whole_row']


def prepare_data(file_dataframe):
    """Function separates data frame to axes and data

    Function takes pandas data frame and separates the
    cols and rows names as x and y axis and matrix values

    Args:
        file_dataframe (str): data frame from read_file()

    Returns:
        list: list of x_labels, y_labels, data, respectively
    """
    x_labels = file_dataframe.columns
    y_labels = file_dataframe.index
    data = file_dataframe.values
    return [x_labels, y_labels, data]


def join_nargs_arg(arg_value):
    """
    Joins nargs argument values and returns a single array containing all the
    individual values.

    If the arg_value is not a list or a list of lists, the arg_value is
    returned.

    This function exists to handle the legacy syntax where arguments used
    "append" over "nargs".
    """
    if type(arg_value) != list:
        return arg_value
    joined = []
    for value_n in arg_value:
        if type(value_n) != list:
            joined.append(value_n)
        else:
            joined.extend(value_n)
    return joined


@classmethod
def get(cls, deployment_id):
    """Get information about a deployment.

        .. versionadded:: v2.17

        Parameters
        ----------
        deployment_id : str
            the id of the deployment

        Returns
        -------
        deployment : Deployment
            the queried deployment

        Examples
        --------
        .. code-block:: python

            from datarobot import Deployment
            deployment = Deployment.get(deployment_id='5c939e08962d741e34f609f0')
            deployment.id
            >>>'5c939e08962d741e34f609f0'
            deployment.label
            >>>'New Deployment'
        """
    path = '{}{}/'.format(cls._path, deployment_id)
    return cls.from_location(path)


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 Nu_coil_Xin_Ebadian(Pr, Gr, horizontal=False):
    """Calculates Nusselt number for natural convection around a vertical
    or horizontal helical coil suspended in a fluid without
    forced convection.

    For horizontal cases:

    .. math::
        Nu_D = 0.318 Ra_D^{0.293},\\; 5 \\times {10}^{3} < Ra < 1 \\times {10}^5

    For vertical cases:

    .. math::
        Nu_D = 0.290 Ra_D^{0.293},\\; 5 \\times {10}^{3} < Ra < 1 \\times {10}^5

    Parameters
    ----------
    Pr : float
        Prandtl number calculated with the film temperature -
        wall and temperature very far from the coil average, [-]
    Gr : float
        Grashof number calculated with the film temperature -
        wall and temperature very far from the coil average,
        and using the outer diameter of the coil [-]
    horizontal : bool, optional
        Whether the coil is horizontal or vertical, [-]

    Returns
    -------
    Nu : float
        Nusselt number using the outer diameter of the coil
        and the film temperature, [-]

    Notes
    -----
    This correlation is also reviewed in [2]_.

    Examples
    --------
    >>> Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=False)
    4.755689726250451
    >>> Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=True)
    5.2148597687849785

    References
    ----------
    .. [1] Xin, R. C., and M. A. Ebadian. "Natural Convection Heat Transfer
       from Helicoidal Pipes." Journal of Thermophysics and Heat Transfer 10,
       no. 2 (1996): 297-302.
    .. [2] Prabhanjan, Devanahalli G., Timothy J. Rennie, and G. S. Vijaya
       Raghavan. "Natural Convection Heat Transfer from Helical Coiled Tubes."
       International Journal of Thermal Sciences 43, no. 4 (April 1, 2004):
       359-65.
    """
    Ra = Pr * Gr
    if horizontal:
        return 0.318 * Ra ** 0.293
    else:
        return 0.29 * Ra ** 0.293


def action_unlink(force_delete: bool=False):
    """Unlink this action from the active action slot (and/or exit Tweak Mode)

    :param force_delete: Force Delete, Clear Fake User and remove copy stashed in this datablock’s NLA stack
    :type force_delete: bool
    """
    pass


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

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

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


def getDictFrom(s):
    """Returns a dict from string representation p_s of the form
       "key1:value1,key2:value2"."""
    res = {}
    if s:
        for part in s.split(','):
            key, value = part.split(':')
            res[key] = value
    return res


@classmethod
def get_comp_level_octo(cls, match_number):
    """ No 2015 support """
    if match_number <= 24:
        return 'ef'
    elif match_number <= 36:
        return 'qf'
    elif match_number <= 42:
        return 'sf'
    else:
        return 'f'


def ndim(input):
    """Return the number of dimensions of the tensor.

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

    Returns
    -------
    int
        The number of dimensions
    """
    pass


def extract_text_from_doc(doc_path):
    """
    Helper function to extract plain text from .doc files

    :param doc_path: path to .doc file to be extracted
    :return: string of extracted text
    """
    try:
        try:
            import textract
        except ImportError:
            return ' '
        text = textract.process(doc_path).decode('utf-8')
        return text
    except KeyError:
        return ' '


@classmethod
def script(klass, script, interval):
    """
        Run *script* every *interval* (e.g. "10s") to peform health check
        """
    return {'script': script, 'interval': interval}


@classmethod
def record_rename(cls, old_dn, new_dn):
    """Called to indicate a change in DN.

        :param str old_dn: The old DN.

        :param str new_dn: The new DN.

        :return: None - any returned value is ignored.

        This callback happens when an entry's DN changes.

        This callback can happen in all modes, and in all phases, to indicate
        that an entry's DN has been changed.  In refresh-only mode, and the
        refresh phase of refresh-and-perist mode, the change may have taken
        place at any time since your last update.  In the persist phase of
        refresh-and-persist mode, the entry has just changed.

        You should expect a call to
        :meth:`~syncrepl_client.callbacks.BaseCallback.record_change()` shortly
        after this callback completes.
        """
    pass


@staticmethod
def rename_attributes(**kwds):
    """Rename layout attributes.

        In the style dictionary multiple keywords can be used to address
        attributes. These keywords will be converted to an unique key word,
        used in the remaining code.

        ========= =================================
        keys      other valid keys
        ========= =================================
        fixed     fixed_nodes, fixed_vertices,
                  fixed_n, fixed_v
        positions initial_positions, node_positions
                  vertex_positions, n_positions,
                  v_positions
        ========= =================================

        """
    names = {'fixed': ['fixed_nodes', 'fixed_vertices', 'fixed_v',
        'fixed_n'], 'positions': ['initial_positions', 'node_positions',
        'vertex_positions', 'n_positions', 'v_positions'], 'layout_': [
        'layout_']}
    _kwds = {}
    del_keys = []
    for key, value in kwds.items():
        for attr, name_list in names.items():
            for name in name_list:
                if name in key and name[0] == key[0]:
                    _kwds[key.replace(name, attr).replace('layout_', '')
                        ] = value
                    del_keys.append(key)
                    break
    for key in del_keys:
        del kwds[key]
    return {**_kwds, **kwds}


@staticmethod
def get_default_address(address):
    """Class method format default address variable string into regular property address string.

        Args:
            address (srt): default address variable string.

        Returns:
            srt: Regular property address string.

        Example:
            >> _get_default_address('<defaults.dataBase>')
            >> 'defaults.dataBase'
        """
    return address.replace('>', '').replace('<', '')


def generate_status_bar(percent: float, img_size: int):
    """
    take a percent and create a progress bar
    :param percent: percent complete
    :param img_size: size of the image MB
    :return: progress bar
    """
    bar_length = 50
    number_bars = round(int(str(percent).split('.')[0]) / (100 / bar_length))
    progress_bar = '['
    current_write = img_size * (percent / 100)
    for i in range(number_bars):
        if i == number_bars - 1:
            progress_bar += '>'
        else:
            progress_bar += '='
    for i in range(bar_length - number_bars):
        progress_bar += ' '
    return progress_bar + '] ' + str(round(percent)) + '% - ' + str(round(
        current_write)) + '/' + str(img_size) + ' MB Written'


def version_from_string(version_str):
    """ Convert a version string of the form m.n or m.n.o to an encoded version
    number (or None if it was an invalid format).  version_str is the version
    string.
    """
    parts = version_str.split('.')
    if not isinstance(parts, list):
        return None
    if len(parts) == 2:
        parts.append('0')
    if len(parts) != 3:
        return None
    version = 0
    for part in parts:
        try:
            v = int(part)
        except ValueError:
            return None
        version = (version << 8) + v
    return version


def grab_from_import(module, as_from=False):
    """ Used to import a object, class, etc. from a Python module.

        Should be used when you want to do the equivilent of

            from mymodule import someclass

        So you would pass in as the "module" variable:

            grab_from_import('mymodule.someclass', as_from=True)

        If you simply wanted to do the following:

            import mymodule.someclass

        You just pass in:

            grab_from_import('mymodule.someclass')

        The 'default_module' variable will be returned if the
    """
    if not as_from:
        return __import__(module, globals(), locals(), [], -1)
    else:
        _pieces = module.split('.')
        _module = '.'.join(_pieces[:-1])
        _obj = _pieces[-1]
        _temp = __import__(_module, globals(), locals(), [_obj], -1)
        return getattr(_temp, _obj)


def package_root(varmap):
    """Return correct directory for the root package.

    The "root" package is the one where modules which do not
    belong to a package are located (see the distutils docs).
    This function should not need to be called directly in
    your actual setup script, but it can be useful for testing.
    Note that it looks for a ``package_root`` setup var, which
    can be used as a shortcut if your "root" package is not in
    the standard place (which is your setup script directory),
    rather than having to declare a ``package_dir`` dictionary
    with a ``''`` key.
    """
    try:
        return varmap['package_dir']['']
    except KeyError:
        try:
            result = varmap['package_root']
        except KeyError:
            return '.'
        else:
            dirmap = varmap.setdefault('package_dir', {})
            if '' not in dirmap:
                dirmap[''] = result
            return result


def uninstall(context):
    """Uninstall script"""


def add_channel_arguments(parser):
    """Add arguments only used if running mulled over a whole conda channel."""
    parser.add_argument('--repo-data', dest='repo_data', required=True,
        help=
        'Published repository data. If you want to build all containers for bioconda, this parameter needs to be set to "bioconda"'
        )
    parser.add_argument('--diff-hours', dest='diff_hours', default='25',
        help=
        'If finding all recently changed recipes, use this number of hours.')
    parser.add_argument('--recipes-dir', dest='recipes_dir', default=
        './bioconda-recipes')
    parser.add_argument('--force-rebuild', dest='force_rebuild', action=
        'store_true', help='Rebuild package even if already published.')


@classmethod
def set_db(cls, db):
    """
        if you use the set_db_path method in this library then calling set_db on
        each model is unnecessary
        """
    cls.__db = db


def _a_decode_none(stream, offset, count, mapping):
    """
    'a0n',3,0 -> 3,None
    """
    assert count == 0
    return offset, None


@staticmethod
def _pos_isequal(pos, pos2, key_indices):
    """
        Сравнивает две позиции
        :param pos:
        :param pos2:
        :param key_indices:
        :return:
        """
    for i1, i2 in key_indices:
        if pos[i1] != pos2[i2]:
            return False
    return True


@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)


def getTLDs():
    """Return a sequence of ccTLDs and their languages.
        """


def construct_failure_signature(stage_id, test_map):
    """ Old characterize specific ML method """
    signature = ''
    for test_index, document_list in test_map.items():
        signature += str(test_index)
        for document in document_list:
            signature += document[0][0] + document[1] + '|'
    return stage_id, signature


def Nu_Nusselt_Rayleigh_Probert(Pr, Gr, buoyancy=True):
    """Calculates the Nusselt number for natural convection between two
    theoretical flat plates. The height between the plates is infinite, and
    one of the other dimensions of the plates is much larger than the other.

    Two sets of equations are used.

    For the laminar regime :math:`1708 < \\text{Ra} \\le 2.2\\times 10^{4}`:

    .. math::
        \\text{Nu} = 0.208(\\text{Ra})^{0.25}

    For the turbulent regime :math:`2.2\\times 10^{4} < \\text{Ra}`:

    .. math::
        \\text{Nu} = 0.092(\\text{Ra})^{1/3}

    Parameters
    ----------
    Pr : float
        Prandtl number with respect to fluid properties [-]
    Gr : float
        Grashof number with respect to fluid properties and plate - plate
        temperature difference [-]
    buoyancy : bool, optional
        Whether or not the plate's free convection is buoyancy assisted (hot
        plate) or not, [-]

    Returns
    -------
    Nu : float
        Nusselt number with respect to height between the two plates, [-]

    Notes
    -----
    This model is recommended in [2]_ as a rough model.

    For :math:`Ra < 1708`, `Nu` = 1; for cases not assited by `buoyancy`,
    `Nu` is also 1.

    Examples
    --------
    >>> Nu_Nusselt_Rayleigh_Probert(5.54, 3.21e8, buoyancy=True)
    111.46181048289132

    References
    ----------
    .. [1] Probert, SD, RG Brooks, and M Dixon. "Heat Transfer across
       Rectangular Cavities." CHEMICAL AND PROCESS ENGINEERING, 1970, 35.
    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.
       Berlin ; New York: Springer, 2010.
    """
    if not buoyancy:
        return 1.0
    Rac = 1708
    Ra = Gr * Pr
    if Ra < Rac:
        return 1.0
    elif Ra < 22000.0:
        return 0.208 * Ra ** 0.25
    else:
        return 0.092 * Ra ** (1.0 / 3.0)


def getRecord(metadataPrefix, identifier):
    """Get a record for a metadataPrefix and identifier.

        metadataPrefix - identifies metadata set to retrieve
        identifier - repository-unique identifier of record

        Should raise error.CannotDisseminateFormatError if
        metadataPrefix is unknown or not supported by identifier.

        Should raise error.IdDoesNotExistError if identifier is
        unknown or illegal.

        Returns a header, metadata, about tuple describing the record.
        """


def assert_query_has_qmark(query: str, context: str='') ->None:
    """Throws Exception if the query does not contain any question marks."""
    if '?' in query:
        return
    message = ''
    if context:
        message = ' ' + context
    message = (message +
        "Query commands must contain question-marks. Sent query: '{0}'".
        format(query.strip('\n')))
    raise Exception(message)


def hide_tracks(unselected: bool=False):
    """Hide selected tracks

    :param unselected: Unselected, Hide unselected tracks
    :type unselected: bool
    """
    pass


def _apply_rewrites(date_classes, rules):
    """
    Return a list of date elements by applying rewrites to the initial date element list
    """
    for rule in rules:
        date_classes = rule.execute(date_classes)
    return date_classes


def check_is_fitted(is_fitted):
    """Check if the class has been fitted."""
    if not is_fitted:
        raise AttributeError('Run the pipeline before calling this method!')


def rowscols(n, cols=8):
    """divide n things up into rows*columns things"""
    rows, xt = divmod(n, cols)
    if rows == 0:
        rows, cols = 1, xt
    return rows, cols


def url(pattern, handler, kwargs=None, name=None):
    """ Converts parameters to tupple of length four.
        Used for convenience to name parameters and skip
        unused.
    """
    return pattern, handler, kwargs, name


def iterate_time(number_of_timesteps, line):
    """Increases the number of timesteps

    Iterates the number of timesteps and finds the new timestep value.

    Parameters
    ----------
    number_of_timesteps: int
        Number of timesteps found so far.
    line: str
        'TITLE' line from the pdb file which has timestep information.

    Returns
    -------
    int
        Number of timesteps iterated by 1.
    float
        Time of newest timestep.
    """
    number_of_timesteps += 1
    new_time = float(line.split()[-1])
    return number_of_timesteps, new_time


def lambd_NH3_SO3_CB89(T, P):
    """n-a: ammonia sulfite [CB89]."""
    lambd = 0.158
    valid = T == 298.15
    return lambd, valid


def check_wig_includes_zeros(wig_list):
    """Returns boolean list showing whether the given files include empty sites
    (zero) or not.

    Arguments:
        wig_list (list): List of paths to wig files.

    Returns:
        list: List of boolean values.
    """
    if not wig_list:
        return []
    includes = [(False) for i in range(len(wig_list))]
    for i, wig_filename in enumerate(wig_list):
        with open(wig_filename) as wig_file:
            for line in wig_file:
                if line[0] not in '0123456789':
                    continue
                tmp = line.split()
                pos = int(tmp[0])
                rd = float(tmp[1])
                if rd == 0:
                    includes[i] = True
                    break
    return includes


def get_size_of_table(connection: 'Connection', table_name: str,
    table_schema: str) ->int:
    """
    Get the size on disk in bytes of a table in the database.

    Parameters
    ----------
    connection : "Connection"
    table_name : str
        Name of table to get size of
    table_schema : str
        Schema of the table

    Returns
    -------
    int
        Number of bytes on disk this table uses in total

    """
    sql = f"SELECT table_size('{table_name}', '{table_schema}')"
    try:
        return int(connection.fetch(sql)[0][0])
    except IndexError:
        raise ValueError(
            f"Table '{table_schema}.{table_name}' does not exist on this connection."
            )


def legacy_html_escape(s):
    """legacy HTML escape for non-unicode mode."""
    s = s.replace('&', '&')
    s = s.replace('>', '>')
    s = s.replace('<', '<')
    s = s.replace('"', '"')
    s = s.replace("'", ''')
    return s


@staticmethod
def host_halo_selection(return_subhalos=False, **kwargs):
    """ Method divides sample in to host halos and subhalos, and returns
        either the hosts or the hosts and the subs depending
        on the value of the input ``return_subhalos``.
        """
    table = kwargs['table']
    mask = table['halo_upid'] == -1
    if return_subhalos is False:
        return table[mask]
    else:
        return table[mask], table[~mask]


@classmethod
def _get_version(cls):
    """Return VCS program version."""
    return cls._popen(['--version'], merge_err=False)


@staticmethod
def deleteJobTemplate(jobTemplate):
    """
        Deallocate a job template.

        :Parameters:
          jobTemplate : JobTemplate
            the job temptare to be deleted

        This routine has no effect on running jobs.
        """
    jobTemplate.delete()


def bench1_with_time(x):
    """Same as bench1 but returns the computation time (constant)."""
    return x[0] ** 2, 2.22


@classmethod
def create(cls, context):
    """
        创建ys_requests 实例
        :param context:
        :return: 实例对象
        """
    return cls(context)


def _compute_char_shifts(tokens):
    """Compute the shifts in characters that occur when comparing the
    tokens string with the string consisting of all tokens separated with a
    space

    For instance, if "hello?world" is tokenized in ["hello", "?", "world"],
    then the character shifts between "hello?world" and "hello ? world" are
    [0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2]
    """
    characters_shifts = []
    if not tokens:
        return characters_shifts
    current_shift = 0
    for token_index, token in enumerate(tokens):
        if token_index == 0:
            previous_token_end = 0
            previous_space_len = 0
        else:
            previous_token_end = tokens[token_index - 1].end
            previous_space_len = 1
        offset = token.start - previous_token_end - previous_space_len
        current_shift -= offset
        token_len = token.end - token.start
        index_shift = token_len + previous_space_len
        characters_shifts += [current_shift for _ in range(index_shift)]
    return characters_shifts


@classmethod
def global_config(cls, key, *args):
    """ This reads or sets the global settings stored in class.settings. """
    if args:
        cls.settings = cls.settings.copy()
        cls.settings[key] = args[0]
    else:
        return cls.settings[key]


@classmethod
def from_byte_stream(cls, byte_stream, executor, observer=None):
    """Read from a stream of NDJSON bytes.

        Convenience wrapper for `from_lines`.

        :return: An iterator of commands
        :rtype: Iterator[Command]
        """
    return cls.from_lines(cls._bytes_to_lines(byte_stream), executor, observer)


def _to_bytes(str_bytes):
    """Takes UTF-8 string or bytes and safely spits out bytes"""
    try:
        bytes = str_bytes.encode('utf8')
    except AttributeError:
        return str_bytes
    return bytes


@staticmethod
def _norm(pkg_name):
    """Normalized a package name"""
    return str(pkg_name).lower().replace('-', '_').replace('.', '_')


def to_sequence_dict(frame, into=dict):
    """Convert a pandas DataFrame to a dict with sequences as strings."""
    return frame.apply(lambda x: ''.join(x)).to_dict(into=into)


def begin():
    """Explicitly begin and return a new transaction.

        If an existing transaction is in progress and the transaction
        manager not in explicit mode, the previous transaction will be
        aborted.  If an existing transaction is in progress and the
        transaction manager is in explicit mode, an
        `AlreadyInTransaction` exception will be raised..

        The `~ISynchronizer.newTransaction` method of registered synchronizers is called,
        passing the new transaction object.

        Note that when not in explicit mode, transactions may be
        started implicitly without calling `begin`. In that case,
        ``newTransaction`` isn't called because the transaction
        manager doesn't know when to call it.  The transaction is
        likely to have begun long before the transaction manager is
        involved. (Conceivably the `commit` and `abort` methods
        could call `begin`, but they don't.)
        """


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

    The ".dev0" means dirty.

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


def flavor_delete(transport, request, name):
    """Deletes the flavor `name`

    :param transport: Transport instance to use
    :type transport: `transport.base.Transport`
    :param request: Request instance ready to be sent.
    :type request: `transport.request.Request`
    :param name: Flavor reference name.
    :type name: `six.text_type`
    """
    request.operation = 'flavor_delete'
    request.params['flavor_name'] = name
    transport.send(request)


def get_maxrate(ratelimits, size):
    """
    Returns number of requests allowed per second for given size.
    """
    last_func = None
    if size:
        size = int(size)
        for ratesize, rate, func in ratelimits:
            if size < ratesize:
                break
            last_func = func
        if last_func:
            return last_func(size)
    return None


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


@classmethod
def alternate_render(cls, arguments, precedence=None, **kwargs):
    """Return an alternate rendering for a function."""


def extend_env(conn, arguments):
    """
    get the remote environment's env so we can explicitly add the path without
    wiping out everything
    """
    try:
        result = conn.gateway.remote_exec(
            'import os; channel.send(os.environ.copy())')
        env = result.receive()
    except Exception:
        conn.logger.exception(
            'failed to retrieve the remote environment variables')
        env = {}
    path = env.get('PATH', '')
    env['PATH'
        ] = path + '/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin'
    arguments['env'] = env
    if arguments.get('extend_env'):
        for key, value in arguments['extend_env'].items():
            arguments['env'][key] = value
        arguments.pop('extend_env')
    return arguments


def create_pop_count_op(names, op_code, shifts, BW_in, BW_out, module_name,
    reset_name, depth):
    """
    Creates an popcount tree op
    names = [ out_name, a_name, b_name, c_name ]
    op_code = 0 -> - a - b - c
    op_code = 1 -> - a - b + c
    op_code = 2 -> - a + b - c
    op_code = 3 -> - a + b + c
    op_code = 4 ->   a - b - c
    op_code = 5 ->   a - b + c
    op_code = 6 ->   a + b - c
    op_code = 7 ->   a + b + c
    shifts = [ shift_a, shift_b, shift_c ]
    BW_in -> the bitwidth of the input
    BW_out -> the bitwidth of the output
    module_name -> the name to call the adder
    reset_name -> the reset to use, will assert the reset on the cycle before use ( not used in this op )
    depth -> how deep the op is down the tree, inputs have a depth of 0 ( not used in this op )
    """
    assert names[3] == str(BW_out
        ) + "'h0", 'Three inputs not implemented in this adder'
    assert shifts[0] == 0 and shifts[1
        ] == 0, 'Shift registers not implemented in this adder'
    bw = depth + BW_in + 3
    if bw > BW_out:
        bw = BW_out
    op_str = ''
    if depth == 0:
        op_str = ' $signed( '
    op_mod = 4
    for n in names[1:3]:
        if op_code < op_mod:
            op_str += ' - '
        elif op_mod != 4:
            op_str += ' + '
        op_code = op_code % op_mod
        op_mod = op_mod >> 1
        if depth == 0:
            op_str += " { %d'b0, %s } " % (bw - BW_in, n)
        else:
            op_str += '$signed( %s ) ' % n
    if depth == 0:
        op_str += ' )'
    add_op = (
        'reg [%d:0] %s;\nalways @( posedge clock ) begin\n%s <= %s;\nend\n' %
        (bw - 1, names[0], names[0], op_str))
    return add_op, bw


def update_kwargs(kwargs, **keyvalues):
    """Update dict with keys and values if keys do not already exist.

    >>> kwargs = {'one': 1, }
    >>> update_kwargs(kwargs, one=None, two=2)
    >>> kwargs == {'one': 1, 'two': 2}
    True

    """
    for key, value in keyvalues.items():
        if key not in kwargs:
            kwargs[key] = value


def _get_max_word_per_col(csv_dict) ->dict:
    """Computes the maximum word lengthin for each column

    Arguments:
        csv_dict: a dictionary whose keys are column numbers and values are column lists

    Returns:
        word_length_dict: a dictionary whose keys are column numbers and whose values are the maximum word length for that column
    """
    word_length_dict = {}
    for key in csv_dict:
        max_word_length = 0
        for val in csv_dict[key]:
            if len(val) > max_word_length:
                max_word_length = len(val)
        word_length_dict[key] = max_word_length
    return word_length_dict


def is_wms(imagery):
    """Determine if an imagery path is a WMS endpoint"""
    return '{bbox}' in imagery


def location_clear(clear_delta: bool=False):
    """Clear the object’s location

    :param clear_delta: Clear Delta, Clear delta location in addition to clearing the normal location transform
    :type clear_delta: bool
    """
    pass


def is_none(string_: str, default='raise') ->bool:
    """
    Check if a string is equivalent to None.

    Parameters
    ----------
    string_ : str
    default : {'raise', False}
        Default behaviour if none of the "None" strings is detected.

    Returns
    -------
    is_none : bool

    Examples
    --------
    >>> is_none('2', default=False)
    False
    >>> is_none('undefined', default=False)
    True
    """
    none = ['none', 'undefined', 'unknown', 'null', '']
    if string_.lower() in none:
        return True
    elif not default:
        return False
    else:
        raise ValueError("The value '{}' cannot be mapped to none.".format(
            string_))


def freestyle_add_face_marks_to_keying_set():
    """Add the data paths to the Freestyle Face Mark property of selected polygons to the active keying set

    """
    pass


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

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

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


@classmethod
def get_config_opts(cls):
    """Defines the configuration options to be associated to this loadable

        :return: A list of configuration options relative to this Loadable
        :rtype: list of :class:`oslo_config.cfg.Opt` instances
        """
    return []


def _convert_steplist_to_string(step_data):
    """Converts list of step data into a single string.

	Parameters
	----------
	step_data : list
		List of step data

	Returns
	-------
	str
		A space delimited string where every 6th value is followed by a newline.

	"""
    text = ''
    for i, datum in enumerate(step_data):
        if i == 0:
            text += f'\n{datum}\n'
        elif i % 6 == 0:
            text += f'{datum}\n'
        else:
            text += f'{datum} '
    return text


@staticmethod
def _get_context(document):
    """Get context for rendering document."""
    context = document.metadata.copy()
    context['content'] = document.content
    return context


def set_non_empty_attr(element, attribute, value):
    """Set a tag for an XML element if the value is not empty."""
    if value:
        element.set(attribute, value)


def plot(traj, x, y, **kwargs):
    """ Create a matplotlib plot of property x against property y

    Args:
        x,y (str): names of the properties
        **kwargs (dict): kwargs for :meth:`matplotlib.pylab.plot`

    Returns:
        List[matplotlib.lines.Lines2D]: the lines that were plotted

    """
    from matplotlib import pylab
    xl = yl = None
    if type(x) is str:
        strx = x
        x = getattr(traj, x)
        xl = '%s / %s' % (strx, getattr(x, 'units', 'dimensionless'))
    if type(y) is str:
        stry = y
        y = getattr(traj, y)
        yl = '%s / %s' % (stry, getattr(y, 'units', 'dimensionless'))
    plt = pylab.plot(x, y, **kwargs)
    pylab.xlabel(xl)
    pylab.ylabel(yl)
    pylab.grid()
    return plt


def box_aspect(ax, aspect=1):
    """
    Adjust figure size to axes size in inches
    Parameters: aspect: float, optional aspect ratio

    """
    position = ax.get_position()
    fig_width, fig_height = ax.get_figure().get_size_inches()
    fig_aspect = fig_height / fig_width
    pb = position.frozen()
    pb1 = pb.shrunk_to_aspect(aspect, pb, fig_aspect)
    ax.set_position(pb1)


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


@staticmethod
def convert_bool_value_by_string(value: str):
    """
        Returns 0 if value equals 'false', returns 1 if value equals 'true' (case-insensitive).
        In other values, just returns init value
        """
    if value.lower() == 'false':
        return 0
    if value.lower() == 'true':
        return 1
    return value


def deleteObject(cursor, oid_int, tid_int):
    """
        Delete the revision of *oid_int* in transaction *tid_int*.

            This method marks an object as deleted via a new object
            revision. Subsequent attempts to load current data for the
            object will fail with a POSKeyError, but loads for
            non-current data will suceed if there are previous
            non-delete records. The object will be removed from the
            storage when all not-delete records are removed.

            The serial argument must match the most recently committed
            serial for the object. This is a seat belt.

            --- Documentation for ``IExternalGC``

        In history-free databases there is no such thing as a delete record, so
        this should remove the single
        revision of *oid_int* (which *should* be checked to verify it
        is at *tid_int*), leading all access to *oid_int* in the
        future to throw ``POSKeyError``.

        In history preserving databases, this means to set the state for the object
        at the transaction to NULL, signifying that it's been deleted. A subsequent
        pack operation is required to actually remove these deleted items.
        """


def isDirty(ICachableItem):
    """True if cached information requires update for ICachableItem"""


def get_fs(module, blade):
    """Return Filesystem or None"""
    fsys = []
    fsys.append(module.params['name'])
    try:
        res = blade.file_systems.list_file_systems(names=fsys)
        return res.items[0]
    except Exception:
        return None


@classmethod
def is_valid(cls, url):
    """
        Class method to control if passed url is valid for current backend. By
        default it is done by :py:data:`re_detect` regex.

        :type url: str
        """
    return True if cls.re_detect.match(url) else False


def withdraw_version_approval(message):
    """Withdraw a previous request for approval
        Implementation should raise VersioningError, if the
        currently unapproved version has no request for approval yet,
        or if there is no unapproved version.
        """


def main():
    """Perform sanitization checks"""
    pass


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

        :param BinderRemoveSectionDetails val:
        :rtype: EventDetails
        """
    return cls('binder_remove_section_details', val)


def StopExecutionOnFailure(*args, **kwargs):
    """ Stub Anduin function."""
    print('StopExecutionOnFailure', args, kwargs)


def range_n(n, start=0):
    """ Return the sequence [start, start+1, ..., start+N-1]. """
    return list(range(start, start + n))


@classmethod
def isai(cls):
    """Returns true if the class is ai-enabled, False otherwise."""
    return False


def build_dot_value(key, value):
    """Build new dictionaries based off of the dot notation key.

    For example, if a key were 'x.y.z' and the value was 'foo',
    we would expect a return value of: ('x', {'y': {'z': 'foo'}})

    Args:
        key (str): The key to build a dictionary off of.
        value: The value associated with the dot notation key.

    Returns:
        tuple: A 2-tuple where the first element is the key of
            the outermost scope (e.g. left-most in the dot
            notation key) and the value is the constructed value
            for that key (e.g. a dictionary)
    """
    if key.count('.') == 0:
        return key, value
    final_value = value
    reverse_split = key.split('.')[::-1]
    end = len(reverse_split) - 1
    for idx, k in enumerate(reverse_split):
        if idx == end:
            return k, final_value
        final_value = {k: final_value}


def sgd(params, lr, batch_size):
    """Mini-batch stochastic gradient descent."""
    for param in params:
        param[:] = param - lr * param.grad / batch_size


def _shallow_annotate(element, annotations):
    """Annotate the given ClauseElement and copy its internals so that
    internal objects refer to the new annotated object.

    Basically used to apply a "dont traverse" annotation to a
    selectable, without digging throughout the whole
    structure wasting time.
    """
    element = element._annotate(annotations)
    element._copy_internals()
    return element


def search(site, q: str):
    """
        String search query
        """


def example_function(param='param'):
    """
    Prints hello world and returns param.
    Good link on how to write these napolean docs:
    https://sphinxcontrib-napoleon.readthedocs.io/en/latest/

    Parameters
    ----------
    param
        A string to be prtined. Very creative.

    Returns
    -------
    string
        Whatever param is set to.
    """
    print('Hello world')
    return param


def is_iterable(variable):
    """
    Returns True if variable is a list, tuple or any other iterable object
    """
    return hasattr(variable, '__iter__')


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


def merge():
    """ merge/replace the source with the copy, context is the copy.
        """


def get_indent_of_specifier(file, current_line, encapsulators):
    """
    Get indentation of the indent specifer itself.

    :param file:          A tuple of strings.
    :param current_line:  Line number of indent specifier (initial 1)
    :param encapsulators: A tuple with all the ranges of encapsulators
    :return:              Indentation of the specifier.
    """
    start = current_line
    _range = 0
    while _range < len(encapsulators) and encapsulators[_range
        ].end.line <= current_line:
        if current_line == encapsulators[_range].end.line:
            if encapsulators[_range].start.line < start:
                start = encapsulators[_range].start.line
        _range += 1
    return len(file[start - 1]) - len(file[start - 1].lstrip())


def tdiff(date1, date2):
    """ Returns difference ( date1 - date2 ) as a datetime object,
    where date1 and date 2 are datetime objects

    """
    return date1 - date2


@staticmethod
def in_quint(progress):
    """.. image:: images/anim_in_quint.png
        """
    return progress * progress * progress * progress * progress


def json_formatter(obj):
    """Formatter for unserialisable values."""
    return str(obj)


def work(task):
    """Just execute task."""
    return task.execute()


def localDigitsStrToInt(value, digitsToLocalDict, localToDigitsDict):
    """Convert digits to integer."""
    tmp = value.translate(digitsToLocalDict)
    if tmp == value:
        return int(value.translate(localToDigitsDict))
    else:
        raise ValueError('string contains regular digits')


def dict_update_new(target, source, fail=False):
    """Update values in `source` that are new (not present) in `target`.

    If `fail` is True and a value is already set, an error is raised.

    """
    for key in source:
        if key not in target:
            target[key] = source[key]
        elif fail:
            raise TypeError('key "{}" already in target'.format(key))


@classmethod
def put(cls, *args, **kwargs):
    """ Shortcut for creating a PUT update """
    return cls(cls.PUT, *args, **kwargs)


def has_metadata(name):
    """Does the package's distribution contain the named metadata?"""


def read_utf8(fh, byteorder, dtype, count, offsetsize):
    """Read tag data from file and return as unicode string."""
    return fh.read(count).decode('utf-8')


def ilove7(*args):
    """a scalar function"""
    print('ilove7 got', args, 'but I love 7')
    return 7


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

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


def search_menu():
    """Pop-up a search menu over all available operators in current context

    """
    pass


def _truncate_seq_pair(tokens_a, tokens_b, max_length):
    """Truncates a sequence pair in place to the maximum length."""
    while True:
        total_length = len(tokens_a) + len(tokens_b)
        if total_length <= max_length:
            break
        if len(tokens_a) > len(tokens_b):
            tokens_a.pop()
        else:
            tokens_b.pop()


def priority(cls):
    """
        Each backend class must supply a priority, a number (float or integer)
        indicating the priority of the backend relative to all other backends.
        The priority need not be static -- it may (and should) vary based
        attributes of the environment in which is runs (platform, available
        packages, etc.).

        A higher number indicates a higher priority. The priority should raise
        a RuntimeError with a message indicating the underlying cause if the
        backend is not suitable for the current environment.

        As a rule of thumb, a priority between zero but less than one is
        suitable, but a priority of one or greater is recommended.
        """


def getid(obj):
    """
    Abstracts the common pattern of allowing both an object or an object's ID
    as a parameter when dealing with relationships.
    """
    try:
        return obj.id
    except AttributeError:
        return obj


def getCDXJLineClosestTo(datetimeTarget, cdxjLines):
    """ Get the closest CDXJ entry for a datetime and URI-R """
    smallestDiff = float('inf')
    bestLine = None
    datetimeTarget = int(datetimeTarget)
    for cdxjLine in cdxjLines:
        dt = int(cdxjLine.split(' ')[1])
        diff = abs(dt - datetimeTarget)
        if diff < smallestDiff:
            smallestDiff = diff
            bestLine = cdxjLine
    return bestLine


@staticmethod
def cyan(text):
    """ turns text cyan """
    return f'\x1b[36m{text}\x1b[0m'


def PowerStack_Calc(Power, N):
    """
    Calculate power_stack.

    :param Power: single cell power [W]
    :type Power : float
    :param N: number of single cells
    :type N : int
    :return: power stack [W] as float
    """
    try:
        result = N * Power
        return result
    except TypeError:
        print('[Error] Power Stack Calculation Error (Power:%s, N:%s)' % (
            str(Power), str(N)))


def _is_iter(val):
    """Checks if value is a list or tuple"""
    return isinstance(val, tuple) or isinstance(val, list)


def step(f):
    """
    The step decorator. Makes a method a step in the workflow.
    """
    f.is_step = True
    f.decorators = []
    try:
        f.name = f.__name__
    except:
        f.name = f.__func__.func_name
    return f


def import_string(import_name, silent=False):
    """Imports an object based on a string.  This is useful if you want to
    use import paths as endpoints or something similar.  An import path can
    be specified either in dotted notation (``xml.sax.saxutils.escape``)
    or with a colon as object delimiter (``xml.sax.saxutils:escape``).

    If the `silent` is True the return value will be `None` if the import
    fails.

    :return: imported object
    """
    try:
        if ':' in import_name:
            module, obj = import_name.split(':', 1)
        elif '.' in import_name:
            items = import_name.split('.')
            module = '.'.join(items[:-1])
            obj = items[-1]
        else:
            return __import__(import_name)
        return getattr(__import__(module, None, None, [obj]), obj)
    except (ImportError, AttributeError):
        if not silent:
            raise ImportError('Unable to import %s' % import_name)


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

        :param FileResolveCommentType val:
        :rtype: EventType
        """
    return cls('file_resolve_comment', val)


def convert_atype_to_width(atype):
    """Converts an audio type to the number of bytes each value takes.
    params:
        atype: A string, which is an audio type
    return: An integer within 1-4 (inclusive)
    """
    if atype == 'int8':
        return 1
    if atype == 'uint8':
        return 1
    if atype == 'int16':
        return 2
    if atype == 'int24':
        return 3
    if atype == 'float32':
        return 4


def df_count_uniques(data):
    """Returns the number of unique values in the columns of a dataframe"""
    return data.apply(lambda x: len(x.unique()))


def parse_target_pcr_metrics(metrics_report, stats):
    """
    Parse Picard PcrMetrics report file and save relevant data to ``stats``.

    The are only two relevant lines: the one starting with CUSTOM_AMPLICON_SET
    (containing labels) and the next one (containing coresponding values).
    """
    with open(metrics_report) as pcr_metrics:
        for line in pcr_metrics:
            if line.startswith('#'):
                continue
            if line.startswith('CUSTOM_AMPLICON_SET'):
                labels = line.strip().split('\t')
                values = next(pcr_metrics).strip().split('\t')
        for lab, val in zip(labels, values):
            stats[lab] = val


@classmethod
def from_dict(cls, id, name, owner, version, config):
    """Parse the config dict and return a new R2Experiment object.

        :param int id: The id of the experiment from the base config.
        :param str name: The name of the experiment from the base config.
        :param str owner: The owner of the experiment from the base config.
        :param dict config: The "experiment" config dict from the base config.
        :rtype: :py:class:`baseplate.experiments.providers.r2.R2Experiment`
        """
    return cls(id=id, name=name, owner=owner, version=version, variants=
        config['variants'], targeting=config.get('targeting'), overrides=
        config.get('overrides'), seed=config.get('seed'), bucket_val=config
        .get('bucket_val', 'user_id'), newer_than=config.get('newer_than'))