def _check_name(filename):
    """
    check if name has a common parquet file-extension
    Args:
        filename (str): old filename with or without extension

    Returns:
        str: new filename with extension
    """
    if not (filename.endswith('.parq') or filename.endswith('.parquet')):
        filename += '.parq'
    return filename


@classmethod
def get_verify_schema(cls, resource_type):
    """Returns the verify schema for a resource type

        :returns: a dictionary representing the schema
        """
    raise NotImplementedError


def get_package_name() ->str:
    """
    Retrieves the toplevel package name.
    """
    root = __name__
    first_dot = root.find('.')
    if first_dot > 0:
        root = root[:first_dot]
    return root


@staticmethod
def metadata_id(item):
    """Extracts the identifier from an event item."""
    return str(item['Date of Event'] + '_' + item['Club Name'])


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

        :param list of [str] val:
        :rtype: GroupMembersRemoveError
        """
    return cls('users_not_found', val)


def alpha(requestContext, seriesList, alpha):
    """
    Assigns the given alpha transparency setting to the series. Takes a float
    value between 0 and 1.
    """
    for series in seriesList:
        series.options['alpha'] = alpha
    return seriesList


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


def autogenAppend(autogenCmd, outputLines, autogenDict, entryDict):
    """
    Handle any pattern replacements requested by the user.
    """
    if not autogenDict.has_key('append'):
        return
    appendDict = autogenDict['append']
    for key, valueDict in appendDict.iteritems():
        with autogenCmd.getRoleIfContext(valueDict.get('onroles', None),
            outputLines) as ric:
            outputLines.append('%sAPPEND_FILE %s %s \n' % (ric.spaces, key,
                appendDict[key]))
        outputLines.append('\n')
    return


def get_decimal_scale(decimal):
    """
       Get the scale of the decimal.

       Parameters
       ---------
       decimal : Decimal
         The decimal value

       Returns
       -------
       int : The calculated scale
       """
    return max(0, -decimal.as_tuple().exponent)


def altseriesaccel(a, n):
    """
    Convergence acceleration for alternating series.  This is Algorithm 1 from
    /Convergence Acceleration of Alternating Series/ by Cohen, Villegas, and
    Zagier, with a minor tweak so that the d-value isn't computed via floating
    point.  The article is available at
    https://people.mpim-bonn.mpg.de/zagier/files/exp-math-9/fulltext.pdf.
    Input:
        a -- an iterable.  The series to be summed is a[0] - a[1] + a[2] - ...
        n -- the number of terms to use.  A couple dozen terms is probably good.
    Output: a floating-point number.
    Examples:
    """
    Vl, Vh = 2, 6
    for bit in bin(n)[2:]:
        Vl, Vh = (Vh * Vl - 6, Vh * Vh - 2) if bit == '1' else (Vl * Vl - 2,
            Vh * Vl - 6)
    d = Vl // 2
    b, c, s = -1, -d, 0
    for k in range(n):
        c = b - c
        s = s + c * next(a)
        b = (k + n) * (k - n) * b / ((k + 0.5) * (k + 1))
    return s / d


def theta(flag, S, K, t, r, sigma, b, pricing_function):
    """Calculate option theta using numerical integration.

    :param S: underlying asset price
    :type S: float
    :param K: strike price
    :type K: float
    :param sigma: annualized standard deviation, or volatility
    :type sigma: float
    :param t: time to expiration in years
    :type t: float
    :param r: risk-free interest rate
    :type r: float
    :param b: see above
    :type b: float
    :param flag: 'c' or 'p' for call or put.
    :type flag: str
    :param pricing_function: any function returning the price of an option
    :type pricing_function: python function object
    """
    if t <= 1.0 / 365.0:
        return pricing_function(flag, S, K, 1e-05, r, sigma, b
            ) - pricing_function(flag, S, K, t, r, sigma, b)
    else:
        return pricing_function(flag, S, K, t - 1.0 / 365.0, r, sigma, b
            ) - pricing_function(flag, S, K, t, r, sigma, b)


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

    Parameters
    ----------
    a : array_like
        Input tebsir.  If it is not already a tensor, a conversion is
        attempted.

    Returns
    -------
    number_of_dimensions : int
        The number of dimensions in `a`.  Scalars are zero-dimensional.

    See Also
    --------
    ndarray.ndim : equivalent method
    shape : dimensions of tensor
    Tensor.shape : dimensions of tensor

    Examples
    --------
    >>> import mars.tensor as mt
    >>> mt.ndim([[1,2,3],[4,5,6]])
    2
    >>> mt.ndim(mt.array([[1,2,3],[4,5,6]]))
    2
    >>> mt.ndim(1)
    0

    """
    from ..datasource import asarray
    try:
        return a.ndim
    except AttributeError:
        return asarray(a).ndim


def channel_to_freq(channel):
    """
	freq -- frequqncy in Hz
	return -- channel number
	"""
    if 1 <= channel <= 13:
        return 2407000000 + channel * 5 * 1000000
    if channel == 14:
        return 2484000000
    if channel >= 15:
        return 5035000000 + (channel - 7) * 5 * 1000000
    return None


def days_of_inventory_on_hand(number_of_days, inventory_turnover):
    """Computes days of inventory on hand.

    @params
    -------
    number_of_days: number of days in period
    inventory_turnover: inventory_turnover

    returns
    -------
    Days of inventory on hand, int or float

    explanation
    -----------

    """
    return number_of_days / inventory_turnover


def bounds(sizes):
    """Convert sequence of numbers into pairs of low-high pairs

    >>> bounds((1, 10, 50))
    [(0, 1), (1, 11), (11, 61)]

    """
    low = 0
    rv = []
    for size in sizes:
        rv.append((low, low + size))
        low += size
    return rv


@classmethod
def _snake_case(cls, text):
    """
        Transform text to snake cale (Based on SCREAMING_SNAKE_CASE)

        :param text:
        :return:
        """
    if text.islower():
        return text
    return cls._screaming_snake_case(text).lower()


def list_all_uploads():
    """Return a list of uploader objects, one for each upload that
        currently has an object available (tracked with weakrefs). This is
        intended for debugging purposes."""


def FindAtomIndexByIDs(atomData, loc, IDs, Draw=True):
    """finds the set of atom array indices for a list of atom IDs. Will search
    either the Atom table or the drawAtom table.

    :param list atomData: Atom or drawAtom table containting coordinates, etc.
    :param int loc: location of atom id in atomData record
    :param list IDs: atom IDs to be found
    :param bool Draw: True if drawAtom table to be searched; False if Atom table
      is searched

    :returns: list indx: atom (or drawAtom) indices

    """
    indx = []
    for i, atom in enumerate(atomData):
        if Draw and atom[loc] in IDs:
            indx.append(i)
        elif atom[loc] in IDs:
            indx.append(i)
    return indx


@classmethod
def is_mine(cls, pathname, filename='*.txt', plugin='', light=True, first=True
    ):
    """Check if it can handle the report file.

        :param str pathname: Path to the report directory.
        :param str filename: Regex matching the report file.
        :param str plugin: Name of the plugin that generated the report.
        :param bool light: `True` to only parse the ranking of the findings from the report.
        :param bool first: Only process first file (``True``) or each file that matched (``False``).

        :return: `True` if it supports the report, `False` otherwise.
        :rtype: :class:`bool`

        """
    if plugin:
        return True
    return False


def align_bone_y_axis(obj, bone, vec):
    """ Matches the bone y-axis to
        the given vector.
        Must be in edit mode.
    """
    bone_e = obj.data.edit_bones[bone]
    vec.normalize()
    vec = vec * bone_e.length
    bone_e.tail = bone_e.head + vec


def loc_eval(x, b):
    """
    Evaluate `x` using locally-weighted regression parameters.
    Degree of polynomial used in loess is inferred from b. `x`
    is assumed to be a scalar.
    """
    loc_est = 0
    for i in enumerate(b):
        loc_est += i[1] * x ** i[0]
    return loc_est


def add(a, b):
    """ Add two values, ignoring None """
    if a is None:
        if b is None:
            return None
        else:
            return b
    elif b is None:
        return a
    return a + b


def usage():
    """Print the usage message."""
    print('USAGE:   python3 main.py [-h -c -g -p <string> -l <loops>]\n')
    print('OPTIONS:')
    print('\t-h or --help: print the help')
    print('\t-c or --cmdl: use the command line version')
    print('\t-g or --gui: use the graphic user interface version')
    print(
        '\t-p or --profile: use the profile module to evaluate program performance.'
        )
    print('\t\t<string> is the string to use for prediction computation.')
    print('\t-l or --loops: run the profiling operation multiple times.')
    print('\t\t<loops> is the number of loops.')


def admin_user_global_sign_out(UserPoolId=None, Username=None):
    """
    Signs out users from all devices, as an administrator.
    Requires developer credentials.
    See also: AWS API Documentation

    :example: response = client.admin_user_global_sign_out(
        UserPoolId='string',
        Username='string'
    )

    :type UserPoolId: string
    :param UserPoolId: [REQUIRED]
            The user pool ID.

    :type Username: string
    :param Username: [REQUIRED]
            The user name.

    :rtype: dict
    :return: {}

    """
    pass


def _changes_available(isdsAppliance):
    """
    Check for pending changes on the appliance
    :param isdsAppliance:
    :return:
    """
    return True


def is_comment(line):
    """This function simply checks to see if a line in a RASP file is a comment.
    Comments begin with a ';' character.

    Args:
        line (str): Line from html text.

    Returns:
        bool: Whether or not a line is a comment.

    """
    return line.startswith(';')


def untag_resource(ResourceArn=None, TagKeys=None):
    """
    An API operation for removing tags from a resource.
    See also: AWS API Documentation

    :example: response = client.untag_resource(
        ResourceArn='string',
        TagKeys=[
            'string',
        ]
    )

    :type ResourceArn: string
    :param ResourceArn: [REQUIRED]
            The Amazon Resource Name (ARN) of the resource. Tagging is only supported for directories.

    :type TagKeys: list
    :param TagKeys: [REQUIRED]
            Keys of the tag that need to be removed from the resource.
            (string) --

    :rtype: dict
    :return: {}

    :returns:
    (dict) --

    """
    pass


def _to_pickleable_representation(model_name, model_type):
    """
    Extract a pickleable representation of the input Model type.

    Model types are runtime created types and so they are not pickleable.
    In order to workaround this limitation we extract a representation,
    which is pickleable such that we can re-create the input Model type
    (via ``_from_pickleable_representation``).

    NOTE:   This API should not be considered a public API and is meant
            only to be used by bravado_core.spec.Spec.__getstate__ .
    """
    return {'swagger_spec': model_type._swagger_spec, 'model_name':
        model_name, 'model_spec': model_type._model_spec, 'bases':
        model_type.__bases__, 'json_reference': model_type._json_reference}


@classmethod
def _getChildText(cls, parent, childname):
    """ provides text of child named by childname

        :param parent: parent node
        :type parent: :class:`lxml.etree.Element`
        :param childname: child name
        :type childname: :opj:`str`
        :returns: text string
        :rtype: :obj:`str`
        """
    children = parent.findall(childname)
    return cls._getText(children[0]) if len(children) else None


