@classmethod
def _new(cls, name, *args, **kwargs):
    """
        User custom instance constructor.

        implement constructor this way::

            def _new(cls, name, *args, **kwargs):
                self = cls.__new__(cls)
                # put __init__(...) logic here
                self.name = name
                return self
        """
    raise NotImplementedError


def toKilometers(x):
    """
    Converts x from Miles to Kilometers
    :param x:
    :return: x * 1.609

    >>> toKilometers(1)
    1.60934
    """
    return x * 1.609


def replace_set_selected():
    """Replace text with specified text and set as selected

    """
    pass


def is_valid_bounding_box(wesn):
    """
    Check if a given bounding box meets the GSHHG conventions.

    :param wesn: bounding box as (west, east, south, north) in [deg]
    """
    w, e, s, n = wesn
    return (w <= e and s <= n and -90.0 <= s <= 90.0 and -90.0 <= n <= 90.0 and
        -180.0 <= w < 360.0 and -180.0 <= e < 360.0)


@classmethod
def add_port(cls, ports, kind='tcp', permanent=True):
    """
        agrega un puerto usando firewall-cmd

        Parameters
        ==========
        ports: str
            formato de puertos puede ser el numero o un rango
            25672, 5671-5672
        kind: str
            tipo del puerto tcp o udp
        permanent: bool
        """
    if not permanent:
        raise NotImplementedError
    else:
        permanent = '--permanent'
    return cls(permanent, '--add-port={}/{}'.format(ports, kind))


def get_rect_ymin(data):
    """Find minimum y value from four (x,y) vertices."""
    return min(data[0][1], data[1][1], data[2][1], data[3][1])


def __iter__():
    """An iterator over all the banned email addresses.

        :return: iterator over `IBan`"""


def SetLogFile(fileName):
    """Setup a file name to log to
    FILE-NAME = string
              The name of a file to log to
    Returns: void

    Sets up a log file.
    """
    global _logfilename


def is_container(obj, classinfo):
    """ 'obj' is an instance of 'classinfo', but is not a 'str' or 'bytes'
        instance. """
    if isinstance(obj, classinfo) and not isinstance(obj, (str, bytes)):
        return True
    return False


def load_10X(data_dir, sparse=True, gene_labels='symbol', allow_duplicates=None
    ):
    """magic.io is deprecated. Please use scprep.io instead.
       Read more at http://scprep.readthedocs.io/
    """
    raise RuntimeError(
        'magic.io is deprecated. Please use scprep.io instead. Read more at http://scprep.readthedocs.io'
        , FutureWarning)


def _revert_alt(keys):
    """TWC automatically changes a-key to a sequence of esc + key, because
    that's how shells work. We have to revert this, because it's internal
    implementation detail."""
    if len(keys) > 1 and keys[0] == 'escape':
        return 'a-{}'.format(''.join(keys[1:]))
    return keys


def convert(name: str) ->str:
    """Convert path name into valid JSON.

    Parameters
    ----------
    name : str
        a path name

    Returns
    -------
    str
        valid JSON path

    """
    if '-' in name or ' ' in name:
        return '["{}"]'.format(name[1:])
    return name


@classmethod
def FromRSAKeyPath(cls, rsa_key_path):
    """Create a :class:`PythonRSASigner` instance using the provided private key.

        Parameters
        ----------
        rsa_key_path : str
            The path to the private key; the public key must be ``rsa_key_path + '.pub'``.

        Returns
        -------
        PythonRSASigner
            A :class:`PythonRSASigner` with private key ``rsa_key_path`` and public key ``rsa_key_path + '.pub'``

        """
    with open(rsa_key_path + '.pub') as f:
        pub = f.read()
    with open(rsa_key_path) as f:
        priv = f.read()
    return cls(pub, priv)


def extract_aa_pos_from_sample_names(df_with_sn_as_index, start_aa, end_aa,
    newcol_name):
    """Extract the amino acid position from sample names in the index of a dataframe.

    Note this cannot be used if the data contains double-mutants. Consider using a dictionary approach instead.

    Parameters
    ----------
    df_with_sn_as_index : dataframe with the sample name as the index
        Dataframe to be altered, will be returned with the new column
    start_aa : int, starting amino acid in range of amino acids mutated
        UniProt style, NOT python indexing style
    end_aa : int, end amino acid in range of amino acids mutated
        UniProt style where the number is the last aa to be included, NOT python indexing style
    newcol_name : name of the new column containing the index

    Returns
    -------
    df_with_sn_as_index : original dataframe, with the new column
    """
    for i in range(start_aa, end_aa + 1):
        for sn in df_with_sn_as_index.index:
            if str(i) in sn:
                df_with_sn_as_index.loc[sn, newcol_name] = i


def cp2np(u):
    """Identity function."""
    return u


def __repr__(A):
    """For `print` and `pprint`"""
    return A.to_str()


def format_log_context(msg, connection=None, keyspace=None):
    """Format log message to add keyspace and connection context"""
    connection_info = connection or 'DEFAULT_CONNECTION'
    if keyspace:
        msg = '[Connection: {0}, Keyspace: {1}] {2}'.format(connection_info,
            keyspace, msg)
    else:
        msg = '[Connection: {0}] {1}'.format(connection_info, msg)
    return msg


@classmethod
def find(cls, *args, **kw):
    """Query the collection this class is bound to.

		Additional arguments are processed according to `_prepare_find` prior to passing to PyMongo, where positional
		parameters are interpreted as query fragments, parametric keyword arguments combined, and other keyword
		arguments passed along with minor transformation.

		https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.find
		"""
    Doc, collection, query, options = cls._prepare_find(*args, **kw)
    return collection.find(query, **options)


def multiindex_dataframe_from_tuple_map(x, labels):
    """ Create pandas.DataFrame from map of param-tuple -> value

    :param x: map of parameter-tuple -> value pairs
    :type x: dict
    :param labels: list of item labels
    :type labels: list
    :returns: DataFrame object
    :rtype: pandas.DataFrame

    """
    import pandas as pd
    k, v = zip(*[(k, v) for k, v in x.iteritems()])
    i = pd.MultiIndex.from_tuples(k, names=labels)
    return pd.DataFrame(list(v), index=i)


def spec_to_group_name(spec):
    """Return a name that can be used as a NuSMV identifier, based on spec."""
    return 'spec' + str(spec).replace(' ', '_').replace(',', '_').replace('&',
        'and').replace('|', 'or').replace('<', '').replace('>', '').replace('~'
        , '').replace("'", '').replace('=', '').replace('(', '').replace(')',
        '').replace('[', '').replace(']', '').replace('!', '')


@staticmethod
def conj(x, *args, **kwargs):
    """WARNING: IDENTITY FUNCTION (does nothing)

            This backend currently does not support complex tensors
        """
    return x


def _is_dunder(name):
    """Returns True if name is a __dunder_variable_name__."""
    return len(name) > 4 and name.startswith('__') and name.endswith('__')


@staticmethod
def _get_data_format_size(data_format):
    """
        ### get_data_format() ###

        Getter for frame data format.

        **Params:**

        * ``data_format`` **(bytes)** - Data format in data frames. Should be 16-bit flag.

        **Returns:**

        * ``dict`` with PHASOR, ANALOG, and FREQ measurement size in bytes.
        ``{'phasor' : phasors_byte_size, 'analog' : analog_byte_size, 'freq' : freq_byte_size}``

        """
    if data_format & 2 != 0:
        phasors_byte_size = 8
    else:
        phasors_byte_size = 4
    if data_format & 4 != 0:
        analog_byte_size = 4
    else:
        analog_byte_size = 2
    if data_format & 8 != 0:
        freq_byte_size = 4
    else:
        freq_byte_size = 2
    return {'phasor': phasors_byte_size, 'analog': analog_byte_size, 'freq':
        freq_byte_size}


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 __test_isfir(gorig, M):
    """ Internal function that tests if original window is FIR.

    Dual window is FIR if length of the original window is <= M. This is true
    if the length was not explicitly defined and gorig is a string.

    - Input parameters:

    :param gorig: window parameters
    :type gorig: dict (with parameters of the window as keywords)
    :param int M: the number of channels.

    - Output parameters:

    :rtype: boolean
    """
    if isinstance(gorig, dict) and gorig:
        if 'M' in gorig and gorig['M'] <= M:
            return True
    if isinstance(gorig, str):
        return True
    return False


@classmethod
def _write_inittab(cls, f, inittab, c_inittab, py_version):
    """ Write the Python version specific extension module inittab. """
    if py_version >= 196608:
        init_type = 'PyObject *'
        init_prefix = 'PyInit_'
    else:
        init_type = 'void '
        init_prefix = 'init'
    sorted_inittab = sorted(inittab)
    for name in sorted_inittab:
        base_name = name.split('.')[-1]
        f.write('extern "C" %s%s%s(void);\n' % (init_type, init_prefix,
            base_name))
    f.write('\nstatic struct _inittab %s[] = {\n' % c_inittab)
    for name in sorted_inittab:
        base_name = name.split('.')[-1]
        f.write('    {"%s", %s%s},\n' % (name, init_prefix, base_name))
    f.write('    {NULL, NULL}\n};\n')


def get_arxiv_csl_item_zotero(arxiv_id):
    """
    Generate CSL JSON Data for an arXiv ID using Zotero's translation-server.
    """
    from manubot.cite.zotero import get_csl_item
    return get_csl_item(f'arxiv:{arxiv_id}')


@classmethod
def from_string(cls, string):
    """
        Instantiates a pred from a string, normalising as necessary
        """
    normalised = cls.normalise_string(string)
    return cls.from_normalised_string(normalised)


def p_global_var_list(p):
    """global_var_list : global_var_list COMMA global_var
                       | global_var"""
    if len(p) == 4:
        p[0] = p[1] + [p[3]]
    else:
        p[0] = [p[1]]


@classmethod
def is_datasource_for(cls, data, header, **kwargs):
    """Determines if header corresponds to an HMI image"""
    return str(header.get('instrume', '')).startswith('HMI')


def is_table(engine, sql):
    """ Check with the given sql arg is query or table

    Args:
        engine: SQLAlchemy connection engine
        sql: SQL query or table name

    Returns:
        True for table or False if not
    """
    if engine.dialect.has_table(engine, sql):
        return True
    return False


def largura_imagem(img):
    """
    Retorna a largura da imagem
    :param img: Imagem
    :return: Int
    """
    return img.get_width()


def render_layer_remove():
    """Remove the selected render layer

    """
    pass


@classmethod
def from_json(cls, _json, project):
    """
        Build a TimeSeries entity object from a json

        :param _json: _json response from host
        :param project: project id
        :return: Time Series object
        """
    return cls(createdAt=_json.get('createdAt', None), updatedAt=_json.get(
        'updatedAt', None), owner=_json.get('owner', None), name=_json.get(
        'name', None), id=_json.get('id', None), project=project)