@staticmethod
def count_unzero_items(items_list):
    """Count nonzero items in list."""
    counter = 0
    for item in items_list:
        if items_list[item] != 0:
            counter += 1
    return counter


def prior_sample(bn):
    """Randomly sample from bn's full joint distribution. The result
    is a {variable: value} dict. [Figure 14.13]"""
    event = {}
    for node in bn.nodes:
        event[node.variable] = node.sample(event)
    return event


@staticmethod
def is_tomoscan_dir(directory: str, **kwargs) ->bool:
    """
        Check if the given directory is holding an acquisition

        :param str directory:
        :return: does the given directory contains any acquisition
        :rtype: bool
        """
    raise NotImplementedError('Base class')


def finalize_close(d):
    """ Finalize the closing of the declaration object.

    This is performed as a deferred call so that the window may fully
    close before the declaration is potentially destroyed.

    """
    d.visible = False
    d.closed()
    if d.destroy_on_close:
        d.destroy()


def get_vectors(mat1, mat2):
    """
    Uses sparse matrix tricks to convert
    into a vector the matrix values such
    that zero values that appear in only
    one of the matrices is kept. But
    zeros in two matrices are removed

    Requires two sparse matrices as input
    """
    assert mat1.shape == mat2.shape, 'Matrices have different shapes. Computation of correlation is not possible.'
    _mat = mat1 + mat2
    _mat.data += 1
    values1 = (_mat - mat1).data - 1
    values2 = (_mat - mat2).data - 1
    return values1, values2


def set_phagesdb_gnm_file(gnm):
    """Set the filename of a PhagesDB genome object."""
    file_url = gnm.misc['qced_genbank_file']
    if file_url is None:
        gnm.filename = ''
    else:
        gnm.filename = file_url


@staticmethod
def get(yf_query, params=None):
    """Run query to retrieve Yahoo fantasy football data.

        :param yf_query: chosen yfpy query method to run
        :param params: (optional) dict of parameters to be passed to chosen yfpy query function
        :return: result of the yfpy query
        """
    if params:
        return yf_query(**params)
    else:
        return yf_query()


def default_sub_generator(user):
    """
    Default function for setting OIDC_IDTOKEN_SUB_GENERATOR.
    """
    return str(user.id)


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

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

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


def __init__(cls, name, bases, namespace, **kwargs):
    """
        Needed for compatibility with Python 3.5
        """
    super().__init__(name, bases, namespace)


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

    The ".dev0" means dirty.

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


def link_to_collection(collection_index: int=-1, is_new: bool=False,
    new_collection_name: str=''):
    """Link objects to a collection

    :param collection_index: Collection Index, Index of the collection to move to
    :type collection_index: int
    :param is_new: New, Move objects to a new collection
    :type is_new: bool
    :param new_collection_name: Name, Name of the newly added collection
    :type new_collection_name: str
    """
    pass


def to_MWh(kwh):
    """ Converts from kilowatt-hours to megawatt-hours """
    return kwh / 1000


def calc_align(offset: int, align: int) ->int:
    """Calculate difference from given offset to next aligned offset."""
    return (align - offset) % align


def provide_postgresql_settings(settings):
    """
    Add some PostgreSQL-specific settings to the app config.  Specifically,
    this enables retrying transactions a second time, in an attempt to
    gracefully handle database restarts.
    """
    try:
        import pyramid_retry
    except ImportError:
        settings.setdefault('tm.attempts', 2)
    else:
        settings.setdefault('retry.attempts', 2)


def sourceids(obj, reftype):
    """ Return a set of objectids which have ``obj`` as a relationship
        source using ``reftype``.  ``obj`` can be an object or an object id."""


@staticmethod
def _prepare_all(messages):
    """
        Prepare a list of messages/notifications for storage.
        """
    for message in messages:
        message.prepare()


def nicer_type_name(name: str) ->str:
    """
    Make a nicer name for a type.

    :param name: The ugly name
    :return: The nicer name
    """
    if name.endswith('_factory'):
        name = name[:-8] + 's'
    name = name.capitalize()
    return name


def load(word, reload=False):
    """ load from cache if not found read from anywhere"""


def httpdate(date_obj):
    """
    Formats a datetime object for use in HTTP headers.

        >>> import datetime
        >>> httpdate(datetime.datetime(1970, 1, 1, 1, 1, 1))
        'Thu, 01 Jan 1970 01:01:01 GMT'
    """
    return date_obj.strftime('%a, %d %b %Y %H:%M:%S GMT')


def circle(start, end):
    """Draw circle from start to end."""
    pass


@staticmethod
def field_to_dynamo_type(field):
    """Returns the dynamo type character given the field."""
    raise NotImplementedError('Child class must implement field_to_dynamo_type'
        )


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 '+'


@classmethod
def from_raw_json(cls, conn, raw_json):
    """
        Create a MoodleCourse object from raw JSON information.
        """
    return cls(conn=conn, course_id=raw_json['id'], fullname=raw_json[
        'fullname'], shortname=raw_json['shortname'])


def fib(n):
    """Fibonacci example function

    Args:
      n (int): integer

    Returns:
      int: n-th Fibonacci number
    """
    assert n > 0
    a, b = 1, 1
    for i in range(n - 1):
        a, b = b, a + b
    return a


def get_xml_event_start(event_buffer):
    """ get the event start of an event that is different (in time)from the
        adjoining event, in XML format """
    result_pattern = "<result offset='"
    time_key_pattern = "<field k='_time'>"
    time_start_pattern = '<value><text>'
    time_end_pattern = '<'
    event_end_pattern = '</result>'
    event_start = event_buffer.find(result_pattern)
    event_end = event_buffer.find(event_end_pattern, event_start) + len(
        event_end_pattern)
    if event_end < 0:
        return -1, -1, ''
    time_key_start = event_buffer.find(time_key_pattern, event_start)
    time_start = event_buffer.find(time_start_pattern, time_key_start) + len(
        time_start_pattern)
    time_end = event_buffer.find(time_end_pattern, time_start + 1)
    last_time = event_buffer[time_start:time_end]
    event_start = event_end
    while event_end > 0:
        event_start = event_buffer.find(result_pattern, event_start + 1)
        event_end = event_buffer.find(event_end_pattern, event_start) + len(
            event_end_pattern)
        if event_end < 0:
            return -1, -1, ''
        time_key_start = event_buffer.find(time_key_pattern, event_start)
        time_start = event_buffer.find(time_start_pattern, time_key_start)
        time_end = event_buffer.find(time_end_pattern, time_start)
        this_time = event_buffer[time_start:time_end]
        if this_time != last_time:
            return event_start, event_end, last_time
        event_start = event_end
    return -1, -1, ''


def safe_version(*args, **kwargs) ->str:
    """
    Package resources is a very slow load
    """
    import pkg_resources
    return pkg_resources.safe_version(*args, **kwargs)


def group_ndof(ndof_molec, nmolecs, molec_group=None):
    """
    Sums up the partitioned degrees of freedom for a
    given group or the entire system.

    Parameters
    ----------
    ndof_molec : List[dict]
        Partitioned degrees of freedom per molecule.
    nmolecs : int
        Total number of molecules in the system.
    molec_group : iterable
        Indeces of the group to be summed up. None defaults to all molecules
        in the system. Default: None.

    Returns
    -------
    ndof : dict
        Dictionary of partitioned degrees of freedom for the group.
    """
    ndof = {'tot': 0, 'tra': 0, 'rni': 0, 'rot': 0, 'int': 0}
    if molec_group is None:
        molec_group = range(nmolecs)
    for idx_molec in molec_group:
        for key in ndof.keys():
            ndof[key] += ndof_molec[idx_molec][key]
    return ndof


def escape_curly_brackets(url_path):
    """
    Double brackets in regex of url_path for escape string formatting
    """
    return url_path.replace('{', '{{').replace('}', '}}')


def add_node(graph, node_id, attrs=dict()):
    """Add a node to a graph.

    Parameters
    ----------
    graph : regraph.Graph
    node_id : hashable
        Prefix that is prepended to the new unique name.
    attrs : dict, optional
        Node attributes.

    Raises
    -------
    regraph.exceptions.GraphError
        Raises an error if node already exists in the graph.
    """
    graph.add_node(node_id, attrs)


def without_last_method(form):
    """ Return a new form without last method from methods_stack """
    stack = form[4][:-1]
    return form[:4] + (stack,)


@staticmethod
def get_report_data_file_id():
    """
        Get the report.data id of the extractor.
        :return: the report.data id
        """
    return 'basecaller.sequencing.summary.1d.extractor'


def getPrincipalsForGroup(groupid):
    """Get principals which belong to the group"""


@classmethod
def private2public(cls, private_key: str) ->bytes:
    """
        generate public key from private key

        :param private_key: private key
        :return: public key in bytes format

        .. code-block: python

            >>> from asimov import AccountFactory
            >>> AccountFactory.private2public("0xbba692e559fda550d0157669b101bafddb23e7f57aeeb5cef5494e7a41a1f056")
            >>> b'043a68576342553357f042c6ede12bd3ed01cb61ad39848908883cab93f66c76016fb60b2b472d6caf316c699cb38f61d5daef3792402461ddc449a18b0fc8ee32'
        """
    key_hex = cls.__private2public(private_key)
    return cls.__add_bitcoin_byte(key_hex)


def manage_medium(padmet, new_growth_medium=None, padmetRef=None, verbose=False
    ):
    """
    Manage medium of a padmet. If new_growth_medium give, use this list of compound
    to define the new medium and create transport and exchange reactions.
    if padmetRef given, use the information from padmetRef to create the missing compound.
    If no new_growth_medium given: remove the current medium in the padmet.

    Parameters
    ----------
    padmet: padmet.classes.PadmetSpec
        padmet to update
    new_growth_medium: list
        list of compound id representing the medium
    padmetRef: padmet.classes.PadmetRef
        padmet containing the database of reference
    verbose: bool
        if True print information

    Returns
    -------
    padmet.classes.PadmetSpec:
        New padmet after updating medium
    """
    if new_growth_medium:
        padmet.set_growth_medium(new_growth_medium=new_growth_medium,
            padmetRef=padmetRef, verbose=verbose)
    else:
        padmet.remove_growth_medium(verbose=verbose)
    return padmet


def setQualifiedSubjects(qualified_subjects):
    """Set the qualified Subjects elements.

        The argument must be a sequence of Subject `IDublinCoreElementItem`.
        """


def create_or_update(model, *, defaults=None, save=True, **kwargs):
    """
    Create or update a django model instance.

    :param model:
    :param defaults:
    :param kwargs:
    :return: object, created, updated

    """
    obj, created = model._default_manager.get_or_create(defaults=defaults,
        **kwargs)
    updated = False
    if not created:
        if defaults:
            for k, v in defaults.items():
                if getattr(obj, k) != v:
                    setattr(obj, k, v)
                    updated = True
        if updated and save:
            obj.save()
    return obj, created, updated