def _gf_div(f, g, p):
    """
    Compute `\\frac f g` modulo `p` for two univariate polynomials over
    `\\mathbb Z_p`.

    """
    ring = f.ring
    dom = ring.domain
    domp = dom.finite_field(p)
    f, g = map(lambda x: x.set_domain(domp), (f, g))
    return tuple(map(lambda x: x.set_domain(dom), divmod(f, g)))


def policy_error_scope(error, data):
    """Scope a schema error to its policy name and resource."""
    err_path = list(error.absolute_path)
    if err_path[0] != 'policies':
        return error
    pdata = data['policies'][err_path[1]]
    pdata.get('name', 'unknown')
    error.message = 'Error on policy:{} resource:{}\n'.format(pdata.get(
        'name', 'unknown'), pdata.get('resource', 'unknown')) + error.message
    return error


def _get_reporoot():
    """Returns the absolute path to the repo root directory on the current
    system.
    """
    from os import path
    import acorn
    medpath = path.abspath(acorn.__file__)
    return path.dirname(path.dirname(medpath))


def is_valid(key):
    """check key if is valid"""
    if key is not None and key != '':
        return True
    return False


def fly():
    """Interactively fly around the scene

    """
    pass


def to_joules(ujoules):
    """ Converts from microjoules to joules """
    return ujoules * 10 ** -6


@classmethod
def create_pixelpin_auth(cls, user, uid, provider):
    """Create a UserPixelpinAuth instance for given user"""
    raise NotImplementedError('Implement in subclass')


def create_listlike_dataset(py_obj, h_group, call_id=0, **kwargs):
    """ Dumper for list, set, tuple

    Args:
        py_obj: python object to dump; should be list-like
        h_group (h5.File.group): group to dump data into.
        call_id (int): index to identify object's relative location in the iterable.
    """
    dtype = str(type(py_obj))
    obj = list(py_obj)
    d = h_group.create_dataset('data_%i' % call_id, data=obj, **kwargs)
    d.attrs['type'] = [dtype]