def safe_decode(s, coding='utf-8', errors='surrogateescape'):
    """decode bytes to str, with round-tripping "invalid" bytes"""
    if s is None:
        return None
    return s.decode(coding, errors)


def find_component(interpreter, component_name):
    """Finds a component in a pipeline."""
    for c in interpreter.pipeline:
        if c.name == component_name:
            return c
    return None


def read_bytes_from_field_file(field_file):
    """
    Returns the bytes read from a FieldFile

    :param ~django.db.models.fields.files.FieldFile field_file:
    :return six.binary_type: bytes read from the given field_file
    """
    try:
        field_file.open()
        result = field_file.read()
    finally:
        field_file.close()
    return result


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

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

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


@classmethod
def _process_foreign_keys(cls, foreign_keys, node_data):
    """For each foreign key try to load the actual object so load_bulk
        doesn't fail trying to load an int where django expects a
        model instance
        """
    for key in foreign_keys.keys():
        if key in node_data:
            node_data[key] = foreign_keys[key].objects.get(pk=node_data[key])


@classmethod
def add_from_case_control(cls, line, line_upper, lines, i):
    """
        Creates a card from the Case Control Deck

        Parameters
        ----------
        line : str
            the line of the card
        line_upper : str
            unused
        lines : List[str]
            unused
        i : int
            unused

        """
    value = line_upper.split('=')[1]
    try:
        out = cls(value)
    except ValueError:
        print(line)
        raise
    return out


def loads(model_obj, data_dict):
    """将dict数据按key写入到模具的属性"""
    for key, value in data_dict.items():
        if hasattr(model_obj, key) and getattr(model_obj, key) == value:
            continue
        setattr(model_obj, key, value)


def parse_longitude(longitude, hemisphere):
    """Parse a NMEA-formatted longitude pair.

    :param str longitude: Longitude in DDDMM.MMMM
    :param str hemisphere: East or West
    :rtype: ``float``
    :return: Decimal representation of longitude

    """
    longitude = int(longitude[:3]) + float(longitude[3:]) / 60
    if hemisphere == 'W':
        longitude = -longitude
    elif not hemisphere == 'E':
        raise ValueError('Incorrect North/South value %r' % hemisphere)
    return longitude


def _bmaction(old, new):
    """small utility for bookmark pushing"""
    if not old:
        return b'export'
    elif not new:
        return b'delete'
    return b'update'


def get_tags_for_deliverable(team_data, team, name):
    """Return the tags for the deliverable owned by the team."""
    if team not in team_data:
        return set()
    team_info = team_data[team]
    dinfo = team_info['deliverables'].get(name)
    if not dinfo:
        return set()
    return set(dinfo.get('tags', [])).union(set(team_info.get('tags', [])))


@classmethod
def run_hooks(cls, hook_type, *args, **kwargs):
    """Run all hooks of specified type.

        :param cls: class that registers hooks
        :param hook_type: hook type, e.g., '__pre_parse_args__'
        :param args: args to be passed to every hook function
        :param kwargs: kwargs to be passed to every hook function
        """
    hook_funcs = cls._hooks_map.get(hook_type) or []
    for hook_func in hook_funcs:
        hook_func(*args, **kwargs)


def is_boolean(obj):
    """Test if input object is a boolean.

    > *Input arguments*

    * `obj`: Input variable.

    > *Returns*

    `True`, if `obj` is a boolean.
    """
    return isinstance(obj, bool) or obj in [0, 1]


def update_team_member(projectId=None, userArn=None, projectRole=None,
    remoteAccessAllowed=None):
    """
    Updates a team member's attributes in an AWS CodeStar project. For example, you can change a team member's role in the project, or change whether they have remote access to project resources.
    See also: AWS API Documentation

    :example: response = client.update_team_member(
        projectId='string',
        userArn='string',
        projectRole='string',
        remoteAccessAllowed=True|False
    )

    :type projectId: string
    :param projectId: [REQUIRED]
            The ID of the project.

    :type userArn: string
    :param userArn: [REQUIRED]
            The Amazon Resource Name (ARN) of the user for whom you want to change team membership attributes.

    :type projectRole: string
    :param projectRole: The role assigned to the user in the project. Project roles have different levels of access. For more information, see Working with Teams in the AWS CodeStar User Guide.

    :type remoteAccessAllowed: boolean
    :param remoteAccessAllowed: Whether a team member is allowed to remotely access project resources using the SSH public key associated with the user's profile. Even if this is set to True, the user must associate a public key with their profile before the user can access resources.

    :rtype: dict
    :return: {
        'userArn': 'string',
        'projectRole': 'string',
        'remoteAccessAllowed': True|False
    }

    """
    pass


def smooth_tilt():
    """Interpolate tilt of selected points

    """
    pass


def dfchange(df1, df2):
    """Determines the differences between two pandas dataframes"""
    dfchanges = df2.loc[df2[~df2.isin(df1)].dropna(how='all').index,]
    nchanges = dfchanges.shape[0]
    return dfchanges, nchanges


@classmethod
def from_string(cls, s: str) ->'ComponentRef':
    """
        Convert the string pointing to a component using dot notation to
        a component reference.
        :param s: string pointing to component using dot notation
        :return: ComponentRef
        """
    components = s.split('.')
    return cls.from_tuple(components)


def drop_duplicate_cols(df):
    """Drop duplicate column names from a DataFrame, keeping the first."""
    seen = set()
    renamer = {}
    cols = df.columns.tolist()
    for i, c in enumerate(df.columns):
        if c in seen:
            renamer[i] = c + '_dup'
            cols[i] = renamer[i]
        else:
            seen.add(c)
    df.columns = cols
    df = df.drop(renamer.values(), 1)
    return df


@staticmethod
def _communicate(subproc, inputstr=None):
    """
        Encode the input given to the subprocess if any
        :param subproc:
        :param inputstr:
        :return: A tuple of (stdout, stderr)
        """
    if inputstr is None:
        return subproc.communicate()
    if not inputstr:
        inputstr = ''
    return subproc.communicate(inputstr.encode())


def get_param_map(iline, word, required_keys=None):
    """
    get the optional arguments on a line

    Examples
    --------
    >>> iline = 0
    >>> word = 'elset,instance=dummy2,generate'
    >>> params = get_param_map(iline, word, required_keys=['instance'])
    params = {
        'elset' : None,
        'instance' : 'dummy2,
        'generate' : None,
    }
    """
    if required_keys is None:
        required_keys = []
    words = word.split(',')
    param_map = {}
    for wordi in words:
        if '=' not in wordi:
            key = wordi.strip()
            value = None
        else:
            sword = wordi.split('=')
            assert len(sword) == 2, sword
            key = sword[0].strip()
            value = sword[1].strip()
        param_map[key] = value
    msg = ''
    for key in required_keys:
        if key not in param_map:
            msg += 'line %i: %r not found in %r\n' % (iline, key, word)
    if msg:
        raise RuntimeError(msg)
    return param_map


def extend(other=None, **kwargs):
    """ Add a set of keys and values, not overwriting any previous
        values.  The ``other`` structure may be a list of two-tuples or a
        dictionary.  If ``**kwargs`` is passed, its value *will* overwrite
        existing values."""


def timeseries(start='2000-01-01', end='2000-01-31', freq='1s',
    partition_freq='1d', dtypes={'name': str, 'id': int, 'x': float, 'y':
    float}, seed=None, **kwargs):
    """ Create timeseries dataframe with random data

    Parameters
    ----------
    start : datetime (or datetime-like string)
        Start of time series
    end : datetime (or datetime-like string)
        End of time series
    dtypes : dict
        Mapping of column names to types.
        Valid types include {float, int, str, 'category'}
    freq : string
        String like '2s' or '1H' or '12W' for the time series frequency
    partition_freq : string
        String like '1M' or '2Y' to divide the dataframe into partitions
    seed : int (optional)
        Randomstate seed
    kwargs:
        Keywords to pass down to individual column creation functions.
        Keywords should be prefixed by the column name and then an underscore.

    Examples
    --------
    >>> import dask
    >>> df = dask.datasets.timeseries()
    >>> df.head()  # doctest: +SKIP
              timestamp    id     name         x         y
    2000-01-01 00:00:00   967    Jerry -0.031348 -0.040633
    2000-01-01 00:00:01  1066  Michael -0.262136  0.307107
    2000-01-01 00:00:02   988    Wendy -0.526331  0.128641
    2000-01-01 00:00:03  1016   Yvonne  0.620456  0.767270
    2000-01-01 00:00:04   998   Ursula  0.684902 -0.463278
    >>> df = dask.datasets.timeseries(
    ...     '2000', '2010',
    ...     freq='2H', partition_freq='1D', seed=1,  # data frequency
    ...     dtypes={'value': float, 'name': str, 'id': int},  # data types
    ...     id_lam=1000  # control number of items in id column
    ... )
    """
    from dask.dataframe.io.demo import make_timeseries
    return make_timeseries(start=start, end=end, freq=freq, partition_freq=
        partition_freq, seed=seed, dtypes=dtypes, **kwargs)


@staticmethod
def mask_string(s):
    """
        return empty string or as many ``*`` as the length of the string
        """
    if s is None:
        return ''
    else:
        return '*' * len(s)


def build_empty_response(search_path, operation_name, service_model):
    """
    Creates an appropriate empty response for the type that is expected,
    based on the service model's shape type. For example, a value that
    is normally a list would then return an empty list. A structure would
    return an empty dict, and a number would return None.

    :type search_path: string
    :param search_path: JMESPath expression to search in the response
    :type operation_name: string
    :param operation_name: Name of the underlying service operation.
    :type service_model: :ref:`botocore.model.ServiceModel`
    :param service_model: The Botocore service model
    :rtype: dict, list, or None
    :return: An appropriate empty value
    """
    response = None
    operation_model = service_model.operation_model(operation_name)
    shape = operation_model.output_shape
    if search_path:
        for item in search_path.split('.'):
            item = item.strip('[0123456789]$')
            if shape.type_name == 'structure':
                shape = shape.members[item]
            elif shape.type_name == 'list':
                shape = shape.member
            else:
                raise NotImplementedError(
                    'Search path hits shape type {0} from {1}'.format(shape
                    .type_name, item))
    if shape.type_name == 'structure':
        response = {}
    elif shape.type_name == 'list':
        response = []
    elif shape.type_name == 'map':
        response = {}
    return response


def convert_by_vocab(vocab, items):
    """Converts a sequence of [tokens|ids] using the vocab."""
    output = []
    for item in items:
        output.append(vocab[item])
    return output


def out_filter(user):
    """
    输出给用户是，出于安全考虑，以及格式要求，进行过滤操作
    :param user: 用户对象
    :return: user 过滤后的用户对象
    """
    if user is None:
        return user
    if user.get('pwd_hash') is None:
        user['has_pwd'] = 0
    else:
        user['has_pwd'] = 1
        user.pop('pwd_hash')
        user.pop('salt')
    return user