def broadcast_maximum(lhs=None, rhs=None, name=None, attr=None, out=None,
    **kwargs):
    """Returns element-wise maximum of the input arrays with broadcasting.

    This function compares two input arrays and returns a new array having the element-wise maxima.

    Example::

       x = [[ 1.,  1.,  1.],
            [ 1.,  1.,  1.]]

       y = [[ 0.],
            [ 1.]]

       broadcast_maximum(x, y) = [[ 1.,  1.,  1.],
                                  [ 1.,  1.,  1.]]

    Defined in src/operator/tensor/elemwise_binary_broadcast_op_extended.cc:L81

    Parameters
    ----------
    lhs : Symbol
        First input to the function
    rhs : Symbol
        Second input to the function

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

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


def _simplify_dfas(dfas):
    """
    This is not theoretically optimal, but works well enough.
    Algorithm: repeatedly look for two states that have the same
    set of arcs (same labels pointing to the same nodes) and
    unify them, until things stop changing.

    dfas is a list of DFAState instances
    """
    changes = True
    while changes:
        changes = False
        for i, state_i in enumerate(dfas):
            for j in range(i + 1, len(dfas)):
                state_j = dfas[j]
                if state_i == state_j:
                    del dfas[j]
                    for state in dfas:
                        state.unifystate(state_j, state_i)
                    changes = True
                    break


def list_available_zones():
    """
    Lists the Availability Zones that have available AWS CloudHSM capacity.
    See also: AWS API Documentation

    :example: response = client.list_available_zones()

    :rtype: dict
    :return: {
        'AZList': [
            'string',
        ]
    }

    """
    pass


def html_escape(string):
    """ Escape HTML special characters ``&<>`` and quotes ``'"``. """
    return string.replace('&', '&').replace('<', '<').replace('>',
        '>').replace('"', '"').replace("'", ''')


def array_copy(data: (bytes or bytearray), data_index: int, bs: (bytes or
    bytearray), bs_index: int, length: int):
    """从bs的bs_index开始取长度为le的数据写入到data的data_index位置"""
    data[data_index:data_index + length] = bs[bs_index:bs_index + length]


def set_auto_forward(auto):
    """Set the default mode for automatic forward propagation.

    When it is set to `True` , forward propagation is invoked immediately when the computation graph
    is updated.

    Args:
        auto (bool): Whether forward computation is executed when the
            computation graph is updated.

    Returns: bool
    """
    global __auto_forward_state
    __auto_forward_state = auto


def brightness(new_brightness):
    """Set the display brightness between 0.0 and 1.0.
        :param new_brightness: Brightness from 0.0 to 1.0 (default 1.0)"""
    global _brightness
    if new_brightness > 1 or new_brightness < 0:
        raise ValueError('Brightness level must be between 0 and 1')
    _brightness = new_brightness


def _check_test_parameter(parameters, par_name):
    """
    Function to check if the parameter_name(par_name) is on the parameter's keys

    :param parameters: Parameters send in looq_test_question
    :param par_name: Desire name to be found in key
    :return: The value of the par_name in parameter or None
    """
    par_return = None
    if hasattr(parameters, par_name):
        par_return = parameters[par_name]
    return par_return


def slicelist(b):
    """Produce a list of slices given the boolean array b.

    Start and stop in each slice describe the True sections in b."""
    slicelst = []
    started = False
    for i, e in enumerate(b):
        if e and not started:
            start = i
            started = True
        elif not e and started:
            slicelst.append(slice(start, i))
            started = False
    if e:
        slicelst.append(slice(start, i + 1))
    return slicelst


@classmethod
def disableLogOutput(cls):
    """Disables the :class:`logging.StreamHandler` which dumps log records,
           by default, to the stderr.
        """
    cls.initRoot().removeHandler(cls.stream_handler)


def ondrag(gr, ev):
    """Move a Graphic instance while dragging"""
    pos = gr.pos
    dp = ev.rel
    gr.pos = pos[0] + dp[0], pos[1] + dp[1]


@classmethod
def from_api_response(cls, reddit_session, json_dict):
    """Return an instance of the appropriate class from the json_dict."""
    return cls(reddit_session, json_dict=json_dict)


@classmethod
def values(cls):
    """The constants of this enum type, in the order they are declared."""
    return cls._values


def get_service_type(f):
    """Retrieves service type from function."""
    return getattr(f, 'service_type', None)


def _get_block_length(lines, k):
    """ Calculates the length (in number of lines) of a edit of added/deleted lines starting in a
        given line k.

    Args:
        lines: dictionary of added or deleted lines
        k: line number to check for

    Returns:
        block_size: number of lines in the contiguously block that was modified
    """
    if k not in lines or k > 1 and k - 1 in lines:
        edit = False
        block_size = 0
    else:
        edit = True
        block_size = 1
    while edit:
        if k + block_size in lines:
            block_size += 1
        else:
            edit = False
    return block_size


@classmethod
def _new2(cls, *args, **kwargs):
    """Bypass sympy `_new` that hard codes `Matrix.__new__` to call our own."""
    return cls.__new__(cls, *args, **kwargs)


def levenshtein_2d_blocks(string, transpositions=False, flag1='\x00', flag2
    ='\x01', flag3='\x02'):
    """
    Function returning the minimal set of longest Levenshtein distance <= 2
    blocking keys of target string. Note that this method is basically a
    generalization of the `levensthein_1d_blocks` scheme.

    Args:
        string (str): Target string.
        transpositions (bool, optional): Whether to support transpositions
            like with the Damerau-Levenshtein distance. Defaults to False.

    Returns:
        tuple: Resulting blocks.

    """
    n = len(string)
    q = n % 3
    if q == 0:
        h = n // 3
        basic = flag1 + string[:h], flag2 + string[h:h * 2], flag3 + string[
            h * 2:]
        if transpositions:
            h1 = h - 1
            return basic + (flag1 + string[:h1] + string[h], flag2 + string
                [h1] + string[h + 1:h * 2], flag3 + string[h * 2 - 1] +
                string[h * 2 + 1:])
        return basic
    elif q == 2:
        h1 = n // 3
        h = h1 + 1
        return flag1 + string[:h], flag2 + string[h:h * 2], flag3 + string[
            h * 2:], flag1 + string[:h1], flag2 + string[h1:h + h1
            ], flag3 + string[h + h1:], flag2 + string[h:h + h1]
    elif q == 1:
        h1 = n // 3
        h = h1 + 1
        return flag1 + string[:h], flag2 + string[h:h + h1], flag3 + string[
            h + h1:], flag1 + string[:h1], flag2 + string[h1:h1 + h
            ], flag2 + string[h1:h1 * 2], flag3 + string[h1 * 2:]


def dd2dms(dd):
    """Convert decimal degrees to degrees, minutes, seconds
    """
    n = dd < 0
    dd = abs(dd)
    m, s = divmod(dd * 3600, 60)
    d, m = divmod(m, 60)
    if n:
        d = -d
    return d, m, s


@classmethod
def decode_canonical(cls, input):
    """IMPORTANT: this is class method, override it with @classmethod!"""
    pass


def populate_obj(obj, attrs):
    """Populates an object's attributes using the provided dict
    """
    for k, v in attrs.iteritems():
        setattr(obj, k, v)


def get_keywords():
    """Get the keywords needed to look up the version information."""
    git_refnames = '$Format:%d$'
    git_full = '$Format:%H$'
    git_date = '$Format:%ci$'
    keywords = {'refnames': git_refnames, 'full': git_full, 'date': git_date}
    return keywords


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 _different_coordinates(row_i, row_j):
    """
    Return True if the coordinates values are different.

    Genomic coordinates values are only compared when end and start phases
    are not -1. Phase -1 can be present because of UTR regions, which could
    have different genomic coordinates, but still have the same protein
    sequence.
    """
    if row_i['StartPhase'] != -1 and row_j['StartPhase'] != -1:
        if row_i['GenomicCodingStart'] != row_j['GenomicCodingStart']:
            return True
    if row_i['EndPhase'] != -1 and row_j['EndPhase'] != -1:
        if row_i['GenomicCodingEnd'] != row_j['GenomicCodingEnd']:
            return True
    return False


def _find_metadata(file_alf):
    """
    Loof for an existing meta-data file for an alf_file
    :param file_alf: PurePath of existing alf file
    :return: PurePath of meta-data if exists
    """
    ns, obj = file_alf.name.split('.')[:2]
    meta_data_file = list(file_alf.parent.glob(f'{ns}.{obj}*.metadata*.json'))
    if meta_data_file:
        return meta_data_file[0]


def get_directory_name() ->str:
    """
    Returns: Name of geodata data directory where geonames.org files are
    """
    return 'geoname_data'


def write_filter_file(filename, filter):
    """
    Outputs cluster assignments to a file

    :param filename: String
        File to be written
    :param filter: set(String)
        Set of gene names included in the filter

    """
    with open(filename, 'w') as fout:
        fout.write('\t'.join(filter) + '\n')


def _is_plottable(structure):
    """ Determines if a PDS4 structure is plottable.

    Plottable structures are either:
        (1) 1D arrays, or
        (2) Tables

    Parameters
    ----------
    structure : Structure
        PDS4 structure to check.

    Returns
    -------
    bool
        True if *structure* can be plotted, False otherwise.
    """
    plottable = False
    if structure.is_table():
        plottable = True
    elif structure.is_array() and structure.meta_data.num_axes() == 1:
        plottable = True
    return plottable


def get_schema():
    """Schema structure of this resource

    :return: schema dictionary
    :rtype: dict
    """
    return {'schema': {'schema_version': {'type': 'integer', 'default': 1},
        'imported_from': {'schema_version': 1, 'title': 'Imported from',
        'comment': 'Item importation source (alignak-backend-import, ...)',
        'type': 'string', 'default': 'unknown'}, 'definition_order': {
        'schema_version': 1, 'title': 'Definition order', 'comment':
        'Priority level if several elements have the same name', 'type':
        'integer', 'default': 100}, 'first_notification': {'schema_version':
        1, 'title': 'First notification count', 'comment':
        'Nagios legacy. Number of the first notification this escalation will be used. **Note** that this property will be deprecated in favor of the ``first_notification_time``.'
        , 'type': 'integer'}, 'last_notification': {'schema_version': 1,
        'title': 'Last notification count', 'comment':
        'Nagios legacy. Number of the last notification this escalation will not be used anymore. **Note** that this property will be deprecated in favor of the ``last_notification_time``.'
        , 'type': 'integer'}, 'name': {'schema_version': 1, 'title':
        'Host escalation name', 'comment': 'Unique host escalation name',
        'type': 'string', 'required': True, 'empty': False, 'unique': True},
        'alias': {'schema_version': 1, 'title': 'Alias', 'comment':
        'Element friendly name used by the Web User Interface.', 'type':
        'string', 'default': ''}, 'notes': {'schema_version': 1, 'title':
        'Notes', 'comment':
        'Element notes. Free text to store element information.', 'type':
        'string', 'default': ''}, 'hosts': {'schema_version': 1, 'title':
        'Hosts', 'comment':
        'List of the hosts concerned by the escalation.', 'type': 'list',
        'schema': {'type': 'objectid', 'data_relation': {'resource': 'host',
        'embeddable': True}}}, 'hostgroups': {'schema_version': 1, 'title':
        'Hosts groups', 'comment':
        'List of the hosts groups concerned by the escalation.', 'type':
        'list', 'schema': {'type': 'objectid', 'data_relation': {'resource':
        'hostgroup', 'embeddable': True}}}, 'first_notification_time': {
        'schema_version': 1, 'title': 'First notification time', 'comment':
        'Duration in minutes before sending the first escalated notification.',
        'type': 'integer', 'default': 60}, 'last_notification_time': {
        'schema_version': 1, 'title': 'Last notification time', 'comment':
        'Duration in minutes before sending the last escalated notification. Escalated notifications will be sent-out between the first_notification_time and last_notification_time period.'
        , 'type': 'integer', 'default': 240}, 'escalation_period': {
        'schema_version': 1, 'title': 'Escalation time period', 'comment':
        'No escalation notifications will be sent-out except during this time period.'
        , 'type': 'objectid', 'data_relation': {'resource': 'timeperiod',
        'embeddable': True}}, 'escalation_options': {'schema_version': 1,
        'title': 'Escalation options', 'comment':
        'List of the notifications types this escalation is concerned with. This escalation will be used only if the host is in one of the states specified in this property.'
        , 'type': 'list', 'default': ['d', 'x', 'r'], 'allowed': ['d', 'x',
        'r']}, 'notification_interval': {'schema_version': 1, 'title':
        'Notifications interval', 'comment':
        'Number of minutes to wait before re-sending the escalated notifications if the problem is still present. If you set this value to 0, only one notification will be sent out.'
        , 'type': 'integer', 'default': 60}, 'users': {'schema_version': 1,
        'title': 'Escalation users', 'comment':
        'List of the users concerned by this escalation.', 'type': 'list',
        'schema': {'type': 'objectid', 'data_relation': {'resource': 'user',
        'embeddable': True}}}, 'usergroups': {'schema_version': 1, 'title':
        'Escalation users groups', 'comment':
        'List of the users groups concerned by this escalation.', 'type':
        'list', 'schema': {'type': 'objectid', 'data_relation': {'resource':
        'usergroup', 'embeddable': True}}}, '_realm': {'schema_version': 1,
        'title': 'Realm', 'comment': 'Realm this element belongs to.',
        'type': 'objectid', 'data_relation': {'resource': 'realm',
        'embeddable': True}, 'required': True}, '_sub_realm': {
        'schema_version': 1, 'title': 'Sub-realms', 'comment':
        'Is this element visible in the sub-realms of its realm?', 'type':
        'boolean', 'default': True}, '_users_read': {'schema_version': 1,
        'type': 'list', 'schema': {'type': 'objectid', 'data_relation': {
        'resource': 'user', 'embeddable': True}}}, '_users_update': {
        'schema_version': 1, 'type': 'list', 'schema': {'type': 'objectid',
        'data_relation': {'resource': 'user', 'embeddable': True}}},
        '_users_delete': {'schema_version': 1, 'type': 'list', 'schema': {
        'type': 'objectid', 'data_relation': {'resource': 'user',
        'embeddable': True}}}}, 'schema_deleted': {}}


@staticmethod
def add_default_params(params: dict, payload: dict):
    """
			Ajoute les paramètres par défaut à la charge utile et retourne le résultat.
		"""
    _dict = {}
    for key in params:
        if 'value' in params[key]:
            _dict.update({key: params[key]['value']})
    _dict.update(payload)
    return _dict


def create_adjancency_matrix(db, save_folder='../../data/interim/',
    num_orders=10):
    """
    Create and save a weighted adjacency matrix of the instacart database.

    Args:
        db (Database): The connected instacart database.
        save_folder (str, optional): File location to save the data to. Defaults
            to "../../data/interim/".
        num_orders (int, optional): The number of orders to get interactions from.
            Defaults to 10.

    Raises:
        TypeError: If the number of orders is not an int.
    """
    if not isinstance(num_orders, int):
        raise TypeError('Number of orders must be of type int.')
    query_string = (
        """
        SELECT
            CAST (o.user_id AS INTEGER),
            p.product_id,
            COUNT(p.product_id) AS weight
        FROM
            order_products__prior as p
        INNER JOIN
            (
                SELECT
                    order_id,
                    user_id
                FROM
                    orders
                WHERE
                    eval_set='prior'
                LIMIT
                    {}
            ) AS o
        ON
            o.order_id=p.order_id
        GROUP BY
            o.user_id, p.product_id
        ;
        """
        .format(num_orders))
    df = db.get_dataframe(query_string)
    df.to_csv(save_folder + 'weighted_adjacency_matrix_{}_orders.csv'.
        format(num_orders), index=False)
    prior_orders_query = (
        """
        SELECT
            o.user_id, p.product_id,
            products.department_id, products.aisle_id,
            p.order_id, p.add_to_cart_order,
            p.reordered, o.order_number,
            o.order_dow, o.order_hour_of_day,
            CAST (o.days_since_prior AS INTEGER)
        FROM
            order_products__prior AS p
        INNER JOIN
        (
            SELECT
                user_id, order_id, order_number,
                order_dow, order_hour_of_day,
                days_since_prior
            FROM
                orders
            WHERE
                order_id IN
                (
                    SELECT
                        DISTINCT order_id
                    FROM
                        orders
                    WHERE
                        eval_set='prior'
                    LIMIT
                        {}
                )
        ) AS o
        ON
            o.order_id=p.order_id
        INNER JOIN
            products
        ON
            products.product_id=p.product_id
        ;
    """
        .format(num_orders))
    df = db.get_dataframe(prior_orders_query)
    df.to_csv(save_folder + 'full_info_{}_prior_orders.csv'.format(
        num_orders), index=False)
    db.close()


@classmethod
def year_from_isodate(cls, date):
    """Return just the year portion of an ISO8601 date.  Expects
        a string, returns an integer"""
    return int(date.split('-')[0])


def mask_hash(hash, show=6, char='*'):
    """
    Return the given hash, with only the first ``show`` number shown. The
    rest are masked with ``char`` for security reasons.
    """
    masked = hash[:show]
    masked += char * len(hash[show:])
    return masked


@classmethod
def decode(cls, val):
    """Creates Integer object from any int-convertible object val.

        >>> Integer[8].decode(0xffff)
        Integer[8](255)
        """
    return cls(int(val))


def prepends(file, pre, suf):
    """
    Check if filename starts with/ends with stuff.

    :param file: File to check.
    :type file: str

    :param pre: Prefix(es) to check.
    :type pre: str or list or tuple

    :param suf: Suffix(es) to check.
    :type suf: str or list or tuple
    """
    return file.startswith(pre) and file.endswith(suf)


def check_ethinca_against_bank_params(ethincaParams, metricParams):
    """
    Cross-check the ethinca and bank layout metric calculation parameters
    and set the ethinca metric PN order equal to the bank PN order if not
    previously set.

    Parameters
    ----------
    ethincaParams: instance of ethincaParameters
    metricParams: instance of metricParameters
    """
    if ethincaParams.doEthinca:
        if metricParams.f0 != metricParams.fLow:
            raise ValueError(
                'If calculating ethinca metric, f0 and f-low must be equal!')
        if (ethincaParams.fLow is not None and ethincaParams.fLow !=
            metricParams.fLow):
            raise ValueError(
                'Ethinca metric calculation does not currently support a f-low value different from the bank metric!'
                )
        if ethincaParams.pnOrder is None:
            ethincaParams.pnOrder = metricParams.pnOrder
    else:
        pass


def _get2DArea(box):
    """Get area of a 2D box"""
    return (box['right'] - box['left']) * (box['bottom'] - box['top'])


def auth_url_uk():
    """Return the Rackspace Cloud UK Auth URL"""
    return 'https://lon.identity.api.rackspacecloud.com/v2.0/'


def get_ip_port_dict_list(ip_list, port_list):
    """Convert as ip | port dict list
    """
    targets = []
    for ip in ip_list:
        for port in port_list:
            targets.append({'host': ip, 'port': port})
    return targets


def irange(start, stop, step=1):
    """
    Iterate over all values greater or equal than `start` and less than `stop`.
    (Or the reverse, if `step < 0`.)

    Example::

      >>> list(irange(1, 5))
      [1, 2, 3, 4]
      >>> list(irange(0, 8, 3))
      [0, 3, 6]
      >>> list(irange(8, 0, -2))
      [8, 6, 4, 2]

    Unlike the built-in `range` function, `irange` also accepts
    floating-point values::

      >>> list(irange(0.0, 1.0, 0.5))
      [0.0, 0.5]

    Also unlike the built-in `range`, *both* `start` and `stop` have
    to be specified::

      >>> try:
      ...   irange(42)
      ... except TypeError:
      ...   print("missing required argument!")
      missing required argument!

    Of course, a null `step` is not allowed::

      >>> try:
      ...   list(irange(1, 2, 0))
      ... except AssertionError as err:
      ...   assert 'Null step in irange.' in str(err)
    """
    assert float(step) != 0.0, 'Null step in irange.'
    value = start
    if step > 0:
        while value < stop:
            yield value
            value += step
    else:
        while value > stop:
            yield value
            value += step


def _constrainTriclinic(lattice):
    """Make constraints for Triclinic systems.

    """
    return


def update_package_data(distribution):
    """update build_py options to get package_data changes"""
    build_py = distribution.get_command_obj('build_py')
    build_py.finalize_options()


def _write_clusters(fname, cluster_lookup, order):
    """ Writes the cluster lookup to file """
    fmt = '{}' + ' {}' * order
    with open(fname, 'w') as f:
        f.write(str(len(cluster_lookup)) + '\n\n')
        for c, i in cluster_lookup.items():
            line = fmt.format(*c, i) + '\n'
            f.write(line)


def delete_group(GroupName=None):
    """
    Deletes the specified IAM group. The group must not contain any users or have any attached policies.
    See also: AWS API Documentation

    :example: response = client.delete_group(
        GroupName='string'
    )

    :type GroupName: string
    :param GroupName: [REQUIRED]
            The name of the IAM group to delete.
            This parameter allows (per its regex pattern ) a string of characters consisting of upper and lowercase alphanumeric characters with no spaces. You can also include any of the following characters: =,.@-

    """
    pass


def cfile(file_path, body=None, modify_type='w'):
    """
    Create a file. By default, it creates an empty file.
    file_path = Absolute file path to the file you want to create
    body (optional) = String to write in the file
    modify_type (optional) = a to append, w to overwrite ect.
    """
    from pathlib import Path
    Path(file_path).touch()
    if not body == None:
        with open(file_path, modify_type) as cfileF:
            cfileF.write(body)


def graph_to_json(graph):
    """Create a JSON representation of a graph."""
    j_data = graph.to_json()
    return j_data


def _tabulate_dofs(ir):
    """Generate code for tabulate_dofs."""
    add = format['addition']
    iadd = format['iadd']
    multiply = format['multiply']
    assign = format['assign']
    component = format['component']
    entity_index = format['entity index']
    num_entities_format = format['num entities']
    unsigned_int = format['uint declaration']
    dofs_variable = format['argument dofs']
    if ir is None:
        return assign(component(dofs_variable, 0), 0)
    dofs_per_element, num_dofs_per_element, need_offset, fakes = ir
    code = []
    offset_name = '0'
    if need_offset:
        offset_name = 'offset'
        code.append(format['declaration'](unsigned_int, offset_name, 0))
    i = 0
    for no, num_dofs in enumerate(dofs_per_element):
        if fakes[no] and num_dofs_per_element[no] == 1:
            code.append(assign(component(dofs_variable, i), offset_name))
            if offset_name != '0':
                code.append(iadd(offset_name, 1))
            i += 1
            continue
        for dim, num in enumerate(num_dofs):
            if not num[0]:
                continue
            for k, dofs in enumerate(num):
                v = multiply([len(num[k]), component(entity_index, (dim, k))])
                for j, dof in enumerate(dofs):
                    value = add([offset_name, v, j])
                    code.append(assign(component(dofs_variable, dof + i),
                        value))
            if need_offset:
                addition = multiply([len(num[0]), component(
                    num_entities_format, dim)])
                code.append(iadd('offset', addition))
        i += num_dofs_per_element[no]
    return '\n'.join(code)


def _field_name(name, prefix=None):
    """
    Util for quick prefixes

    >>> _field_name(1)
    '1'
    >>> _field_name("henk")
    'henk'
    >>> _field_name("henk", 1)
    '1henk'
    """
    if prefix is None:
        return str(name)
    return '%s%s' % (prefix, name)


def create_relationship_dict(field):
    """Creates a relationship dict for imports and suggests

    :param: field: string for the field name
    :return: relationship dict with name of package as key
    and version number as value
    """
    relationship = field.relationships
    package_dict = {}
    for i in relationship:
        version = ''
        if hasattr(i, 'version'):
            version = i.version
        package_dict[i.name] = version
    return package_dict


def list_for_tag(tags, tag):
    """Takes a tags object as returned by read_tags and a tag name,
    returns a set of all the resources which have that tag."""
    rv = set()
    for f in tags.keys():
        if tag in tags[f]:
            rv.add(f)
    return rv


def compoundPartitioning(agents):
    """Compute and return sections with compound criteria

    agents is a dict with keys "d", "id", "od", "s", "is", "os"
    with sectorialized_agents__ with each of these criteria
    """
    exc_h = set(agents['d'][-1][2]) & set(agents['id'][-1][2]) & set(agents
        ['od'][-1][2]) & set(agents['s'][-1][2]) & set(agents['is'][-1][2]
        ) & set(agents['os'][-1][2])
    exc_i = set(agents['d'][-1][1]) & set(agents['id'][-1][1]) & set(agents
        ['od'][-1][1]) & set(agents['s'][-1][1]) & set(agents['is'][-1][1]
        ) & set(agents['os'][-1][1])
    exc_p = set(agents['d'][-1][0]) & set(agents['id'][-1][0]) & set(agents
        ['od'][-1][0]) & set(agents['s'][-1][0]) & set(agents['is'][-1][0]
        ) & set(agents['os'][-1][0])
    exc = exc_p, exc_i, exc_h
    inc_h = set(agents['d'][-1][2]) | set(agents['id'][-1][2]) | set(agents
        ['od'][-1][2]) | set(agents['s'][-1][2]) | set(agents['is'][-1][2]
        ) | set(agents['os'][-1][2])
    inc_i = set(agents['d'][-1][1]) | set(agents['id'][-1][1]) | set(agents
        ['od'][-1][1]) | set(agents['s'][-1][1]) | set(agents['is'][-1][1]
        ) | set(agents['os'][-1][1])
    inc_p = set(agents['d'][-1][0]) | set(agents['id'][-1][0]) | set(agents
        ['od'][-1][0]) | set(agents['s'][-1][0]) | set(agents['is'][-1][0]
        ) | set(agents['os'][-1][0])
    inc = inc_p, inc_i, inc_h
    total = set(agents['d'][-1][0] + agents['d'][-1][1] + agents['d'][-1][2])
    excc_h = exc[2]
    excc_p = inc[0]
    excc_i = total - (exc[2] | inc[0])
    excc = excc_p, excc_i, excc_h
    incc_h = inc[2]
    incc_p = excc[0]
    incc_i = total - (incc_h | incc_p)
    incc = incc_p, incc_i, incc_h
    exce_h = exc[2]
    exce_i = inc[1]
    exce_p = total - (exce_h | exce_i)
    exce = exce_p, exce_i, exce_h
    ince_h = inc[2]
    ince_i = exc[1]
    ince_p = total - (ince_h | ince_i)
    ince = ince_p, ince_i, ince_h
    return dict(total=total, exc=exc, inc=inc, excc=excc, incc=incc, exce=
        exce, ince=ince)


@classmethod
def none(cls):
    """A factory method that creates a :class:`CacheLevel` with no caching."""
    return cls(0)


def revcomp_str(seq):
    """
	Returns the reverse complement of a `str` nucleotide sequence.

	Parameters
	----------
	+ seq `str` nucleotide sequence
	"""
    comp = str.maketrans('ACGTRYMKWSBDHV', 'TGCAYRKMWSVHDB')
    anti = seq.translate(comp)[::-1]
    return anti


def parse_ha_filename_file(ha_filename_path):
    """Return a parsed ha_filenames file as a dict."""
    name_map = {}
    with open(ha_filename_path) as hfp:
        hfp.readline()
        hfp.readline()
        for line in hfp:
            line = line.strip()
            if not line:
                continue
            tkns = line.split('\t')
            try:
                slname, trip_name = tkns[2], tkns[3]
            except IndexError:
                continue
            if len(tkns) >= 6:
                description_name = tkns[5].split()[0]
                name_map[description_name] = slname
            name_map[slname] = slname
            name_map[trip_name] = slname
    return name_map


def getResponseCode(response):
    """
    Get the Https response code
    :param response: Response object in JSON
    :return: String - response code
    """
    return response.status_code


def try_str_without(item, excluded, latex=False):
    """Try to call item.str_without(excluded); fall back to str(item)"""
    if latex and hasattr(item, 'latex'):
        return item.latex(excluded)
    elif hasattr(item, 'str_without'):
        return item.str_without(excluded)
    return str(item)


@staticmethod
def getReprSubscriptNumeral(number):
    """
                HLevel.getReprSubscriptNumeral

                number  : (int)
        """
    strnumber = str(number)
    res = []
    digit_to_subscriptdigit = {'-': '-', '0': chr(8320), '1': chr(8321),
        '2': chr(8322), '3': chr(8323), '4': chr(8324), '5': chr(8325), '6':
        chr(8326), '7': chr(8327), '8': chr(8328), '9': chr(8329)}
    for digit in str(strnumber):
        res.append(digit_to_subscriptdigit[digit])
    return ''.join(res)


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 key_function(row, index):
    """
    This example shows how to define a function to extract X and Y values
    from custom data.

    :param row:
        The function will be called with the row data, in whatever format it
        was provided to the :class:`.Series`.
    :param index:
        The row index in the series data will also be provided.
    :returns:
        The function must return a chartable value.
    """
    pass


def instance(cls):
    """Create a new instance of a class.

    Parameters
    ----------
    cls : type
        The class to create an instance of.

    Returns
    -------
    instance : cls
        A new instance of ``cls``.
    """
    return cls()


def propertyValues():
    """Return a list of actual property objects.
        """


@classmethod
def load_entry(cls, api, entry):
    """Create an object starting with one single entry."""
    raise NotImplementedError


def iter_uniques(iterable):
    """ Creates an ordered set from a list of tuples or other hashable items

    >>> ''.join(iter_uniques('abracadabra'))
    'abrcd'
    >>> ''.join(iter_uniques('simsalabim'))
    'simalb'
    """
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item


def paste_tracks():
    """Paste tracks from clipboard

    """
    pass


@classmethod
def clean_data(cls, data_dict):
    """Splits the data into formdata and files"""
    files = dict()
    data = dict()
    for key, value in data_dict.items():
        try:
            file = value
            if type(value) == tuple and hasattr(value[1], 'read'):
                file = value[1]
                files.update({key: (value[0].split('/')[-1], file.read())})
            elif hasattr(file, 'read') and hasattr(file, 'name'):
                files.update({key: (file.name, file.read())})
            else:
                data.update({key: value})
        except Exception as e:
            data.update({key: value})
    as_json = not bool(files)
    return data, files, as_json


def flatten(l, ltypes=(list, tuple, set)):
    """
    Flatten a list or tuple that contains additional lists or tuples. Like
    the numpy flatten, but for python types.

    Parameters
    ----------
    l: tuple or list,
        The data that is to be flattened
    ltypes: tuple,
        Data types to attempt to flatten

    Returns
    -------
    list

    See Also
    --------
    numpy.flatten()

    Notes
    -----
    This code was taken from:
    <http://rightfootin.blogspot.com.au/2006/09/more-on-python-flatten.html>

    Examples
    --------
    >>> a=[[1,3,4,1], ('test', 'this'), [5,2]]
    >>> flatten(a)
    [1, 3, 4, 1, 'test', 'this', 5, 2]
    """
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)


def etree_last_child(elem):
    """Returns the last child of the element, ignoring children that are lxml comments."""
    for child in reversed(elem):
        if not callable(child.tag):
            return child


def humanize_bytes(bytes, precision=1):
    """Return a humanized string representation of a number of bytes.

    Assumes `from __future__ import division`.

    >>> humanize_bytes(1)
    '1 byte'
    >>> humanize_bytes(1024)
    '1.0 kB'
    >>> humanize_bytes(1024*123)
    '123.0 kB'
    >>> humanize_bytes(1024*12342)
    '12.1 MB'
    >>> humanize_bytes(1024*12342,2)
    '12.05 MB'
    >>> humanize_bytes(1024*1234,2)
    '1.21 MB'
    >>> humanize_bytes(1024*1234*1111,2)
    '1.31 GB'
    >>> humanize_bytes(1024*1234*1111,1)
    '1.3 GB'
    """
    abbrevs = (1 << 50, 'PB'), (1 << 40, 'TB'), (1 << 30, 'GB'), (1 << 20, 'MB'
        ), (1 << 10, 'kB'), (1, 'bytes')
    if bytes == 1:
        return '1 byte'
    for factor, suffix in abbrevs:
        if bytes >= factor:
            break
    return '%.*f %s' % (precision, bytes / factor, suffix)


def package_exists(package_name):
    """This is a simple function returning True/False for if a requested package string exists
    in the add-on repository."""
    return package_name == 'frank'


@classmethod
def get_pixelpin_auth(cls, provider, uid):
    """Return UserPixelpinAuth for given provider and uid"""
    raise NotImplementedError('Implement in subclass')


@staticmethod
def id_dammit(object_or_id):
    """ Get the id of an object
        """
    if hasattr(object_or_id, 'id'):
        return object_or_id.id
    return object_or_id


def add_even_sub_odd(operator, operand):
    """Add even numbers, subtract odd ones. See http://1w6.org/w6 """
    try:
        for i, x in enumerate(operand):
            if x % 2:
                operand[i] = -x
        return operand
    except TypeError:
        if operand % 2:
            return -operand
        return operand


def category_points(category, reviewed):
    """
    Convert reviewed contributions to points.
    """
    if category == 'ideas':
        return reviewed * 0.75
    elif category == 'development':
        return reviewed * 2.0
    elif category == 'translations':
        return reviewed * 1.25
    elif category == 'graphics':
        return reviewed * 1.0
    elif category == 'documentation':
        return reviewed * 0.75
    elif category == 'copywriting':
        return reviewed * 0.75
    elif category == 'tutorials':
        return reviewed * 1.0
    elif category == 'analysis':
        return reviewed * 1.25
    elif category == 'social':
        return reviewed * 1.0
    elif category == 'blog':
        return reviewed * 0.75
    elif category == 'video-tutorials':
        return reviewed * 1.25
    elif category == 'bug-hunting':
        return reviewed * 1.0
    elif category == 'task-ideas':
        return reviewed * 0.5
    elif category == 'task-development':
        return reviewed * 0.5
    elif category == 'task-bug-huntung':
        return reviewed * 0.5
    elif category == 'task-translations':
        return reviewed * 0.5
    elif category == 'task-graphics':
        return reviewed * 0.5
    elif category == 'task-documentation':
        return reviewed * 0.5
    elif category == 'task-analysis':
        return reviewed * 0.5
    elif category == 'task-social':
        return reviewed * 0.5


def SolcoreMaterialToStr(material_input):
    """Translate a solcore material composition into a string that is what the Adachi calculator needs."""
    material_string = material_input.__str__().strip('<>').split(' ')
    material_name = material_string[0].strip("'")
    composition = {'material': material_name}
    if len(material_name) > 4:
        material_composition = material_string[2].split('=')
        for i, comp in enumerate(material_composition):
            if comp in material_name:
                composition['element'] = material_composition[i]
                composition['fraction'] = float(material_composition[i + 1])
    output = "%s {'%s':%s}" % (composition['material'], composition[
        'element'], composition['fraction'])
    return output


def valid_nombre_arch(nombre):
    """
    Valida el nombre de un fuente.

    Parameters
    ----------
    nombre : str
        El nombre propuesto para el fuente.
    Returns
    -------
    str
        Un nombre de fuente válido.
    """
    for x in ['\\', '/', '|', ':*', '?', '"', '>', '<']:
        nombre = nombre.replace(x, '_')
    return nombre.strip()


def public_download_url(file, **kwargs):
    """Directs downloads to file.url (useful for normal file system storage)"""
    return file.url


def isintriangle(tri_x, tri_y, point_x, point_y):
    """
    Returns a boolean as to whether the point (point_x, point_y) is within the triangle (tri_x, tri_y)

    Parameters
    ----------
    tri_x, tri_y : np.ndarray
        Coordinates of the triangle vertices.
    point_x, point_y : float
        Position to test.

    Returns
    -------
    isin : bool
        True if the position (point_x, point_y) is in the triangle defined by (tri_x, tri_y).

    Notes
    -----
    Method from http://totologic.blogspot.co.uk/2014/01/accurate-point-in-triangle-test.html without edge test used
    in getcrossectiontriangles.

    """
    x1 = tri_x[0]
    x2 = tri_x[1]
    x3 = tri_x[2]
    y1 = tri_y[0]
    y2 = tri_y[1]
    y3 = tri_y[2]
    a = ((y2 - y3) * (point_x - x3) + (x3 - x2) * (point_y - y3)) / ((y2 -
        y3) * (x1 - x3) + (x3 - x2) * (y1 - y3))
    b = ((y3 - y1) * (point_x - x3) + (x1 - x3) * (point_y - y3)) / ((y2 -
        y3) * (x1 - x3) + (x3 - x2) * (y1 - y3))
    c = 1 - a - b
    is_in = 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1
    return is_in


def manage_afterClone(item):
    """Gets called after being cloned"""


def _nonbreaking_spaces(match_obj):
    """
    Make spaces visible in HTML by replacing all `` `` with `` ``

    Call with a ``re`` match object.  Retain group 1, replace group 2
    with nonbreaking speaces.
    """
    spaces = ' ' * len(match_obj.group(2))
    return f'{match_obj.group(1)}{spaces}'


def __init_subclass__(cls, *args, **kwargs):
    """
        An __init_subclass__ hook initializes all of the subclasses of a given class.
        So for each subclass, it will call this block of code on import.
        This replicates some metaclass magic without the need to be aware of metaclasses.
        Here we use this to register each subclass in a dict that has the `_can_handle_query` attribute.
        This is then passed into the UnifiedDownloaderFactory so we can register them.
        This means that Fido can use the clients internally.
        """
    super().__init_subclass__(**kwargs)
    if cls.__name__ != 'GenericClient':
        cls._registry[cls] = cls._can_handle_query


@staticmethod
def get_creation_arguments_model():
    """
        This is needed so the BaseConnection can validate the provided
        creation arguments as well as for auto documentation.
        return = {
            'required_creation_arguments': {
                'required_creation_arg_1': type,
                'required_creation_arg_2': type,
            },
            'optional_creation_arguments': {
                'optional_creation_arg_1': type,
                'optional_creation_arg_2': type,
            },
        }
        """
    return {'required_creation_arguments': {'on_new_request': lambda args,
        to_send, states, config: True}, 'optional_creation_arguments': {}}


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


def check_required(settings, required):
    """Ensure ``settings`` contains the ``required`` keys."""
    missing = []
    for r in required:
        if r not in settings:
            missing.append(r)
    if missing:
        raise ValueError('Missing required settings: {}'.format(', '.join(
            missing)))


@staticmethod
def from_namedtuples(records):
    """Return a reader object which will iterate over the given
        namedtuple records.
        """
    records = iter(records)
    first_record = next(records, None)
    if first_record:
        yield first_record._fields
        yield first_record
    for record in records:
        yield record


def safe_import_cv2():
    """Gracefully fail ModuleNotFoundError due to cv2

    :return: None
    """
    try:
        import cv2
    except ModuleNotFoundError:
        raise ModuleNotFoundError(
            """
        No python bindings for OpenCV found when attempting to `import cv2`.
        If you have not installed OpenCV you can install with:

            pip install vidstab[cv2]

        If you'd prefer to install OpenCV from source you can see the docs here:
            https://docs.opencv.org/3.4.1/da/df6/tutorial_py_table_of_contents_setup.html
        """
            )


def change_event_name(event):
    """
    Change event names from json style to html (ex: BLOCKED_SHOT to BLOCK).

    :param event: event type

    :return: fixed event type
    """
    event_types = {'PERIOD START': 'PSTR', 'FACEOFF': 'FAC', 'BLOCKED SHOT':
        'BLOCK', 'GAME END': 'GEND', 'GIVEAWAY': 'GIVE', 'GOAL': 'GOAL',
        'HIT': 'HIT', 'MISSED SHOT': 'MISS', 'PERIOD END': 'PEND', 'SHOT':
        'SHOT', 'STOPPAGE': 'STOP', 'TAKEAWAY': 'TAKE', 'PENALTY': 'PENL',
        'EARLY INT START': 'EISTR', 'EARLY INT END': 'EIEND',
        'SHOOTOUT COMPLETE': 'SOC', 'CHALLENGE': 'CHL',
        'EMERGENCY GOALTENDER': 'EGPID'}
    return event_types.get(event.upper(), event)


def key_verify(expected_hash, signature, key):
    """Verify that the signature data matches the calculated digest of
    the data being signed using the key that made the signature.
    """
    return key.verify(signature, expected_hash)


def adjust_order_items():
    """adjust the `packages` field for order items, creating order items as necessary.

    See `IProviderOrderItem.adjust` for details.
    """


@classmethod
def get_default_level(cls):
    """
        Compatibility with Django MPTT: level value for root node.
        See https://github.com/uralbash/sqlalchemy_mptt/issues/56
        """
    return getattr(cls, 'sqlalchemy_mptt_default_level', 1)


def rid_access_data(message_type, msg_tow, msg_horizontal, msg_vertical,
    msg_depth, msg_flag, msg_sats, numofmsg):
    """
    Gets rid of all access data in lists.
    Only trigger and interpolated data remains.
    """
    itt = 0
    while itt < numofmsg:
        if msg_tow[itt] == 0 or message_type[itt] != 'MsgExtEvent':
            message_type.pop(itt)
            msg_tow.pop(itt)
            msg_sats.pop(itt)
            msg_horizontal.pop(itt)
            msg_vertical.pop(itt)
            msg_depth.pop(itt)
            msg_flag.pop(itt)
            itt -= 1
            numofmsg -= 1
        itt += 1
    return numofmsg


def _extract_msg(args, kwargs, msg_idx, default_msg, non_msg_params):
    """Extracts the ``msg`` argument from the passed ``args``.

    Returns
    -------
    tuple
        The found ``msg``, the args and kwargs with that ``msg``
        removed, and any remaining positional args after ``msg``.
    """
    rem_args = []
    if 'msg' in kwargs:
        msg = kwargs.pop('msg')
    elif len(args) > non_msg_params and msg_idx < len(args):
        msg = args[msg_idx]
        if 0 <= msg_idx:
            rem_args = args[msg_idx + 1:]
        args = args[:msg_idx]
    else:
        msg = default_msg
    return msg, args, rem_args, kwargs


def get_diff(cached_list, curr_list):
    """Diff two lists, return a tuple of lists to be installed, to be
    deleted.

    """
    to_install = list(set(curr_list) - set(cached_list))
    to_delete = list(set(cached_list) - set(curr_list))
    return to_install, to_delete


def _set_tree(value):
    """Set the shared tree to a specific value (for testing)."""
    global _tree
    _tree = value


@staticmethod
def init_target_configuration(target_configuration):
    """ Perform any package specific initialisation of the target
        target configuration.  Typically this is the initialisation of package
        specific attributes.  To avoid name clashes attributes should be given
        a package specific prefix.  target_configuration is the target
        configuration.
        """
    target_configuration.qtwebengine_sip_dir = None


def is_attribute(fieldname):
    """Return True if the `fieldname` represents an XML attribute selector."""
    return fieldname.startswith('@')


@staticmethod
def find_site_name(soup) ->str:
    """
        Attempts to find Site Name

        :param soup: BeautifulSoup of site
        :return: str
        """
    site_name_meta = ['og:site_name', 'og:title', 'application:name',
        'twitter:app:name:iphone']
    for p in site_name_meta:
        try:
            name = soup.find(name='meta', property=p).get('content')
            if name:
                return name
        except AttributeError:
            pass
    try:
        title = soup.find(name='title').text
        if title:
            return title
    except AttributeError:
        pass
    return ''


def gen_buy_from_chinese(*args, **kwargs):
    """
    抱歉！由于中文生成策略的方法也需要遵循一定的语法和句式，对于完全不熟悉编程的人可能会产生错误，'
          '造成无谓的经济损失，所以中文自动生成交易策略模块暂时不开放接口以及源代码！
    """
    print(
        '抱歉！由于中文生成策略的方法也需要遵循一定的语法和句式，对于完全不熟悉编程的人可能会产生错误，造成无谓的经济损失，所以中文自动生成交易策略模块暂时不开放接口以及源代码！'
        )


def tweet_training(dataset_file, model_file='', test=False, param='dp',
    type='stat'):
    """
    Train a classifier on a dataset.
    :param config: pyTweetBot configuration object
    :param dataset_file: Path to the dataset file
    :param model_file: Path to model file if needed
    :param data: Title or content
    :param test: Test the classification success rate
    :param param: Model parameter (dp, ...)
    :param type: Model's type (stat, tfidf, stat2, textblob)
    """
    """if os.path.exists(model_file):
        model = StatisticalModel.load_from_file(model_file)
    else:
        if type == "stat":
            model = StatisticalModel("tweet_stat_model", ['tweet', 'skip'], last_update=datetime.datetime.utcnow(),
                                     smoothing=param, smoothing_param=0.5)
        elif type == "tfidf":
            model = TFIDFModel("tweet_tfidf_model", ['tweet', 'skip'], last_update=datetime.datetime.utcnow())
        elif type == "stat2":
            model = Statistical2GramModel("tweet_stat2_model", ['tweet', 'skip'],
                                          last_update=datetime.datetime.utcnow(), smoothing=param,
                                          smoothing_param=0.5)
        # end
    # end if"""
    """if os.path.exists(dataset_file):
        with open(dataset_file, 'r') as f:
            dataset = pickle.load(f)
            n_samples = len(dataset[0].keys())
        # end with
    else:
        logging.error(u"Cannot find dataset file {}".format(dataset_file))
    # end if

    # Train or test
    if not test:
        try:
            # For each URL in the dataset
            for index, url in enumerate(dataset[0].keys()):
                if not model.is_example_seen(url):
                    # Class
                    c = dataset[0][url]

                    # Log
                    print(u"Downloading example {}".format(url))

                    # Get URL's text
                    try:
                        html = urllib.urlopen(url).read().decode('utf-8', errors='ignore')
                        soup = BeautifulSoup(html, "lxml")
                        text = soup.get_text()

                        # HTML entities
                        text = clean_html_text(text)

                        # Train
                        logger.info(u"Training example {}/{} as {}...".format(index + 1, n_samples, c))
                        if ".fr" in url or ".ch" in url:
                            model.train(text, c)
                        else:
                            model.train(text, c)
                        # end if

                        # I've seen that
                        model.add_url(url)

                        # Display info
                        print(model)
                    except IOError as e:
                        logger.error(u"Error downloading example {} : {}".format(url, e))
                        model.add_url(url)
                        pass
                    except UnicodeError as e:
                        logger.error(u"URL contains unicode characters {}".format(url, e))
                        model.add_url(url)
                        pass
                    # end except
                # end if
            # end for
        except (KeyboardInterrupt, SystemExit):
            pass
        # end try

        # Save the model
        logger.info(u"Saving model to {}".format(args.model))
        model.save(args.model)
    else:
        # Stats
        count = 0.0
        success = 0.0
        false_positive = 0.0
        false_positive_urls = list()

        try:
            # For each URL in the dataset
            for url in dataset[0].keys():
                # Class
                c = dataset[0][url]

                # Log
                logger.info(u"Testing {}".format(url))

                # Get URL's text
                html = urllib.urlopen(url).read()
                soup = BeautifulSoup(html, "lxml")
                text = soup.get_text()

                # HTML entities
                text = clean_html_text(text)

                # Predict
                if ".fr" in url or ".ch" in url:
                    prediction, probs = model(text)
                else:
                    prediction, probs = model(text)
                # end if

                # Same result
                if probs['tweet'] == probs['skip']:
                    prediction = "skip"
                # end if

                # False positive
                if prediction == "tweet" and c == "skip":
                    false_positive += 1.0
                    false_positive_urls.append(url)
                # end if

                # Compare
                logger.info(u"Predicted {} for observation {}".format(prediction, c))
                if prediction == c:
                    success += 1.0
                # end if
                count += 1.0
            # end for
        except (KeyboardInterrupt, SystemExit):
            pass
        # end try

        # Show performance
        logger.info(u"Success rate of {} on dataset, {} false positive".format(success / count * 100.0,
                                                                               false_positive / count * 100.0))

        # Show false positives
        logger.info(u"False positives")
        for url in false_positive_urls:
            print(url)
        # end for
    # end if"""


def match(needle, haystack):
    """
    Command-T-style string matching.
    """
    score = 1
    j = 0
    last_match = 0
    needle = needle.lower()
    haystack = haystack.lower()
    for c in needle:
        while j < len(haystack) and haystack[j] != c:
            j += 1
        if j >= len(haystack):
            return 0
        score += 1 / (last_match + 1.0)
        last_match = j
        j += 1
    return score


def product(x, d):
    """Return time-series product over the past d days."""
    return x.rolling(d).apply(lambda x: x.prod(), raw=True)


def _validate_entity_params(id, df, time_index):
    """Validation checks for Entity inputs"""
    assert isinstance(id, str), 'Entity id must be a string'
    assert len(df.columns) == len(set(df.columns)), 'Duplicate column names'
    for c in df.columns:
        if not isinstance(c, str):
            raise ValueError(
                'All column names must be strings (Column {} is not a string)'
                .format(c))
    if time_index is not None and time_index not in df.columns:
        raise LookupError('Time index not found in dataframe')


def isInbetween(number, low, high):
    """Returns True if number is inbetween low and high, returns False otherwise"""
    if low <= number <= high:
        return True
    else:
        return False


def run(httpd):
    """ Run Lambda Gateway server.

        :param object httpd: ThreadingHTTPServer instance
    """
    host, port = httpd.socket.getsockname()[:2]
    url_host = f'[{host}]' if ':' in host else host
    print(f'Serving HTTP on {host} port {port} (http://{url_host}:{port}/) ...'
        )
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print('\nKeyboard interrupt received, exiting.')
    finally:
        httpd.shutdown()


def get_route_edge_attributes(G, route, attribute=None, minimize_key=
    'length', retrieve_default=None):
    """
    Get a list of attribute values for each edge in a path.

    Parameters
    ----------
    G : networkx multidigraph
    route : list
        list of nodes in the path
    attribute : string
        the name of the attribute to get the value of for each edge.
        If not specified, the complete data dict is returned for each edge.
    minimize_key : string
        if there are parallel edges between two nodes, select the one with the
        lowest value of minimize_key
    retrieve_default : Callable[Tuple[Any, Any], Any]
        Function called with the edge nodes as parameters to retrieve a default value, if the edge does not
        contain the given attribute. Per default, a `KeyError` is raised
    Returns
    -------
    attribute_values : list
        list of edge attribute values
    """
    attribute_values = []
    for u, v in zip(route[:-1], route[1:]):
        data = min(G.get_edge_data(u, v).values(), key=lambda x: x[
            minimize_key])
        if attribute is None:
            attribute_value = data
        elif retrieve_default is not None:
            attribute_value = data.get(attribute, retrieve_default(u, v))
        else:
            attribute_value = data[attribute]
        attribute_values.append(attribute_value)
    return attribute_values


def shortest_path_select(use_face_step: bool=False, use_topology_distance:
    bool=False, use_fill: bool=False, nth: int=1, skip: int=1, offset: int=0):
    """Selected vertex path between two vertices

    :param use_face_step: Face Stepping, Traverse connected faces (includes diagonals and edge-rings)
    :type use_face_step: bool
    :param use_topology_distance: Topology Distance, Find the minimum number of steps, ignoring spatial distance
    :type use_topology_distance: bool
    :param use_fill: Fill Region, Select all paths between the source/destination elements
    :type use_fill: bool
    :param nth: Nth Selection
    :type nth: int
    :param skip: Skip
    :type skip: int
    :param offset: Offset
    :type offset: int
    """
    pass


def runfcgi(func, addr=('localhost', 8000)):
    """Runs a WSGI function as a FastCGI server."""
    import flup.server.fcgi as flups
    return flups.WSGIServer(func, multiplexed=True, bindAddress=addr, debug
        =False).run()


def _collect_set(x):
    """Part of the generation of a set from a group.

    collect_list and collect_set must be different functions, otherwise
    pandas will raise error.
    """
    return x.tolist()


def min_ge(seq, val):
    """
    Same as min_gt() except items equal to val are accepted as well.

    :param seq:
    :param val:
    :return:

    Examples:
        min_ge([1, 3, 6, 7], 6)
        >>>6
        min_ge([2, 3, 4, 8], 8)
        >>>8
    """
    for v in seq:
        if v >= val:
            return v
    return None


def load_config():
    """
	Fill global structures with user params
	"""
    try:
        from config import __author__, __tool_name__, __site__, __version__
    except ImportError:
        __author__ = __tool_name__ = __site__ = __version__ = 'unknown'
    from .structs import AppSettings
    AppSettings.author = __author__
    AppSettings.tool_name = __tool_name__
    AppSettings.project_site = __site__
    AppSettings.version = __version__


@classmethod
def pk_names(cls):
    """
        Primary key column name list.
        """
    if cls._cache_pk_names is None:
        cls._cache_pk_names = cls._get_primary_key_names()
    return cls._cache_pk_names


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 __filter_substring(items, attr, value):
    """select from items list where 'value' is a substring of the attribute"""
    filtered_items = []
    for item in items:
        if value.lower() in item[attr].lower():
            filtered_items.append(item)
    return filtered_items


def tuple_sub(tup, orig, new):
    """
    Replace an item in a tuple
    """
    idx = tup.index(orig)
    return tup[:idx] + (new,) + tup[idx + 1:]


def s2hms(sec):
    """Convert seconds to hours, minutes, seconds."""
    t = sec
    h = t // 3600.0
    t -= h * 3600.0
    m = t // 60.0
    t -= m * 60.0
    s = t
    return h, m, s


def fqdn(name, zone=None):
    """ This produces a string version of a name that is dot terminated
        and ends with the trailing zone.  If the name already ends with
        the zone name, it is not appended.  For example

            (a) -> a.
            (a.) -> a.
            (a,example.com) -> a.example.com.
            (a.example.com,example.com) -> a.example.com.

        the return value is ascii, not unicode

        Note: does not detect multi
    """
    if not name.endswith('.'):
        if zone == None:
            name += '.'
        elif not zone.endswith('.'):
            if name.endswith(zone):
                name = name + '.'
            else:
                name = name + '.' + zone + '.'
        else:
            name += '.'
            if not name.endswith(zone):
                name = name + zone
    return name


def write_content(outfile, content):
    """
    Write GitHub content into a file.

    :param str outfile: The output file
    :param str content: The file content to write

    """
    with open(outfile, 'w+') as f:
        f.write(content.encode('utf-8'))


def moduleProvides(*interfaces):
    """Declare interfaces provided by a module

        This function is used in a module definition.

        The arguments are one or more interfaces or interface
        specifications (IDeclaration objects).

        The given interfaces (including the interfaces in the
        specifications) are used to create the module's direct-object
        interface specification.  An error will be raised if the module
        already has an interface specification.  In other words, it is
        an error to call this function more than once in a module
        definition.

        This function is provided for convenience. It provides a more
        convenient way to call directlyProvides for a module. For example::

          moduleImplements(I1)

        is equivalent to::

          directlyProvides(sys.modules[__name__], I1)
        """


def extract_tag_version(tag):
    """
    extract a version string from a tag, or None if
    it is not a valid numerical version.
    """
    if tag.startswith('v'):
        return tag[1:]
    return None


def explode_pm_to_src(dfrel, dfpm, datecolname='Date', pm10colname='PM10'):
    """Return the proportion of each source for a given PM timeserie

    Parameters
    ----------

    dfrel : pd.DataFrame
        Monthly relative contribution of each sources.
    dfpm : pd.DataFrame
        PM concentration timeserie, with a date column
    datecolname : str, default 'Date'
        Name of the date column in dfpm
    pm10colname : str, default 'PM10'
        Name of the PM column in dfpm

    Returns
    -------

    dfpm_bysrc : pd.DataFrame with the absolute contribution of the sources as
        new columns
    """
    dfpm_bysrc = dfpm.copy()
    dfpm_bysrc['month'] = dfpm_bysrc[datecolname].apply(lambda x: x.month)
    for c in dfrel.columns:
        for m in range(1, 13):
            idx = dfpm_bysrc['month'] == m
            dfpm_bysrc.loc[idx, c] = dfpm_bysrc.loc[idx, pm10colname
                ] * dfrel.loc[m, c]
            if c == 'Unnamed: 0':
                print(c)
    return dfpm_bysrc


@classmethod
def encrypted_string(cls, plaintext):
    """Sends a string to DataRobot to be encrypted

        This is used for passwords that DataRobot uses to access external data sources

        Parameters
        ----------
        plaintext : str
            The string to encrypt

        Returns
        -------
        ciphertext : str
            The encrypted string
        """
    endpoint = 'stringEncryptions/'
    response = cls._client.post(endpoint, data={'plain_text': plaintext})
    return response.json()['cipherText']


def configPrintException(enable):
    """
    Configure whether full stacktraces should be dumped in the console output

    :param enable:

    :return:
    """
    global verbose_exceptions
    verbose_exceptions = enable


def _aslist(obj):
    """
    Turn object into a list; lists and tuples are left as-is, None
    becomes [], and everything else turns into a one-element list.
    """
    if obj is None:
        return []
    elif isinstance(obj, (list, tuple)):
        return obj
    else:
        return [obj]


def dumpbin(file_handler, data, dtype='d'):
    """ Dump a sequence of data to a binary file """
    pass


def write_graph(path, dot_graph, _format, prog, **pydot_args):
    """Write DOT graph to file.

    Parameters
    ----------
    path
    dot_graph
    _format
    prog
    pydot_args

    Returns
    -------

    """
    import os
    path = os.path.normpath(path)
    return dot_graph.write(path, format=_format, prog=prog, **pydot_args)


def timestamp_to_microseconds(ts):
    """Converts a datetime object to the number of microseconds since epoch.

    Args:
        ts (datetime.datetime): The datetime object.

    Returns:
        int: The number of microseconds from epoch.
    """
    microsecond_amount = 1000000
    return ts.timestamp() * microsecond_amount


@classmethod
def promote_from_model(cls, literal_model):
    """
        Creates an object of this type from the model primitive defining it.
        :param flytekit.models.literals.Literal literal_model:
        :rtype: Integer
        """
    return cls(literal_model.scalar.primitive.integer)


def header_name(name):
    """Convert header name like HTTP_XXXX_XXX to Xxxx-Xxx:"""
    words = name[5:].split('_')
    for i in range(len(words)):
        words[i] = words[i][0].upper() + words[i][1:].lower()
    result = '-'.join(words)
    return result


def color_mode(mode, max_1=255, max_2=None, max_3=None, max_alpha=255):
    """Set the color mode of the renderer.

    :param mode: One of {'RGB', 'HSB'} corresponding to Red/Green/Blue
        or Hue/Saturation/Brightness
    :type mode: str

    :param max_1: Maximum value for the first color channel (default:
        255)
    :type max_1: int

    :param max_2: Maximum value for the second color channel (default:
        max_1)
    :type max_2: int

    :param max_3: Maximum value for the third color channel (default:
        max_1)
    :type max_3: int

    :param max_alpha: Maximum valu for the alpha channel (default:
        255)
    :type max_alpha: int

    """
    global color_parse_mode
    global color_range
    if max_2 is None:
        max_2 = max_1
    if max_3 is None:
        max_3 = max_1
    color_range = max_1, max_2, max_3, max_alpha
    color_parse_mode = mode


def queue_list(transport, request, callback=None, **kwargs):
    """Gets a list of queues

    :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 callback: Optional callable to use as callback.
        If specified, this request will be sent asynchronously.
        (IGNORED UNTIL ASYNC SUPPORT IS COMPLETE)
    :type callback: Callable object.
    :param kwargs: Optional arguments for this operation.
        - marker: Where to start getting queues from.
        - limit: Maximum number of queues to get.
    """
    request.operation = 'queue_list'
    request.params.update(kwargs)
    resp = transport.send(request)
    if not resp.content:
        return {'links': [], 'queues': []}
    return resp.deserialized_content


def is_Tuple_ellipsis(tpl):
    """Python version independent function to check if a typing.Tuple object
    contains an ellipsis."""
    try:
        return tpl.__tuple_use_ellipsis__
    except AttributeError:
        try:
            if tpl.__args__ is None:
                return False
            if tpl.__args__[-1] is Ellipsis:
                return True
        except AttributeError:
            pass
        return False


def seq_strip(seq, stripper=lambda x: x.strip()):
    """ Strip a sequence of strings.
    """
    if isinstance(seq, list):
        return map(stripper, seq)
    if isinstance(seq, tuple):
        return tuple(map(stripper, seq))
    raise ValueError('%s of unsupported sequencetype %s' % (seq, type(seq)))


def parse_experiment_params(name_exp):
    """Parse experiment parameters from the data directory name

    Args
    ----
    name_exp: str
        Name of data directory with experiment parameters

    Returns
    -------
    tag_params: dict of str
        Dictionary of parsed experiment parameters
    """
    if '/' in name_exp or '\\' in name_exp:
        raise ValueError(
            "The path {} appears to be a path. Please pass only the data directory's name (i.e. the experiment name)"
            .format(name_exp))
    tag_params = dict()
    tag_params['experiment'] = name_exp
    tag_params['tag_model'] = name_exp.split('_')[1].replace('-', '')
    tag_params['tag_id'] = name_exp.split('_')[2]
    tag_params['animal'] = name_exp.split('_')[3]
    tag_params['notes'] = name_exp.split('_')[4]
    return tag_params


def can_edit(key):
    """Returns if the user has permission to edit the given feature"""


def get_mod(modulePath):
    """Import a module."""
    return __import__(modulePath, globals(), locals(), [''])


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

    The ".dev0" means dirty.

    Exceptions:
    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


@staticmethod
def open_sql_file(file):
    """
        Opens a sql file or other txt like file
        and formats it to be used by the execute() command

        :param file: File to be opened
        :return: Formatted query text
        """
    with open(file, 'r') as f:
        query = f.read().replace('\n', ' ')
    f.close()
    return query


def file_get(file_path):
    """Returns the UTF-8 decoded contents of a file"""
    with open(file_path, 'r') as f:
        return f.read().decode('utf-8')


@classmethod
def need_info(cls, question, key, disable_echo=False):
    """
        Create a new NEEDINFO response.

        :param str question: question (or prompt) to display for the user
        :param str key: identifier key for the response (this will key the response in ``key_value_pairs`` parameter)
        :param bool disable_echo: turn echo off for the user input (useful for e.g. password input); default: False
        :return type: :class:`AAResponse`
        """
    return cls(verdict='NEEDINFO', question=(key, question, disable_echo))


def build_cmd_str(cmd, args=None):
    """
    Build a command string that can be sent to the arduino.

    Input:
        cmd (str): the command to send to the arduino, must not
            contain a % character
        args (iterable): the arguments to send to the command

    @TODO: a strategy is needed to escape % characters in the args
    """
    if args:
        args = '%'.join(map(str, args))
    else:
        args = ''
    return '@{cmd}%{args}$!'.format(cmd=cmd, args=args)


@classmethod
def with_client(cls, client: 'md_client.Client', **kwargs):
    """
        Creates a manager and automatically registers events.
        """
    obb = cls(client=client, **kwargs)
    obb.register_events()
    return obb


def freq(an_iterable):
    """
    Generates a dictionary of object frequencies for the given iterable
    """
    freq_dict = {}
    for c in an_iterable:
        if c not in freq_dict:
            freq_dict[c] = 1
        else:
            freq_dict[c] += 1
    return freq_dict


@staticmethod
def get_human_bytesize(bytes, suffix=''):
    """
        Convert the bytes to something readable

        :param bytes: amount of bytes
        :type bytes: int
        :param suffix: add a string after
        :type suffix: str
        :return:
        """
    if bytes > 1024 * 1024 * 1024 * 1024:
        bytes = str(round(bytes / (1024 * 1024 * 1024 * 1024), 2)
            ) + ' tB' + suffix
    elif bytes > 1024 * 1024 * 1024:
        bytes = str(round(bytes / (1024 * 1024 * 1024), 2)) + ' gB' + suffix
    elif bytes > 1024 * 1024:
        bytes = str(round(bytes / (1024 * 1024), 2)) + ' mB' + suffix
    elif bytes > 1024:
        bytes = str(round(bytes / 1024, 2)) + ' kB' + suffix
    else:
        bytes = str(bytes) + ' B' + suffix
    return bytes


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 default_add_one_res_2_all_res2(one_res: list, all_res: list) ->list:
    """
    默认函数2: one_res 增加到all_res
    :param one_res:
    :param all_res:
    :return:
    """
    for i in one_res:
        all_res.append(i)
    return all_res


def right_on_field(wdg_clicked, wdg_autofill):
    """establecemos el texto del campo auto-fill"""
    val = wdg_autofill['text']
    wdg_clicked.delete(0, 'end')
    wdg_clicked.insert(0, val)
    if val.isdigit():
        wdg_autofill['text'] = str(int(wdg_autofill['text']) + 1)


def _convert_stringval(value):
    """Converts a value to, hopefully, a more appropriate Python object."""
    value = str(value)
    try:
        value = int(value)
    except (ValueError, TypeError):
        pass
    return value


def sanitize_filename(fname):
    """ Given a file name (string) returns it with back-slashes reversed.
    This is to make all BASIC programs compatible in all OSes
    """
    return fname.replace('\\', '/')


def _trace_S(s, j, b, S_cosets):
    """
    Return the representative h satisfying s[h[b]] == j

    If there is not such a representative return None

    """
    for h in S_cosets[b]:
        if s[h[b]] == j:
            return h


def iszero(x: int) ->bool:
    """Return True if x is zero.

    >>> iszero(-1)
    False
    >>> iszero(0)
    True
    >>> iszero(1)
    False
    """
    return x == 0


def six_hump_camel_func(x):
    """
    Definition of the six-hump camel
    """
    x1 = x[0]
    x2 = x[1]
    term1 = (4 - 2.1 * x1 ** 2 + x1 ** 4 / 3) * x1 ** 2
    term2 = x1 * x2
    term3 = (-4 + 4 * x2 ** 2) * x2 ** 2
    return term1 + term2 + term3


def process(proc_data):
    """
    Final processing to conform to the schema.

    Parameters:

        proc_data:   (dictionary) raw structured data to process

    Returns:

        List of dictionaries. Structured data with the following schema:

        [
          {
            "filesystem":   string,
            "mount_point":  string,
            "type":         string,
            "access": [
                            string
            ]
          }
        ]
    """
    return proc_data


def migrate_keys(from_dict, to_dict, key_list):
    """Migrate keys from one component to another that are not in a list
    of predefined keys.

    Args:
         from_dict (dict): Component dictionary to migrate keys from.
         to_dict (dict): List of component dictionaries to migrate keys to.
         key_list (list): List of allowable keys for the original component.
             All keys in the original that are not in this list will be moved.

    """
    assert isinstance(to_dict, list)
    if len(to_dict) == 0:
        return
    klist = list(from_dict.keys())
    for k in klist:
        if k not in key_list:
            v = from_dict.pop(k)
            for d in to_dict:
                d.setdefault(k, v)


def strip_domain_address(ip_address):
    """Return the address or address/netmask from a route domain address.

    When an address is retrieved from the BIG-IP that has a route domain
    it contains a %<number> in it.  We need to strip that out so we are
    just dealing with an IP address or IP address/mask.

    Examples:
        192.168.1.1%20 ==> 192.168.1.1
        192.168.1.1%20/24 ==> 192.168.1.1/24
    """
    mask_index = ip_address.find('/')
    if mask_index > 0:
        return ip_address[:mask_index].split('%')[0] + ip_address[mask_index:]
    else:
        return ip_address.split('%')[0]


def normalize_to_tuple(obj):
    """
    If obj is a tuple, return it as-is; otherwise, return it in a tuple with it
    as its single element.
    """
    if obj is not None:
        if isinstance(obj, (list, tuple)):
            return tuple(obj)
        return obj,
    return tuple()


@classmethod
def get_dict_parsed_restql_query(cls, parsed_restql_query):
    """
        Returns the parsed query as a dict.
        """
    keys = {}
    include = parsed_restql_query.get('include', [])
    exclude = parsed_restql_query.get('exclude', [])
    for item in include:
        if isinstance(item, str):
            keys[item] = True
        elif isinstance(item, dict):
            for key, nested_items in item.items():
                key_base = key
                nested_keys = cls.get_dict_parsed_restql_query(nested_items)
                keys[key_base] = nested_keys
    for item in exclude:
        if isinstance(item, str):
            keys[item] = False
        elif isinstance(item, dict):
            for key, nested_items in item.items():
                key_base = key
                nested_keys = cls.get_dict_parsed_restql_query(nested_items)
                keys[key_base] = nested_keys
    return keys


def p_const_map(p):
    """const_map : '{' const_map_seq '}' """
    p[0] = dict(p[2])


def fetch_package_version(dist_name):
    """
    >>> fetch_package_version('sentry')
    """
    try:
        import pkg_resources
    except ImportError:
        raise NotImplementedError(
            'pkg_resources is not available on this Python install')
    dist = pkg_resources.get_distribution(dist_name)
    return dist.version


@classmethod
def ensure_frequency(cls, frequency):
    """Ensure the given args is Frequency.

        :param frequency: args to create a Frequency instance.
        :type frequency: Frequency / dict / list / tuple
        :return: Frequency instance
        :rtype: Frequency
        """
    if isinstance(frequency, cls):
        return frequency
    elif isinstance(frequency, dict):
        return cls(**frequency)
    else:
        return cls(*frequency)


@classmethod
def from_file(cls, filepath):
    """Initialize the object from a netcdf_ file."""
    return cls(filepath)


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


@staticmethod
def writeFile(filename, data):
    """
		Writes data to a file
		"""
    with open(filename, 'wb') as f:
        f.write(data.encode('utf-8'))


def exhaust(iterable, exception=StopIteration):
    """
        call next on an iterator until it's exhausted

        @param iterable: iterable to exhaust
        @param exception: exception marking end of iteration
        """


def gap_remove(all: bool=False):
    """Remove gap at current frame to first strip at the right, independent of selection or locked state of strips

    :param all: All Gaps, Do all gaps to right of current frame
    :type all: bool
    """
    pass


@classmethod
def get_configuration_for_impersonation(cls, uri, impersonate_user, username):
    """
        Return a configuration dictionary that can be merged with other configs
        that can set the correct properties for impersonating users
        :param uri: URI string
        :param impersonate_user: Bool indicating if impersonation is enabled
        :param username: Effective username
        :return: Dictionary with configs required for impersonation
        """
    return {}


def rqst_user_input(property, current_value):
    """
    Ask user to modify the property
    given and retuns the modification
    """
    print('Currently: {prop} = {value}'.format(prop=property, value=
        current_value))
    update = input('Please modify (leave blank to leave unchanged):')
    if update == '':
        return current_value
    else:
        return update


def promote_nested_tags(tag, xml):
    """We don't currently support certain tags nested inside subparts, so
    promote each up one level"""
    for subjgrp_xml in reversed(xml.xpath('.//SUBPART/' + tag)):
        subpart_xml = subjgrp_xml.getparent()
        subpart_parent = subpart_xml.getparent()
        idx = subpart_parent.index(subpart_xml) + 1
        subpart_parent.insert(idx, subjgrp_xml)


def _run(query, dbconn, roll_back, table_to_lock=None):
    """Run a query with a single table locked. If an exception
    is thrown, we roll back the transaction and then unlock the table
    before re-raising the exception.

    :param query: a function which takes a db cursor as its only argument
    :param dbconn: any DBI-compliant MySQL connection object
    :param str table_to_lock: optional table to lock (in WRITE mode) while
                              running the query
    :param bool roll_back: if true, always roll back after issuing the query

    If there is already a transaction in progress on *dbconn*, we'll roll
    it back, and unlock any tables currently locked.
    """
    dbconn.rollback()
    cursor = dbconn.cursor()
    try:
        cursor.execute('START TRANSACTION')
        cursor.execute('UNLOCK TABLES')
        cursor.execute('SET autocommit = 0')
        if table_to_lock:
            cursor.execute('LOCK TABLES `%s` WRITE' % table_to_lock)
        result = query(cursor)
        if roll_back:
            dbconn.rollback()
        else:
            dbconn.commit()
        return result
    except:
        dbconn.rollback()
        raise
    finally:
        cursor.execute('UNLOCK TABLES')


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

        :param PaperChangePolicyType val:
        :rtype: EventType
        """
    return cls('paper_change_policy', val)


@staticmethod
def cell_dimensions(grid_width: int, grid_height: int, grid_margin_x: int,
    grid_margin_y: int, n: int, m: int):
    """Return the cell width & height, given the grid width, grid height, cell offset, and number of rows (or columns).

        INPUT
        -----
        grid_width : int, total width of grid (including margins)

        grid_margins : Tuple[int, int], horizontal and vertical offset between edge of grid and its nearest cell

        n : int, number of rows (or columns) in the nxm matrix

        RETURN:
        -------
        Tuple[int, int], row & column number of corresponding cell
        """
    return int((grid_width - 2 * grid_margin_x) / n), int((grid_height - 2 *
        grid_margin_y) / m)


def delta_decode(in_array):
    """A function to delta decode an int array.

    :param in_array: the input array of integers
    :return the decoded array"""
    if len(in_array) == 0:
        return []
    this_ans = in_array[0]
    out_array = [this_ans]
    for i in range(1, len(in_array)):
        this_ans += in_array[i]
        out_array.append(this_ans)
    return out_array


@classmethod
def skip(cls, options):
    """This task is always explicitly requested."""
    return False


@classmethod
def without_pos(cls, *args, **kwargs):
    """
        Create an instance of the class itself without specifying
        ``start_pos`` and ``end_pos`` attributes.
        """
    return cls(None, None, *args, **kwargs)


def precision(tp, tn, fp, fn):
    """精确率=(TP+TN)/(TP+TN+FP+FN)"""
    return (tp + tn) / (tp + tn + fp + fn)