def pastebuffer(autoselect: bool=True, active_collection: bool=True):
    """Objects from the clipboard are pasted

    :param autoselect: Select, Select pasted objects
    :type autoselect: bool
    :param active_collection: Active Collection, Put pasted objects in the active collection
    :type active_collection: bool
    """
    pass


def insert(index, header, pattern, chain=None, tag=None):
    """Insert a header match rule.

        Inserts the given rule at the given index position in this
        mailing list's header match list.

        :param index: The index to insert the rule at.
        :type index: integer
        :param header: The email header to filter on.  It will be converted to
            lower case for consistency.
        :type header: string
        :param pattern: The regular expression to use.
        :type pattern: string
        :param chain: The chain to jump to, or None to use the site-wide
            antispam jump chain via the configuration.  Defaults to None.
        :type chain: string or None
        :param tag: An arbitrary value to identify a set of IHeaderMatches.
        :type tag: string or None
        :raises ValueError: if the header/pattern pair already exists for this
            mailing list.
        """


def is_multiprocessing_queue(queue):
    """Return whether `queue` is a multiprocessing queue."""
    return queue.__module__.startswith('multiprocessing')


def GetMRUEntryLabel(n, path):
    """
    Returns the string used for the MRU list items in the menu.

    :param integer `n`: the index of the file name in the MRU list;
    :param string `path`: the full path of the file name.

    :note: The index `n` is 0-based, as usual, but the strings start from 1.
    """
    pathInMenu = path.replace('&', '&&')
    return '&%d %s' % (n + 1, pathInMenu)


def _parse_boolean(xml_boolean):
    """Converts strings "true" and "false" from XML files to Python bool"""
    if xml_boolean is not None:
        assert xml_boolean in ['true', 'false'
            ], 'The boolean string must be "true" or "false"'
        return {'true': True, 'false': False}[xml_boolean]


def quotient(a, b):
    """Le quotient de la division de ``a`` par ``b``.

    Arguments:
        a (int): Un nombre entier.
        b (int): Un nombre entier non nul.
    """
    return a // b


def calc_q_c1ncs(q_c1n, delta_q_c1n):
    """
    q_c1ncs from CPT, Eq 2.10
    """
    q_c1ncs = q_c1n + delta_q_c1n
    return q_c1ncs


@classmethod
def geom_col_name(cls):
    """
        Return the name of the metadata column used to store the feature
        geometry column.
        """
    return 'f_geometry_column'


@property
def _mapping_(cls):
    """Only for indexed (Not BaseClass)."""
    return NotImplemented


@classmethod
def arg_xaxis(cls, parser):
    """Add an `~argparse.ArgumentGroup` for X-axis options.
        """
    return cls._arg_axis('x', parser)


def _constrain(value, lb=0, ub=1):
    """Helper for Color constructors.  Constrains a value to a range."""
    if value < lb:
        return lb
    elif value > ub:
        return ub
    else:
        return value


def __new__(cls, val, *args):
    """Creates str subtype."""
    if not isinstance(val, str):
        raise TypeError('Terminal value must be str.')
    return str.__new__(cls, val)


def is_token_subtype(ttype, other):
    """
    Return True if ``ttype`` is a subtype of ``other``.

    exists for backwards compatibility. use ``ttype in other`` now.
    """
    return ttype in other


@classmethod
def attempt_convert_uuid_hex_to_bytes(cls, value):
    """Attempt to convert value to bytes or return value.

        :param value: value to attempt to convert to bytes
        :returns: tuple containing boolean indicating whether user_id was
                  stored as bytes and uuid value as bytes or the original value

        """
    try:
        return True, cls.convert_uuid_hex_to_bytes(value)
    except ValueError:
        return False, value


def split_command_line(command_line):
    """This splits a command line into a list of arguments. It splits arguments
    on spaces, but handles embedded quotes, doublequotes, and escaped
    characters. It's impossible to do this with a regular expression, so I
    wrote a little state machine to parse the command line. """
    arg_list = []
    arg = ''
    state_basic = 0
    state_esc = 1
    state_singlequote = 2
    state_doublequote = 3
    state_whitespace = 4
    state = state_basic
    for c in command_line:
        if state == state_basic or state == state_whitespace:
            if c == '\\':
                state = state_esc
            elif c == "'":
                state = state_singlequote
            elif c == '"':
                state = state_doublequote
            elif c.isspace():
                if state == state_whitespace:
                    None
                else:
                    arg_list.append(arg)
                    arg = ''
                    state = state_whitespace
            else:
                arg = arg + c
                state = state_basic
        elif state == state_esc:
            arg = arg + c
            state = state_basic
        elif state == state_singlequote:
            if c == "'":
                state = state_basic
            else:
                arg = arg + c
        elif state == state_doublequote:
            if c == '"':
                state = state_basic
            else:
                arg = arg + c
    if arg != '':
        arg_list.append(arg)
    return arg_list


def order_set(l):
    """

    Reduce ``l`` to uniques while preserving order.

    :param l: an iterable
    :type l: ``iterable``
    :return: see description.
    """
    to_return = list()
    for i in l:
        if i not in to_return:
            to_return.append(i)
    return to_return


@classmethod
def find_in_registry(cls, entity_registry_id: str, registry_id: str=None,
    registry_name: str=None):
    """Get an entity from a registry by their ids.

        :param entity_registry_id: entity registry id
        :param registry_id: registery id. If none, 'registry_name' must be provided.
        :param registry_name: registry name. If None, 'registry_id' must be provided
        :return: instance
        """
    entities = cls.get_in_registry([entity_registry_id], registry_id=
        registry_id, registry_name=registry_name)
    if entities:
        return entities[0]
    return None


def HTML_Input_Table(Input_Dict, Input_Params, file):
    """
    Add table to html file.

    :param Input_Dict: input values dictionary
    :type Input_Dict : dict
    :param Input_Params: input parameters dictionary
    :type Input_Params : dict
    :param file: html file object
    :type file : file object
    :return: None
    """
    file.write('
Inputs
\n')
    file.write(
        '
\n'
        )
    file.write(
        '
\n'
        )
    file.write(
        '\n'
         + 'Input\n	')
    file.write(
        '\n'
         + """Description
	""")
    file.write(
        '\n'
         + """Value

""")
    Input_Params_Keys = sorted(Input_Params.keys())
    for key in Input_Params_Keys:
        file.write(
            """

"""
            )
        file.write(
            '\n'
             + key + '\n	\n')
        file.write(
            '\n'
             + Input_Params[key] + '\n	\n')
        file.write(
            '\n'
             + str(Input_Dict[key]) + '\n	\n')
    file.write('
\n')


def get_sctrajs(ftrajs, scaler):
    """
    Scale a dictionary of featurized trajectories
    :param traj_dict: The dictionary of featurized trajectories, represented as np.arrays of shape (n_frames, n_features)
    :param scaler: A scaler object which must have been fit first
    :return ftrajs: A dict of scaled trajectories, represented as np.arrays of shape (n_frames, n_features)
    """
    sctrajs = {}
    for k, v in ftrajs.items():
        sctrajs[k] = scaler.partial_transform(v)
    return sctrajs


def get_breadcrumbs(url):
    """Given a url returns a list of breadcrumbs, which are each a tuple of (name, url)."""

    def breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen):
        """Add tuples of (name, url) to the breadcrumbs list, progressively chomping off parts of the url."""
        return []


def __create_paired_window__(hypothesis, reference, window_size,
    lamprier_et_al_2007_fix):
    """
    Create a set of pairs of units from each segmentation to go over using a
    window.
    """
    phantom_size = 0
    if lamprier_et_al_2007_fix is False:
        units_ref_hyp = zip(reference, hypothesis)
    else:
        phantom_size = window_size
        phantom_size = 1 if phantom_size <= 0 else phantom_size
        phantom = tuple([0] * phantom_size)
        units_ref_hyp = zip(phantom + reference + phantom, phantom +
            hypothesis + phantom)
    return list(units_ref_hyp), phantom_size


def checkPassword(user, pswd, service, default_realm, verify=True):
    """
    This function provides a simple way to verify that a user name and password match
    those normally used for Kerberos authentication. It does this by checking that the
    supplied user name and password can be used to get a ticket for the supplied service.
    If the user name does not contain a realm, then the default realm supplied is used.

    NB For this to work properly the Kerberos must be configured properly on this machine.
    That will likely mean ensuring that the edu.mit.Kerberos preference file has the correct
    realms and KDCs listed.

    @param user:          a string containing the Kerberos user name. A realm may be
        included by appending an '@' followed by the realm string to the actual user id.
        If no realm is supplied, then the realm set in the default_realm argument will
        be used.
    @param pswd:          a string containing the password for the user.
    @param service:       a string containging the Kerberos service to check access for.
        This will be of the form 'sss/xx.yy.zz', where 'sss' is the service identifier
        (e.g., 'http', 'krbtgt'), and 'xx.yy.zz' is the hostname of the server.
    @param default_realm: a string containing the default realm to use if one is not
        supplied in the user argument. Note that Kerberos realms are normally all
        uppercase (e.g., 'EXAMPLE.COM').
    @param verify: a boolean flagging KDC verification as enabled or disabled
        (default: True, i.e. enabled).
    @return:              True if authentication succeeds, False otherwise.
    """


@staticmethod
def is_required(field):
    """ Return True is field's value should be defined.

        :return bool:

        """
    return True


def encrypt(message: str, key: int):
    """
    Encrypts a message in the caesar cipher with a given key
    :param: message String - The message that should be encrypted
    :param: key Integer - The key that has to be used to encrypt the message
    :return: encryptedMessage String - Returns the encrypted message
    """
    if message == '':
        print('[ERROR] The message cannot be empty')
        return
    elif key > 26 or key < 1:
        print('[ERROR] The key cannot be higher than 26 or less than 1')
        return
    else:
        encryptedMessage = ''
        for character in message:
            if character.isalpha():
                number = ord(character)
                number += key
                if character.isupper():
                    if number > ord('Z'):
                        number -= 26
                    elif number < ord('A'):
                        number += 26
                elif character.islower():
                    if number > ord('z'):
                        number -= 26
                    elif number < ord('a'):
                        number += 26
                encryptedMessage += chr(number)
            else:
                encryptedMessage += character
        return encryptedMessage


def isPrivate(urlPath, repos):
    """Check if a URL is a private URL

    >>> isPrivate('/downloads/me/', None)
    True
    >>> isPrivate('/downloads/me/', [])
    False
    >>> isPrivate('/downloads/me/', ['me'])
    True
    >>> isPrivate('/repos/me/', ['me'])
    True
    >>> isPrivate('/downloads/me/', ['unknown'])
    False
    >>> isPrivate('/somewhere/me/', ['me'])
    False
    """
    if repos is None:
        return True
    for repo in repos:
        if not repo:
            continue
        api_repo = '/repos/%s/' % (repo,)
        dl_repo = '/downloads/%s/' % (repo,)
        if api_repo in urlPath or dl_repo in urlPath:
            return True
    return False


@classmethod
def validate(cls, value):
    """
        Validate method is automatically called pydantic.
        """
    addr = cls._get_addr(value)
    mask = cls._get_mask(value)
    rdid = cls._get_rdid(value)
    cls._validate_rdid(rdid)
    if mask:
        cls._validate_ip(f'{addr}/{mask}')
    else:
        cls._validate_ip(addr)
    return cls(f'{value}')


def get_attachment_upload_dir(instance, filename):
    """Determine upload dir for task attachment files.
    """
    return '/'.join(['tasks', 'attachments', str(instance.task.id), filename])


@classmethod
def is_reply(cls, tweet):
    """Check if the tweet is a reply"""
    return bool(tweet['in_reply_to_user_id']) or tweet['text'].startswith('@')


def heading_depth(line):
    """Returns depth of heading indent

    '# heading' returns 1
    '### heading' returns 3

    Args:
        line (str): line in a markdown page
    """
    assert line.startswith('#')
    n = 0
    while line[n:n + 1] == '#':
        n += 1
    return n


def histogram(inlist, numbins=10, defaultreallimits=None, printextras=0):
    """
Returns (i) a list of histogram bin counts, (ii) the smallest value
of the histogram binning, and (iii) the bin width (the last 2 are not
necessarily integers).  Default number of bins is 10.  If no sequence object
is given for defaultreallimits, the routine picks (usually non-pretty) bins
spanning all the numbers in the inlist.

Usage:   lhistogram (inlist, numbins=10, defaultreallimits=None,suppressoutput=0)
Returns: list of bin values, lowerreallimit, binsize, extrapoints
"""
    if defaultreallimits != None:
        if type(defaultreallimits) not in [list, tuple] or len(
            defaultreallimits) == 1:
            lowerreallimit = defaultreallimits
            upperreallimit = 1.000001 * max(inlist)
        else:
            lowerreallimit = defaultreallimits[0]
            upperreallimit = defaultreallimits[1]
        binsize = (upperreallimit - lowerreallimit) / float(numbins)
    else:
        estbinwidth = (max(inlist) - min(inlist)) / float(numbins) + 1e-06
        binsize = (max(inlist) - min(inlist) + estbinwidth) / float(numbins)
        lowerreallimit = min(inlist) - binsize / 2
    bins = [0] * numbins
    extrapoints = 0
    for num in inlist:
        try:
            if num - lowerreallimit < 0:
                extrapoints = extrapoints + 1
            else:
                bintoincrement = int((num - lowerreallimit) / float(binsize))
                bins[bintoincrement] = bins[bintoincrement] + 1
        except:
            extrapoints = extrapoints + 1
    if extrapoints > 0 and printextras == 1:
        print('\nPoints outside given histogram range =', extrapoints)
    return bins, lowerreallimit, binsize, extrapoints


def describe_tape_archives(TapeARNs=None, Marker=None, Limit=None):
    """
    Returns a description of specified virtual tapes in the virtual tape shelf (VTS). This operation is only supported in the tape gateway architecture.
    If a specific TapeARN is not specified, AWS Storage Gateway returns a description of all virtual tapes found in the VTS associated with your account.
    See also: AWS API Documentation

    Examples
    Returns a description of specified virtual tapes in the virtual tape shelf (VTS).
    Expected Output:

    :example: response = client.describe_tape_archives(
        TapeARNs=[
            'string',
        ],
        Marker='string',
        Limit=123
    )

    :type TapeARNs: list
    :param TapeARNs: Specifies one or more unique Amazon Resource Names (ARNs) that represent the virtual tapes you want to describe.
            (string) --

    :type Marker: string
    :param Marker: An opaque string that indicates the position at which to begin describing virtual tapes.

    :type Limit: integer
    :param Limit: Specifies that the number of virtual tapes descried be limited to the specified number.

    :rtype: dict
    :return: {
        'TapeArchives': [
            {
                'TapeARN': 'string',
                'TapeBarcode': 'string',
                'TapeCreatedDate': datetime(2015, 1, 1),
                'TapeSizeInBytes': 123,
                'CompletionTime': datetime(2015, 1, 1),
                'RetrievedTo': 'string',
                'TapeStatus': 'string',
                'TapeUsedInBytes': 123
            },
        ],
        'Marker': 'string'
    }

    """
    pass


def get_pixel_scale():
    """Return: arcsec / pixel, something like 0.02 (NaCo)"""
    from abism.util import get_root
    try:
        pxll = get_root().header.sinf_pixel_scale
    except:
        pxll = get_root().header.pixel_scale
    return pxll


def create_temp_folders_if_needed(targets):
    """ Create temp folders for targets if needed """
    for target in targets:
        try:
            target.create_temp_folder()
        except AttributeError as err:
            next


@classmethod
def get_doc_type(cls):
    """
        Get the doc-type of the row.
        This method is called internally during save to ensure that the record in the
        proxy model always have the right doc_type
        :return: string (doc_type)
        """
    return ''


def cleanup_uri(uri):
    """remove angle brackets from a URI, if any"""
    if uri.startswith('<') and uri.endswith('>'):
        return uri[1:-1]
    return uri


def default_object_scoper(object_name):
    """ Scopes a basic data model object name, via a tag for that object """
    return 'tag="{}"'.format(object_name)


def doc_handle_find(event):
    """Documentation for handlers bound to ``evt.EVT_C_FIND``.

    User implementation of this event handler is required if one or more
    services that use C-FIND are to be supported. If a handler is
    not implemented and bound to ``evt.EVT_C_FIND`` then the C-FIND request
    will be responded to using a  *Status* value of ``0xC311`` - Failure.

    Yields ``(status, identifier)`` pairs, where *status* is either an
    ``int`` or pydicom ``Dataset`` containing a (0000,0900) *Status*
    element and *identifier* is a C-FIND *Identifier* ``Dataset``.

    **Event**

    ``evt.EVT_C_FIND``

    **Supported Service Classes**

    * *Query/Retrieve Service Class*
    * *Basic Worklist Management Service*
    * *Relevant Patient Information Query Service*
    * *Substance Administration Query Service*
    * *Hanging Protocol Query/Retrieve Service*
    * *Defined Procedure Protocol Query/Retrieve Service*
    * *Color Palette Query/Retrieve Service*
    * *Implant Template Query/Retrieve Service*

    **Status**

    Success
      | ``0x0000`` - Success

    Failure
      | ``0xA700`` - Out of resources
      | ``0xA900`` - Identifier does not match SOP class
      | ``0xC000`` to ``0xCFFF`` - Unable to process

    Cancel
      | ``0xFE00`` - Matching terminated due to Cancel request

    Pending
      | ``0xFF00`` - Matches are continuing: current match is supplied and
         any Optional Keys were supported in the same manner as Required
         Keys
      | ``0xFF01`` - Matches are continuing: warning that one or more Optional
        Keys were not supported for existence and/or matching for this
        Identifier

    Parameters
    ----------
    event : events.Event
        The event representing a service class receiving a C-FIND
        request message. ``Event`` attributes are:

        * ``assoc`` : the
          :py:class:`association <pynetdicom.association.Association>`
          that is running the service that received the C-FIND request.
        * ``context`` : the presentation context the request was sent under
          as a ``presentation.PresentationContextTuple``.
        * ``event`` : the event that occurred as ``namedtuple``.
        * ``request`` : the received
          :py:class:`C-FIND request <pynetdicom.dimse_primitives.C_FIND>`
        * ``timestamp`` : the
          `date and time <https://docs.python.org/3/library/datetime.html#datetime-objects>`_
          that the C-FIND request was processed by the service.

        ``Event`` properties are:

        * ``identifier`` : the decoded
          :py:class:`Dataset <pydicom.dataset.Dataset>` contained within the
          C-FIND request's *Identifier* parameter. Because *pydicom* uses
          a deferred read when decoding data, if the decode fails the returned
          ``Dataset`` will only raise an exception at the time of use.
        * ``is_cancelled`` : returns ``True`` if a
          C-CANCEL request has been received, False otherwise. If a C-CANCEL
          is received then the handler should ``yield (0xFE00, None)`` and
          return.

    Yields
    ------
    status : pydicom.dataset.Dataset or int
        The status returned to the peer AE in the C-FIND response. Must be
        a valid C-FIND status vuale for the applicable Service Class as
        either an ``int`` or a ``Dataset`` object containing (at a minimum)
        a (0000,0900) *Status* element. If returning a ``Dataset`` object then
        it may also contain optional elements related to the *Status* (as in
        DICOM Standard Part 7, Annex C).
    identifier : pydicom.dataset.Dataset or None
        If the status category is 'Pending' then the *Identifier* ``Dataset``
        for a matching SOP Instance. The exact requirements for the C-FIND
        response *Identifier* are Service Class specific (see the
        DICOM Standard, Part 4).

        If the status category is 'Failure' or 'Cancel' then yield ``None``.

        If the status category is 'Success' then yield ``None``, however
        yielding a final 'Success' status is not required and will be ignored
        if necessary.

    See Also
    --------
    :py:meth:`send_c_find()<pynetdicom.association.Association.send_c_find>`
    :py:class:`C_FIND<pynetdicom.dimse_primitives.C_FIND>`
    :py:class:`QueryRetrieveServiceClass<pynetdicom.service_class.QueryRetrieveServiceClass>`
    :py:class:`BasicWorklistManagementServiceClass<pynetdicom.service_class.BasicWorklistManagementServiceClass>`
    :py:class:`RelevantPatientInformationQueryServiceClass<pynetdicom.service_class.RelevantPatientInformationQueryServiceClass>`
    :py:class:`SubstanceAdministrationQueryServiceClass<pynetdicom.service_class.SubstanceAdministrationQueryServiceClass>`
    :py:class:`HangingProtocolQueryRetrieveServiceClass<pynetdicom.service_class.HangingProtocolQueryRetrieveServiceClass>`
    :py:class:`DefinedProcedureProtocolQueryRetrieveServiceClass<pynetdicom.service_class.DefinedProcedureProtocolQueryRetrieveServiceClass>`
    :py:class:`ColorPaletteQueryRetrieveServiceClass<pynetdicom.service_class.ColorPaletteQueryRetrieveServiceClass>`
    :py:class:`ImplantTemplateQueryRetrieveServiceClass<pynetdicom.service_class.ImplantTemplateQueryRetrieveServiceClass>`

    References
    ----------

    * DICOM Standard Part 4, Annexes
      `C <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_C>`_,
      `K <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_K>`_,
      `Q <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_Q>`_,
      `U <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_U>`_,
      `V <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_V>`_,
      `X <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_X>`_,
      `BB <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_BB>`_,
      `CC <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_CC>`_
      and `HH <http://dicom.nema.org/medical/dicom/current/output/html/part04.html#chapter_HH>`_
    * DICOM Standard Part 7, Sections
      `9.1.2 <http://dicom.nema.org/medical/dicom/current/output/html/part07.html#sect_9.1.2>`_,
      `9.3.2 <http://dicom.nema.org/medical/dicom/current/output/html/part07.html#sect_9.3.2>`_
      and `Annex C <http://dicom.nema.org/medical/dicom/current/output/html/part07.html#chapter_C>`_
    """
    pass


@staticmethod
def p_generic_parameter_list_optional(p):
    """generic_parameter_list_optional : empty
                                           | generic_parameter_list"""


def check_bounds(d, xmin=None, xmax=None):
    """Check if we need to apply strict bounds."""
    if len(d) > 0:
        if xmin is not None and d.min() - xmin > 0.01 * (d.max() - d.min()):
            xmin = None
        if xmax is not None and xmax - d.max() > 0.01 * (d.max() - d.min()):
            xmax = None
    return xmin, xmax


@staticmethod
def serialize_configuration():
    """Return ModeResources, PresetResources friendlyNames serialized for an API response."""
    return []


@classmethod
def all(cls):
    """
        Returns a queryset representing all stored objects

        This is a pass-through to the model objects().all()
        """
    return cls.objects.all()


def s3_path_to_bucket_key(s3_path):
    """
    Splits out s3 file path to bucket key combination
    """
    s3_path = s3_path.replace('s3://', '')
    bucket, key = s3_path.split('/', 1)
    return bucket, key


def boundOnFinalRegret(T_RH, T_SH, T_TR, nbPlayers, nbArms):
    """ Use the upper-bound on regret when :math:`T_{RH}`, :math:`T_{SH}` and :math:`T_{TR}` and :math:`M` are known.

    - The "constant" regret of course grows linearly with :math:`T_{RH}`, :math:`T_{SH}` and :math:`T_{TR}`, as:

        .. math:: \\forall T \\geq T_{RH} + T_{SH} + T_{TR}, \\;\\; R_T \\leq M (T_{RH} + (1 - \\frac{M}{K}) T_{SH} + T_{TR}).

    .. warning:: this bound is not a deterministic result, it is only value with a certain probability (at least :math:`1 - \\delta`, if :math:`T_{RH}`, :math:`T_{SH}` and :math:`T_{TR}` is chosen as given by :func:`special_times`).

    - Cf. Theorem 1 of [Kumar et al., 2018](XXX).
    - Examples:

    >>> boundOnFinalRegret(197, 26949, -280, 2, 8)  # doctest: +ELLIPSIS
    40257.5
    >>> boundOnFinalRegret(279, 34468, 616, 2, 8)   # doctest: +ELLIPSIS
    53492.0
    >>> boundOnFinalRegret(362, 41987, 1512, 2, 8)  # doctest: +ELLIPSIS
    66728.5

        + For :math:`M=5`:

    >>> boundOnFinalRegret(197, 26949, -280, 5, 8)  # doctest: +ELLIPSIS
    50114.375
    >>> boundOnFinalRegret(279, 34468, 616, 5, 8)   # doctest: +ELLIPSIS
    69102.5
    >>> boundOnFinalRegret(362, 41987, 1512, 5, 8)  # doctest: +ELLIPSIS
    88095.625

        + For :math:`M=K=8`:

    >>> boundOnFinalRegret(197, 26949, -280, 8, 8)  # doctest: +ELLIPSIS
    -664.0  # there is something wrong with T_TR !
    >>> boundOnFinalRegret(279, 34468, 616, 8, 8)   # doctest: +ELLIPSIS
    7160.0
    >>> boundOnFinalRegret(362, 41987, 1512, 8, 8)  # doctest: +ELLIPSIS
    14992.0
    """
    return nbPlayers * (T_RH + T_SH * (1.0 - float(nbPlayers) / nbArms) + T_TR)


def get_quoted_user_id(status):
    """
    Retrieve the user id of the original tweet
    :param status: Tweet object
    :return: user id or None
    """
    try:
        return status.quoted_status.user.id if status.is_quote_status else None
    except AttributeError:
        return None


@classmethod
def get(cls, name):
    """Retrieves the value of setting

        Args:
            name (str): The key which value should be returned
        """
    return cls._settings[name]


@staticmethod
def addon_defaults_list(session=None):
    """
        Return a list of default add-ons.

        The return value must be a list with meta description following the
        `PyPI JSON api`_ specification. At the minimum 'info.name' and
        'info.version' must be supplied. e.g.

            `[{'info': {'name': 'Super Pkg', 'version': '4.2'}}]

        .. _`PyPI JSON api`:
            https://warehouse.readthedocs.io/api-reference/json/
        """
    return []


def nine(x) ->int:
    """Shorthand for int(x % 9)."""
    return int(x % 9)


def nomodify(value):
    """A modifier that does not modify the value"""
    return value


@classmethod
def header_hash(cls, header):
    """Given a header return the hash."""
    import x16r_hash
    return x16r_hash.getPoWHash(header)


@staticmethod
def _format_values(values):
    """Format entries returned by Field.values.

        Multiple entries are formatted as [entry1,entry2,entryN], single
        entries are formatted as entry1, empty values return a ..

        Args:
            values: entries in Field.values

        Returns:
            list with a single str element (as required by vcfpy)
        """
    values_set = sorted(set(values))
    if len(values_set) > 1:
        return [f"[{'|'.join(values_set)}]"]
    elif len(values_set) == 1:
        return [values_set.pop()]
    else:
        return ['.']


def __new__(mcs, cls, bases, classdict):
    """ This is executed at the beginning of runtime when CRS class is created
        """
    for direction, direction_value in [('N', '6'), ('S', '7')]:
        for zone in range(1, 61):
            classdict['UTM_{}{}'.format(zone, direction)] = '32{}{}'.format(
                direction_value, str(zone).zfill(2))
    return super().__new__(mcs, cls, bases, classdict)


def run(args):
    """Initializes the REST application with all configured component endpoints.
    """
    from clearshare import app, start, stop
    start()


def decorate(decorator, base, *args, **kwargs):
    """Return function decorated with the operate decorator.

    Inline replacement for @*decorator(*args, **kwargs)*
    """
    return decorator(*args, **kwargs)(base)


def unwrap(tokens):
    """ Unwraps grouped tokens. """
    if tokens:
        return tokens[0]


@classmethod
def get_catalogue_header_value(cls, catalog, key):
    """Get `.po` header value."""
    header_value = None
    if '' in catalog:
        for line in catalog[''].split('\n'):
            if line.startswith('%s:' % key):
                header_value = line.split(':', 1)[1].strip()
    return header_value


def get(oid):
    """Return the persistent object with oid 'oid'.

        If the object was not in the cache and the object's class is
        ghostable, then a ghost will be returned.  If the object is
        already in the cache, a reference to the cached object will be
        returned.

        Applications seldom need to call this method, because objects
        are loaded transparently during attribute lookup.

        Parameters:
        oid: an object id

        Raises KeyError if oid does not exist.

            It is possible that an object does not exist as of the current
            transaction, but existed in the past.  It may even exist again in
            the future, if the transaction that removed it is undone.

        Raises ConnectionStateError if the connection is closed.
        """


def update_locals(locals_instance, instance_iterator, *args, **kwargs):
    """import all of the detector classes into the local namespace to make it
    easy to do things like `import scrubadub.detectors.NameDetector` without
    having to add each new ``Detector`` or ``Filth``
    """
    for instance in instance_iterator():
        locals_instance.update({type(instance).__name__: instance.__class__})


@classmethod
def Serial(cls):
    """Postgres Serial Type"""
    return cls(int, 'SERIAL')


@classmethod
def supports_from_pcm(cls):
    """returns True if all necessary components are available
        to support the .from_pcm() classmethod"""
    try:
        from audiotools.encoders import encode_mp3
        return True
    except ImportError:
        return False


def enhance_inst(inst, off, line, is_line_start, stack):
    """
  Add some useful fields to Instruction:
  * off: logical offset; the address of the first EXTENDED_ARG for instructions with preceding EXTENDED_ARG.
  * line: the preceding start_line if this instruction does not have one.
  * is_line_start: bool of starts_line, but also True when preceded by EXTENDED_ARG that has starts_line set.
  * stack: represents the approximate static scope of all live frames on the block stack.
  The remaining fields are flags that are set in certain cases.
  """
    inst.off = off
    inst.line = line
    inst.is_line_start = is_line_start
    inst.stack = stack
    inst.is_SF_exc_opt = False
    inst.is_exc_match = False
    inst.is_exc_match_jmp_src = False
    inst.is_exc_match_jmp_dst = False


@classmethod
def _from_lonlat(cls, coords, frame=None):
    """Create a `~MapCoord` from a tuple of coordinate vectors.

        The first two elements of the tuple should be longitude and latitude in degrees.

        Parameters
        ----------
        coords : tuple
            Tuple of `~numpy.ndarray`.

        Returns
        -------
        coord : `~MapCoord`
            A coordinates object.
        """
    if isinstance(coords, (list, tuple)):
        coords_dict = {'lon': coords[0], 'lat': coords[1]}
        for i, c in enumerate(coords[2:]):
            coords_dict[f'axis{i}'] = c
    else:
        raise ValueError('Unrecognized input type.')
    return cls(coords_dict, frame=frame, match_by_name=False)


def _get_usage(ctx):
    """Alternative, non-prefixed version of 'get_usage'."""
    formatter = ctx.make_formatter()
    pieces = ctx.command.collect_usage_pieces(ctx)
    formatter.write_usage(ctx.command_path, ' '.join(pieces), prefix='')
    return formatter.getvalue().rstrip('\n')


@classmethod
def configure_arggroup(cls, parser):
    """Configure argument parser."""
    parser.add_argument('--ecm-plot', help=
        'Filename to save ECM plot to (supported extensions: pdf, png, svg and eps)'
        )


def get_common_kwargs(**kwargs):
    """
    Get common kwargs for the ColourMap/ColourMap3, SpotPlot and derived classes
    kwargs...
        palette: A Bokeh palette for the colour mapping
        cfile: path to a file RGBA floats for palette (will be used instead of palette if not None)
        revcols: reverse colour palette if True
        xlab: x axis label
        ylab: y axis label
        zlab: z axis label
        dmlab: data label
        rmin: minimum value for the colour scale (no autoscaling if neither this nor rmax is None)
        rmax: maximum value for the colour scale
        xran: x axis range
        yran: y axis range
    """
    palette = kwargs.get('palette', 'Viridis256')
    cfile = kwargs.get('cfile', 'jet.txt')
    revcols = kwargs.get('revcols', False)
    xlab = kwargs.get('xlab', 'x')
    ylab = kwargs.get('ylab', 'y')
    zlab = kwargs.get('zlab', 'Index')
    dmlab = kwargs.get('dmlab', 'Data')
    rmin = kwargs.get('rmin', None)
    rmax = kwargs.get('rmax', None)
    xran = kwargs.get('xran', None)
    yran = kwargs.get('yran', None)
    return (palette, cfile, revcols, xlab, ylab, zlab, dmlab, rmin, rmax,
        xran, yran)


def centroid(positions):
    """
    Centroid is the mean position of all the points in all of the coordinate
    directions, from a vectorset X.

    https://en.wikipedia.org/wiki/Centroid

    C = sum(X)/len(X)

    Parameters
    ----------
    X : array
        (N,D) matrix, where N is points and D is dimension.

    Returns
    -------
    C : float
        centroid
    """
    return positions.mean(axis=0)


@classmethod
def run_model(cls, model, inputs, device=None, **kwargs):
    """
        Compute the prediction.

        :param model: :class:`onnxruntime.InferenceSession` returned
            by function *prepare*
        :param inputs: inputs
        :param device: requested device for the computation,
            None means the default one which depends on
            the compilation settings
        :param kwargs: see :class:`onnxruntime.RunOptions`
        :return: predictions
        """
    rep = cls.prepare(model, device, **kwargs)
    return rep.run(inputs, **kwargs)


def explode_azure_storage_url(url):
    """Explode Azure Storage URL into parts
    :param url str: storage url
    :rtype: tuple
    :return: (sa, mode, ep, rpath, sas)
    """
    tmp = url.split('/')
    host = tmp[2].split('.')
    sa = host[0]
    mode = host[1].lower()
    ep = '.'.join(host[2:])
    tmp = '/'.join(tmp[3:]).split('?')
    rpath = tmp[0]
    if len(tmp) > 1:
        sas = tmp[1]
    else:
        sas = None
    return sa, mode, ep, rpath, sas


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


def read_file_1st_col_only(fname):
    """
    read a CSV file (ref_classes.csv) and return the
    list of names
    """
    lst = []
    with open(fname, 'r') as f:
        _ = f.readline()
        for line in f:
            lst.append(line.split(',')[0])
    return lst


@classmethod
def move(cls, position):
    """
        Move the scene to a new position

        :param position: new position
        :return:
        """
    cls.unbuild()
    cls.reposition(position)
    cls.build()


def get_annotation_data(context):
    """Return some metadata to be used by the `annotate_row` method below.

        This will be called only once, before lines are processed.
        If this raises an error, that annotator won't be used.
        """


def print_cmd(line, commands_file, todo_only, mode='a'):
    """
    Print unix command-line depending on the choosen output and DRS action.

    :param str line: The command-line to write.
    :param str commands_file: The output file to write command-lines, None if not.
    :param boolean todo_only: True to only print Unix command-lines to apply (i.e., as dry-run)
    :param str mode: File open() mode

    """
    if commands_file and todo_only:
        with open(commands_file, mode) as f:
            f.write('{}\n'.format(line))
    else:
        print(line)


def _normalise_path_segments(segments, absolute):
    """
    Normalises the supplied path segments.

    Collapses redundant pathing operators to produce a minimal set of path segments.

    This method expects a valid set of path segments (as exported by decompose()).

    :param segments: Path segments.
    :param absolute: True if the path is absolute, False if path is relative.
    :return: Normalised path segments.
    """
    new_segments = []
    for segment in segments:
        if segment == '.':
            continue
        if segment == '..':
            if absolute:
                if new_segments:
                    new_segments.pop()
            elif not new_segments or new_segments[-1] == '..':
                new_segments.append('..')
            else:
                new_segments.pop()
        else:
            new_segments.append(segment)
    return new_segments


def deserialize_date(string):
    """Deserializes string to date.

    :param string: str.
    :type string: str
    :return: date.
    :rtype: date
    """
    try:
        from dateutil.parser import parse
        return parse(string).date()
    except ImportError:
        return string


def _format_kpoint_path(kpoint_path):
    """
    Prepare the lines for the Wannier90 input file related to
    the kpoint_path.

    :param kpoint_path: a ParameterData containing two entries:
        a 'path' list with the labels of the endpoints of each
        path segment, and a dictionary called "point_coords" that gives the
        three (fractional) coordinates for each label.
    :return: a list of strings to be added to the input file, within the
        kpoint_info block
    """
    kinfo = kpoint_path.get_dict()
    path = kinfo.pop('path')
    point_coords = kinfo.pop('point_coords')
    res = []
    for point1, point2 in path:
        coord1 = point_coords[point1]
        coord2 = point_coords[point2]
        path_line = '{} {} {} {} '.format(point1, *coord1)
        path_line += ' {} {} {} {}'.format(point2, *coord2)
        res.append(path_line)
    return res


def total_precip(precip_largescale, precip_convective):
    """Sum of convective and large-scale precipitation.

    Parameters
    ----------
    precip_largescale, precip_convective : xarray.DataArrays
        Precipitation from grid-scale condensation and from convective
        parameterization, respectively.

    Returns
    -------
    xarray.DataArray
    """
    return precip_largescale + precip_convective


def printChoices(files):
    """Returns the choosen fileInfo object.

    files -- CKAN_API.FileInfo object list
    """
    print('\nChoose wich file to download: ')
    print(
        'Warning: English versions should be prefered due to parsing issues.\n'
        )
    limit = len(files)
    for i in range(0, limit):
        print('\t {0}. {1} ( {2} ) : {3}'.format(i + 1, files[i].get_name(),
            files[i].get_language(), files[i].get_format()))
    print('')
    choice, quit = None, False
    while quit is False and choice is None:
        choice = input('Enter file number to download (or q to quit): ')
        if choice.lower() == 'q':
            quit = True
        else:
            try:
                choice = int(choice)
                assert choice > 0 and choice <= limit
            except:
                print('Invalid choice.')
                choice = None
    return None if quit else files[choice - 1]


def assign_charge(mol, force_recalc=False):
    """Assign charges in physiological condition"""
    mol.require('Aromatic')
    for i, nbrs in mol.neighbors_iter():
        atom = mol.atom(i)
        nbrcnt = len(nbrs)
        if atom.symbol == 'N':
            if not atom.pi:
                mol.atom(i).charge_phys = 1
            elif nbrcnt == 1 and atom.pi == 2:
                ni = list(nbrs.keys())[0]
                conj = False
                sp2n = None
                for nni, nnb in mol.neighbors(ni).items():
                    if mol.atom(nni
                        ).symbol == 'N' and nnb.order == 2 and not mol.atom(nni
                        ).aromatic:
                        mol.atom(nni).charge_conj = 1
                        conj = True
                    elif mol.atom(nni).symbol == 'N' and nni != i:
                        sp2n = nni
                if conj:
                    mol.atom(i).charge_phys = 1
                    if sp2n is not None:
                        mol.atom(sp2n).charge_conj = 1
        elif atom.symbol == 'O' and nbrcnt == 1 and atom.pi == 2:
            ni = list(nbrs.keys())[0]
            conj = False
            if mol.atom(ni).symbol == 'N':
                mol.atom(i).n_oxide = True
                mol.atom(ni).n_oxide = True
            for nni, nnb in mol.neighbors(ni).items():
                if mol.atom(nni).symbol in ('O', 'S'
                    ) and nnb.order == 2 and not mol.atom(ni).n_oxide:
                    mol.atom(nni).charge_conj = -1
                    conj = True
            if conj:
                mol.atom(i).charge_phys = -1
        elif atom.symbol == 'S' and nbrcnt == 1:
            ni = list(nbrs.keys())[0]
            if mol.atom(ni).aromatic:
                mol.atom(i).charge_phys = -1
    mol.charge_assigned = True
    mol.descriptors.add('Phys_charge')


def explain_all_succ(fsm, state, sat):
    """
    Give all the successors of state belonging to sat.
    The returned value is a set of tuples (action, successor)
    where successor is a successor of state through action belonging to sat.

    fsm -- the fsm;
    state -- a state of fsm able to reach sat in one step;
    sat -- a BDD representing a set of states of fsm.
    """
    successors = set()
    for next in fsm.pick_all_states(fsm.post(state) & sat):
        inputs = fsm.pick_one_inputs(fsm.get_inputs_between_states(state, next)
            )
        successors.add((inputs, next))
    return successors


@classmethod
def from_connections(cls, connections):
    """
        Alternate constructor accepting `.Connection` objects.

        .. versionadded:: 2.0
        """
    group = cls()
    group.extend(connections)
    return group


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 reject_vpc_peering_connection(DryRun=None, VpcPeeringConnectionId=None):
    """
    Rejects a VPC peering connection request. The VPC peering connection must be in the pending-acceptance state. Use the  DescribeVpcPeeringConnections request to view your outstanding VPC peering connection requests. To delete an active VPC peering connection, or to delete a VPC peering connection request that you initiated, use  DeleteVpcPeeringConnection .
    See also: AWS API Documentation

    :example: response = client.reject_vpc_peering_connection(
        DryRun=True|False,
        VpcPeeringConnectionId='string'
    )

    :type DryRun: boolean
    :param DryRun: Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation . Otherwise, it is UnauthorizedOperation .

    :type VpcPeeringConnectionId: string
    :param VpcPeeringConnectionId: [REQUIRED]
            The ID of the VPC peering connection.

    :rtype: dict
    :return: {
        'Return': True|False
    }

    """
    pass


def cmp(a, b):
    """Returs -1 if a<b, 0 if a==b, and 1 if a>b.  Removed in python3."""
    return (a > b) - (a < b)


def _procesar_valid(símismo):
    """
        Esta función procesa las predicciones de un modelo para usarlas en una validación (o también calibración).
        Por ejemplo, interpola las predicciones para coincidir con las fechas de las observaciones, etc. Todo se guarda
        en los diccionarios símismo.matrs_simul['d_l_matrs_valid'] y ['matrs_valid'].
        """
    d_l_m_predics = símismo.dic_simul['d_l_m_predics_v']
    d_l_m_valid = símismo.dic_simul['d_l_m_valid']
    info = símismo.dic_simul['d_l_í_valid']
    for t_dist, l_matr in d_l_m_valid.items():
        for i, m_v in enumerate(l_matr):
            días_v_e, días_p_e = info[t_dist][i]['exactos']
            if len(días_v_e):
                m_p = d_l_m_predics[t_dist][i]
                m_v[..., días_v_e] = m_p[..., días_p_e]
            días_v_i, *días_p_i = info[t_dist][i]['interpol']
            if len(días_v_i):
                m_v[..., días_v_i] = días_p_i[1]
                m_v[..., días_v_i] -= días_p_i[0]
                m_v[..., días_v_i] *= días_p_i[2]
                m_v[..., días_v_i] += días_p_i[0]


def make_figure_agg_curves(extractors, what):
    """
    $ oq plot 'agg_curves?kind=mean&loss_type=structural' -1
    """
    import matplotlib.pyplot as plt
    fig = plt.figure()
    got = {}
    for i, ex in enumerate(extractors):
        aw = ex.get(what + '&absolute=1')
        agg_curve = aw.array.squeeze()
        got[ex.calc_id, aw.kind[0]] = agg_curve
    oq = ex.oqparam
    periods = aw.return_period
    ax = fig.add_subplot(1, 1, 1)
    ax.set_xlabel('risk_inv_time=%dy' % oq.risk_investigation_time)
    ax.set_ylabel('PoE')
    for ck, arr in got.items():
        ax.loglog(periods, agg_curve, '-', label='%s_%s' % ck)
        ax.loglog(periods, agg_curve, '.')
    ax.grid(True)
    ax.legend()
    return plt


def replace_enquote(string):
    """Replace \\enquote with proper quotes."""
    front = string[:string.find('\\enquote{')]
    back = string[string.find('\\enquote{'):].replace('}', "''", 1)
    back = back.replace('\\enquote{', '``')
    return front + back


def read_csv(filepath_or_buffer, encoding='utf8', sep='\t', **args):
    """
    Calls function `read_csv <http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html?highlight=read_csv#pandas.read_csv>`_
    with different defaults values. If the encoding is utf8 and the data is a file name, the function
    checks there is no BOM at the beginning. Otherwise, it uses the encoding ``utf-8-sig``.

    @param      encoding                encoding
    @param      filepath_or_buffer      filepath_or_buffer
    @param      sep                     column separator
    @return                             DataFrame

    .. faqref::
        :tag: pandas
        :title: Caractères bizarres en utf8 et sous Windows (BOM) ?

        .. index:: encoding, BOM, UTF8

        Sous Windows, certains logiciels comme `Notepad <http://fr.wikipedia.org/wiki/Bloc-notes_%28Windows%29>`_
        permettent d'enregister un fichier sous différents `encodings <http://en.wikipedia.org/wiki/Character_encoding>`_.
        Avec l'encoding `UTF8 <http://fr.wikipedia.org/wiki/UTF-8>`_, on a parfois un problème avec le premier caractère
        ``\\ufeff`` car Notepad ajoute ce qu'on appelle un `BOM <http://fr.wikipedia.org/wiki/Indicateur_d%27ordre_des_octets>`_.
        Par exemple ::

            import pandas
            df = pandas.read_csv("dataframe.txt",sep="\\t", encoding="utf8")
            print(df)

        Provoque une erreur des plus énervantes ::

            UnicodeEncodeError: 'charmap' codec can't encode character '\\ufeff' in position 0: character maps to <undefined>

        Pour contrecarrer ceci, il suffit de modifier l'encoding par
        `utf-8-sig <https://docs.python.org/3/library/codecs.html#encodings-and-unicode>`_ ::

            import pandas
            df = pandas.read_csv("dataframe.txt",sep="\\t", encoding="utf-8-sig")
            print(df)
    """
    import pandas
    if isinstance(filepath_or_buffer, str):
        if encoding in ['utf8', 'utf-8']:
            try:
                df = pandas.read_csv(filepath_or_buffer, encoding=encoding,
                    sep=sep, **args)
                if df.columns[0].startswith('\ufeff'):
                    raise UnicodeError(
                        "'charmap' codec can't encode characters in position 0-1325: character maps to <undefined>"
                        )
                return df
            except UnicodeDecodeError:
                df = pandas.read_csv(filepath_or_buffer, encoding=
                    'utf-8-sig', sep=sep, **args)
                return df
            except UnicodeError:
                df = pandas.read_csv(filepath_or_buffer, encoding=
                    'utf-8-sig', sep=sep, **args)
                return df
        else:
            return pandas.read_csv(filepath_or_buffer, encoding=encoding,
                sep=sep, **args)
    else:
        return pandas.read_csv(filepath_or_buffer, encoding=encoding, sep=
            sep, **args)


def parent_path(path, level):
    """ for level 3 and path /a/b/c/d/e/f this returns /a/b/c """
    return '/'.join(path.split('/')[0:level + 1])


@staticmethod
def safe_either(method, dictionary, key1, key2, default_value=None):
    """A helper-wrapper for the safe_value_2() family."""
    value = method(dictionary, key1)
    return value if value is not None else method(dictionary, key2,
        default_value)


def make_rand_recordset(zone_name, record_type):
    """Create a rand recordset by type
    This essentially just dispatches to the relevant random recordset
    creation functions.

    :param str zone_name: The zone name the recordset applies to
    :param str record_type: The type of recordset (ie A, MX, NS, etc...)
    """
    func = globals()['rand_{}_recordset'.format(record_type.lower())]
    return func(zone_name)


def fail(exception='FAILED'):
    """Mark the message as failed, with the given exception message.
        """


def printProgressBar(iteration, total, prefix='', suffix='', decimals=1,
    length=50, fill='█'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ('{0:.' + str(decimals) + 'f}').format(100 * (iteration /
        float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end='\r')
    if iteration == total:
        print()


def matched_rule_tokens_str(match):
    """
    Return an iterable of matched rule token strings given a match.
    Punctuation is removed, spaces are normalized (new line is replaced by a space),
    case is preserved.
    """
    for pos, token in enumerate(match.rule.tokens()):
        if match.ispan.start <= pos <= match.ispan.end:
            if pos in match.ispan:
                yield token
            else:
                yield '<%s>' % token


@classmethod
def _screaming_snake_case(cls, text):
    """
        Transform text to SCREAMING_SNAKE_CASE

        :param text:
        :return:
        """
    if text.isupper():
        return text
    result = ''
    for pos, symbol in enumerate(text):
        if symbol.isupper() and pos > 0:
            result += '_' + symbol
        else:
            result += symbol.upper()
    return result


@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
    """Make a new Triple object from a sequence or iterable"""
    result = new(cls, iterable)
    if len(result) != 3:
        raise TypeError('Expected 3 arguments, got %d' % len(result))
    return result


def get_task_name(task):
    """Return the task name (= class name)
    """
    return task.__class__.__name__


def unpack2(var, pattern, buff):
    """
    Create struct.unpack call for when pattern refers to variable.

    :param var: variable the stores the result of unpack call, ``str``
    :param pattern: name of variable that unpack will read from, ``str``
    :param buff: buffer that the unpack reads from, ``StringIO``
    """
    return '%s = struct.unpack(%s, %s)' % (var, pattern, buff)


def absolute_abundance(coverage, total_bases):
    """
	absolute abundance = (number of bases mapped to genome / total number of bases in sample) * 100
	"""
    absolute = {}
    for genome in coverage:
        absolute[genome] = []
        index = 0
        for calc in coverage[genome]:
            bases = calc[0]
            total = total_bases[index]
            absolute[genome].append(bases / total * float(100))
            index += 1
    total_assembled = [(0) for i in absolute[genome]]
    for genome in absolute:
        index = 0
        for cov in absolute[genome]:
            total_assembled[index] += cov
            index += 1
    absolute['Unassembled'] = [(100 - i) for i in total_assembled]
    return absolute


def _ordered(u, v):
    """Returns the nodes in an undirected edge in lower-triangular order"""
    return (u, v) if u < v else (v, u)


@staticmethod
def extract_demographics(data_df):
    """ Extracts demographic information (age, gender, education, affinity, experience) from
        a given dataset if the corresponding columns are available.

        Parameters
        ----------
        data_df : pd.DataFrame
            Dataframe to extract demographic information from.

        Returns
        -------
        dict(str, object)
            Dictionary containing demographic information.

        """
    demographics = {}
    demo_data = ['age', 'gender', 'education', 'affinity', 'experience']
    for data in demo_data:
        if data in data_df.columns:
            demographics[data] = data_df[data].unique().tolist()
            if len(demographics[data]) == 1:
                demographics[data] = demographics[data][0]
    return demographics


def monthdelta(date, delta):
    """because we wish datetime.timedelta had a month kwarg.

    Courtesy of: http://stackoverflow.com/a/3425124/3916180

    Parameters
    ----------
    date : datetime.date
        Date object
    delta : int
        Month delta

    Returns
    -------
    datetime.date
        New Date object with delta offset.
    """
    month, year = (date.month + delta) % 12, date.year + (date.month +
        delta - 1) // 12
    if not month:
        month = 12
    day = min(date.day, [31, 29 if year % 4 == 0 and not year % 400 == 0 else
        28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1])
    return date.replace(day=day, month=month, year=year)


def _comma_separator(i, length):
    """A separator for an entirely comma-separated list given current item
    index `i` and total list length `length`. `None` if there should be
    no separator (last item).
    """
    if length == 1:
        return None
    elif i != length - 1:
        return ', '
    else:
        return None


@staticmethod
def can_flash(target):
    """
        Check if target should be flashed by drag and drop method.
        Currently there is no reason not to try it.
        :param target: target board
        :return: True
        """
    return True


def psi_K_Li_Cl_PK74(T, P):
    """c-c'-a: potassium lithium chloride [PK74]."""
    psi = -0.01
    valid = T == 298.15
    return psi, valid


def t_INTEGER(t):
    """-?[0-9]+(?![a-fA-F0-9:.])"""
    t.value = int(t.value)
    return t


def get_windows_dir():
    """
    Return the Windows directory e.g. C:\\Windows.
    """
    from ... import compat
    windir = compat.win32api.GetWindowsDirectory()
    if not windir:
        raise SystemExit('Error: Can not determine your Windows directory')
    return windir


@classmethod
def update(cls, id, params):
    """Update an existing vlan."""
    cls.echo('Updating your vlan.')
    result = cls.call('hosting.vlan.update', cls.usable_id(id), params)
    return result


def _validate_output_feature_name_from_train_stats(output_feature_name,
    train_stats_per_model):
    """Validate prediction output_feature_name from model train stats and return it as list.

    :param output_feature_name: output_feature_name containing ground truth
    :param train_stats_per_model: list of per model train stats
    :return output_feature_names: list of output_feature_name(s) containing ground truth
    """
    output_feature_names_set = set()
    for ls in train_stats_per_model:
        for _, values in ls.items():
            for key in values:
                output_feature_names_set.add(key)
    try:
        if output_feature_name in output_feature_names_set:
            return [output_feature_name]
        else:
            return output_feature_names_set
    except TypeError:
        return output_feature_names_set


@staticmethod
def getId(obj, idFormat='_V%i_'):
    """returns an id string for the given object which has the following
           two properties:
            - It is unique for this object during all its life
            - It is a string that can be used as a variable or method name

        :param obj: (object) the python object whose id is requested
        :param idFormat: (str) a format string containing a "`%i`" which,
                         when expanded must be a valid variable name
                         (i.e. it must match
                         `[a-zA-Z_][a-zA-Z0-9_]*`). The default is `_V%i_`
        """
    return idFormat % id(obj)


def _extract_reason(kw):
    """
    Internal helper. Extracts a reason (possibly both reasons!) from
    the kwargs for a circuit failed or closed event.
    """
    try:
        reason = kw['REASON']
        try:
            reason = '{}, {}'.format(reason, kw['REMOTE_REASON'])
        except KeyError:
            pass
    except KeyError:
        reason = 'unknown'
    return reason


def import_qt(glbls):
    """ Delayed qt loader. """
    if 'QtCore' in glbls:
        return
    from projexui.qt import QtCore, QtGui, wrapVariant, uic
    from projexui.widgets.xloggersplashscreen import XLoggerSplashScreen
    glbls['QtCore'] = QtCore
    glbls['QtGui'] = QtGui
    glbls['wrapVariant'] = wrapVariant
    glbls['uic'] = uic
    glbls['XLoggerSplashScreen'] = XLoggerSplashScreen


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

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

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


def _ignorefiles():
    """Return a list of files containing patterns to ignore."""